video_core: Move some common state management out of specific render backends. (#15)

This commit is contained in:
Steveice10
2023-01-09 09:28:18 -08:00
committed by GitHub
parent 447f29285f
commit 9c206db630
13 changed files with 203 additions and 362 deletions

View File

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

View File

@@ -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 {

View File

@@ -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<std::size_t>(sizeof(VSUniformData), uniform_buffer_alignment);
Common::AlignUp<std::size_t>(sizeof(Pica::Shader::VSUniformData), uniform_buffer_alignment);
uniform_size_aligned_fs =
Common::AlignUp<std::size_t>(sizeof(UniformData), uniform_buffer_alignment);
Common::AlignUp<std::size_t>(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<GLenum, 4> 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<GLuint>(UniformBindings::VS),
uniform_buffer.GetHandle(), offset + used_bytes, sizeof(VSUniformData));
glBindBufferRange(GL_UNIFORM_BUFFER, static_cast<GLuint>(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<GLuint>(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<GLuint>(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;
}

View File

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

View File

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

View File

@@ -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<PicaVSConfig, Pica::Shader::ShaderSetup> 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.

View File

@@ -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<BoolAligned, 16> bools;
alignas(16) std::array<Common::Vec4u, 4> i;
alignas(16) std::array<Common::Vec4f, 96> 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;

View File

@@ -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 : "<null>",
callback_data->pMessage ? callback_data->pMessage : "<null>");
return VK_FALSE;
}

View File

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

View File

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

View File

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

View File

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

View File

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