diff options
| author | Stenzek <stenzek@gmail.com> | 2019-10-02 12:19:47 +1000 |
|---|---|---|
| committer | Stenzek <stenzek@gmail.com> | 2019-10-02 12:19:47 +1000 |
| commit | c98a5f7dfd6d5f779c4f18735656becc4fd9f365 (patch) | |
| tree | 2fba2f65c90b7ecc8315a0f76441c12f36e539bd /Source/Core/VideoCommon | |
| parent | b44a0980eb310b221feb84a195db63b89276a053 (diff) | |
Renderer: Draw ImGui interface to both eyes
Diffstat (limited to 'Source/Core/VideoCommon')
| -rw-r--r-- | Source/Core/VideoCommon/PostProcessing.cpp | 7 | ||||
| -rw-r--r-- | Source/Core/VideoCommon/RenderBase.cpp | 129 | ||||
| -rw-r--r-- | Source/Core/VideoCommon/RenderBase.h | 13 |
3 files changed, 97 insertions, 52 deletions
diff --git a/Source/Core/VideoCommon/PostProcessing.cpp b/Source/Core/VideoCommon/PostProcessing.cpp index 0212793f98..8329b74e79 100644 --- a/Source/Core/VideoCommon/PostProcessing.cpp +++ b/Source/Core/VideoCommon/PostProcessing.cpp @@ -719,15 +719,10 @@ bool PostProcessing::CompilePixelShader() bool PostProcessing::CompilePipeline() { - // 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). - const bool use_quad_buffer_gs = g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer && - g_ActiveConfig.backend_info.api_type != APIType::OpenGL; - AbstractPipelineConfig config = {}; config.vertex_shader = m_vertex_shader.get(); config.geometry_shader = - use_quad_buffer_gs ? g_shader_cache->GetTexcoordGeometryShader() : nullptr; + g_renderer->UseGeometryShaderForUI() ? g_shader_cache->GetTexcoordGeometryShader() : nullptr; config.pixel_shader = m_pixel_shader.get(); config.rasterization_state = RenderState::GetNoCullRasterizationState(PrimitiveType::Triangles); config.depth_state = RenderState::GetNoDepthTestingDepthState(); diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 31d3192933..c533814fc8 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 @@ -916,8 +930,8 @@ static std::string GenerateImGuiVertexShader() 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 float3 v_tex0 : TEXCOORD,\n" + << " out float4 v_col0 : COLOR,\n" << " out float4 out_pos : SV_Position)\n"; } else @@ -925,14 +939,14 @@ static std::string GenerateImGuiVertexShader() 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" + << "VARYING_LOCATION(0) out float3 v_tex0;\n" + << "VARYING_LOCATION(1) out float4 v_col0;\n" << "void main()\n"; } ss << "{\n" - << " frag_uv = rawtex0;\n" - << " frag_color = rawcolor0;\n"; + << " v_tex0 = float3(rawtex0, 0.0);\n" + << " v_col0 = 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 * " @@ -955,15 +969,15 @@ static std::string GenerateImGuiPixelShader() { 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" + << "void main(in float3 v_tex0 : TEXCOORD,\n" + << " in float4 v_col0 : 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" + << "VARYING_LOCATION(0) in float3 v_tex0; \n" + << "VARYING_LOCATION(1) in float4 v_col0;\n" << "FRAGMENT_OUTPUT_LOCATION(0) out float4 ocol0;\n" << "void main()\n"; } @@ -971,9 +985,9 @@ static std::string GenerateImGuiPixelShader() ss << "{\n"; if (api_type == APIType::D3D) - ss << " ocol0 = tex0.Sample(samp0, float3(frag_uv, 0.0)) * frag_color;\n"; + ss << " ocol0 = tex0.Sample(samp0, float3(v_tex0.xy, 0.0)) * v_col0;\n"; else - ss << " ocol0 = texture(samp0, float3(frag_uv, 0.0)) * frag_color;\n"; + ss << " ocol0 = texture(samp0, float3(v_tex0.xy, 0.0)) * v_col0;\n"; ss << "}\n"; @@ -1007,21 +1021,66 @@ bool Renderer::InitializeImGui() return false; } - const std::string vertex_shader_source = GenerateImGuiVertexShader(); - const std::string pixel_shader_source = GenerateImGuiPixelShader(); + // 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, vertex_shader_source); + CreateShaderFromSource(ShaderStage::Vertex, GenerateImGuiVertexShader()); std::unique_ptr<AbstractShader> pixel_shader = - CreateShaderFromSource(ShaderStage::Pixel, pixel_shader_source); + CreateShaderFromSource(ShaderStage::Pixel, 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 +1102,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 +1194,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); diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 16ce52aaa4..b323946c5a 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -199,9 +199,6 @@ public: void SaveScreenshot(std::string filename, bool wait_for_completion); void DrawDebugText(); - // ImGui initialization depends on being able to create textures and pipelines, so do it last. - bool InitializeImGui(); - virtual void ClearScreen(const MathUtil::Rectangle<int>& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z); virtual void ReinterpretPixelData(EFBReinterpretType convtype); @@ -243,6 +240,10 @@ public: virtual std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler(); + // Returns true if a layer-expanding geometry shader should be used when rendering the user + // interface and final XFB. + bool UseGeometryShaderForUI() const; + // Returns a lock for the ImGui mutex, enabling data structures to be modified from outside. // Use with care, only non-drawing functions should be called from outside the video thread, // as the drawing is tied to a "frame". @@ -275,6 +276,12 @@ protected: void CheckFifoRecording(); void RecordVideoMemory(); + // ImGui initialization depends on being able to create textures and pipelines, so do it last. + bool InitializeImGui(); + + // Recompiles ImGui pipeline - call when stereo mode changes. + bool RecompileImGuiPipeline(); + // Sets up ImGui state for the next frame. // This function itself acquires the ImGui lock, so it should not be held. void BeginImGuiFrame(); |
