video_core: Move some common state management out of specific render backends. (#15)
This commit is contained in:
@@ -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
|
||||
|
@@ -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 {
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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.
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user