diff options
Diffstat (limited to 'Source/Core/VideoCommon/RenderBase.cpp')
| -rw-r--r-- | Source/Core/VideoCommon/RenderBase.cpp | 191 |
1 files changed, 75 insertions, 116 deletions
diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 31d3192933..8559ca86b6 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -59,6 +59,7 @@ #include "VideoCommon/FPSCounter.h" #include "VideoCommon/FrameDump.h" #include "VideoCommon/FramebufferManager.h" +#include "VideoCommon/FramebufferShaderGen.h" #include "VideoCommon/ImageWrite.h" #include "VideoCommon/NetPlayChatUI.h" #include "VideoCommon/NetPlayGolfUI.h" @@ -442,6 +443,13 @@ void Renderer::CheckForConfigChanges() // Notify the backend of the changes, if any. OnConfigChanged(changed_bits); + // If there's any shader changes, wait for the GPU to finish before destroying anything. + if (changed_bits & (CONFIG_CHANGE_BIT_HOST_CONFIG | CONFIG_CHANGE_BIT_MULTISAMPLES)) + { + WaitForGPUIdle(); + SetPipeline(nullptr); + } + // Framebuffer changed? if (changed_bits & (CONFIG_CHANGE_BIT_MULTISAMPLES | CONFIG_CHANGE_BIT_STEREO_MODE | CONFIG_CHANGE_BIT_TARGET_SIZE)) @@ -453,8 +461,6 @@ void Renderer::CheckForConfigChanges() if (changed_bits & (CONFIG_CHANGE_BIT_HOST_CONFIG | CONFIG_CHANGE_BIT_MULTISAMPLES)) { OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL); - WaitForGPUIdle(); - SetPipeline(nullptr); g_vertex_manager->InvalidatePipelineObject(); g_shader_cache->SetHostConfig(new_host_config); g_shader_cache->Reload(); @@ -467,6 +473,14 @@ void Renderer::CheckForConfigChanges() BPFunctions::SetViewport(); BPFunctions::SetScissor(); } + + // Stereo mode change requires recompiling our post processing pipeline and imgui pipelines for + // rendering the UI. + if (changed_bits & CONFIG_CHANGE_BIT_STEREO_MODE) + { + RecompileImGuiPipeline(); + m_post_processor->RecompilePipeline(); + } } // Create On-Screen-Messages @@ -896,90 +910,6 @@ void Renderer::RecordVideoMemory() texMem); } -static std::string GenerateImGuiVertexShader() -{ - const APIType api_type = g_ActiveConfig.backend_info.api_type; - std::stringstream ss; - - // Uniform buffer contains the viewport size, and we transform in the vertex shader. - if (api_type == APIType::D3D) - ss << "cbuffer PSBlock : register(b0) {\n"; - else if (api_type == APIType::OpenGL) - ss << "UBO_BINDING(std140, 1) uniform PSBlock {\n"; - else if (api_type == APIType::Vulkan) - ss << "UBO_BINDING(std140, 1) uniform PSBlock {\n"; - ss << "float2 u_rcp_viewport_size_mul2;\n"; - ss << "};\n"; - - if (api_type == APIType::D3D) - { - ss << "void main(in float2 rawpos : POSITION,\n" - << " in float2 rawtex0 : TEXCOORD,\n" - << " in float4 rawcolor0 : COLOR,\n" - << " out float2 frag_uv : TEXCOORD,\n" - << " out float4 frag_color : COLOR,\n" - << " out float4 out_pos : SV_Position)\n"; - } - else - { - ss << "ATTRIBUTE_LOCATION(" << SHADER_POSITION_ATTRIB << ") in float2 rawpos;\n" - << "ATTRIBUTE_LOCATION(" << SHADER_TEXTURE0_ATTRIB << ") in float2 rawtex0;\n" - << "ATTRIBUTE_LOCATION(" << SHADER_COLOR0_ATTRIB << ") in float4 rawcolor0;\n" - << "VARYING_LOCATION(0) out float2 frag_uv;\n" - << "VARYING_LOCATION(1) out float4 frag_color;\n" - << "void main()\n"; - } - - ss << "{\n" - << " frag_uv = rawtex0;\n" - << " frag_color = rawcolor0;\n"; - - ss << " " << (api_type == APIType::D3D ? "out_pos" : "gl_Position") - << "= float4(rawpos.x * u_rcp_viewport_size_mul2.x - 1.0, 1.0 - rawpos.y * " - "u_rcp_viewport_size_mul2.y, 0.0, 1.0);\n"; - - // Clip-space is flipped in Vulkan - if (api_type == APIType::Vulkan) - ss << " gl_Position.y = -gl_Position.y;\n"; - - ss << "}\n"; - return ss.str(); -} - -static std::string GenerateImGuiPixelShader() -{ - const APIType api_type = g_ActiveConfig.backend_info.api_type; - - std::stringstream ss; - if (api_type == APIType::D3D) - { - ss << "Texture2DArray tex0 : register(t0);\n" - << "SamplerState samp0 : register(s0);\n" - << "void main(in float2 frag_uv : TEXCOORD,\n" - << " in float4 frag_color : COLOR,\n" - << " out float4 ocol0 : SV_Target)\n"; - } - else - { - ss << "SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n" - << "VARYING_LOCATION(0) in float2 frag_uv; \n" - << "VARYING_LOCATION(1) in float4 frag_color;\n" - << "FRAGMENT_OUTPUT_LOCATION(0) out float4 ocol0;\n" - << "void main()\n"; - } - - ss << "{\n"; - - if (api_type == APIType::D3D) - ss << " ocol0 = tex0.Sample(samp0, float3(frag_uv, 0.0)) * frag_color;\n"; - else - ss << " ocol0 = texture(samp0, float3(frag_uv, 0.0)) * frag_color;\n"; - - ss << "}\n"; - - return ss.str(); -} - bool Renderer::InitializeImGui() { if (!ImGui::CreateContext()) @@ -1007,21 +937,66 @@ bool Renderer::InitializeImGui() return false; } - const std::string vertex_shader_source = GenerateImGuiVertexShader(); - const std::string pixel_shader_source = GenerateImGuiPixelShader(); - std::unique_ptr<AbstractShader> vertex_shader = - CreateShaderFromSource(ShaderStage::Vertex, vertex_shader_source); + // Font texture(s). + { + ImGuiIO& io = ImGui::GetIO(); + u8* font_tex_pixels; + int font_tex_width, font_tex_height; + io.Fonts->GetTexDataAsRGBA32(&font_tex_pixels, &font_tex_width, &font_tex_height); + + TextureConfig font_tex_config(font_tex_width, font_tex_height, 1, 1, 1, + AbstractTextureFormat::RGBA8, 0); + std::unique_ptr<AbstractTexture> font_tex = CreateTexture(font_tex_config); + if (!font_tex) + { + PanicAlert("Failed to create imgui texture"); + return false; + } + font_tex->Load(0, font_tex_width, font_tex_height, font_tex_width, font_tex_pixels, + sizeof(u32) * font_tex_width * font_tex_height); + + io.Fonts->TexID = font_tex.get(); + + m_imgui_textures.push_back(std::move(font_tex)); + } + + if (!RecompileImGuiPipeline()) + return false; + + m_imgui_last_frame_time = Common::Timer::GetTimeUs(); + BeginImGuiFrame(); + return true; +} + +bool Renderer::RecompileImGuiPipeline() +{ + std::unique_ptr<AbstractShader> vertex_shader = CreateShaderFromSource( + ShaderStage::Vertex, FramebufferShaderGen::GenerateImGuiVertexShader()); std::unique_ptr<AbstractShader> pixel_shader = - CreateShaderFromSource(ShaderStage::Pixel, pixel_shader_source); + CreateShaderFromSource(ShaderStage::Pixel, FramebufferShaderGen::GenerateImGuiPixelShader()); if (!vertex_shader || !pixel_shader) { PanicAlert("Failed to compile imgui shaders"); return false; } + // GS is used to render the UI to both eyes in stereo modes. + std::unique_ptr<AbstractShader> geometry_shader; + if (UseGeometryShaderForUI()) + { + geometry_shader = CreateShaderFromSource( + ShaderStage::Geometry, FramebufferShaderGen::GeneratePassthroughGeometryShader(1, 1)); + if (!geometry_shader) + { + PanicAlert("Failed to compile imgui geometry shader"); + return false; + } + } + AbstractPipelineConfig pconfig = {}; pconfig.vertex_format = m_imgui_vertex_format.get(); pconfig.vertex_shader = vertex_shader.get(); + pconfig.geometry_shader = geometry_shader.get(); pconfig.pixel_shader = pixel_shader.get(); pconfig.rasterization_state = RenderState::GetNoCullRasterizationState(PrimitiveType::Triangles); pconfig.depth_state = RenderState::GetNoDepthTestingDepthState(); @@ -1043,31 +1018,6 @@ bool Renderer::InitializeImGui() return false; } - // Font texture(s). - { - ImGuiIO& io = ImGui::GetIO(); - u8* font_tex_pixels; - int font_tex_width, font_tex_height; - io.Fonts->GetTexDataAsRGBA32(&font_tex_pixels, &font_tex_width, &font_tex_height); - - TextureConfig font_tex_config(font_tex_width, font_tex_height, 1, 1, 1, - AbstractTextureFormat::RGBA8, 0); - std::unique_ptr<AbstractTexture> font_tex = CreateTexture(font_tex_config); - if (!font_tex) - { - PanicAlert("Failed to create imgui texture"); - return false; - } - font_tex->Load(0, font_tex_width, font_tex_height, font_tex_width, font_tex_pixels, - sizeof(u32) * font_tex_width * font_tex_height); - - io.Fonts->TexID = font_tex.get(); - - m_imgui_textures.push_back(std::move(font_tex)); - } - - m_imgui_last_frame_time = Common::Timer::GetTimeUs(); - BeginImGuiFrame(); return true; } @@ -1160,6 +1110,15 @@ void Renderer::DrawImGui() m_current_framebuffer)); } +bool Renderer::UseGeometryShaderForUI() const +{ + // OpenGL doesn't render to a 2-layer backbuffer like D3D/Vulkan for quad-buffered stereo, + // instead drawing twice and the eye selected by glDrawBuffer() (see + // OGL::Renderer::RenderXFBToScreen). + return g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer && + g_ActiveConfig.backend_info.api_type != APIType::OpenGL; +} + std::unique_lock<std::mutex> Renderer::GetImGuiLock() { return std::unique_lock<std::mutex>(m_imgui_mutex); |
