rsx/vk: Plumb programmable blending shader emitter

This commit is contained in:
kd-11
2026-09-07 21:09:01 +03:00
committed by kd-11
parent ab95783bc9
commit c47bbab85f
13 changed files with 127 additions and 23 deletions
+1 -1
View File
@@ -344,7 +344,7 @@ void GLFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
OS << "void main()\n";
OS << "{\n";
::glsl::insert_rop_init(OS);
::glsl::insert_rop_init(OS, m_prog.mrt_buffers_count);
OS << "\n" << " fs_main();\n\n";
+16 -1
View File
@@ -151,8 +151,13 @@ namespace glsl
;
}
void insert_rop_init(std::ostream& OS)
void insert_rop_init(std::ostream& OS, u32 mrt_buffer_count)
{
program_common::define_glsl_constants<u32>(OS,
{
{ "_MRT_BUFFERS_COUNT", mrt_buffer_count },
});
OS <<
#include "GLSLSnippets/RSXProg/RSXROPPrologue.glsl"
;
@@ -346,6 +351,11 @@ namespace glsl
enabled_options.push_back("_ENABLE_ROP_CHANNEL_REMAPPING");
}
if (props.ROP_programmable_blend)
{
enabled_options.push_back("_ENABLE_PROGRAMMABLE_BLENDING");
}
if (props.require_fog_read)
{
program_common::define_glsl_constants<rsx::fog_mode>(OS,
@@ -493,6 +503,11 @@ namespace glsl
}
}
}
if (props.ROP_programmable_blend)
{
insert_blend_prologue(OS);
}
}
std::string getFunctionImpl(FUNCTION f)
+1 -1
View File
@@ -77,7 +77,7 @@ namespace glsl
std::string getHalfTypeNameImpl(usz elementCount);
std::string compareFunctionImpl(COMPARE f, std::string_view Op0, std::string_view Op1, bool scalar = false);
void insert_vertex_input_fetch(std::stringstream& OS, glsl_rules rules, bool glsl4_compliant=true);
void insert_rop_init(std::ostream& OS);
void insert_rop_init(std::ostream& OS, u32 mrt_buffers_count);
void insert_rop(std::ostream& OS, const shader_properties& props);
void insert_glsl_legacy_function(std::ostream& OS, const shader_properties& props);
std::string getFunctionImpl(FUNCTION f);
@@ -1,7 +1,5 @@
R"(
#define _MRT_BUFFERS_COUNT 4 // TODO
#ifdef _32_BIT_OUTPUT
// Everything is fp32 on ouput channels
#define _mrt_color_t(expr) expr
@@ -4,9 +4,9 @@ R"(
* Required register definitions from ROP config
struct {
vec4 blend_constants; // fp32x4
uint blend_func; // rgb16, a16
uint blend_factors_a; // src16, dst16
uint blend_factors_rgb; // src16, dst16
uint blend_eqn; // Packed RGB in lower 16 bits, A in upper 16 bits
uint blend_sfactors; // Ditto
uint blend_dfactors; // Ditto
}
*/
@@ -91,9 +91,9 @@ vec3 get_blend_factor_rgb(const in uint op, const in vec4 src, const in vec4 dst
float apply_blend_func_a(const in vec4 src, const in vec4 dst)
{
uint blend_factor_a_s = _get_bits(blend_factors_a, 0, 16);
uint blend_factor_a_d = _get_bits(blend_factors_a, 16, 16);
uint func = _get_bits(blend_func, 16, 16);
uint blend_factor_a_s = _get_bits(blend_sfactors, 16, 16);
uint blend_factor_a_d = _get_bits(blend_dfactors, 16, 16);
uint func = _get_bits(blend_eqn, 16, 16);
const float src_factor_a = get_blend_factor_a(blend_factor_a_s, src, dst);
const float dst_factor_a = get_blend_factor_a(blend_factor_a_d, src, dst);
@@ -119,9 +119,9 @@ float apply_blend_func_a(const in vec4 src, const in vec4 dst)
vec3 apply_blend_func_rgb(const in vec4 src, const in vec4 dst)
{
uint blend_factor_rgb_s = _get_bits(blend_factors_rgb, 0, 16);
uint blend_factor_rgb_d = _get_bits(blend_factors_rgb, 16, 16);
uint func = _get_bits(blend_func, 0, 16);
uint blend_factor_rgb_s = _get_bits(blend_sfactors, 0, 16);
uint blend_factor_rgb_d = _get_bits(blend_dfactors, 0, 16);
uint func = _get_bits(blend_eqn, 0, 16);
const vec3 src_factor_rgb = get_blend_factor_rgb(blend_factor_rgb_s, src, dst);
const vec3 dst_factor_rgb = get_blend_factor_rgb(blend_factor_rgb_d, src, dst);
@@ -20,11 +20,26 @@ R"(
#endif
#if defined(_ENABLE_PROGRAMMABLE_BLENDING) && _MRT_BUFFERS_COUNT >= 1
#define FRAG_LOAD(n) mrt_color[n] = subpassLoad(frag_src_##n)
// TODO: Multisampled output support.
vec4 mrt_color[_MRT_BUFFERS_COUNT];
for (int n = 0; n < _MRT_BUFFERS_COUNT; ++n)
{
mrt_color[n] = subpassLoad(mrtAttachments[n]);
}
#if _MRT_BUFFERS_COUNT >= 1
FRAG_LOAD(0);
#endif
#if _MRT_BUFFERS_COUNT >= 2
FRAG_LOAD(1);
#endif
#if _MRT_BUFFERS_COUNT >= 3
FRAG_LOAD(2);
#endif
#if _MRT_BUFFERS_COUNT == 4
FRAG_LOAD(3);
#endif
#undef FRAG_LOAD
#endif
)"
+1
View File
@@ -51,6 +51,7 @@ namespace glsl
bool ROP_polygon_stipple_test : 1;
bool ROP_discard : 1;
bool ROP_channel_remap : 1;
bool ROP_programmable_blend : 1;
// Texturing spec
bool require_texture_ops : 1; // Global switch to enable/disable all texture code
+50 -1
View File
@@ -96,6 +96,15 @@ void VKFragmentDecompilerThread::prepareBindingTable()
{
vk_prog->binding_table.frag_depth_input_location = location++;
}
std::memset(vk_prog->binding_table.frag_src_location, 0xff, sizeof(vk_prog->binding_table.frag_src_location));
if (m_prog.ctrl & RSX_SHADER_CONTROL_PROGRAMMABLE_BLENDING)
{
for (u32 i = 0; i < m_prog.mrt_buffers_count; ++i)
{
vk_prog->binding_table.frag_src_location[i] = location++;
}
}
}
void VKFragmentDecompilerThread::insertHeader(std::stringstream & OS)
@@ -262,6 +271,22 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS)
));
}
if (m_prog.ctrl & RSX_SHADER_CONTROL_PROGRAMMABLE_BLENDING)
{
for (u32 i = 0; i < m_prog.mrt_buffers_count; ++i)
{
OS << "layout(input_attachment_index= " << i << ", set=" << vk::glsl::binding_set_index_fragment << ", binding=" << vk_prog->binding_table.frag_src_location[i] << ") uniform subpassInput frag_src_" << i << ";\n";
inputs.push_back(vk::glsl::program_input::make(
glsl::glsl_fragment_program,
fmt::format("frag_src_%u", i),
vk::glsl::input_type_attachment,
vk::glsl::binding_set_index_fragment,
vk_prog->binding_table.frag_src_location[i]
));
}
}
// Draw params are always provided by vertex program. Instead of pointer chasing, they're provided as varyings.
if (!(m_prog.ctrl & RSX_SHADER_CONTROL_INTERPRETER_MODEL))
{
@@ -300,6 +325,29 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS)
OS << " uvec4 stipple_pattern[];\n";
OS << "};\n\n";
if (m_prog.ctrl & RSX_SHADER_CONTROL_PROGRAMMABLE_BLENDING)
{
OS <<
"layout(push_constant) uniform push_constants_block\n"
"{\n"
" layout(offset = 4) uint blend_eqn;\n"
" uint blend_sfactors;\n"
" uint blend_dfactors;\n"
" vec4 blend_constants;\n"
"};\n\n";
vk::glsl::program_input push_constants
{
.domain = glsl::glsl_fragment_program,
.type = vk::glsl::input_type_push_constant,
.bound_data = vk::glsl::push_constant_ref{ .offset = 4, .size = 28 },
.set = vk::glsl::binding_set_index_fragment,
.location = umax,
.name = "push_constants_block"
};
inputs.push_back(std::move(push_constants));
}
vk::glsl::program_input in
{
.domain = glsl::glsl_fragment_program,
@@ -357,6 +405,7 @@ void VKFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS)
m_shader_props.ROP_polygon_stipple_test = !!(m_prog.ctrl & RSX_SHADER_CONTROL_POLYGON_STIPPLE);
m_shader_props.ROP_discard = !!(m_prog.ctrl & RSX_SHADER_CONTROL_USES_KIL);
m_shader_props.ROP_channel_remap = !!(m_prog.ctrl & RSX_SHADER_CONTROL_ROP_OUTPUT_REMAP);
m_shader_props.ROP_programmable_blend = !!(m_prog.ctrl & RSX_SHADER_CONTROL_PROGRAMMABLE_BLENDING);
m_shader_props.require_tex1D_ops = properties.has_tex1D;
m_shader_props.require_tex2D_ops = properties.has_tex2D;
@@ -499,7 +548,7 @@ void VKFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
" const float alpha_ref = fs_contexts[_fs_context_offset].alpha_ref;\n\n";
}
::glsl::insert_rop_init(OS);
::glsl::insert_rop_init(OS, m_prog.mrt_buffers_count);
OS << "\n" << " fs_main();\n\n";
+1
View File
@@ -76,6 +76,7 @@ public:
u32 ftex_location[16]; // Texture locations array
u32 ftex_stencil_location[16]; // Texture stencil mirror array
u32 frag_depth_input_location = umax; // Fragment depth compare
u32 frag_src_location[4]; // Fragment input attachment locations
} binding_table;
+23
View File
@@ -2290,6 +2290,29 @@ void VKGSRender::update_vertex_env(u32 id, const vk::vertex_upload_info& vertex_
4,
&push_val);
if (current_fragment_program.ctrl & RSX_SHADER_CONTROL_PROGRAMMABLE_BLENDING)
{
// TODO: This should be cached aggressively.
u32 blend_config[7];
blend_config[0] = REGS(m_ctx)->registers[NV4097_SET_BLEND_EQUATION];
blend_config[1] = REGS(m_ctx)->registers[NV4097_SET_BLEND_FUNC_SFACTOR];
blend_config[2] = REGS(m_ctx)->registers[NV4097_SET_BLEND_FUNC_DFACTOR];
const auto blend_colors = rsx::get_constant_blend_colors();
blend_config[3] = std::bit_cast<u32>(blend_colors[0]);
blend_config[4] = std::bit_cast<u32>(blend_colors[1]);
blend_config[5] = std::bit_cast<u32>(blend_colors[2]);
blend_config[6] = std::bit_cast<u32>(blend_colors[3]);
vkCmdPushConstants(
*m_current_command_buffer,
m_program->layout(),
VK_SHADER_STAGE_FRAGMENT_BIT,
4,
28,
blend_config);
}
// Now actually fill in the data
m_draw_processor.fill_vertex_layout_state(
m_vertex_layout,
+2
View File
@@ -60,6 +60,8 @@ namespace vk
return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
case input_type_storage_texture:
return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
case input_type_attachment:
return VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
default:
fmt::throw_exception("Unexpected program input type %d", static_cast<int>(type));
}
+1
View File
@@ -22,6 +22,7 @@ namespace vk
input_type_storage_buffer,
input_type_storage_texture,
input_type_push_constant,
input_type_attachment,
// Meta
input_type_max_enum,
+3 -4
View File
@@ -454,9 +454,6 @@ namespace gcm
RSX_SHADER_CONTROL_UNKNOWN0 = 0x00000400, // seemingly always set
RSX_SHADER_CONTROL_UNKNOWN1 = 0x00008000, // seemingly set when srgb packer is used??
// Meta
RSX_SHADER_CONTROL_GCM_FLAGS_MASK = 0x000007ff, // Reserved range for GCM flags. We don't care about most GCM-specific flags.
// Custom
RSX_SHADER_CONTROL_FLAT_SHADING = 0x00000800, // Interpolate front/back colors using the provoking vertex
RSX_SHADER_CONTROL_ATTRIBUTE_INTERPOLATION = 0x00010000, // Rasterizing triangles and not lines or points
@@ -478,9 +475,11 @@ namespace gcm
RSX_SHADER_CONTROL_MULTISAMPLED_ZBUFFER = 0x10000000, // Z buffer is multisampled. Only affects depth comparison behavior at this time.
RSX_SHADER_CONTROL_ROP_OUTPUT_REMAP = 0x20000000, // ROP outputs need channel swizzles.
RSX_SHADER_CONTROL_PROGRAMMABLE_BLENDING = 0x40000000, // Enable programmable blending.
// Meta
RSX_SHADER_CONTROL_META_USES_DISCARD = (RSX_SHADER_CONTROL_USES_KIL | RSX_SHADER_CONTROL_TEXTURE_ALPHA_KILL | RSX_SHADER_CONTROL_ALPHA_TEST | RSX_SHADER_CONTROL_POLYGON_STIPPLE | RSX_SHADER_CONTROL_ALPHA_TO_COVERAGE)
RSX_SHADER_CONTROL_META_USES_DISCARD = (RSX_SHADER_CONTROL_USES_KIL | RSX_SHADER_CONTROL_TEXTURE_ALPHA_KILL | RSX_SHADER_CONTROL_ALPHA_TEST | RSX_SHADER_CONTROL_POLYGON_STIPPLE | RSX_SHADER_CONTROL_ALPHA_TO_COVERAGE),
RSX_SHADER_CONTROL_META_GCM_FLAGS_MASK = 0x000007ff, // Reserved range for GCM flags. We don't care about most GCM-specific flags.
};
// GCM Reports