diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 5077c8203..d7a059fa2 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -265,7 +265,7 @@ Antialiasing Filter Reduces the amount of aliasing, resulting in smoother edges. FXAA is extremely lightweight but more aggressive and lower quality. SMAA is heavier but is higher quality and more selective with the edges it smooths. Output Scaling - The method by which the game output is scaled to the screen. Nearest doesn\'t smooth visuals but causes uneven pixels at non-integer ratios. Bilinear smooths visuals but may cause aliasing when downscaling. Adaptive uses bilinear for upscaling, but uses area sampling to downscale without creating aliasing. FSR 1 is an upscaler which allows sharpening and allows better visuals without increasing the internal resolution. This should be used with antialiasing and a minimum internal resolution of 2x Native. Sharp Bilinear looks similar to nearest but is slightly smoothed to prevent uneven pixels at non-integer ratios. + The method by which the game output is scaled to the screen. Nearest doesn\'t smooth visuals but causes uneven pixels at non-integer ratios. Bilinear smooths visuals but may cause aliasing when downscaling. Adaptive uses bilinear for upscaling, but uses area sampling to downscale without creating aliasing. FSR 1 is an upscaler which allows sharpening and allows better visuals without increasing the internal resolution, but needs to be used with antialiasing and a minimum internal resolution of 2x Native. Sharp Bilinear looks similar to nearest but is slightly smoothed to prevent uneven pixels at non-integer ratios. FSR Sharpness Specifies the strength of the sharpening pass when using FSR Delay Game Render Thread diff --git a/src/video_core/host_shaders/scaling/FSR/ffx_fsr1.h b/src/video_core/host_shaders/scaling/FSR/ffx_fsr1.h index 4e0b3d548..ae62d5a32 100644 --- a/src/video_core/host_shaders/scaling/FSR/ffx_fsr1.h +++ b/src/video_core/host_shaders/scaling/FSR/ffx_fsr1.h @@ -199,7 +199,7 @@ AF1 outputSizeInPixelsY){ con2[3]=AU1_AF1(AF1_( 2.0)*ARcpF1(inputSizeInPixelsY)); con3[0]=AU1_AF1(AF1_( 0.0)*ARcpF1(inputSizeInPixelsX)); con3[1]=AU1_AF1(AF1_( 4.0)*ARcpF1(inputSizeInPixelsY)); - con3[2]=con3[3]=0;} + con3[2]=con3[3]=0u;} //If the an offset into the input image resource A_STATIC void FsrEasuConOffset( @@ -668,8 +668,8 @@ AF1 sharpness){ varAF2(hSharp)=initAF2(sharpness,sharpness); con[0]=AU1_AF1(sharpness); con[1]=AU1_AH2_AF2(hSharp); - con[2]=0; - con[3]=0;} + con[2]=0u; + con[3]=0u;} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //_____________________________________________________________/\_______________________________________________________________ diff --git a/src/video_core/host_shaders/scaling/opengl_area_sampling.frag b/src/video_core/host_shaders/scaling/opengl_area_sampling.frag index f1991de10..9c9647e67 100644 --- a/src/video_core/host_shaders/scaling/opengl_area_sampling.frag +++ b/src/video_core/host_shaders/scaling/opengl_area_sampling.frag @@ -52,8 +52,8 @@ vec4 AreaSampling(sampler2D textureSampler, vec2 texCoords) { avg_color += area_se * texelFetch(textureSampler, ivec2(f_end.x, f_end.y), 0); // Determine the size of the pixel box. - int x_range = int(f_end.x - f_beg.x - 0.5); - int y_range = int(f_end.y - f_beg.y - 0.5); + int x_range = int(float(f_end.x) - float(f_beg.x) - 0.5); + int y_range = int(float(f_end.y) - float(f_beg.y) - 0.5); // Accumulate top and bottom edge pixels. for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x) { diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 5b99a272f..7ad1f8fab 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -124,6 +124,21 @@ RendererOpenGL::RendererOpenGL(Core::System& system, Pica::PicaCore& pica_, RendererOpenGL::~RendererOpenGL() = default; void RendererOpenGL::SwapBuffers() { +#ifdef ANDROID + // On Android, if secondary_window is defined at all, + // it means we have a second display + if (secondary_window) { + usingSecondaryLayout = true; + } else { + usingSecondaryLayout = false; + } +#else + if (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows) { + usingSecondaryLayout = true; + } else { + usingSecondaryLayout = false; + } +#endif system.perf_stats->StartSwap(); // Maintain the rasterizer's state as a priority OpenGLState prev_state = OpenGLState::GetCurState(); @@ -138,6 +153,7 @@ void RendererOpenGL::SwapBuffers() { render_window.SwapBuffers(); #else const auto& main_layout = render_window.GetFramebufferLayout(); + isSecondaryWindow = false; RenderToMailbox(main_layout, render_window.mailbox, false); #ifdef ANDROID @@ -145,6 +161,7 @@ void RendererOpenGL::SwapBuffers() { // it means we have a second display if (secondary_window) { const auto& secondary_layout = secondary_window->GetFramebufferLayout(); + isSecondaryWindow = true; RenderToMailbox(secondary_layout, secondary_window->mailbox, false); secondary_window->PollEvents(); } @@ -152,6 +169,7 @@ void RendererOpenGL::SwapBuffers() { if (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows) { ASSERT(secondary_window); const auto& secondary_layout = secondary_window->GetFramebufferLayout(); + isSecondaryWindow = true; RenderToMailbox(secondary_layout, secondary_window->mailbox, false); secondary_window->PollEvents(); } @@ -412,17 +430,25 @@ void RendererOpenGL::AllocatePPTextures(){ } void RendererOpenGL::AllocateOutputSizeTextures(){ - for (int i = 0; i < intermediateOutputSizeTextures.size(); i++){ - if (currOutputScreenRects[i].GetHeight() != 0 && currOutputScreenRects[i].GetWidth() != 0){ - for (int j = 0; j < intermediateOutputSizeTextures[0].size(); j++){ - intermediateOutputSizeTextures[i][j].Release(); - intermediateOutputSizeTextures[i][j].Create(); - intermediateOutputSizeTextures[i][j].Allocate(GL_TEXTURE_2D, 1, GL_RGBA16F, currOutputScreenRects[i].GetWidth(), currOutputScreenRects[i].GetHeight()); + for (int i = 0; i < intermediateOutputSizeTextures[isSecondaryWindow].size(); i++){ + if (currOutputScreenRects[isSecondaryWindow][i].GetHeight() != 0 && currOutputScreenRects[isSecondaryWindow][i].GetWidth() != 0){ + for (int j = 0; j < intermediateOutputSizeTextures[isSecondaryWindow][0].size(); j++){ + intermediateOutputSizeTextures[isSecondaryWindow][i][j].Release(); + intermediateOutputSizeTextures[isSecondaryWindow][i][j].Create(); + intermediateOutputSizeTextures[isSecondaryWindow][i][j].Allocate(GL_TEXTURE_2D, 1, GL_RGBA16F, currOutputScreenRects[isSecondaryWindow][i].GetWidth(), currOutputScreenRects[isSecondaryWindow][i].GetHeight()); } } } - LOG_INFO(Render_OpenGL, "Reallocated OutputSize Textures"); + LOG_INFO(Render_OpenGL, "Reallocated OutputSize Textures. PrevRects:\n{}x{}\n{}x{}\n{}x{}\nCurrRects:\n{}x{}\n{}x{}\n{}x{}", + prevOutputScreenRects[isSecondaryWindow][0].GetWidth(), prevOutputScreenRects[isSecondaryWindow][0].GetHeight(), + prevOutputScreenRects[isSecondaryWindow][1].GetWidth(), prevOutputScreenRects[isSecondaryWindow][1].GetHeight(), + prevOutputScreenRects[isSecondaryWindow][2].GetWidth(), prevOutputScreenRects[isSecondaryWindow][2].GetHeight(), + currOutputScreenRects[isSecondaryWindow][0].GetWidth(), currOutputScreenRects[isSecondaryWindow][0].GetHeight(), + currOutputScreenRects[isSecondaryWindow][1].GetWidth(), currOutputScreenRects[isSecondaryWindow][1].GetHeight(), + currOutputScreenRects[isSecondaryWindow][2].GetWidth(), currOutputScreenRects[isSecondaryWindow][2].GetHeight() + ); + // } /** @@ -589,7 +615,9 @@ void RendererOpenGL::ReloadShader(Settings::StereoRenderOption render_3d) { FSR_PASS_1_shader_frag_data += HostShaders::OPENGL_FSR_PASS1_PART3_FRAG; FSR_PASS_1_shader.Create(HostShaders::OPENGL_FSR_PASS1_VERT, FSR_PASS_1_shader_frag_data); - SharpBilinear_shader.Create(HostShaders::OPENGL_SHARPBILINEAR_VERT, HostShaders::OPENGL_SHARPBILINEAR_FRAG); + std::string SharpBilinear_shader_frag_data = fragment_shader_precision_OES; + SharpBilinear_shader_frag_data += HostShaders::OPENGL_SHARPBILINEAR_FRAG; + SharpBilinear_shader.Create(HostShaders::OPENGL_SHARPBILINEAR_VERT, SharpBilinear_shader_frag_data); state.Apply(); if (render_3d == Settings::StereoRenderOption::Anaglyph || @@ -1085,7 +1113,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree state.viewport.width = screenWidth; state.viewport.height = screenHeight; state.Apply(); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, intermediateOutputSizeTextures[currOutputScreen][0].handle, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, intermediateOutputSizeTextures[isSecondaryWindow][currOutputScreen][0].handle, 0); glClear(GL_COLOR_BUFFER_BIT); state.draw.shader_program = FSR_PASS_0_shader.handle; state.Apply(); @@ -1104,12 +1132,12 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree state.viewport.width = screenWidth; state.viewport.height = screenHeight; state.Apply(); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, intermediateOutputSizeTextures[currOutputScreen][1].handle, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, intermediateOutputSizeTextures[isSecondaryWindow][currOutputScreen][1].handle, 0); glClear(GL_COLOR_BUFFER_BIT); state.draw.shader_program = FSR_PASS_1_shader.handle; state.Apply(); AttachUniforms(); - state.texture_units[0].texture_2d = intermediateOutputSizeTextures[currOutputScreen][0].handle; + state.texture_units[0].texture_2d = intermediateOutputSizeTextures[isSecondaryWindow][currOutputScreen][0].handle; state.texture_units[0].sampler = samplers[1].handle; glUniform1f(uniform_fsr_sharpening, fsr_sharpening); glUniform4f(uniform_o_resolution, screenWidth, screenHeight, 1.0f / screenWidth, 1.0f / screenHeight); @@ -1129,7 +1157,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree state.draw.shader_program = Present_shader.handle; state.Apply(); AttachUniforms(); - state.texture_units[0].texture_2d = intermediateOutputSizeTextures[currOutputScreen][1].handle; + state.texture_units[0].texture_2d = intermediateOutputSizeTextures[isSecondaryWindow][currOutputScreen][1].handle; state.texture_units[0].sampler = samplers[1].handle; glUniform1i(uniform_color_texture, 0); glUniform1i(uniform_convert_colors, 0); @@ -1304,15 +1332,21 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f prevBottomTextureHeight = currBottomTextureHeight; //Track Layout Changes - currOutputScreenRects[0] = layout.top_screen; - currOutputScreenRects[1] = layout.bottom_screen; - currOutputScreenRects[2] = layout.additional_screen; - if (currOutputScreenRects[0] != prevOutputScreenRects[0] || currOutputScreenRects[1] != prevOutputScreenRects[1] || currOutputScreenRects[2] != prevOutputScreenRects[2]){ - AllocateOutputSizeTextures(); + currOutputScreenRects[isSecondaryWindow][0] = layout.top_screen; + currOutputScreenRects[isSecondaryWindow][1] = layout.bottom_screen; + currOutputScreenRects[isSecondaryWindow][2] = layout.additional_screen; + if (currOutputScreenRects[isSecondaryWindow][0] != prevOutputScreenRects[isSecondaryWindow][0] || currOutputScreenRects[isSecondaryWindow][1] != prevOutputScreenRects[isSecondaryWindow][1]){ + if (layout.additional_screen_enabled){ + if (currOutputScreenRects[isSecondaryWindow][2] != prevOutputScreenRects[isSecondaryWindow][2]){ + AllocateOutputSizeTextures(); + } + } else { + AllocateOutputSizeTextures(); + } } - prevOutputScreenRects[0] = currOutputScreenRects[0]; - prevOutputScreenRects[1] = currOutputScreenRects[1]; - prevOutputScreenRects[2] = currOutputScreenRects[2]; + prevOutputScreenRects[isSecondaryWindow][0] = currOutputScreenRects[isSecondaryWindow][0]; + prevOutputScreenRects[isSecondaryWindow][1] = currOutputScreenRects[isSecondaryWindow][1]; + prevOutputScreenRects[isSecondaryWindow][2] = currOutputScreenRects[isSecondaryWindow][2]; //Set the Viewport state.viewport.x = 0; diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 455959651..da759782f 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -116,9 +116,9 @@ private: std::array antialiasFBOTexture; //Intermediate Textures at output size. These are for Top Screen, Bottom Screen and Additional Screen Respectively - std::array, 3> intermediateOutputSizeTextures; - std::array, 3> prevOutputScreenRects; - std::array, 3> currOutputScreenRects; + std::array, 3>, 2> intermediateOutputSizeTextures; + std::array, 3>, 2> prevOutputScreenRects; + std::array, 3>, 2> currOutputScreenRects; int currOutputScreen; OGLTexture areatex; OGLTexture searchtex; @@ -158,6 +158,11 @@ private: float currBottomTextureWidth; float currBottomTextureHeight; std::array originalViewport; + + // Secondary Layout Fix + bool usingSecondaryLayout; + bool isSecondaryWindow; + }; } // namespace OpenGL diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index b0c82a1a4..d1bf2e26f 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -2057,10 +2057,19 @@ void RendererVulkan::DrawScreens(Frame* frame, const Layout::FramebufferLayout& currOutputScreenRects[0] = layout.top_screen; currOutputScreenRects[1] = layout.bottom_screen; currOutputScreenRects[2] = layout.additional_screen; - if (currOutputScreenRects[0] != prevOutputScreenRects[0] || currOutputScreenRects[1] != prevOutputScreenRects[1] || currOutputScreenRects[2] != prevOutputScreenRects[2]){ - AllocateOutputSizeTextures(); - CreateOutputSizeTextureFramebuffers(); + + if (currOutputScreenRects[0] != prevOutputScreenRects[0] || currOutputScreenRects[1] != prevOutputScreenRects[1]){ + if (layout.additional_screen_enabled){ + if (currOutputScreenRects[2] != prevOutputScreenRects[2]){ + AllocateOutputSizeTextures(); + CreateOutputSizeTextureFramebuffers(); + } + } else { + AllocateOutputSizeTextures(); + CreateOutputSizeTextureFramebuffers(); + } } + prevOutputScreenRects[0] = currOutputScreenRects[0]; prevOutputScreenRects[1] = currOutputScreenRects[1]; prevOutputScreenRects[2] = currOutputScreenRects[2]; diff --git a/src/video_core/shader/generator/glsl_shader_gen.h b/src/video_core/shader/generator/glsl_shader_gen.h index 5d6ad8661..e316bf78d 100644 --- a/src/video_core/shader/generator/glsl_shader_gen.h +++ b/src/video_core/shader/generator/glsl_shader_gen.h @@ -6,15 +6,17 @@ // High precision may or may not be supported in GLES3. If it isn't, use medium precision instead. static constexpr char fragment_shader_precision_OES[] = R"( -#if GL_ES +#ifdef GL_ES #ifdef GL_FRAGMENT_PRECISION_HIGH precision highp int; precision highp float; +precision highp sampler2D; precision highp samplerBuffer; precision highp uimage2D; #else precision mediump int; precision mediump float; +precision highp sampler2D; precision mediump samplerBuffer; precision mediump uimage2D; #endif // GL_FRAGMENT_PRECISION_HIGH