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() {
|
||||
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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user