mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-25 12:26:51 +01:00
pipeline: look up draw programs and pipelines from the command buffer
This commit is contained in:
@@ -10983,7 +10983,7 @@ public:
|
||||
shaders.SetCsUserSgpr(12 + i, output.fields[i]);
|
||||
ShaderComputeInputInfo input{};
|
||||
(void)context.GetPipelineCache().GetComputeProgram(
|
||||
shaders.GetCs(), processor.GetCtx().GetShaderRegisters(), input);
|
||||
shaders.GetCs(), input);
|
||||
PreparedBindings bindings;
|
||||
executor.PrepareBindings(input.stage, bindings);
|
||||
executor.RebindImages(bindings);
|
||||
@@ -11098,7 +11098,7 @@ public:
|
||||
}
|
||||
ShaderComputeInputInfo input{};
|
||||
const auto program = context.GetPipelineCache().GetComputeProgram(
|
||||
shaders.GetCs(), processor.GetCtx().GetShaderRegisters(), input);
|
||||
shaders.GetCs(), input);
|
||||
if (original_id == 0) original_id = program.id;
|
||||
Require(name, "exact function identity",
|
||||
(program.id == original_id) == (test.value == 41),
|
||||
@@ -11190,7 +11190,7 @@ public:
|
||||
LibKernel::Memory::WriteBacking(output, actual.data(), wave_size * 4);
|
||||
ShaderComputeInputInfo input{};
|
||||
const auto program = context.GetPipelineCache().GetComputeProgram(
|
||||
shaders.GetCs(), processor.GetCtx().GetShaderRegisters(), input);
|
||||
shaders.GetCs(), input);
|
||||
if (phase == 1) original_vector_id = program.id;
|
||||
if (phase >= 2)
|
||||
Require(name, "ordered helper identity", (program.id == original_vector_id) == (phase == 3),
|
||||
@@ -11733,7 +11733,7 @@ public:
|
||||
const auto clean_tick = scheduler.CurrentTick();
|
||||
ShaderComputeInputInfo input{};
|
||||
const auto program = context.GetPipelineCache().GetComputeProgram(
|
||||
shaders.GetCs(), processor.GetCtx().GetShaderRegisters(), input);
|
||||
shaders.GetCs(), input);
|
||||
if (previous_program.id != 0) {
|
||||
Require(name, "count permutation reuse", program.id == previous_program.id,
|
||||
"a changing GPU count compiled a new shader permutation");
|
||||
@@ -11815,7 +11815,7 @@ public:
|
||||
input.workgroup_counts[0] = input.workgroup_counts[1] = 1;
|
||||
input.workgroup_counts[2] = test.groups;
|
||||
const auto program = context.GetPipelineCache().GetComputeProgram(
|
||||
shaders.GetCs(), processor.GetCtx().GetShaderRegisters(), input);
|
||||
shaders.GetCs(), input);
|
||||
Require(name, "workgroup table refresh and coalescing",
|
||||
input.workgroup_counts[2] == test.groups &&
|
||||
input.stage.program->info.images.size() == 1 &&
|
||||
@@ -11833,7 +11833,7 @@ public:
|
||||
const auto *image_storage = snapshot->images.data();
|
||||
const auto flattened_capacity = snapshot->flattened_srt.capacity();
|
||||
const auto repeated = context.GetPipelineCache().GetComputeProgram(
|
||||
shaders.GetCs(), processor.GetCtx().GetShaderRegisters(), input);
|
||||
shaders.GetCs(), input);
|
||||
Require(name, "workgroup table cache-hit storage reuse",
|
||||
repeated.id == program.id && input.stage.resources == snapshot &&
|
||||
snapshot->images.data() == image_storage &&
|
||||
@@ -12072,7 +12072,7 @@ public:
|
||||
input.workgroup_counts[0] = material_groups;
|
||||
input.workgroup_counts[1] = input.workgroup_counts[2] = 1u;
|
||||
(void)context.GetPipelineCache().GetComputeProgram(
|
||||
shaders.GetCs(), processor.GetCtx().GetShaderRegisters(), input);
|
||||
shaders.GetCs(), input);
|
||||
const auto &info = input.stage.program->info;
|
||||
const auto root = std::ranges::find_if(info.buffers, [](const auto &buffer) {
|
||||
return buffer.indirect_resources.size() == material_rows;
|
||||
@@ -18365,10 +18365,12 @@ public:
|
||||
mode.polymode_back_ptype = back;
|
||||
mode.provoking_vtx_last = provoking_last;
|
||||
registers.SetModeControl(mode);
|
||||
return context.GetPipelineCache().GetGraphicsPipeline(
|
||||
std::span{&color, 1u}, depth, std::span{&vertex, 1u}, scheduler.Current(), &pixel,
|
||||
topology, false,
|
||||
PipelineCache::GraphicsPrograms{{vertex_shader}, pixel_shader});
|
||||
DrawRenderState state{.depth_info = depth, .color_info = {color}, .color_count = 1,
|
||||
.topology = topology, .ps_active = true,
|
||||
.vertex_info = {vertex}, .ps_input_info = pixel};
|
||||
state.vertex_info[0].stage.handle = &vertex_shader;
|
||||
state.ps_input_info.stage.handle = &pixel_shader;
|
||||
return context.GetPipelineCache().GetGraphicsPipeline(scheduler.Current(), state);
|
||||
};
|
||||
auto &filled = pipeline(true, 2, 2);
|
||||
const auto draw = [&](const PipelineCache::Pipeline &selected, uint32_t vertex_count = 3,
|
||||
@@ -18719,17 +18721,50 @@ public:
|
||||
ShaderMapUserData(pixel_address,
|
||||
{.type = Prospero::ShaderBinaryType::kPs,
|
||||
.code_size_bytes = static_cast<uint32_t>(native_pixel.size() * sizeof(u32))});
|
||||
HW::VertexShaderInfo native_vertex_regs{};
|
||||
native_vertex_regs.es_regs.data_addr = vertex_address;
|
||||
HW::PixelShaderInfo native_pixel_regs{};
|
||||
native_pixel_regs.ps_regs.data_addr = pixel_address;
|
||||
shaders.SetEsShaderBase(vertex_address);
|
||||
shaders.SetPsShaderBase(pixel_address);
|
||||
const auto owned_vertex_shader = vertex_shader;
|
||||
const auto owned_pixel_shader = pixel_shader;
|
||||
depth.stencil_test_enable = false;
|
||||
registers.SetViewportTransformControl(0x300);
|
||||
user_config.SetPrimitiveType(Prospero::PrimitiveType::kTriList);
|
||||
std::array<Prospero::ColorComponentMapping, 8> export_mapping{};
|
||||
std::array<ShaderVertexInputInfo, 3> native_vertex_info{};
|
||||
// The cache reads the bound shaders, the color outputs and the export mapping itself.
|
||||
const auto refresh = [&] {
|
||||
DrawRenderState state{};
|
||||
context.GetPipelineCache().GetGraphicsPrograms(scheduler.Current(), state);
|
||||
return state;
|
||||
};
|
||||
const auto native_programs = [&] {
|
||||
const auto native = refresh();
|
||||
vertex = native.vertex_info[0];
|
||||
pixel = native.ps_input_info;
|
||||
vertex_shader = *vertex.stage.handle;
|
||||
pixel_shader = *pixel.stage.handle;
|
||||
};
|
||||
const auto silent = refresh();
|
||||
registers.SetDepthShaderControl({.shader_kill_enable = true});
|
||||
const auto killing = refresh();
|
||||
registers.SetDepthShaderControl({.shader_z_export_enable = true});
|
||||
const auto depth_writing = refresh();
|
||||
registers.SetDepthShaderControl({});
|
||||
registers.SetTargetOutputMode(0, 4);
|
||||
const auto writing = refresh();
|
||||
// Slot 1 takes color output, but the pixel program exports only MRT0.
|
||||
registers.SetRenderTargetMask(0xff);
|
||||
registers.SetShaderMask(0xff);
|
||||
registers.SetTargetOutputMode(1, 4);
|
||||
const auto partial = refresh();
|
||||
registers.SetTargetOutputMode(1, 0);
|
||||
registers.SetShaderMask(0xf);
|
||||
registers.SetRenderTargetMask(0xf);
|
||||
Require(name, "pixel stage activity",
|
||||
!silent.ps_active && !silent.ps_input_info.stage && silent.mrt_mask == 0 &&
|
||||
killing.ps_active && killing.ps_input_info.stage && killing.mrt_mask == 0 &&
|
||||
depth_writing.ps_active && depth_writing.mrt_mask == 0 &&
|
||||
writing.ps_active && writing.mrt_mask == 1u && partial.mrt_mask == 1u &&
|
||||
writing.VertexStages().size() == 1 &&
|
||||
writing.vertex_info[0].stage.handle != nullptr,
|
||||
"pixel activity or its MRT mask ignored the color outputs or depth side effects");
|
||||
std::array<uint64_t, 2> wave_ids{};
|
||||
std::array<std::vector<u32>, 2> wave_keys;
|
||||
struct PixelWaveCase { uint32_t control, width, color; };
|
||||
@@ -18737,9 +18772,7 @@ public:
|
||||
PixelWaveCase{0x8008, 32, 0x3e800000},
|
||||
PixelWaveCase{0x0008, 64, 0}}) {
|
||||
registers.SetPsInControl(wave.control);
|
||||
const auto programs = context.GetPipelineCache().GetGraphicsPrograms(
|
||||
native_vertex_regs, native_pixel_regs, registers.GetShaderRegisters(),
|
||||
registers, user_config, export_mapping, true, native_vertex_info, pixel);
|
||||
native_programs();
|
||||
Require(name, "pixel wave metadata propagation",
|
||||
pixel.input_num == 8 && pixel.stage.program->wave_size == wave.width,
|
||||
"SPI_PS_IN_CONTROL width did not reach the compiled pixel program");
|
||||
@@ -18748,14 +18781,11 @@ public:
|
||||
BuildStageStaticKey(pixel, key);
|
||||
if (wave_ids[index] != 0) {
|
||||
Require(name, "pixel wave cache reuse",
|
||||
programs.pixel.id == wave_ids[index] && key == wave_keys[index],
|
||||
pixel_shader.id == wave_ids[index] && key == wave_keys[index],
|
||||
"restoring wave64 did not reuse its original program");
|
||||
}
|
||||
wave_ids[index] = programs.pixel.id;
|
||||
wave_ids[index] = pixel_shader.id;
|
||||
wave_keys[index] = std::move(key);
|
||||
vertex_shader = programs.vertex[0];
|
||||
pixel_shader = programs.pixel;
|
||||
vertex = native_vertex_info[0];
|
||||
draw(pipeline(true, 2, 2));
|
||||
const auto wave_pixels = read_color();
|
||||
for (size_t component = 0; component < wave_pixels.size(); component++) {
|
||||
@@ -18791,8 +18821,8 @@ public:
|
||||
*(position + 1) = EncodeExp1(3, 4, 0, 9);
|
||||
return code;
|
||||
}();
|
||||
native_vertex_regs.es_regs.data_addr = reinterpret_cast<uint64_t>(waterfall_vertex.data());
|
||||
ShaderMapUserData(native_vertex_regs.es_regs.data_addr,
|
||||
shaders.SetEsShaderBase(reinterpret_cast<uint64_t>(waterfall_vertex.data()));
|
||||
ShaderMapUserData(shaders.GetVs().es_regs.data_addr,
|
||||
{.type = Prospero::ShaderBinaryType::kGs, .user_data = &native_user_data,
|
||||
.code_size_bytes = static_cast<u32>(waterfall_vertex.size() * sizeof(u32))});
|
||||
registers.SetPsInControl(0x8008);
|
||||
@@ -18800,12 +18830,7 @@ public:
|
||||
for (const u32 wave : {32u, 64u}) {
|
||||
registers.SetShaderStages((saved_stages & ~0x00400000u) |
|
||||
(wave == 32u ? 0x00400000u : 0u));
|
||||
const auto programs = context.GetPipelineCache().GetGraphicsPrograms(
|
||||
native_vertex_regs, native_pixel_regs, registers.GetShaderRegisters(),
|
||||
registers, user_config, export_mapping, true, native_vertex_info, pixel);
|
||||
vertex_shader = programs.vertex[0];
|
||||
pixel_shader = programs.pixel;
|
||||
vertex = native_vertex_info[0];
|
||||
native_programs();
|
||||
Require(name, "native NGG waterfall wave",
|
||||
vertex.stage.program->stage == ShaderType::Vertex &&
|
||||
vertex.stage.program->wave_size == wave,
|
||||
@@ -18820,7 +18845,7 @@ public:
|
||||
}
|
||||
}
|
||||
registers.SetShaderStages(saved_stages);
|
||||
native_vertex_regs.es_regs.data_addr = vertex_address;
|
||||
shaders.SetEsShaderBase(vertex_address);
|
||||
|
||||
// Reversed RGBA targets must use logical Sa for RGB, with a separate
|
||||
// zero or unit source factor for separate alpha attenuation or accumulation.
|
||||
@@ -18835,8 +18860,8 @@ public:
|
||||
AppendEnd(&code);
|
||||
return code;
|
||||
}();
|
||||
native_pixel_regs.ps_regs.data_addr = reinterpret_cast<uint64_t>(blend_pixel.data());
|
||||
ShaderMapUserData(native_pixel_regs.ps_regs.data_addr,
|
||||
shaders.SetPsShaderBase(reinterpret_cast<uint64_t>(blend_pixel.data()));
|
||||
ShaderMapUserData(shaders.GetPs().ps_regs.data_addr,
|
||||
{.type = Prospero::ShaderBinaryType::kPs,
|
||||
.code_size_bytes = static_cast<uint32_t>(blend_pixel.size() * sizeof(u32))});
|
||||
const auto saved_blend = registers.GetBlendControl(0);
|
||||
@@ -18845,8 +18870,13 @@ public:
|
||||
registers.SetTargetOutputMode(0, 4);
|
||||
auto blend_target_info = saved_target_info;
|
||||
blend_target_info.blend_bypass = false;
|
||||
// A reversed RGBA32F target exports through the ABGR mapping.
|
||||
blend_target_info.format = Prospero::ChannelLayout::k32_32_32_32;
|
||||
blend_target_info.channel_type = Prospero::ChannelType::kFloat;
|
||||
blend_target_info.channel_order = Prospero::ChannelOrder::kReversed;
|
||||
registers.SetColorInfo(0, blend_target_info);
|
||||
export_mapping[0] = color.export_mapping = Prospero::ColorMappingAbgr;
|
||||
registers.SetColorBase(0, {.addr = depth_address + 0x10000});
|
||||
color.export_mapping = Prospero::ColorMappingAbgr;
|
||||
HW::BlendControl alpha_blend{};
|
||||
alpha_blend.enable = true;
|
||||
alpha_blend.color_srcblend = static_cast<uint8_t>(Prospero::BlendFactor::kSrcAlpha);
|
||||
@@ -18869,22 +18899,18 @@ public:
|
||||
alpha_blend.separate_alpha_blend = test.separate;
|
||||
alpha_blend.alpha_srcblend = static_cast<uint8_t>(test.alpha_source);
|
||||
registers.SetBlendControl(0, alpha_blend);
|
||||
const auto programs = context.GetPipelineCache().GetGraphicsPrograms(
|
||||
native_vertex_regs, native_pixel_regs, registers.GetShaderRegisters(),
|
||||
registers, user_config, export_mapping, true, native_vertex_info, pixel);
|
||||
native_programs();
|
||||
Require(name, "logical alpha blend program", pixel.alpha_blend_source == test.mode &&
|
||||
pixel.dual_source_blending,
|
||||
pixel.dual_source_blending &&
|
||||
pixel.target_export_mapping[0] == Prospero::ColorMappingAbgr,
|
||||
"the separate alpha equation did not reach the compiled pixel program");
|
||||
vertex_shader = programs.vertex[0];
|
||||
pixel_shader = programs.pixel;
|
||||
vertex = native_vertex_info[0];
|
||||
auto &selected = pipeline(true, 2, 2);
|
||||
if (test.mode == ShaderAlphaBlendSource::SourceAlpha) {
|
||||
Require(name, "equal blend equation cache reuse",
|
||||
broadcast_program == 0 || (programs.pixel.id == broadcast_program &&
|
||||
broadcast_program == 0 || (pixel_shader.id == broadcast_program &&
|
||||
selected.pipeline == broadcast_pipeline),
|
||||
"equivalent separate alpha state created another shader or pipeline");
|
||||
broadcast_program = programs.pixel.id;
|
||||
broadcast_program = pixel_shader.id;
|
||||
broadcast_pipeline = selected.pipeline;
|
||||
}
|
||||
constexpr std::array<float, 4> destination{0.3f, 0.3f, 0.1f, 0.2f};
|
||||
@@ -18898,9 +18924,10 @@ public:
|
||||
"reversed blending changed logical RGB or the separate alpha equation");
|
||||
}
|
||||
}
|
||||
native_pixel_regs.ps_regs.data_addr = pixel_address;
|
||||
export_mapping[0] = color.export_mapping = {};
|
||||
shaders.SetPsShaderBase(pixel_address);
|
||||
color.export_mapping = {};
|
||||
registers.SetBlendControl(0, saved_blend);
|
||||
registers.SetColorBase(0, {});
|
||||
registers.SetColorInfo(0, saved_target_info);
|
||||
registers.SetTargetOutputMode(0, saved_output_mode);
|
||||
|
||||
@@ -18939,17 +18966,12 @@ public:
|
||||
user_config.SetPrimitiveType(Prospero::PrimitiveType::kTriStrip);
|
||||
for (size_t i = 0; i < position_shaders.size(); i++) {
|
||||
const auto &code = position_shaders[i];
|
||||
native_vertex_regs.es_regs.data_addr = reinterpret_cast<uint64_t>(code.data());
|
||||
ShaderMapUserData(native_vertex_regs.es_regs.data_addr,
|
||||
shaders.SetEsShaderBase(reinterpret_cast<uint64_t>(code.data()));
|
||||
ShaderMapUserData(shaders.GetVs().es_regs.data_addr,
|
||||
{.type = Prospero::ShaderBinaryType::kGs,
|
||||
.user_data = &native_user_data,
|
||||
.code_size_bytes = static_cast<uint32_t>(code.size() * sizeof(u32))});
|
||||
const auto programs = context.GetPipelineCache().GetGraphicsPrograms(
|
||||
native_vertex_regs, native_pixel_regs, registers.GetShaderRegisters(),
|
||||
registers, user_config, export_mapping, true, native_vertex_info, pixel);
|
||||
vertex_shader = programs.vertex[0];
|
||||
pixel_shader = programs.pixel;
|
||||
vertex = native_vertex_info[0];
|
||||
native_programs();
|
||||
draw(pipeline(true, 2, 2, false, false, vk::PrimitiveTopology::eTriangleStrip), 4);
|
||||
const auto pixels = read_color();
|
||||
bool second_triangle = false;
|
||||
@@ -19486,11 +19508,7 @@ public:
|
||||
shaders.SetGsShaderResource2({});
|
||||
shaders.SetPsShaderBase(ps_address);
|
||||
user_config.SetPrimitiveType(Prospero::PrimitiveType::kTriList);
|
||||
native_vertex_regs.es_regs.data_addr = vertex_address;
|
||||
native_pixel_regs.ps_regs.data_addr = ps_address;
|
||||
const auto programs = context.GetPipelineCache().GetGraphicsPrograms(
|
||||
native_vertex_regs, native_pixel_regs, registers.GetShaderRegisters(),
|
||||
registers, user_config, export_mapping, true, native_vertex_info, pixel);
|
||||
native_programs();
|
||||
Require(name, "packed format follows export ordinal",
|
||||
pixel.target_output_mode[2] == 9 && pixel.wave_size == test.wave &&
|
||||
pixel.target_packed_unorm_mask == 4u &&
|
||||
@@ -19498,9 +19516,9 @@ public:
|
||||
"packed conversion or rounding contaminated another MRT or followed a physical slot");
|
||||
if (test.slot == 2) {
|
||||
auto &id = test.truncate ? truncate_program : half_up_program;
|
||||
Require(name, "packed rounding program reuse", id == 0 || id == programs.pixel.id,
|
||||
Require(name, "packed rounding program reuse", id == 0 || id == pixel_shader.id,
|
||||
"restoring half-up rounding failed to reuse its program");
|
||||
id = programs.pixel.id;
|
||||
id = pixel_shader.id;
|
||||
}
|
||||
RenderColorInfo packed_target{}, float_target{};
|
||||
RenderExecutorTestAccess::ResolveRenderColorTarget(
|
||||
@@ -44518,13 +44536,13 @@ void CheckComputeLdsLimit(VulkanHarness &vulkan) {
|
||||
uint16_t{112}, uint16_t{128}, uint16_t{128}}) {
|
||||
regs.cs_regs.lds_size = units;
|
||||
ShaderComputeInputInfo input{};
|
||||
const auto program = cache.GetComputeProgram(regs, {}, input);
|
||||
const auto program = cache.GetComputeProgram(regs, input);
|
||||
Require(name, "guest allocation and device backing",
|
||||
input.lds_size_dwords == units * 128u &&
|
||||
input.lds_storage == (units > limit_units),
|
||||
"compute LDS was truncated or chose backing that exceeds the device limit");
|
||||
Require(name, "pipeline creation",
|
||||
cache.GetComputePipeline(input, program).pipeline != nullptr,
|
||||
cache.GetComputePipeline(input).pipeline != nullptr,
|
||||
"full-size LDS shader did not create a Vulkan compute pipeline");
|
||||
if (previous.id != 0) {
|
||||
Require(name, "guest-size cache identity",
|
||||
|
||||
@@ -10810,11 +10810,10 @@ void TestGraphicsComputeGetreg() {
|
||||
ShaderMappedData mapped{};
|
||||
mapped.code_size_bytes = sizeof(shader);
|
||||
ShaderMapUserData(regs.cs_regs.data_addr, mapped);
|
||||
HW::ShaderRegisters sh{};
|
||||
ShaderComputeInputInfo graphics{}, async{};
|
||||
async.async_compute = true;
|
||||
(void)PrepareProgram(regs, sh, graphics);
|
||||
(void)PrepareProgram(regs, sh, async);
|
||||
(void)PrepareProgram(regs, graphics);
|
||||
(void)PrepareProgram(regs, async);
|
||||
Check(!graphics.async_compute && async.async_compute &&
|
||||
MakeStageStaticKey(graphics) != MakeStageStaticKey(async) &&
|
||||
MakeStageStaticKey(graphics).size() == MakeStageStaticKey(async).size(),
|
||||
@@ -15782,13 +15781,12 @@ void TestComputeLdsAllocationIdentity() {
|
||||
ShaderMappedData mapped{};
|
||||
mapped.code_size_bytes = sizeof(shader);
|
||||
ShaderMapUserData(regs.cs_regs.data_addr, mapped);
|
||||
HW::ShaderRegisters sh{};
|
||||
|
||||
const auto compile = [&](uint16_t encoded_lds_size,
|
||||
uint32_t expected_dwords) {
|
||||
regs.cs_regs.lds_size = encoded_lds_size;
|
||||
ShaderComputeInputInfo input_info{};
|
||||
const auto params = PrepareProgram(regs, sh, input_info);
|
||||
const auto params = PrepareProgram(regs, input_info);
|
||||
Check(input_info.lds_size_dwords == expected_dwords,
|
||||
"COMPUTE_PGM_RSRC2 LDS allocation units were not decoded");
|
||||
auto options = MakeCompileOptions(ShaderType::Compute);
|
||||
@@ -15854,7 +15852,7 @@ void TestComputeLdsAllocationIdentity() {
|
||||
ShaderMapUserData(regs.cs_regs.data_addr, mapped);
|
||||
regs.cs_regs.lds_size = decode_lds_field(lds_896_rsrc2);
|
||||
ShaderComputeInputInfo scratch_info{};
|
||||
const auto scratch_params = PrepareProgram(regs, sh, scratch_info);
|
||||
const auto scratch_params = PrepareProgram(regs, scratch_info);
|
||||
Check(scratch_info.scratch_size_dwords == 7,
|
||||
"AGC per-thread scratch size was not propagated");
|
||||
auto scratch_options = MakeCompileOptions(ShaderType::Compute);
|
||||
|
||||
Reference in New Issue
Block a user