vk_shader_gen_spv: Implement scissor testing
* Fixes weird looking map in LBW
This commit is contained in:
@@ -766,8 +766,9 @@ void RasterizerAccelerated::SyncProcTexNoise() {
|
|||||||
|
|
||||||
void RasterizerAccelerated::SyncProcTexBias() {
|
void RasterizerAccelerated::SyncProcTexBias() {
|
||||||
const auto& regs = Pica::g_state.regs.texturing;
|
const auto& regs = Pica::g_state.regs.texturing;
|
||||||
const auto proctex_bias = Pica::float16::FromRaw(regs.proctex.bias_low |
|
const auto proctex_bias =
|
||||||
(regs.proctex_lut.bias_high << 8)).ToFloat32();
|
Pica::float16::FromRaw(regs.proctex.bias_low | (regs.proctex_lut.bias_high << 8))
|
||||||
|
.ToFloat32();
|
||||||
if (proctex_bias != uniform_block_data.data.proctex_bias) {
|
if (proctex_bias != uniform_block_data.data.proctex_bias) {
|
||||||
uniform_block_data.data.proctex_bias = proctex_bias;
|
uniform_block_data.data.proctex_bias = proctex_bias;
|
||||||
uniform_block_data.dirty = true;
|
uniform_block_data.dirty = true;
|
||||||
|
@@ -1372,8 +1372,10 @@ void RasterizerOpenGL::UploadUniforms(bool accelerate_draw) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sync_fs || invalidate) {
|
if (sync_fs || invalidate) {
|
||||||
std::memcpy(uniforms + used_bytes, &uniform_block_data.data, sizeof(Pica::Shader::UniformData));
|
std::memcpy(uniforms + used_bytes, &uniform_block_data.data,
|
||||||
glBindBufferRange(GL_UNIFORM_BUFFER, static_cast<GLuint>(Pica::Shader::UniformBindings::Common),
|
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_buffer.GetHandle(), offset + used_bytes, sizeof(Pica::Shader::UniformData));
|
||||||
uniform_block_data.dirty = false;
|
uniform_block_data.dirty = false;
|
||||||
used_bytes += uniform_size_aligned_fs;
|
used_bytes += uniform_size_aligned_fs;
|
||||||
|
@@ -334,7 +334,8 @@ private:
|
|||||||
case RegisterType::FloatUniform:
|
case RegisterType::FloatUniform:
|
||||||
if (address_register_index != 0) {
|
if (address_register_index != 0) {
|
||||||
// TODO: Verify hardware behavior of out-of-bounds register number.
|
// TODO: Verify hardware behavior of out-of-bounds register number.
|
||||||
return fmt::format("({0} + address_registers.{1} < 96 ? uniforms.f[{0} + address_registers.{1}] : vec4(0))",
|
return fmt::format("({0} + address_registers.{1} < 96 ? uniforms.f[{0} + "
|
||||||
|
"address_registers.{1}] : vec4(0))",
|
||||||
index, "xyz"[address_register_index - 1]);
|
index, "xyz"[address_register_index - 1]);
|
||||||
}
|
}
|
||||||
return fmt::format("uniforms.f[{}]", index);
|
return fmt::format("uniforms.f[{}]", index);
|
||||||
|
@@ -85,7 +85,8 @@ static std::tuple<PicaVSConfig, Pica::Shader::ShaderSetup> BuildVSConfigFromRaw(
|
|||||||
return {PicaVSConfig{raw.GetRawShaderConfig().vs, setup}, setup};
|
return {PicaVSConfig{raw.GetRawShaderConfig().vs, setup}, setup};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetShaderUniformBlockBinding(GLuint shader, const char* name, Pica::Shader::UniformBindings binding,
|
static void SetShaderUniformBlockBinding(GLuint shader, const char* name,
|
||||||
|
Pica::Shader::UniformBindings binding,
|
||||||
std::size_t expected_size) {
|
std::size_t expected_size) {
|
||||||
const GLuint ub_index = glGetUniformBlockIndex(shader, name);
|
const GLuint ub_index = glGetUniformBlockIndex(shader, name);
|
||||||
if (ub_index == GL_INVALID_INDEX) {
|
if (ub_index == GL_INVALID_INDEX) {
|
||||||
|
@@ -298,7 +298,7 @@ void PipelineCache::UseFragmentShader(const Pica::Regs& regs) {
|
|||||||
handle = fragment_shaders_spv.Get(config, instance.GetDevice());
|
handle = fragment_shaders_spv.Get(config, instance.GetDevice());
|
||||||
} else {
|
} else {
|
||||||
handle = fragment_shaders_glsl.Get(config, vk::ShaderStageFlagBits::eFragment,
|
handle = fragment_shaders_glsl.Get(config, vk::ShaderStageFlagBits::eFragment,
|
||||||
instance.GetDevice(), ShaderOptimization::High);
|
instance.GetDevice(), ShaderOptimization::Debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
current_shaders[ProgramType::FS] = handle;
|
current_shaders[ProgramType::FS] = handle;
|
||||||
|
@@ -1587,12 +1587,12 @@ void main() {
|
|||||||
gl_Position = vert_position;
|
gl_Position = vert_position;
|
||||||
gl_Position.z = (gl_Position.z + gl_Position.w) / 2.0;
|
gl_Position.z = (gl_Position.z + gl_Position.w) / 2.0;
|
||||||
|
|
||||||
//gl_ClipDistance[0] = -vert_position.z; // fixed PICA clipping plane z <= 0
|
gl_ClipDistance[0] = -vert_position.z; // fixed PICA clipping plane z <= 0
|
||||||
//if (enable_clip1) {
|
if (enable_clip1) {
|
||||||
// gl_ClipDistance[1] = dot(clip_coef, vert_position);
|
gl_ClipDistance[1] = dot(clip_coef, vert_position);
|
||||||
//} else {
|
} else {
|
||||||
// gl_ClipDistance[1] = 0;
|
gl_ClipDistance[1] = 0;
|
||||||
//}
|
}
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
|
@@ -42,6 +42,9 @@ void FragmentModule::Generate() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the fragment is outside scissor rectangle
|
||||||
|
WriteScissor();
|
||||||
|
|
||||||
// Write shader bytecode to emulate all enabled PICA lights
|
// Write shader bytecode to emulate all enabled PICA lights
|
||||||
if (config.state.lighting.enable) {
|
if (config.state.lighting.enable) {
|
||||||
WriteLighting();
|
WriteLighting();
|
||||||
@@ -56,9 +59,7 @@ void FragmentModule::Generate() {
|
|||||||
WriteTevStage(static_cast<s32>(index));
|
WriteTevStage(static_cast<s32>(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WriteAlphaTestCondition(config.state.alpha_test_func)) {
|
WriteAlphaTestCondition(config.state.alpha_test_func);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.state.fog_mode == TexturingRegs::FogMode::Gas) {
|
if (config.state.fog_mode == TexturingRegs::FogMode::Gas) {
|
||||||
Core::System::GetInstance().TelemetrySession().AddField(
|
Core::System::GetInstance().TelemetrySession().AddField(
|
||||||
@@ -124,6 +125,45 @@ void FragmentModule::WriteDepth() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FragmentModule::WriteScissor() {
|
||||||
|
if (config.state.scissor_test_mode == RasterizerRegs::ScissorMode::Disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Id input_pointer_id{TypePointer(spv::StorageClass::Input, vec_ids.Get(4))};
|
||||||
|
const Id input_pointer{OpAccessChain(input_pointer_id, gl_frag_coord_id)};
|
||||||
|
const Id gl_frag_coord{OpLoad(vec_ids.Get(4), input_pointer)};
|
||||||
|
const Id gl_frag_coord_xy{OpVectorShuffle(vec_ids.Get(2), gl_frag_coord, gl_frag_coord, 0, 1)};
|
||||||
|
|
||||||
|
const Id scissor_x1{GetShaderDataMember(i32_id, ConstS32(6))};
|
||||||
|
const Id scissor_y1{GetShaderDataMember(i32_id, ConstS32(7))};
|
||||||
|
const Id scissor_1{OpCompositeConstruct(vec_ids.Get(2), OpConvertSToF(f32_id, scissor_x1),
|
||||||
|
OpConvertSToF(f32_id, scissor_y1))};
|
||||||
|
|
||||||
|
const Id scissor_x2{GetShaderDataMember(i32_id, ConstS32(8))};
|
||||||
|
const Id scissor_y2{GetShaderDataMember(i32_id, ConstS32(9))};
|
||||||
|
const Id scissor_2{OpCompositeConstruct(vec_ids.Get(2), OpConvertSToF(f32_id, scissor_x2),
|
||||||
|
OpConvertSToF(f32_id, scissor_y2))};
|
||||||
|
|
||||||
|
const Id cond1{OpFOrdGreaterThanEqual(bvec_ids.Get(2), gl_frag_coord_xy, scissor_1)};
|
||||||
|
const Id cond2{OpFOrdLessThan(bvec_ids.Get(2), gl_frag_coord_xy, scissor_2)};
|
||||||
|
|
||||||
|
Id result{OpAll(bool_id, OpCompositeConstruct(bvec_ids.Get(4), cond1, cond2))};
|
||||||
|
if (config.state.scissor_test_mode == RasterizerRegs::ScissorMode::Include) {
|
||||||
|
result = OpLogicalNot(bool_id, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Id merge_block{OpLabel()};
|
||||||
|
const Id kill_label{OpLabel()};
|
||||||
|
OpSelectionMerge(merge_block, spv::SelectionControlMask::MaskNone);
|
||||||
|
OpBranchConditional(result, kill_label, merge_block);
|
||||||
|
|
||||||
|
AddLabel(kill_label);
|
||||||
|
OpKill();
|
||||||
|
|
||||||
|
AddLabel(merge_block);
|
||||||
|
}
|
||||||
|
|
||||||
void FragmentModule::WriteLighting() {
|
void FragmentModule::WriteLighting() {
|
||||||
const auto& lighting = config.state.lighting;
|
const auto& lighting = config.state.lighting;
|
||||||
|
|
||||||
@@ -570,7 +610,7 @@ using ProcTexShift = TexturingRegs::ProcTexShift;
|
|||||||
using ProcTexCombiner = TexturingRegs::ProcTexCombiner;
|
using ProcTexCombiner = TexturingRegs::ProcTexCombiner;
|
||||||
using ProcTexFilter = TexturingRegs::ProcTexFilter;
|
using ProcTexFilter = TexturingRegs::ProcTexFilter;
|
||||||
|
|
||||||
bool FragmentModule::WriteAlphaTestCondition(FramebufferRegs::CompareFunc func) {
|
void FragmentModule::WriteAlphaTestCondition(FramebufferRegs::CompareFunc func) {
|
||||||
using CompareFunc = FramebufferRegs::CompareFunc;
|
using CompareFunc = FramebufferRegs::CompareFunc;
|
||||||
|
|
||||||
// The compare func is to keep the fragment so we invert it to discard it
|
// The compare func is to keep the fragment so we invert it to discard it
|
||||||
@@ -593,13 +633,10 @@ bool FragmentModule::WriteAlphaTestCondition(FramebufferRegs::CompareFunc func)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Don't check for kill, this is done earlier
|
||||||
switch (func) {
|
switch (func) {
|
||||||
case CompareFunc::Never: // Kill the fragment
|
|
||||||
OpKill();
|
|
||||||
OpFunctionEnd();
|
|
||||||
return true;
|
|
||||||
case CompareFunc::Always: // Do nothing
|
case CompareFunc::Always: // Do nothing
|
||||||
return false;
|
break;
|
||||||
case CompareFunc::Equal:
|
case CompareFunc::Equal:
|
||||||
case CompareFunc::NotEqual:
|
case CompareFunc::NotEqual:
|
||||||
case CompareFunc::LessThan:
|
case CompareFunc::LessThan:
|
||||||
@@ -618,10 +655,9 @@ bool FragmentModule::WriteAlphaTestCondition(FramebufferRegs::CompareFunc func)
|
|||||||
AddLabel(kill_label);
|
AddLabel(kill_label);
|
||||||
OpKill();
|
OpKill();
|
||||||
AddLabel(keep_label);
|
AddLabel(keep_label);
|
||||||
return false;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return false;
|
|
||||||
LOG_CRITICAL(Render_Vulkan, "Unknown alpha test condition {}", func);
|
LOG_CRITICAL(Render_Vulkan, "Unknown alpha test condition {}", func);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -975,9 +1011,7 @@ void FragmentModule::DefineProcTexSampler() {
|
|||||||
const Id proctex_alpha_map_offset{GetShaderDataMember(i32_id, ConstS32(13))};
|
const Id proctex_alpha_map_offset{GetShaderDataMember(i32_id, ConstS32(13))};
|
||||||
const Id final_alpha{AppendProcTexCombineAndMap(config.state.proctex.alpha_combiner, u, v,
|
const Id final_alpha{AppendProcTexCombineAndMap(config.state.proctex.alpha_combiner, u, v,
|
||||||
proctex_alpha_map_offset)};
|
proctex_alpha_map_offset)};
|
||||||
const Id final_color_xyz{
|
final_color = OpCompositeInsert(vec_ids.Get(4), final_alpha, final_color, 3);
|
||||||
OpVectorShuffle(vec_ids.Get(3), final_color, final_color, 0, 1, 2)};
|
|
||||||
final_color = OpCompositeConstruct(vec_ids.Get(4), final_color_xyz, final_alpha);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OpReturnValue(final_color);
|
OpReturnValue(final_color);
|
||||||
|
@@ -33,9 +33,13 @@ public:
|
|||||||
/// Emits SPIR-V bytecode corresponding to the provided pica fragment configuration
|
/// Emits SPIR-V bytecode corresponding to the provided pica fragment configuration
|
||||||
void Generate();
|
void Generate();
|
||||||
|
|
||||||
/// Undos the vulkan perspective transformation and applies the pica one
|
private:
|
||||||
|
/// Undos the vulkan perspective transformation and applies the PICA one
|
||||||
void WriteDepth();
|
void WriteDepth();
|
||||||
|
|
||||||
|
/// Emits code to emulate the scissor rectangle
|
||||||
|
void WriteScissor();
|
||||||
|
|
||||||
/// Writes the code to emulate fragment lighting
|
/// Writes the code to emulate fragment lighting
|
||||||
void WriteLighting();
|
void WriteLighting();
|
||||||
|
|
||||||
@@ -46,8 +50,7 @@ public:
|
|||||||
void DefineProcTexSampler();
|
void DefineProcTexSampler();
|
||||||
|
|
||||||
/// Writes the if-statement condition used to evaluate alpha testing.
|
/// Writes the if-statement condition used to evaluate alpha testing.
|
||||||
/// Returns true if the fragment was discarded
|
void WriteAlphaTestCondition(Pica::FramebufferRegs::CompareFunc func);
|
||||||
[[nodiscard]] bool WriteAlphaTestCondition(Pica::FramebufferRegs::CompareFunc func);
|
|
||||||
|
|
||||||
/// Samples the current fragment texel from the provided texture unit
|
/// Samples the current fragment texel from the provided texture unit
|
||||||
[[nodiscard]] Id SampleTexture(u32 texture_unit);
|
[[nodiscard]] Id SampleTexture(u32 texture_unit);
|
||||||
|
Reference in New Issue
Block a user