diff --git a/Core/Config.cpp b/Core/Config.cpp index 5590630ec3..24052b11ee 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -696,6 +696,10 @@ struct ConfigTranslator { typedef ConfigTranslator GPUBackendTranslator; static ConfigSetting graphicsSettings[] = { + ConfigSetting("EnableCardboard", &g_Config.bEnableCardboard, false, true, true), + ConfigSetting("CardboardScreenSize", &g_Config.iCardboardScreenSize, 50, true, true), + ConfigSetting("CardboardXShift", &g_Config.iCardboardXShift, 0, true, true), + ConfigSetting("CardboardYShift", &g_Config.iCardboardXShift, 0, true, true), ConfigSetting("ShowFPSCounter", &g_Config.iShowFPSCounter, 0, true, true), ReportedConfigSetting("GraphicsBackend", &g_Config.iGPUBackend, &DefaultGPUBackend, &GPUBackendTranslator::To, &GPUBackendTranslator::From, true, false), ConfigSetting("FailedGraphicsBackends", &g_Config.sFailedGPUBackends, ""), diff --git a/Core/Config.h b/Core/Config.h index 917bda6faa..27fb772d71 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -150,6 +150,11 @@ public: bool bAutoFrameSkip; bool bFrameSkipUnthrottle; + bool bEnableCardboard; // Cardboard Master Switch + int iCardboardScreenSize; // Screen Size (in %) + int iCardboardXShift; // X-Shift of Screen (in %) + int iCardboardYShift; // Y-Shift of Screen (in %) + int iWindowX; int iWindowY; int iWindowWidth; // Windows and other windowed environments diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 0ab5b9d850..1a0bb55cce 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -782,6 +782,9 @@ void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, GEBu float v0 = 0.0f, v1 = 1.0f; MakePixelTexture(srcPixels, srcPixelFormat, srcStride, 512, 272, u1, v1); + struct CardboardSettings cardboardSettings; + GetCardboardSettings(&cardboardSettings); + // This might draw directly at the backbuffer (if so, applyPostShader is set) so if there's a post shader, we need to apply it here. // Should try to unify this path with the regular path somehow, but this simple solution works for most of the post shaders // (it always runs at output resolution so FXAA may look odd). @@ -807,9 +810,18 @@ void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, GEBu DrawTextureFlags flags = g_Config.iBufFilter == SCALE_LINEAR ? DRAWTEX_LINEAR : DRAWTEX_NEAREST; flags = flags | DRAWTEX_TO_BACKBUFFER; - // Fullscreen Image - SetViewport2D(0, 0, pixelWidth_, pixelHeight_); - DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags); + if (cardboardSettings.enabled) { + // Left Eye Image + SetViewport2D(cardboardSettings.leftEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight); + DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags | DRAWTEX_KEEP_TEX); + // Right Eye Image + SetViewport2D(cardboardSettings.rightEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight); + DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags); + } else { + // Fullscreen Image + SetViewport2D(0, 0, pixelWidth_, pixelHeight_); + DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags); + } gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE); } @@ -854,6 +866,9 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { u32 offsetX = 0; u32 offsetY = 0; + CardboardSettings cardboardSettings; + GetCardboardSettings(&cardboardSettings); + VirtualFramebuffer *vfb = GetVFBAt(displayFramebufPtr_); if (!vfb) { // Let's search for a framebuf within this range. Note that we also look for @@ -969,9 +984,19 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { // flip V. if (needBackBufferYSwap_) std::swap(v0, v1); - // Fullscreen Image - SetViewport2D(0, 0, pixelWidth_, pixelHeight_); - DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags); + if (cardboardSettings.enabled) { + // Left Eye Image + SetViewport2D(cardboardSettings.leftEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight); + DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags | DRAWTEX_KEEP_TEX); + + // Right Eye Image + SetViewport2D(cardboardSettings.rightEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight); + DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags); + } else { + // Fullscreen Image + SetViewport2D(0, 0, pixelWidth_, pixelHeight_); + DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags); + } } else if (usePostShader_ && extraFBOs_.size() == 1 && !postShaderAtOutputResolution_) { // An additional pass, post-processing shader to the extra FBO. shaderManager_->DirtyLastShader(); // dirty lastShader_ @@ -987,8 +1012,8 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { DrawTextureFlags flags = g_Config.iBufFilter == SCALE_LINEAR ? DRAWTEX_LINEAR : DRAWTEX_NEAREST; DrawActiveTexture(0, 0, fbo_w, fbo_h, fbo_w, fbo_h, 0.0f, 0.0f, 1.0f, 1.0f, ROTATION_LOCKED_HORIZONTAL, flags); - draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }); + draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); // Use the extra FBO, with applied post-processing shader, as a texture. // fbo_bind_as_texture(extraFBOs_[0], FB_COLOR_BIT, 0); @@ -1005,10 +1030,19 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { Bind2DShader(); flags = (!postShaderIsUpscalingFilter_ && g_Config.iBufFilter == SCALE_LINEAR) ? DRAWTEX_LINEAR : DRAWTEX_NEAREST; flags = flags | DRAWTEX_TO_BACKBUFFER; - // Fullscreen Image - SetViewport2D(0, 0, pixelWidth_, pixelHeight_); - draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_); - DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags); + if (g_Config.bEnableCardboard) { + // Left Eye Image + SetViewport2D(cardboardSettings.leftEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight); + DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags | DRAWTEX_KEEP_TEX); + + // Right Eye Image + SetViewport2D(cardboardSettings.rightEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight); + DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags); + } else { + // Fullscreen Image + SetViewport2D(0, 0, pixelWidth_, pixelHeight_); + DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags); + } } else { shaderManager_->DirtyLastShader(); // dirty lastShader_ BEFORE drawing draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }); @@ -1024,9 +1058,19 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { PostShaderUniforms uniforms{}; CalculatePostShaderUniforms(vfb->bufferWidth, vfb->bufferHeight, vfb->renderWidth, vfb->renderHeight, &uniforms); BindPostShader(uniforms); - // Fullscreen Image - SetViewport2D(0, 0, pixelWidth_, pixelHeight_); - DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags); + if (g_Config.bEnableCardboard) { + // Left Eye Image + SetViewport2D(cardboardSettings.leftEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight); + DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags | DRAWTEX_KEEP_TEX); + + // Right Eye Image + SetViewport2D(cardboardSettings.rightEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight); + DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags); + } else { + // Fullscreen Image + SetViewport2D(0, 0, pixelWidth_, pixelHeight_); + DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags); + } } } else if (useBufferedRendering_) { @@ -1805,6 +1849,27 @@ void FramebufferManagerCommon::CalculatePostShaderUniforms(int bufferWidth, int uniforms->video = textureCache_->VideoIsPlaying(); } +void FramebufferManagerCommon::GetCardboardSettings(CardboardSettings *cardboardSettings) { + // Calculate Cardboard Settings + float cardboardScreenScale = g_Config.iCardboardScreenSize / 100.0f; + float cardboardScreenWidth = pixelWidth_ / 2.0f * cardboardScreenScale; + float cardboardScreenHeight = pixelHeight_ / 2.0f * cardboardScreenScale; + float cardboardMaxXShift = (pixelWidth_ / 2.0f - cardboardScreenWidth) / 2.0f; + float cardboardUserXShift = g_Config.iCardboardXShift / 100.0f * cardboardMaxXShift; + float cardboardLeftEyeX = cardboardMaxXShift + cardboardUserXShift; + float cardboardRightEyeX = pixelWidth_ / 2.0f + cardboardMaxXShift - cardboardUserXShift; + float cardboardMaxYShift = pixelHeight_ / 2.0f - cardboardScreenHeight / 2.0f; + float cardboardUserYShift = g_Config.iCardboardYShift / 100.0f * cardboardMaxYShift; + float cardboardScreenY = cardboardMaxYShift + cardboardUserYShift; + + cardboardSettings->enabled = g_Config.bEnableCardboard; + cardboardSettings->leftEyeXPosition = cardboardLeftEyeX; + cardboardSettings->rightEyeXPosition = cardboardRightEyeX; + cardboardSettings->screenYPosition = cardboardScreenY; + cardboardSettings->screenWidth = cardboardScreenWidth; + cardboardSettings->screenHeight = cardboardScreenHeight; +} + Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u16 h, Draw::FBColorDepth depth) { u64 key = ((u64)reason << 48) | ((u64)depth << 32) | ((u32)w << 16) | h; auto it = tempFBOs_.find(key); diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h index 5fbcb05571..584f1014b8 100644 --- a/GPU/Common/FramebufferCommon.h +++ b/GPU/Common/FramebufferCommon.h @@ -46,6 +46,15 @@ namespace Draw { class Framebuffer; } +struct CardboardSettings { + bool enabled; + float leftEyeXPosition; + float rightEyeXPosition; + float screenYPosition; + float screenWidth; + float screenHeight; +}; + class VulkanFBO; struct PostShaderUniforms { @@ -316,6 +325,9 @@ protected: virtual void Bind2DShader() = 0; virtual void BindPostShader(const PostShaderUniforms &uniforms) = 0; + // Cardboard Settings Calculator + void GetCardboardSettings(CardboardSettings *cardboardSettings); + bool UpdateSize(); void SetNumExtraFBOs(int num); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 83bcfb8ff2..e694a74c4f 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -442,6 +442,18 @@ void GameSettingsScreen::CreateViews() { static const char *bufFilters[] = { "Linear", "Nearest", }; graphicsSettings->Add(new PopupMultiChoice(&g_Config.iBufFilter, gr->T("Screen Scaling Filter"), bufFilters, 1, ARRAY_SIZE(bufFilters), gr->GetName(), screenManager())); +#ifdef __ANDROID__ + graphicsSettings->Add(new ItemHeader(gr->T("Cardboard Settings", "Cardboard Settings"))); + CheckBox *cardboardMode = graphicsSettings->Add(new CheckBox(&g_Config.bEnableCardboard, gr->T("Enable Cardboard", "Enable Cardboard"))); + cardboardMode->SetDisabledPtr(&g_Config.bSoftwareRendering); + PopupSliderChoice * cardboardScreenSize = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iCardboardScreenSize, 30, 100, gr->T("Cardboard Screen Size", "Screen Size (in % of the viewport)"), 1, screenManager(), gr->T("% of viewport"))); + cardboardScreenSize->SetDisabledPtr(&g_Config.bSoftwareRendering); + PopupSliderChoice *cardboardXShift = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iCardboardXShift, -100, 100, gr->T("Cardboard Screen X Shift", "X Shift (in % of the void)"), 1, screenManager(), gr->T("% of the void"))); + cardboardXShift->SetDisabledPtr(&g_Config.bSoftwareRendering); + PopupSliderChoice *cardboardYShift = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iCardboardYShift, -100, 100, gr->T("Cardboard Screen Y Shift", "Y Shift (in % of the void)"), 1, screenManager(), gr->T("% of the void"))); + cardboardYShift->SetDisabledPtr(&g_Config.bSoftwareRendering); +#endif + graphicsSettings->Add(new ItemHeader(gr->T("Hack Settings", "Hack Settings (these WILL cause glitches)"))); static const char *bloomHackOptions[] = { "Off", "Safe", "Balanced", "Aggressive" }; diff --git a/android/.gitignore b/android/.gitignore index 94ec461233..4aa0d52b74 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -12,4 +12,3 @@ ui_atlas.zim.png #assets/ui_atlas.zim #jni/ui_atlas.cpp #jni/ui_atlas.h -.cxx