vk_shader_gen_spv: Implement scissor testing

* Fixes weird looking map in LBW
This commit is contained in:
GPUCode
2023-01-11 22:20:06 +02:00
parent 25fe723fa6
commit c8d614139c
9 changed files with 75 additions and 33 deletions

View File

@ -766,8 +766,9 @@ void RasterizerAccelerated::SyncProcTexNoise() {
void RasterizerAccelerated::SyncProcTexBias() {
const auto& regs = Pica::g_state.regs.texturing;
const auto proctex_bias = Pica::float16::FromRaw(regs.proctex.bias_low |
(regs.proctex_lut.bias_high << 8)).ToFloat32();
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;

View File

@ -1372,8 +1372,10 @@ void RasterizerOpenGL::UploadUniforms(bool accelerate_draw) {
}
if (sync_fs || invalidate) {
std::memcpy(uniforms + used_bytes, &uniform_block_data.data, sizeof(Pica::Shader::UniformData));
glBindBufferRange(GL_UNIFORM_BUFFER, static_cast<GLuint>(Pica::Shader::UniformBindings::Common),
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

@ -334,7 +334,8 @@ private:
case RegisterType::FloatUniform:
if (address_register_index != 0) {
// 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]);
}
return fmt::format("uniforms.f[{}]", index);

View File

@ -85,7 +85,8 @@ static std::tuple<PicaVSConfig, Pica::Shader::ShaderSetup> BuildVSConfigFromRaw(
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) {
const GLuint ub_index = glGetUniformBlockIndex(shader, name);
if (ub_index == GL_INVALID_INDEX) {

View File

@ -298,7 +298,7 @@ void PipelineCache::UseFragmentShader(const Pica::Regs& regs) {
handle = fragment_shaders_spv.Get(config, instance.GetDevice());
} else {
handle = fragment_shaders_glsl.Get(config, vk::ShaderStageFlagBits::eFragment,
instance.GetDevice(), ShaderOptimization::High);
instance.GetDevice(), ShaderOptimization::Debug);
}
current_shaders[ProgramType::FS] = handle;

View File

@ -1587,12 +1587,12 @@ void main() {
gl_Position = vert_position;
gl_Position.z = (gl_Position.z + gl_Position.w) / 2.0;
//gl_ClipDistance[0] = -vert_position.z; // fixed PICA clipping plane z <= 0
//if (enable_clip1) {
// gl_ClipDistance[1] = dot(clip_coef, vert_position);
//} else {
// gl_ClipDistance[1] = 0;
//}
gl_ClipDistance[0] = -vert_position.z; // fixed PICA clipping plane z <= 0
if (enable_clip1) {
gl_ClipDistance[1] = dot(clip_coef, vert_position);
} else {
gl_ClipDistance[1] = 0;
}
}
)";

View File

@ -42,6 +42,9 @@ void FragmentModule::Generate() {
return;
}
// Check if the fragment is outside scissor rectangle
WriteScissor();
// Write shader bytecode to emulate all enabled PICA lights
if (config.state.lighting.enable) {
WriteLighting();
@ -56,9 +59,7 @@ void FragmentModule::Generate() {
WriteTevStage(static_cast<s32>(index));
}
if (WriteAlphaTestCondition(config.state.alpha_test_func)) {
return;
}
WriteAlphaTestCondition(config.state.alpha_test_func);
if (config.state.fog_mode == TexturingRegs::FogMode::Gas) {
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() {
const auto& lighting = config.state.lighting;
@ -570,7 +610,7 @@ using ProcTexShift = TexturingRegs::ProcTexShift;
using ProcTexCombiner = TexturingRegs::ProcTexCombiner;
using ProcTexFilter = TexturingRegs::ProcTexFilter;
bool FragmentModule::WriteAlphaTestCondition(FramebufferRegs::CompareFunc func) {
void FragmentModule::WriteAlphaTestCondition(FramebufferRegs::CompareFunc func) {
using CompareFunc = FramebufferRegs::CompareFunc;
// 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) {
case CompareFunc::Never: // Kill the fragment
OpKill();
OpFunctionEnd();
return true;
case CompareFunc::Always: // Do nothing
return false;
break;
case CompareFunc::Equal:
case CompareFunc::NotEqual:
case CompareFunc::LessThan:
@ -618,10 +655,9 @@ bool FragmentModule::WriteAlphaTestCondition(FramebufferRegs::CompareFunc func)
AddLabel(kill_label);
OpKill();
AddLabel(keep_label);
return false;
break;
}
default:
return false;
LOG_CRITICAL(Render_Vulkan, "Unknown alpha test condition {}", func);
break;
}
@ -975,9 +1011,7 @@ void FragmentModule::DefineProcTexSampler() {
const Id proctex_alpha_map_offset{GetShaderDataMember(i32_id, ConstS32(13))};
const Id final_alpha{AppendProcTexCombineAndMap(config.state.proctex.alpha_combiner, u, v,
proctex_alpha_map_offset)};
const Id final_color_xyz{
OpVectorShuffle(vec_ids.Get(3), final_color, final_color, 0, 1, 2)};
final_color = OpCompositeConstruct(vec_ids.Get(4), final_color_xyz, final_alpha);
final_color = OpCompositeInsert(vec_ids.Get(4), final_alpha, final_color, 3);
}
OpReturnValue(final_color);

View File

@ -33,9 +33,13 @@ public:
/// Emits SPIR-V bytecode corresponding to the provided pica fragment configuration
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();
/// Emits code to emulate the scissor rectangle
void WriteScissor();
/// Writes the code to emulate fragment lighting
void WriteLighting();
@ -46,8 +50,7 @@ public:
void DefineProcTexSampler();
/// Writes the if-statement condition used to evaluate alpha testing.
/// Returns true if the fragment was discarded
[[nodiscard]] bool WriteAlphaTestCondition(Pica::FramebufferRegs::CompareFunc func);
void WriteAlphaTestCondition(Pica::FramebufferRegs::CompareFunc func);
/// Samples the current fragment texel from the provided texture unit
[[nodiscard]] Id SampleTexture(u32 texture_unit);