From 9c206db6302709bb5ffea09fd327036cc51f30fd Mon Sep 17 00:00:00 2001 From: Steveice10 <1269164+Steveice10@users.noreply.github.com> Date: Mon, 9 Jan 2023 09:28:18 -0800 Subject: [PATCH] video_core: Move some common state management out of specific render backends. (#15) --- src/video_core/rasterizer_accelerated.cpp | 99 ++++++++++++++++--- src/video_core/rasterizer_accelerated.h | 9 ++ .../renderer_opengl/gl_rasterizer.cpp | 91 +++++------------ .../renderer_opengl/gl_rasterizer.h | 6 +- .../renderer_opengl/gl_shader_gen.cpp | 50 +--------- .../renderer_opengl/gl_shader_manager.cpp | 25 ++--- .../renderer_opengl/gl_shader_manager.h | 80 --------------- .../renderer_vulkan/vk_instance.cpp | 5 +- .../renderer_vulkan/vk_rasterizer.cpp | 86 ++++------------ .../renderer_vulkan/vk_rasterizer.h | 9 +- .../renderer_vulkan/vk_shader_gen.cpp | 51 +--------- src/video_core/shader/shader_uniforms.cpp | 52 ++++++++++ src/video_core/shader/shader_uniforms.h | 2 + 13 files changed, 203 insertions(+), 362 deletions(-) diff --git a/src/video_core/rasterizer_accelerated.cpp b/src/video_core/rasterizer_accelerated.cpp index 904be2ea0..75dcbf571 100644 --- a/src/video_core/rasterizer_accelerated.cpp +++ b/src/video_core/rasterizer_accelerated.cpp @@ -221,6 +221,42 @@ RasterizerAccelerated::VertexArrayInfo RasterizerAccelerated::AnalyzeVertexArray return {vertex_min, vertex_max, vs_input_size}; } +void RasterizerAccelerated::SyncEntireState() { + // Sync renderer-specific fixed-function state + SyncFixedState(); + + // Sync uniforms + SyncClipCoef(); + SyncDepthScale(); + SyncDepthOffset(); + SyncAlphaTest(); + SyncCombinerColor(); + auto& tev_stages = Pica::g_state.regs.texturing.GetTevStages(); + for (std::size_t index = 0; index < tev_stages.size(); ++index) + SyncTevConstColor(index, tev_stages[index]); + + SyncGlobalAmbient(); + for (unsigned light_index = 0; light_index < 8; light_index++) { + SyncLightSpecular0(light_index); + SyncLightSpecular1(light_index); + SyncLightDiffuse(light_index); + SyncLightAmbient(light_index); + SyncLightPosition(light_index); + SyncLightDistanceAttenuationBias(light_index); + SyncLightDistanceAttenuationScale(light_index); + } + + SyncFogColor(); + SyncProcTexNoise(); + SyncProcTexBias(); + SyncShadowBias(); + SyncShadowTextureBias(); + + for (unsigned tex_index = 0; tex_index < 3; tex_index++) { + SyncTextureLodBias(tex_index); + } +} + void RasterizerAccelerated::NotifyPicaRegisterChanged(u32 id) { const auto& regs = Pica::g_state.regs; @@ -655,6 +691,14 @@ void RasterizerAccelerated::NotifyPicaRegisterChanged(u32 id) { SyncTextureLodBias(2); break; + // Clipping plane + case PICA_REG_INDEX(rasterizer.clip_coef[0]): + case PICA_REG_INDEX(rasterizer.clip_coef[1]): + case PICA_REG_INDEX(rasterizer.clip_coef[2]): + case PICA_REG_INDEX(rasterizer.clip_coef[3]): + SyncClipCoef(); + break; + default: // Forward registers that map to fixed function API features to the video backend NotifyFixedFunctionPicaRegisterChanged(id); @@ -682,40 +726,52 @@ void RasterizerAccelerated::SyncDepthOffset() { } void RasterizerAccelerated::SyncFogColor() { - const auto& regs = Pica::g_state.regs; - uniform_block_data.data.fog_color = { - regs.texturing.fog_color.r.Value() / 255.0f, - regs.texturing.fog_color.g.Value() / 255.0f, - regs.texturing.fog_color.b.Value() / 255.0f, + const auto& fog_color_regs = Pica::g_state.regs.texturing.fog_color; + const Common::Vec3f fog_color = { + fog_color_regs.r.Value() / 255.0f, + fog_color_regs.g.Value() / 255.0f, + fog_color_regs.b.Value() / 255.0f, }; - uniform_block_data.dirty = true; + + if (fog_color != uniform_block_data.data.fog_color) { + uniform_block_data.data.fog_color = fog_color; + uniform_block_data.dirty = true; + } } void RasterizerAccelerated::SyncProcTexNoise() { const auto& regs = Pica::g_state.regs.texturing; - uniform_block_data.data.proctex_noise_f = { + const Common::Vec2f proctex_noise_f = { Pica::float16::FromRaw(regs.proctex_noise_frequency.u).ToFloat32(), Pica::float16::FromRaw(regs.proctex_noise_frequency.v).ToFloat32(), }; - uniform_block_data.data.proctex_noise_a = { + const Common::Vec2f proctex_noise_a = { regs.proctex_noise_u.amplitude / 4095.0f, regs.proctex_noise_v.amplitude / 4095.0f, }; - uniform_block_data.data.proctex_noise_p = { + const Common::Vec2f proctex_noise_p = { Pica::float16::FromRaw(regs.proctex_noise_u.phase).ToFloat32(), Pica::float16::FromRaw(regs.proctex_noise_v.phase).ToFloat32(), }; - uniform_block_data.dirty = true; + if (proctex_noise_f != uniform_block_data.data.proctex_noise_f || + proctex_noise_a != uniform_block_data.data.proctex_noise_a || + proctex_noise_p != uniform_block_data.data.proctex_noise_p) { + uniform_block_data.data.proctex_noise_f = proctex_noise_f; + uniform_block_data.data.proctex_noise_a = proctex_noise_a; + uniform_block_data.data.proctex_noise_p = proctex_noise_p; + uniform_block_data.dirty = true; + } } void RasterizerAccelerated::SyncProcTexBias() { const auto& regs = Pica::g_state.regs.texturing; - uniform_block_data.data.proctex_bias = - Pica::float16::FromRaw(regs.proctex.bias_low | (regs.proctex_lut.bias_high << 8)) - .ToFloat32(); - - uniform_block_data.dirty = true; + const auto proctex_bias = Pica::float16::FromRaw(regs.proctex.bias_low | + (regs.proctex_lut.bias_high << 8)).ToFloat32(); + if (proctex_bias != uniform_block_data.data.proctex_bias) { + uniform_block_data.data.proctex_bias = proctex_bias; + uniform_block_data.dirty = true; + } } void RasterizerAccelerated::SyncAlphaTest() { @@ -790,7 +846,8 @@ void RasterizerAccelerated::SyncLightPosition(int light_index) { const Common::Vec3f position = { Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].x).ToFloat32(), Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].y).ToFloat32(), - Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].z).ToFloat32()}; + Pica::float16::FromRaw(Pica::g_state.regs.lighting.light[light_index].z).ToFloat32(), + }; if (position != uniform_block_data.data.light_src[light_index].position) { uniform_block_data.data.light_src[light_index].position = position; @@ -861,4 +918,14 @@ void RasterizerAccelerated::SyncTextureLodBias(int tex_index) { } } +void RasterizerAccelerated::SyncClipCoef() { + const auto raw_clip_coef = Pica::g_state.regs.rasterizer.GetClipCoef(); + const Common::Vec4f new_clip_coef = {raw_clip_coef.x.ToFloat32(), raw_clip_coef.y.ToFloat32(), + raw_clip_coef.z.ToFloat32(), raw_clip_coef.w.ToFloat32()}; + if (new_clip_coef != uniform_block_data.data.clip_coef) { + uniform_block_data.data.clip_coef = new_clip_coef; + uniform_block_data.dirty = true; + } +} + } // namespace VideoCore diff --git a/src/video_core/rasterizer_accelerated.h b/src/video_core/rasterizer_accelerated.h index cf295134b..c29d08e41 100644 --- a/src/video_core/rasterizer_accelerated.h +++ b/src/video_core/rasterizer_accelerated.h @@ -23,6 +23,12 @@ public: void NotifyPicaRegisterChanged(u32 id) override; void ClearAll(bool flush) override; + /// Syncs entire status to match PICA registers + void SyncEntireState() override; + + /// Sync fixed-function pipeline state + virtual void SyncFixedState() = 0; + protected: /// Notifies that a fixed function PICA register changed to the video backend virtual void NotifyFixedFunctionPicaRegisterChanged(u32 id) = 0; @@ -88,6 +94,9 @@ protected: /// Syncs the texture LOD bias to match the PICA register void SyncTextureLodBias(int tex_index); + /// Syncs the clip coefficients to match the PICA register + void SyncClipCoef(); + protected: /// Structure that keeps tracks of the uniform state struct UniformBlockData { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index eac829cbb..8b3e6087a 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -60,9 +60,9 @@ RasterizerOpenGL::RasterizerOpenGL(Frontend::EmuWindow& emu_window, Driver& driv glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment); uniform_size_aligned_vs = - Common::AlignUp(sizeof(VSUniformData), uniform_buffer_alignment); + Common::AlignUp(sizeof(Pica::Shader::VSUniformData), uniform_buffer_alignment); uniform_size_aligned_fs = - Common::AlignUp(sizeof(UniformData), uniform_buffer_alignment); + Common::AlignUp(sizeof(Pica::Shader::UniformData), uniform_buffer_alignment); // Set vertex attributes for software shader path state.draw.vertex_array = sw_vao.handle; @@ -136,8 +136,7 @@ void RasterizerOpenGL::LoadDiskResources(const std::atomic_bool& stop_loading, shader_program_manager.LoadDiskCache(stop_loading, callback); } -void RasterizerOpenGL::SyncEntireState() { - // Sync fixed function OpenGL state +void RasterizerOpenGL::SyncFixedState() { SyncClipEnabled(); SyncCullMode(); SyncBlendEnabled(); @@ -149,37 +148,6 @@ void RasterizerOpenGL::SyncEntireState() { SyncColorWriteMask(); SyncStencilWriteMask(); SyncDepthWriteMask(); - - // Sync uniforms - SyncClipCoef(); - SyncDepthScale(); - SyncDepthOffset(); - SyncAlphaTest(); - SyncCombinerColor(); - auto& tev_stages = Pica::g_state.regs.texturing.GetTevStages(); - for (std::size_t index = 0; index < tev_stages.size(); ++index) - SyncTevConstColor(index, tev_stages[index]); - - SyncGlobalAmbient(); - for (unsigned light_index = 0; light_index < 8; light_index++) { - SyncLightSpecular0(light_index); - SyncLightSpecular1(light_index); - SyncLightDiffuse(light_index); - SyncLightAmbient(light_index); - SyncLightPosition(light_index); - SyncLightDistanceAttenuationBias(light_index); - SyncLightDistanceAttenuationScale(light_index); - } - - SyncFogColor(); - SyncProcTexNoise(); - SyncProcTexBias(); - SyncShadowBias(); - SyncShadowTextureBias(); - - for (unsigned tex_index = 0; tex_index < 3; tex_index++) { - SyncTextureLodBias(tex_index); - } } static constexpr std::array vs_attrib_types{ @@ -717,30 +685,22 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) { void RasterizerOpenGL::NotifyFixedFunctionPicaRegisterChanged(u32 id) { switch (id) { - // Culling - case PICA_REG_INDEX(rasterizer.cull_mode): - SyncCullMode(); - break; - // Clipping plane case PICA_REG_INDEX(rasterizer.clip_enable): SyncClipEnabled(); break; - case PICA_REG_INDEX(rasterizer.clip_coef[0]): - case PICA_REG_INDEX(rasterizer.clip_coef[1]): - case PICA_REG_INDEX(rasterizer.clip_coef[2]): - case PICA_REG_INDEX(rasterizer.clip_coef[3]): - SyncClipCoef(); + // Culling + case PICA_REG_INDEX(rasterizer.cull_mode): + SyncCullMode(); break; // Blending case PICA_REG_INDEX(framebuffer.output_merger.alphablend_enable): - if (driver.IsOpenGLES()) { - // With GLES, we need this in the fragment shader to emulate logic operations - shader_dirty = true; - } SyncBlendEnabled(); + // Update since logic op emulation depends on alpha blend enable. + SyncLogicOp(); + SyncColorWriteMask(); break; case PICA_REG_INDEX(framebuffer.output_merger.alpha_blending): SyncBlendFuncs(); @@ -783,11 +743,9 @@ void RasterizerOpenGL::NotifyFixedFunctionPicaRegisterChanged(u32 id) { // Logic op case PICA_REG_INDEX(framebuffer.output_merger.logic_op): - if (driver.IsOpenGLES()) { - // With GLES, we need this in the fragment shader to emulate logic operations - shader_dirty = true; - } SyncLogicOp(); + // Update since color write mask is used to emulate no-op. + SyncColorWriteMask(); break; } } @@ -1066,16 +1024,6 @@ void RasterizerOpenGL::SyncClipEnabled() { state.clip_distance[1] = Pica::g_state.regs.rasterizer.clip_enable != 0; } -void RasterizerOpenGL::SyncClipCoef() { - const auto raw_clip_coef = Pica::g_state.regs.rasterizer.GetClipCoef(); - const Common::Vec4f new_clip_coef = {raw_clip_coef.x.ToFloat32(), raw_clip_coef.y.ToFloat32(), - raw_clip_coef.z.ToFloat32(), raw_clip_coef.w.ToFloat32()}; - if (new_clip_coef != uniform_block_data.data.clip_coef) { - uniform_block_data.data.clip_coef = new_clip_coef; - uniform_block_data.dirty = true; - } -} - void RasterizerOpenGL::SyncCullMode() { const auto& regs = Pica::g_state.regs; @@ -1132,6 +1080,11 @@ void RasterizerOpenGL::SyncBlendColor() { } void RasterizerOpenGL::SyncLogicOp() { + if (driver.IsOpenGLES()) { + // With GLES, we need this in the fragment shader to emulate logic operations + shader_dirty = true; + } + const auto& regs = Pica::g_state.regs; state.logic_op = PicaToGL::LogicOp(regs.framebuffer.output_merger.logic_op); @@ -1410,18 +1363,18 @@ void RasterizerOpenGL::UploadUniforms(bool accelerate_draw) { uniform_buffer.Map(uniform_size, uniform_buffer_alignment); if (sync_vs) { - VSUniformData vs_uniforms; + Pica::Shader::VSUniformData vs_uniforms; vs_uniforms.uniforms.SetFromRegs(Pica::g_state.regs.vs, Pica::g_state.vs); std::memcpy(uniforms + used_bytes, &vs_uniforms, sizeof(vs_uniforms)); - glBindBufferRange(GL_UNIFORM_BUFFER, static_cast(UniformBindings::VS), - uniform_buffer.GetHandle(), offset + used_bytes, sizeof(VSUniformData)); + glBindBufferRange(GL_UNIFORM_BUFFER, static_cast(Pica::Shader::UniformBindings::VS), + uniform_buffer.GetHandle(), offset + used_bytes, sizeof(vs_uniforms)); used_bytes += uniform_size_aligned_vs; } if (sync_fs || invalidate) { - std::memcpy(uniforms + used_bytes, &uniform_block_data.data, sizeof(UniformData)); - glBindBufferRange(GL_UNIFORM_BUFFER, static_cast(UniformBindings::Common), - uniform_buffer.GetHandle(), offset + used_bytes, sizeof(UniformData)); + std::memcpy(uniforms + used_bytes, &uniform_block_data.data, sizeof(Pica::Shader::UniformData)); + glBindBufferRange(GL_UNIFORM_BUFFER, static_cast(Pica::Shader::UniformBindings::Common), + uniform_buffer.GetHandle(), offset + used_bytes, sizeof(Pica::Shader::UniformData)); uniform_block_data.dirty = false; used_bytes += uniform_size_aligned_fs; } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index b32a64911..49196acb4 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -42,8 +42,7 @@ public: u32 pixel_stride, ScreenInfo& screen_info); bool AccelerateDrawBatch(bool is_indexed) override; - /// Syncs entire status to match PICA registers - void SyncEntireState() override; + void SyncFixedState() override; private: struct SamplerInfo { @@ -76,9 +75,6 @@ private: /// Syncs the clip enabled status to match the PICA register void SyncClipEnabled(); - /// Syncs the clip coefficients to match the PICA register - void SyncClipCoef(); - /// Sets the OpenGL shader in accordance with the current PICA register state void SetShader(); diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 802f427ef..cf89a5bc8 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -12,6 +12,7 @@ #include "video_core/renderer_opengl/gl_shader_gen.h" #include "video_core/renderer_opengl/gl_shader_util.h" #include "video_core/renderer_opengl/gl_vars.h" +#include "video_core/shader/shader_uniforms.h" #include "video_core/video_core.h" using Pica::FramebufferRegs; @@ -23,54 +24,7 @@ using VSOutputAttributes = RasterizerRegs::VSOutputAttributes; namespace OpenGL { -constexpr std::string_view UniformBlockDef = R"( -#define NUM_TEV_STAGES 6 -#define NUM_LIGHTS 8 -#define NUM_LIGHTING_SAMPLERS 24 - -struct LightSrc { - vec3 specular_0; - vec3 specular_1; - vec3 diffuse; - vec3 ambient; - vec3 position; - vec3 spot_direction; - float dist_atten_bias; - float dist_atten_scale; -}; - -layout (std140) uniform shader_data { - int framebuffer_scale; - int alphatest_ref; - float depth_scale; - float depth_offset; - float shadow_bias_constant; - float shadow_bias_linear; - int scissor_x1; - int scissor_y1; - int scissor_x2; - int scissor_y2; - int fog_lut_offset; - int proctex_noise_lut_offset; - int proctex_color_map_offset; - int proctex_alpha_map_offset; - int proctex_lut_offset; - int proctex_diff_lut_offset; - float proctex_bias; - int shadow_texture_bias; - ivec4 lighting_lut_offset[NUM_LIGHTING_SAMPLERS / 4]; - vec3 fog_color; - vec2 proctex_noise_f; - vec2 proctex_noise_a; - vec2 proctex_noise_p; - vec3 lighting_global_ambient; - LightSrc light_src[NUM_LIGHTS]; - vec4 const_color[NUM_TEV_STAGES]; - vec4 tev_combiner_buffer_color; - vec3 tex_lod_bias; - vec4 clip_coef; -}; -)"; +const std::string UniformBlockDef = Pica::Shader::BuildShaderUniformDefinitions(); static std::string GetVertexInterfaceDeclaration(bool is_output, bool separable_shader) { std::string out; diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index ac3bf2733..69ecdb262 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp @@ -12,6 +12,7 @@ #include "video_core/renderer_opengl/gl_shader_disk_cache.h" #include "video_core/renderer_opengl/gl_shader_manager.h" #include "video_core/renderer_opengl/gl_state.h" +#include "video_core/shader/shader_uniforms.h" #include "video_core/video_core.h" namespace OpenGL { @@ -84,7 +85,7 @@ static std::tuple BuildVSConfigFromRaw( return {PicaVSConfig{raw.GetRawShaderConfig().vs, setup}, setup}; } -static void SetShaderUniformBlockBinding(GLuint shader, const char* name, UniformBindings binding, +static void SetShaderUniformBlockBinding(GLuint shader, const char* name, Pica::Shader::UniformBindings binding, std::size_t expected_size) { const GLuint ub_index = glGetUniformBlockIndex(shader, name); if (ub_index == GL_INVALID_INDEX) { @@ -99,9 +100,10 @@ static void SetShaderUniformBlockBinding(GLuint shader, const char* name, Unifor } static void SetShaderUniformBlockBindings(GLuint shader) { - SetShaderUniformBlockBinding(shader, "shader_data", UniformBindings::Common, - sizeof(UniformData)); - SetShaderUniformBlockBinding(shader, "vs_config", UniformBindings::VS, sizeof(VSUniformData)); + SetShaderUniformBlockBinding(shader, "shader_data", Pica::Shader::UniformBindings::Common, + sizeof(Pica::Shader::UniformData)); + SetShaderUniformBlockBinding(shader, "vs_config", Pica::Shader::UniformBindings::VS, + sizeof(Pica::Shader::VSUniformData)); } static void SetShaderSamplerBinding(GLuint shader, const char* name, @@ -147,21 +149,6 @@ static void SetShaderSamplerBindings(GLuint shader) { cur_state.Apply(); } -void PicaUniformsData::SetFromRegs(const Pica::ShaderRegs& regs, - const Pica::Shader::ShaderSetup& setup) { - std::transform(std::begin(setup.uniforms.b), std::end(setup.uniforms.b), std::begin(bools), - [](bool value) -> BoolAligned { return {value ? GL_TRUE : GL_FALSE}; }); - std::transform(std::begin(regs.int_uniforms), std::end(regs.int_uniforms), std::begin(i), - [](const auto& value) -> Common::Vec4u { - return {value.x.Value(), value.y.Value(), value.z.Value(), value.w.Value()}; - }); - std::transform(std::begin(setup.uniforms.f), std::end(setup.uniforms.f), std::begin(f), - [](const auto& value) -> Common::Vec4f { - return {value.x.ToFloat32(), value.y.ToFloat32(), value.z.ToFloat32(), - value.w.ToFloat32()}; - }); -} - /** * An object representing a shader program staging. It can be either a shader object or a program * object, depending on whether separable program is used. diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index 0c6ddb7c3..8561781e5 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h @@ -28,86 +28,6 @@ struct ShaderSetup; namespace OpenGL { -enum class UniformBindings : u32 { Common, VS, GS }; - -struct LightSrc { - alignas(16) Common::Vec3f specular_0; - alignas(16) Common::Vec3f specular_1; - alignas(16) Common::Vec3f diffuse; - alignas(16) Common::Vec3f ambient; - alignas(16) Common::Vec3f position; - alignas(16) Common::Vec3f spot_direction; // negated - float dist_atten_bias; - float dist_atten_scale; -}; - -/** - * Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned - * NOTE: Always keep a vec4 at the end. The GL spec is not clear wether the alignment at - * the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not. - * Not following that rule will cause problems on some AMD drivers. - */ -struct UniformData { - int framebuffer_scale; - int alphatest_ref; - float depth_scale; - float depth_offset; - float shadow_bias_constant; - float shadow_bias_linear; - int scissor_x1; - int scissor_y1; - int scissor_x2; - int scissor_y2; - int fog_lut_offset; - int proctex_noise_lut_offset; - int proctex_color_map_offset; - int proctex_alpha_map_offset; - int proctex_lut_offset; - int proctex_diff_lut_offset; - float proctex_bias; - int shadow_texture_bias; - alignas(16) Common::Vec4i lighting_lut_offset[Pica::LightingRegs::NumLightingSampler / 4]; - alignas(16) Common::Vec3f fog_color; - alignas(8) Common::Vec2f proctex_noise_f; - alignas(8) Common::Vec2f proctex_noise_a; - alignas(8) Common::Vec2f proctex_noise_p; - alignas(16) Common::Vec3f lighting_global_ambient; - LightSrc light_src[8]; - alignas(16) Common::Vec4f const_color[6]; // A vec4 color for each of the six tev stages - alignas(16) Common::Vec4f tev_combiner_buffer_color; - alignas(16) Common::Vec3f tex_lod_bias; - alignas(16) Common::Vec4f clip_coef; -}; - -static_assert(sizeof(UniformData) == 0x500, - "The size of the UniformData does not match the structure in the shader"); -static_assert(sizeof(UniformData) < 16384, - "UniformData structure must be less than 16kb as per the OpenGL spec"); - -/** - * Uniform struct for the Uniform Buffer Object that contains PICA vertex/geometry shader uniforms. - * NOTE: the same rule from UniformData also applies here. - */ -struct PicaUniformsData { - void SetFromRegs(const Pica::ShaderRegs& regs, const Pica::Shader::ShaderSetup& setup); - - struct BoolAligned { - alignas(16) int b; - }; - - std::array bools; - alignas(16) std::array i; - alignas(16) std::array f; -}; - -struct VSUniformData { - PicaUniformsData uniforms; -}; -static_assert(sizeof(VSUniformData) == 1856, - "The size of the VSUniformData does not match the structure in the shader"); -static_assert(sizeof(VSUniformData) < 16384, - "VSUniformData structure must be less than 16kb as per the OpenGL spec"); - class Driver; class OpenGLState; diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index 25c67cc10..a32701180 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -42,8 +42,9 @@ DebugHandler(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessag level = Log::Level::Info; } - LOG_GENERIC(Log::Class::Render_Vulkan, level, "{}: {}", callback_data->pMessageIdName, - callback_data->pMessage); + LOG_GENERIC(Log::Class::Render_Vulkan, level, "{}: {}", + callback_data->pMessageIdName ? callback_data->pMessageIdName : "", + callback_data->pMessage ? callback_data->pMessage : ""); return VK_FALSE; } diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index e15eb4c44..dfc09c815 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -156,42 +156,6 @@ void RasterizerVulkan::LoadDiskResources(const std::atomic_bool& stop_loading, pipeline_cache.LoadDiskCache(); } -void RasterizerVulkan::SyncEntireState() { - // Sync fixed function Vulkan state - SyncFixedState(); - - // Sync uniforms - SyncClipCoef(); - SyncDepthScale(); - SyncDepthOffset(); - SyncAlphaTest(); - SyncCombinerColor(); - auto& tev_stages = Pica::g_state.regs.texturing.GetTevStages(); - for (std::size_t index = 0; index < tev_stages.size(); ++index) - SyncTevConstColor(index, tev_stages[index]); - - SyncGlobalAmbient(); - for (unsigned light_index = 0; light_index < 8; light_index++) { - SyncLightSpecular0(light_index); - SyncLightSpecular1(light_index); - SyncLightDiffuse(light_index); - SyncLightAmbient(light_index); - SyncLightPosition(light_index); - SyncLightDistanceAttenuationBias(light_index); - SyncLightDistanceAttenuationScale(light_index); - } - - SyncFogColor(); - SyncProcTexNoise(); - SyncProcTexBias(); - SyncShadowBias(); - SyncShadowTextureBias(); - - for (unsigned tex_index = 0; tex_index < 3; tex_index++) { - SyncTextureLodBias(tex_index); - } -} - void RasterizerVulkan::SyncFixedState() { SyncClipEnabled(); SyncCullMode(); @@ -834,30 +798,22 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) { void RasterizerVulkan::NotifyFixedFunctionPicaRegisterChanged(u32 id) { switch (id) { - // Culling - case PICA_REG_INDEX(rasterizer.cull_mode): - SyncCullMode(); - break; - // Clipping plane case PICA_REG_INDEX(rasterizer.clip_enable): SyncClipEnabled(); break; - case PICA_REG_INDEX(rasterizer.clip_coef[0]): - case PICA_REG_INDEX(rasterizer.clip_coef[1]): - case PICA_REG_INDEX(rasterizer.clip_coef[2]): - case PICA_REG_INDEX(rasterizer.clip_coef[3]): - SyncClipCoef(); + // Culling + case PICA_REG_INDEX(rasterizer.cull_mode): + SyncCullMode(); break; // Blending case PICA_REG_INDEX(framebuffer.output_merger.alphablend_enable): - if (instance.NeedsLogicOpEmulation()) { - // We need this in the fragment shader to emulate logic operations - shader_dirty = true; - } SyncBlendEnabled(); + // Update since logic op emulation depends on alpha blend enable. + SyncLogicOp(); + SyncColorWriteMask(); break; case PICA_REG_INDEX(framebuffer.output_merger.alpha_blending): SyncBlendFuncs(); @@ -900,11 +856,9 @@ void RasterizerVulkan::NotifyFixedFunctionPicaRegisterChanged(u32 id) { // Logic op case PICA_REG_INDEX(framebuffer.output_merger.logic_op): - if (instance.NeedsLogicOpEmulation()) { - // We need this in the fragment shader to emulate logic operations - shader_dirty = true; - } SyncLogicOp(); + // Update since color write mask is used to emulate no-op. + SyncColorWriteMask(); break; } } @@ -1188,15 +1142,9 @@ vk::Framebuffer RasterizerVulkan::CreateFramebuffer(const FramebufferInfo& info) } void RasterizerVulkan::SyncClipEnabled() { - uniform_block_data.data.enable_clip1 = Pica::g_state.regs.rasterizer.clip_enable != 0; -} - -void RasterizerVulkan::SyncClipCoef() { - const auto raw_clip_coef = Pica::g_state.regs.rasterizer.GetClipCoef(); - const Common::Vec4f new_clip_coef = {raw_clip_coef.x.ToFloat32(), raw_clip_coef.y.ToFloat32(), - raw_clip_coef.z.ToFloat32(), raw_clip_coef.w.ToFloat32()}; - if (new_clip_coef != uniform_block_data.data.clip_coef) { - uniform_block_data.data.clip_coef = new_clip_coef; + bool clip_enabled = Pica::g_state.regs.rasterizer.clip_enable != 0; + if (clip_enabled != uniform_block_data.data.enable_clip1) { + uniform_block_data.data.enable_clip1 = clip_enabled; uniform_block_data.dirty = true; } } @@ -1234,7 +1182,13 @@ void RasterizerVulkan::SyncBlendColor() { } void RasterizerVulkan::SyncLogicOp() { + if (instance.NeedsLogicOpEmulation()) { + // We need this in the fragment shader to emulate logic operations + shader_dirty = true; + } + const auto& regs = Pica::g_state.regs; + pipeline_info.blending.logic_op.Assign(regs.framebuffer.output_merger.logic_op); const bool is_logic_op_emulated = instance.NeedsLogicOpEmulation() && !regs.framebuffer.output_merger.alphablend_enable; @@ -1244,14 +1198,14 @@ void RasterizerVulkan::SyncLogicOp() { // Color output is disabled by logic operation. We use color write mask to skip // color but allow depth write. pipeline_info.blending.color_write_mask.Assign(0); - } else { - pipeline_info.blending.logic_op.Assign(regs.framebuffer.output_merger.logic_op); } } void RasterizerVulkan::SyncColorWriteMask() { const auto& regs = Pica::g_state.regs; - const u32 color_mask = (regs.framebuffer.output_merger.depth_color_mask >> 8) & 0xF; + const u32 color_mask = regs.framebuffer.framebuffer.allow_color_write != 0 + ? (regs.framebuffer.output_merger.depth_color_mask >> 8) & 0xF + : 0; const bool is_logic_op_emulated = instance.NeedsLogicOpEmulation() && !regs.framebuffer.output_merger.alphablend_enable; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index f12c372c8..73be65b81 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -95,11 +95,7 @@ public: u32 pixel_stride, ScreenInfo& screen_info); bool AccelerateDrawBatch(bool is_indexed) override; - /// Syncs entire status to match PICA registers - void SyncEntireState() override; - - /// Sync fixed function pipeline state - void SyncFixedState(); + void SyncFixedState() override; private: void NotifyFixedFunctionPicaRegisterChanged(u32 id) override; @@ -107,9 +103,6 @@ private: /// Syncs the clip enabled status to match the PICA register void SyncClipEnabled(); - /// Syncs the clip coefficients to match the PICA register - void SyncClipCoef(); - /// Syncs the cull mode to match the PICA register void SyncCullMode(); diff --git a/src/video_core/renderer_vulkan/vk_shader_gen.cpp b/src/video_core/renderer_vulkan/vk_shader_gen.cpp index 77e7260fd..501d3b947 100644 --- a/src/video_core/renderer_vulkan/vk_shader_gen.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_gen.cpp @@ -12,6 +12,7 @@ #include "video_core/renderer_opengl/gl_shader_decompiler.h" #include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_shader_gen.h" +#include "video_core/shader/shader_uniforms.h" #include "video_core/video_core.h" using Pica::FramebufferRegs; @@ -23,55 +24,7 @@ using VSOutputAttributes = RasterizerRegs::VSOutputAttributes; namespace Vulkan { -constexpr std::string_view UniformBlockDef = R"( -#define NUM_TEV_STAGES 6 -#define NUM_LIGHTS 8 -#define NUM_LIGHTING_SAMPLERS 24 - -struct LightSrc { - vec3 specular_0; - vec3 specular_1; - vec3 diffuse; - vec3 ambient; - vec3 position; - vec3 spot_direction; - float dist_atten_bias; - float dist_atten_scale; -}; - -layout (set = 0, binding = 1, std140) uniform shader_data { - int framebuffer_scale; - int alphatest_ref; - float depth_scale; - float depth_offset; - float shadow_bias_constant; - float shadow_bias_linear; - int scissor_x1; - int scissor_y1; - int scissor_x2; - int scissor_y2; - int fog_lut_offset; - int proctex_noise_lut_offset; - int proctex_color_map_offset; - int proctex_alpha_map_offset; - int proctex_lut_offset; - int proctex_diff_lut_offset; - float proctex_bias; - int shadow_texture_bias; - bool enable_clip1; - ivec4 lighting_lut_offset[NUM_LIGHTING_SAMPLERS / 4]; - vec3 fog_color; - vec2 proctex_noise_f; - vec2 proctex_noise_a; - vec2 proctex_noise_p; - vec3 lighting_global_ambient; - LightSrc light_src[NUM_LIGHTS]; - vec4 const_color[NUM_TEV_STAGES]; - vec4 tev_combiner_buffer_color; - vec3 tex_lod_bias; - vec4 clip_coef; -}; -)"; +const std::string UniformBlockDef = Pica::Shader::BuildShaderUniformDefinitions("binding = 1,"); static std::string GetVertexInterfaceDeclaration(bool is_output) { std::string out; diff --git a/src/video_core/shader/shader_uniforms.cpp b/src/video_core/shader/shader_uniforms.cpp index 37414ec5c..cc61d9ede 100644 --- a/src/video_core/shader/shader_uniforms.cpp +++ b/src/video_core/shader/shader_uniforms.cpp @@ -23,4 +23,56 @@ void PicaUniformsData::SetFromRegs(const Pica::ShaderRegs& regs, }); } +constexpr std::string_view UniformBlockDefFormat = R"( +#define NUM_TEV_STAGES 6 +#define NUM_LIGHTS 8 +#define NUM_LIGHTING_SAMPLERS 24 +struct LightSrc {{ + vec3 specular_0; + vec3 specular_1; + vec3 diffuse; + vec3 ambient; + vec3 position; + vec3 spot_direction; + float dist_atten_bias; + float dist_atten_scale; +}}; +layout ({}std140) uniform shader_data {{ + int framebuffer_scale; + int alphatest_ref; + float depth_scale; + float depth_offset; + float shadow_bias_constant; + float shadow_bias_linear; + int scissor_x1; + int scissor_y1; + int scissor_x2; + int scissor_y2; + int fog_lut_offset; + int proctex_noise_lut_offset; + int proctex_color_map_offset; + int proctex_alpha_map_offset; + int proctex_lut_offset; + int proctex_diff_lut_offset; + float proctex_bias; + int shadow_texture_bias; + bool enable_clip1; + ivec4 lighting_lut_offset[NUM_LIGHTING_SAMPLERS / 4]; + vec3 fog_color; + vec2 proctex_noise_f; + vec2 proctex_noise_a; + vec2 proctex_noise_p; + vec3 lighting_global_ambient; + LightSrc light_src[NUM_LIGHTS]; + vec4 const_color[NUM_TEV_STAGES]; + vec4 tev_combiner_buffer_color; + vec3 tex_lod_bias; + vec4 clip_coef; +}}; +)"; + +std::string BuildShaderUniformDefinitions(const std::string& extra_layout_parameters) { + return fmt::format(UniformBlockDefFormat, extra_layout_parameters); +} + } // namespace Pica::Shader diff --git a/src/video_core/shader/shader_uniforms.h b/src/video_core/shader/shader_uniforms.h index da7b44337..a984e7c0e 100644 --- a/src/video_core/shader/shader_uniforms.h +++ b/src/video_core/shader/shader_uniforms.h @@ -96,4 +96,6 @@ static_assert(sizeof(VSUniformData) == 1856, static_assert(sizeof(VSUniformData) < 16384, "VSUniformData structure must be less than 16kb as per the OpenGL spec"); +std::string BuildShaderUniformDefinitions(const std::string& extra_layout_parameters = ""); + } // namespace Pica::Shader