diff --git a/Core/Config.cpp b/Core/Config.cpp index cb17b4881e..9870745c28 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -911,10 +911,10 @@ static ConfigSetting graphicsSettings[] = { ConfigSetting("FullScreenMulti", &g_Config.bFullScreenMulti, false), #endif - ConfigSetting("SmallDisplayZoomType", &g_Config.iSmallDisplayZoomType, &DefaultZoomType, true, true), - ConfigSetting("SmallDisplayOffsetX", &g_Config.fSmallDisplayOffsetX, 0.5f, true, true), - ConfigSetting("SmallDisplayOffsetY", &g_Config.fSmallDisplayOffsetY, 0.5f, true, true), - ConfigSetting("SmallDisplayZoomLevel", &g_Config.fSmallDisplayZoomLevel, 1.0f, true, true), + ConfigSetting("DisplayOffsetX", &g_Config.fDisplayOffsetX, 0.5f, true, true), + ConfigSetting("DisplayOffsetY", &g_Config.fDisplayOffsetY, 0.5f, true, true), + ConfigSetting("DisplayScale", &g_Config.fDisplayScale, 1.0f, true, true), + ConfigSetting("DisplayAspectRatio", &g_Config.fDisplayAspectRatio, 1.0f, true, true), ConfigSetting("ImmersiveMode", &g_Config.bImmersiveMode, true, true, true), ConfigSetting("SustainedPerformanceMode", &g_Config.bSustainedPerformanceMode, false, true, true), ConfigSetting("IgnoreScreenInsets", &g_Config.bIgnoreScreenInsets, true, true, false), diff --git a/Core/Config.h b/Core/Config.h index 8b517889b0..6e8a6e808d 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -171,11 +171,14 @@ public: int iTexFiltering; // 1 = auto , 2 = nearest , 3 = linear , 4 = auto max quality int iBufFilter; // 1 = linear, 2 = nearest - int iSmallDisplayZoomType; // Used to fit display into screen 0 = stretch, 1 = partial stretch, 2 = auto scaling, 3 = manual scaling. - float fSmallDisplayOffsetX; // Along with Y it goes from 0.0 to 1.0, XY (0.5, 0.5) = center of the screen - float fSmallDisplayOffsetY; - float fSmallDisplayZoomLevel; //This is used for zoom values, both in and out. - bool bImmersiveMode; // Mode on Android Kitkat 4.4 that hides the back button etc. + + bool bDisplayStretch; // Automatically matches the aspect ratio of the window. + float fDisplayOffsetX; + float fDisplayOffsetY; + float fDisplayScale; // Relative to the most constraining axis (x or y). + float fDisplayAspectRatio; // Stored relative to the PSP's native ratio, so 1.0 is the normal pixel aspect ratio. + + bool bImmersiveMode; // Mode on Android Kitkat 4.4 and later that hides the back button etc. bool bSustainedPerformanceMode; // Android: Slows clocks down to avoid overheating/speed fluctuations. bool bIgnoreScreenInsets; // Android: Center screen disregarding insets if this is enabled. bool bVSync; diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index ca1a72160b..943ba37721 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -2045,15 +2045,17 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o PSP_CoreParameter().fastForward = false; return 0; case EMULATOR_DEVCTL__GET_ASPECT_RATIO: - if (Memory::IsValidAddress(outPtr)) - { - float ar = static_cast(PSP_CoreParameter().pixelWidth) / static_cast(PSP_CoreParameter().pixelHeight); + if (Memory::IsValidAddress(outPtr)) { + float ar = g_Config.fDisplayAspectRatio * (480.0f / 272.0f); Memory::Write_U32(*(reinterpret_cast(&ar)), outPtr); } return 0; case EMULATOR_DEVCTL__GET_SCALE: - if (Memory::IsValidAddress(outPtr)) - Memory::Write_U32(static_cast(dp_xres) / 480.0f, outPtr); + if (Memory::IsValidAddress(outPtr)) { + // TODO: Maybe do something more sophisticated taking the longest side and screen rotation + // into account, etc. + Memory::Write_U32(static_cast(dp_xres) * g_Config.fDisplayScale / 480.0f, outPtr); + } return 0; case EMULATOR_DEVCTL__GET_LTRIGGER: //To-do diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index ce0ef039fa..f8f7149389 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -75,73 +75,58 @@ void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &f bool rotated = rotation == ROTATION_LOCKED_VERTICAL || rotation == ROTATION_LOCKED_VERTICAL180; - SmallDisplayZoom zoomType = (SmallDisplayZoom)g_Config.iSmallDisplayZoomType; + bool stretch = g_Config.bDisplayStretch; + + float offsetX = g_Config.fDisplayOffsetX; + float offsetY = g_Config.fDisplayOffsetY; + // Have to invert Y for GL + if (GetGPUBackend() == GPUBackend::OPENGL) { + offsetY = offsetY * -1.0f; + } + + float scale = g_Config.fDisplayScale; + float aspectRatioAdjust = g_Config.fDisplayAspectRatio; if (IsVREnabled()) { - zoomType = SmallDisplayZoom::STRETCH; + stretch = 0; + rotated = false; + offsetX = 0.0f; + offsetY = 0.0f; + scale = 1.0f; + aspectRatioAdjust = 1.0f; } - if (zoomType == SmallDisplayZoom::STRETCH) { - outW = frame.w; - outH = frame.h; - } else { - if (zoomType == SmallDisplayZoom::MANUAL) { - float offsetX = (g_Config.fSmallDisplayOffsetX - 0.5f) * 2.0f * frame.w + frame.x; - float offsetY = (g_Config.fSmallDisplayOffsetY - 0.5f) * 2.0f * frame.h + frame.y; - // Have to invert Y for GL - if (GetGPUBackend() == GPUBackend::OPENGL) { - offsetY = offsetY * -1.0f; - } - float customZoom = g_Config.fSmallDisplayZoomLevel; - float smallDisplayW = origW * customZoom; - float smallDisplayH = origH * customZoom; - if (!rotated) { - rc->x = floorf(((frame.w - smallDisplayW) / 2.0f) + offsetX); - rc->y = floorf(((frame.h - smallDisplayH) / 2.0f) + offsetY); - rc->w = floorf(smallDisplayW); - rc->h = floorf(smallDisplayH); - return; - } else { - rc->x = floorf(((frame.w - smallDisplayH) / 2.0f) + offsetX); - rc->y = floorf(((frame.h - smallDisplayW) / 2.0f) + offsetY); - rc->w = floorf(smallDisplayH); - rc->h = floorf(smallDisplayW); - return; - } - } else if (zoomType == SmallDisplayZoom::AUTO) { - // Stretch to 1080 for 272*4. But don't distort if not widescreen (i.e. ultrawide of halfwide.) - float pixelCrop = frame.h / 270.0f; - float resCommonWidescreen = pixelCrop - floor(pixelCrop); - if (!rotated && resCommonWidescreen == 0.0f && frame.w >= pixelCrop * 480.0f) { - rc->x = floorf((frame.w - pixelCrop * 480.0f) * 0.5f + frame.x); - rc->y = floorf(-pixelCrop + frame.y); - rc->w = floorf(pixelCrop * 480.0f); - rc->h = floorf(pixelCrop * 272.0f); - return; - } - } + float origRatio = !rotated ? origW / origH : origH / origW; + float frameRatio = frame.w / frame.h; - float origRatio = !rotated ? origW / origH : origH / origW; - float frameRatio = frame.w / frame.h; - - if (origRatio > frameRatio) { - // Image is wider than frame. Center vertically. - outW = frame.w; - outH = frame.w / origRatio; - // Stretch a little bit - if (!rotated && zoomType == SmallDisplayZoom::PARTIAL_STRETCH) - outH = (frame.h + outH) / 2.0f; // (408 + 720) / 2 = 564 + if (stretch) { + // Automatically set aspect ratio to match the display, IF the rotation matches the output display ratio! Otherwise, just + // sets standard aspect ratio because actually stretching will just look silly. + bool globalRotated = g_display_rotation == DisplayRotation::ROTATE_90 || g_display_rotation == DisplayRotation::ROTATE_270; + if (rotated == dp_yres > dp_xres) { + origRatio = frameRatio; } else { - // Image is taller than frame. Center horizontally. - outW = frame.h * origRatio; - outH = frame.h; - if (rotated && zoomType == SmallDisplayZoom::PARTIAL_STRETCH) - outW = (frame.h + outH) / 2.0f; // (408 + 720) / 2 = 564 + origRatio *= aspectRatioAdjust; } + } else { + origRatio *= aspectRatioAdjust; } - rc->x = floorf((frame.w - outW) / 2.0f + frame.x); - rc->y = floorf((frame.h - outH) / 2.0f + frame.y); + float scaledWidth = frame.w * scale; + float scaledHeight = frame.h * scale; + + if (origRatio > frameRatio) { + // Image is wider than frame. Center vertically. + outW = scaledWidth; + outH = scaledWidth / origRatio; + } else { + // Image is taller than frame. Center horizontally. + outW = scaledHeight * origRatio; + outH = scaledHeight; + } + + rc->x = floorf(frame.x + frame.w * offsetX - outW * 0.5f); + rc->y = floorf(frame.y + frame.h * offsetY - outH * 0.5f); rc->w = floorf(outW); rc->h = floorf(outH); } diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index e250da4be2..56051f6a35 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -122,6 +122,9 @@ void DrawEngineGLES::InitDeviceObjects() { } void DrawEngineGLES::DestroyDeviceObjects() { + if (!draw_) { + return; + } draw_->SetInvalidationCallback(InvalidationCallback()); // Beware: this could be called twice in a row, sometimes. diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index a126f70d8d..4244244bf9 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -88,9 +88,6 @@ bool DisplayLayoutScreen::touch(const TouchInput &touch) { using namespace UI; int mode = mode_ ? mode_->GetSelection() : 0; - if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::AUTO) { - mode = -1; - } const Bounds &screenBounds = screenManager()->getUIContext()->GetBounds(); if ((touch.flags & TOUCH_MOVE) != 0 && dragging_) { @@ -100,15 +97,15 @@ bool DisplayLayoutScreen::touch(const TouchInput &touch) { switch (mode) { case MODE_MOVE: { - g_Config.fSmallDisplayOffsetX = startDisplayOffsetX_ + relativeTouchX * 0.5f / screenBounds.w; - g_Config.fSmallDisplayOffsetY = startDisplayOffsetY_ + relativeTouchY * 0.5f / screenBounds.h; + g_Config.fDisplayOffsetX = startDisplayOffsetX_ + relativeTouchX / screenBounds.w; + g_Config.fDisplayOffsetY = startDisplayOffsetY_ + relativeTouchY / screenBounds.h; break; } case MODE_RESIZE: { // Resize. Vertical = scaling; Up should be bigger so let's negate in that direction float diffYProp = -relativeTouchY * 0.007f; - g_Config.fSmallDisplayZoomLevel = startScale_ * powf(2.0f, diffYProp); + g_Config.fDisplayScale = startScale_ * powf(2.0f, diffYProp); break; } } @@ -118,9 +115,9 @@ bool DisplayLayoutScreen::touch(const TouchInput &touch) { dragging_ = true; startX_ = touch.x; startY_ = touch.y; - startDisplayOffsetX_ = g_Config.fSmallDisplayOffsetX; - startDisplayOffsetY_ = g_Config.fSmallDisplayOffsetY; - startScale_ = g_Config.fSmallDisplayZoomLevel; + startDisplayOffsetX_ = g_Config.fDisplayOffsetX; + startDisplayOffsetY_ = g_Config.fDisplayOffsetY; + startScale_ = g_Config.fDisplayScale; } if ((touch.flags & TOUCH_UP) != 0 && dragging_) { @@ -134,29 +131,6 @@ void DisplayLayoutScreen::onFinish(DialogResult reason) { g_Config.Save("DisplayLayoutScreen::onFinish"); } -UI::EventReturn DisplayLayoutScreen::OnCenter(UI::EventParams &e) { - g_Config.fSmallDisplayOffsetX = 0.5f; - g_Config.fSmallDisplayOffsetY = 0.5f; - RecreateViews(); - return UI::EVENT_DONE; -}; - -UI::EventReturn DisplayLayoutScreen::OnZoomTypeChange(UI::EventParams &e) { - switch (g_Config.iSmallDisplayZoomType) { - case (int)SmallDisplayZoom::AUTO: - case (int)SmallDisplayZoom::PARTIAL_STRETCH: - case (int)SmallDisplayZoom::STRETCH: - g_Config.fSmallDisplayOffsetX = 0.5f; - g_Config.fSmallDisplayOffsetY = 0.5f; - break; - default: - // Not SmallDisplayZoom::MANUAL - break; - } - RecreateViews(); - return UI::EVENT_DONE; -}; - void DisplayLayoutScreen::dialogFinished(const Screen *dialog, DialogResult result) { RecreateViews(); } @@ -218,50 +192,27 @@ void DisplayLayoutScreen::CreateViews() { bRotated_ = true; } - mode_ = nullptr; - if (g_Config.iSmallDisplayZoomType >= (int)SmallDisplayZoom::AUTO) { // Scaling - if (g_Config.iSmallDisplayZoomType == (int)SmallDisplayZoom::AUTO) { - float autoBound = bounds.h / 270.0f; - // Case of screen rotated ~ only works with buffered rendering - if (bRotated_) { - autoBound = bounds.h / 480.0f; - } else { // Without rotation in common cases like 1080p we cut off 2 pixels of height, this reflects other cases - float resCommonWidescreen = autoBound - floor(autoBound); - if (resCommonWidescreen != 0.0f) { - float ratio = bounds.w / bounds.h; - if (ratio < orgRatio) { - autoBound = bounds.w / 480.0f; - } - else { - autoBound = bounds.h / 272.0f; - } - } - } - g_Config.fSmallDisplayZoomLevel = autoBound; - g_Config.fSmallDisplayOffsetX = 0.5f; - g_Config.fSmallDisplayOffsetY = 0.5f; - } else { // Manual Scaling - Choice *center = new Choice(di->T("Center"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 74)); - center->OnClick.Handle(this, &DisplayLayoutScreen::OnCenter); - root_->Add(center); - float minZoom = 1.0f; - PopupSliderChoiceFloat *zoomlvl = new PopupSliderChoiceFloat(&g_Config.fSmallDisplayZoomLevel, minZoom, 10.0f, di->T("Zoom"), 1.0f, screenManager(), di->T("* PSP res"), new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 10 + 64 + 64)); - root_->Add(zoomlvl); - mode_ = new ChoiceStrip(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 158 + 64 + 10)); - mode_->AddChoice(di->T("Move")); - mode_->AddChoice(di->T("Resize")); - mode_->SetSelection(0, false); - } - } + Choice *center = new Choice(di->T("Center"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 74)); + center->OnClick.Add([&](UI::EventParams &) { + g_Config.fDisplayOffsetX = 0.5f; + g_Config.fDisplayOffsetY = 0.5f; + return UI::EVENT_DONE; + }); + root_->Add(center); + PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&g_Config.fDisplayAspectRatio, 0.5f, 2.0f, di->T("Aspect Ratio"), screenManager(), "", new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 10 + 64 + 64)); + root_->Add(aspectRatio); + + mode_ = new ChoiceStrip(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10 + leftInset, NONE, NONE, 158 + 64 + 10)); + mode_->AddChoice(di->T("Move")); + mode_->AddChoice(di->T("Resize")); + mode_->SetSelection(0, false); if (mode_) { root_->Add(mode_); } - static const char *zoomLevels[] = { "Stretching", "Partial Stretch", "Auto Scaling", "Manual Scaling" }; - auto zoom = new PopupMultiChoice(&g_Config.iSmallDisplayZoomType, gr->T("Mode"), zoomLevels, 0, ARRAY_SIZE(zoomLevels), gr->GetName(), screenManager(), new AnchorLayoutParams(400, WRAP_CONTENT, bounds.w / 2.0f - 200.0f, NONE, NONE, 10)); - zoom->OnChoice.Handle(this, &DisplayLayoutScreen::OnZoomTypeChange); - rightColumn->Add(zoom); + auto stretch = new CheckBox(&g_Config.bDisplayStretch, gr->T("Stretched")); + rightColumn->Add(stretch); static const char *displayRotation[] = { "Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed" }; auto rotation = new PopupMultiChoice(&g_Config.iInternalScreenRotation, gr->T("Rotation"), displayRotation, 1, ARRAY_SIZE(displayRotation), co->GetName(), screenManager()); diff --git a/UI/DisplayLayoutScreen.h b/UI/DisplayLayoutScreen.h index 520e2a8f6d..6fe0f0f50e 100644 --- a/UI/DisplayLayoutScreen.h +++ b/UI/DisplayLayoutScreen.h @@ -38,9 +38,6 @@ public: const char *tag() const override { return "DisplayLayout"; } protected: - virtual UI::EventReturn OnCenter(UI::EventParams &e); - virtual UI::EventReturn OnZoomTypeChange(UI::EventParams &e); - UI::EventReturn OnPostProcShaderChange(UI::EventParams &e); void sendMessage(const char *message, const char *value) override;