@@ -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);