mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-23 04:16:57 +02:00
Rewrite descriptor bindings and unify graphics push constants
This commit is contained in:
+102
-41
@@ -636,24 +636,22 @@ void TestImagesSamplersAndAliases() {
|
||||
void TestSampleAdjustSamplerScratch() {
|
||||
Fixture fixture(ShaderType::Pixel);
|
||||
const auto active = fixture.Emit(ValueOpcode::WqmMask, {Value(true)});
|
||||
const auto lane = fixture.Emit(ValueOpcode::SelectU32,
|
||||
{active, Value(1u), Value(0u)});
|
||||
const auto low = fixture.Emit(ValueOpcode::BitwiseAnd32,
|
||||
{lane, Value(0xffu)});
|
||||
const auto high = fixture.Emit(ValueOpcode::BitwiseAnd32,
|
||||
{lane, Value(0xffu)});
|
||||
const auto lane =
|
||||
fixture.Emit(ValueOpcode::SelectU32, {active, Value(1u), Value(0u)});
|
||||
const auto low =
|
||||
fixture.Emit(ValueOpcode::BitwiseAnd32, {lane, Value(0xffu)});
|
||||
const auto high =
|
||||
fixture.Emit(ValueOpcode::BitwiseAnd32, {lane, Value(0xffu)});
|
||||
const auto quads = fixture.Emit(
|
||||
ValueOpcode::BitwiseOr32,
|
||||
{low, fixture.Emit(ValueOpcode::ShiftLeftLogical32,
|
||||
{high, Value(8u)})});
|
||||
const auto scratch = fixture.Emit(ValueOpcode::ShiftLeftLogical32,
|
||||
{quads, Value(12u)});
|
||||
const auto word3 = fixture.Emit(ValueOpcode::BitwiseOr32,
|
||||
{fixture.UserData(3), scratch});
|
||||
const auto image = fixture.Image(
|
||||
{Value(0u), Value(0u), Value(0u), Value(0u), Value(0u), Value(0u),
|
||||
Value(0u), Value(0u)},
|
||||
0x1ec);
|
||||
{low, fixture.Emit(ValueOpcode::ShiftLeftLogical32, {high, Value(8u)})});
|
||||
const auto scratch =
|
||||
fixture.Emit(ValueOpcode::ShiftLeftLogical32, {quads, Value(12u)});
|
||||
const auto word3 =
|
||||
fixture.Emit(ValueOpcode::BitwiseOr32, {fixture.UserData(3), scratch});
|
||||
const auto image = fixture.Image({Value(0u), Value(0u), Value(0u), Value(0u),
|
||||
Value(0u), Value(0u), Value(0u), Value(0u)},
|
||||
0x1ec);
|
||||
const auto sampler = fixture.Sampler(
|
||||
{fixture.UserData(0), fixture.UserData(1), fixture.UserData(2), word3},
|
||||
0x1ec);
|
||||
@@ -685,22 +683,21 @@ void TestSampleAdjustSamplerScratch() {
|
||||
const auto CheckRejected = [](uint32_t flags, uint32_t shift,
|
||||
const char *message) {
|
||||
Fixture rejected(ShaderType::Pixel);
|
||||
const auto condition =
|
||||
rejected.Emit(ValueOpcode::WqmMask, {Value(true)});
|
||||
const auto condition = rejected.Emit(ValueOpcode::WqmMask, {Value(true)});
|
||||
const auto bit = rejected.Emit(ValueOpcode::SelectU32,
|
||||
{condition, Value(1u), Value(0u)});
|
||||
const auto dynamic = rejected.Emit(ValueOpcode::ShiftLeftLogical32,
|
||||
{bit, Value(shift)});
|
||||
const auto dynamic_word3 = rejected.Emit(
|
||||
ValueOpcode::BitwiseOr32, {rejected.UserData(3), dynamic});
|
||||
const auto rejected_image = rejected.Image(
|
||||
{Value(0u), Value(0u), Value(0u), Value(0u), Value(0u), Value(0u),
|
||||
Value(0u), Value(0u)},
|
||||
0x200);
|
||||
const auto rejected_sampler = rejected.Sampler(
|
||||
{rejected.UserData(0), rejected.UserData(1), rejected.UserData(2),
|
||||
dynamic_word3},
|
||||
0x200);
|
||||
const auto dynamic =
|
||||
rejected.Emit(ValueOpcode::ShiftLeftLogical32, {bit, Value(shift)});
|
||||
const auto dynamic_word3 = rejected.Emit(ValueOpcode::BitwiseOr32,
|
||||
{rejected.UserData(3), dynamic});
|
||||
const auto rejected_image =
|
||||
rejected.Image({Value(0u), Value(0u), Value(0u), Value(0u), Value(0u),
|
||||
Value(0u), Value(0u), Value(0u)},
|
||||
0x200);
|
||||
const auto rejected_sampler =
|
||||
rejected.Sampler({rejected.UserData(0), rejected.UserData(1),
|
||||
rejected.UserData(2), dynamic_word3},
|
||||
0x200);
|
||||
MemoryInfo rejected_memory;
|
||||
rejected_memory.kind = ResourceKind::Image;
|
||||
rejected_memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
@@ -789,7 +786,7 @@ void TestDynamicStorageMipTracking() {
|
||||
"base-1 through last-3 dynamic storage range was not specialized");
|
||||
ShaderComputeInputInfo compute{};
|
||||
Check(CollectShaderInfo(fixture.program, {.compute = &compute}, &error) &&
|
||||
AllocateBindings(fixture.program, {}, &error),
|
||||
AllocateBindings(fixture.program, 0, &error),
|
||||
"dynamic storage mip bindings were not allocated");
|
||||
const auto *storage_binding =
|
||||
FindBinding(fixture.program.bindings, DescriptorBindingKind::Storage2D);
|
||||
@@ -888,7 +885,7 @@ void TestSrtFlatteningAndRuntimeMemoization() {
|
||||
|
||||
ShaderComputeInputInfo compute{};
|
||||
Check(CollectShaderInfo(fixture.program, {.compute = &compute}, &error) &&
|
||||
AllocateBindings(fixture.program, {}, &error) &&
|
||||
AllocateBindings(fixture.program, 0, &error) &&
|
||||
FindBinding(fixture.program.bindings,
|
||||
DescriptorBindingKind::FlattenedSrt) != nullptr,
|
||||
"flattened typed SRT reads did not receive a binding");
|
||||
@@ -933,7 +930,7 @@ void TestDynamicSrtReadRemainsExplicit() {
|
||||
|
||||
ShaderComputeInputInfo compute{};
|
||||
Check(CollectShaderInfo(fixture.program, {.compute = &compute}, &error) &&
|
||||
AllocateBindings(fixture.program, {}, &error) &&
|
||||
AllocateBindings(fixture.program, 0, &error) &&
|
||||
FindBinding(fixture.program.bindings,
|
||||
DescriptorBindingKind::FlattenedSrt) == nullptr &&
|
||||
FindBinding(fixture.program.bindings,
|
||||
@@ -1198,24 +1195,87 @@ void TestShaderInfoAndBindingLayout() {
|
||||
StageInputKind::GlobalInvocationId,
|
||||
"typed shader values were not reflected in shader info");
|
||||
|
||||
BindingLayoutOptions options;
|
||||
options.descriptor_set = 2;
|
||||
options.max_push_dwords = 1;
|
||||
Check(AllocateBindings(fixture.program, options, &error),
|
||||
Check(AllocateBindings(fixture.program, 0, &error),
|
||||
"typed binding allocation failed");
|
||||
Check(fixture.program.bindings.descriptor_set == 2 &&
|
||||
FindBinding(fixture.program.bindings,
|
||||
DescriptorBindingKind::Buffers) != nullptr &&
|
||||
Check(FindBinding(fixture.program.bindings, DescriptorBindingKind::Buffers) !=
|
||||
nullptr &&
|
||||
FindBinding(fixture.program.bindings, DescriptorBindingKind::Gds) !=
|
||||
nullptr &&
|
||||
FindBinding(fixture.program.bindings,
|
||||
DescriptorBindingKind::UserData) != nullptr,
|
||||
DescriptorBindingKind::UserData) == nullptr &&
|
||||
fixture.program.bindings.push_constant_size ==
|
||||
fixture.program.bindings.ShaderDataDwords() * sizeof(uint32_t),
|
||||
"typed resources were not assigned native bindings");
|
||||
Check(NativeBinding(ShaderType::Compute, DescriptorBindingKind::Buffers) ==
|
||||
static_cast<uint32_t>(DescriptorBindingKind::Buffers) &&
|
||||
NativeBinding(ShaderType::Vertex, DescriptorBindingKind::Buffers) ==
|
||||
static_cast<uint32_t>(DescriptorBindingKind::Buffers) &&
|
||||
NativeBinding(ShaderType::Pixel, DescriptorBindingKind::Buffers) ==
|
||||
static_cast<uint32_t>(DescriptorBindingKind::Count) +
|
||||
static_cast<uint32_t>(DescriptorBindingKind::Buffers),
|
||||
"fixed stage binding ranges are inconsistent");
|
||||
Check(fixture.program.bindings.user_data_registers ==
|
||||
std::vector<uint32_t>({3u, 4u}),
|
||||
"binding layout did not collect live typed user-data values");
|
||||
}
|
||||
|
||||
void TestGraphicsPushConstantLayout() {
|
||||
const auto AddUserData = [](Fixture &fixture, uint32_t count) {
|
||||
for (uint32_t index = 0; index < count; index++) {
|
||||
fixture.Emit(ValueOpcode::ReferenceU32, {fixture.UserData(index)});
|
||||
}
|
||||
fixture.program.shader_info_complete = true;
|
||||
};
|
||||
|
||||
std::string error;
|
||||
Fixture vertex(ShaderType::Vertex);
|
||||
AddUserData(vertex, 9);
|
||||
Check(AllocateBindings(vertex.program, 0, &error) &&
|
||||
vertex.program.bindings.push_constant_offset == 0 &&
|
||||
vertex.program.bindings.push_constant_size == 9 * sizeof(uint32_t),
|
||||
"vertex shader was not placed at the start of the graphics push bank");
|
||||
|
||||
const auto pixel_offset = vertex.program.bindings.push_constant_size;
|
||||
Fixture pixel(ShaderType::Pixel);
|
||||
AddUserData(pixel, 4);
|
||||
Check(AllocateBindings(pixel.program, pixel_offset, &error) &&
|
||||
pixel.program.bindings.push_constant_offset == pixel_offset &&
|
||||
pixel.program.bindings.push_constant_size == 4 * sizeof(uint32_t) &&
|
||||
FindBinding(pixel.program.bindings, DescriptorBindingKind::UserData) ==
|
||||
nullptr,
|
||||
"pixel shader did not follow the vertex data in the graphics push bank");
|
||||
|
||||
Fixture edge(ShaderType::Pixel);
|
||||
AddUserData(edge, 1);
|
||||
Check(AllocateBindings(edge.program, NativePushConstantSize - sizeof(uint32_t),
|
||||
&error) &&
|
||||
edge.program.bindings.push_constant_size == sizeof(uint32_t),
|
||||
"last aligned push-constant dword did not fit in the graphics bank");
|
||||
|
||||
Fixture spill(ShaderType::Pixel);
|
||||
AddUserData(spill, 32);
|
||||
Check(AllocateBindings(spill.program, pixel_offset, &error) &&
|
||||
spill.program.bindings.push_constant_size == 0 &&
|
||||
FindBinding(spill.program.bindings, DescriptorBindingKind::UserData) !=
|
||||
nullptr,
|
||||
"pixel shader overlapping the vertex push data did not spill to storage");
|
||||
|
||||
Fixture full(ShaderType::Pixel);
|
||||
AddUserData(full, 1);
|
||||
Check(AllocateBindings(full.program, NativePushConstantSize, &error) &&
|
||||
full.program.bindings.push_constant_size == 0 &&
|
||||
FindBinding(full.program.bindings, DescriptorBindingKind::UserData) !=
|
||||
nullptr,
|
||||
"full graphics push bank did not spill pixel user data to storage");
|
||||
|
||||
Fixture invalid(ShaderType::Pixel);
|
||||
AddUserData(invalid, 1);
|
||||
Check(!AllocateBindings(invalid.program,
|
||||
NativePushConstantSize + sizeof(uint32_t), &error) &&
|
||||
!invalid.program.binding_layout_complete,
|
||||
"push-constant placement beyond the graphics bank was accepted");
|
||||
}
|
||||
|
||||
void TestResourceLimitIsTransactional() {
|
||||
Fixture fixture;
|
||||
MemoryInfo memory;
|
||||
@@ -1339,6 +1399,7 @@ int main() {
|
||||
Run("exec-masked FLAT address", TestExecMaskedFlatAddressProvenance);
|
||||
Run("buffer swizzle specialization", TestBufferSwizzleSpecialization);
|
||||
Run("shader info and bindings", TestShaderInfoAndBindingLayout);
|
||||
Run("graphics push constants", TestGraphicsPushConstantLayout);
|
||||
Run("resource limit", TestResourceLimitIsTransactional);
|
||||
Run("malformed memory kinds", TestMalformedMemoryKindsRejected);
|
||||
} catch (const std::exception &exception) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+195
-46
@@ -690,6 +690,24 @@ bool SpirvHasDecorationValue(const std::vector<uint32_t> &binary,
|
||||
return SpirvDecorationValueCount(binary, decoration, value) != 0;
|
||||
}
|
||||
|
||||
bool SpirvHasMemberDecorationValue(std::span<const uint32_t> binary,
|
||||
uint32_t decoration, uint32_t value) {
|
||||
for (size_t i = 5; i < binary.size();) {
|
||||
const uint32_t word = binary[i];
|
||||
const uint32_t opcode = word & 0xffffu;
|
||||
const uint32_t word_count = word >> 16u;
|
||||
if (word_count == 0 || i + word_count > binary.size()) {
|
||||
return false;
|
||||
}
|
||||
if (opcode == 72u && word_count >= 5u && binary[i + 3] == decoration &&
|
||||
binary[i + 4] == value) {
|
||||
return true;
|
||||
}
|
||||
i += word_count;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint32_t>
|
||||
SpirvDecorationValueTargets(const std::vector<uint32_t> &binary,
|
||||
uint32_t decoration, uint32_t value) {
|
||||
@@ -9868,22 +9886,23 @@ void TestRenderTargetReverseExportMapping() {
|
||||
mapped.code_size_bytes = sizeof(shader);
|
||||
ShaderMapUserData(regs.ps_regs.data_addr, mapped);
|
||||
HW::ShaderRegisters sh{};
|
||||
ShaderVertexInputInfo vs_info{};
|
||||
vs_info.stage.program = std::make_shared<ShaderRecompiler::IR::Program>();
|
||||
std::array<Prospero::ColorComponentMapping, 8> mappings{};
|
||||
mappings[0] = gr32.export_mapping;
|
||||
ShaderPixelInputInfo compiled_info{};
|
||||
ShaderVertexInputInfo vertex_info{};
|
||||
std::span<const uint32_t> compiled_spirv;
|
||||
Check(ShaderCompileInfoPS(regs, sh, vs_info, mappings, compiled_info,
|
||||
compiled_spirv) &&
|
||||
compiled_info.target_export_mapping[0].IsIdentity(),
|
||||
"inactive reverse MRT mapping was not normalized out of the shader "
|
||||
"cache key");
|
||||
Check(
|
||||
ShaderCompileInfoPS(regs, sh, vertex_info, mappings, compiled_info,
|
||||
compiled_spirv) &&
|
||||
compiled_info.target_export_mapping[0].IsIdentity(),
|
||||
"inactive reverse MRT mapping was not normalized out of the shader "
|
||||
"cache key");
|
||||
sh.target_output_mode[0] = 4;
|
||||
Check(ShaderCompileInfoPS(regs, sh, vs_info, mappings, compiled_info,
|
||||
compiled_spirv) &&
|
||||
compiled_info.target_export_mapping[0] == gr32.export_mapping,
|
||||
"active reverse MRT mapping was lost before shader specialization");
|
||||
Check(
|
||||
ShaderCompileInfoPS(regs, sh, vertex_info, mappings, compiled_info,
|
||||
compiled_spirv) &&
|
||||
compiled_info.target_export_mapping[0] == gr32.export_mapping,
|
||||
"active reverse MRT mapping was lost before shader specialization");
|
||||
}
|
||||
|
||||
void TestNewShaderRecompilerEarlyZDisabledWhenPixelKillEnabled() {
|
||||
@@ -9988,15 +10007,21 @@ void TestNewShaderRecompilerNativeBindingPlan() {
|
||||
"native binding plan did not allocate the sampler");
|
||||
Check(SpirvContainsOpcode(result.spirv, 86),
|
||||
"SPIR-V binary does not combine separate image/sampler descriptors");
|
||||
Check(SpirvHasDecorationValue(result.spirv, 33u, buffers->binding),
|
||||
Check(SpirvHasDecorationValue(result.spirv, 33u,
|
||||
ShaderRecompiler::IR::NativeBinding(
|
||||
result.program.stage, buffers->kind)),
|
||||
"SPIR-V lacks storage-buffer Binding decoration");
|
||||
Check(SpirvHasDecorationValue(result.spirv, 33u, sampled->binding),
|
||||
Check(SpirvHasDecorationValue(result.spirv, 33u,
|
||||
ShaderRecompiler::IR::NativeBinding(
|
||||
result.program.stage, sampled->kind)),
|
||||
"SPIR-V lacks sampled-image Binding decoration");
|
||||
Check(SpirvHasDecorationValue(result.spirv, 33u, samplers->binding),
|
||||
Check(SpirvHasDecorationValue(result.spirv, 33u,
|
||||
ShaderRecompiler::IR::NativeBinding(
|
||||
result.program.stage, samplers->kind)),
|
||||
"SPIR-V lacks sampler Binding decoration");
|
||||
Check(SpirvHasDecorationValue(result.spirv, 34u,
|
||||
result.program.bindings.descriptor_set),
|
||||
"SPIR-V lacks DescriptorSet decoration");
|
||||
Check(SpirvDecorationValueCount(result.spirv, 34u, 0u) ==
|
||||
result.program.bindings.descriptors.size(),
|
||||
"SPIR-V resources do not all use descriptor set zero");
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
|
||||
auto malformed = result.program;
|
||||
@@ -10945,6 +10970,31 @@ void TestComputeLdsAllocationIdentity() {
|
||||
ShaderGetIdCS(regs, lds_896, true),
|
||||
"compute pipeline identity omitted the LDS allocation");
|
||||
|
||||
auto tg_size_disabled = lds_896;
|
||||
auto tg_size_enabled = lds_896;
|
||||
tg_size_enabled.tg_size_en = true;
|
||||
Check(ShaderGetIdCS(regs, tg_size_disabled, false) !=
|
||||
ShaderGetIdCS(regs, tg_size_enabled, false),
|
||||
"compute shader identity omitted TG_SIZE semantics");
|
||||
|
||||
auto dispatch_disabled = lds_896;
|
||||
dispatch_disabled.dispatch_threads_num[0] = 64;
|
||||
dispatch_disabled.dispatch_threads_num[1] = 32;
|
||||
dispatch_disabled.dispatch_threads_num[2] = 1;
|
||||
auto dispatch_enabled = dispatch_disabled;
|
||||
dispatch_enabled.dispatch_thread_dimensions = true;
|
||||
Check(ShaderGetIdCS(regs, dispatch_disabled, false) ==
|
||||
ShaderGetIdCS(regs, dispatch_enabled, false),
|
||||
"runtime dispatch enable created a compute shader variant");
|
||||
|
||||
auto second_extent = dispatch_enabled;
|
||||
second_extent.dispatch_threads_num[0] = 1920;
|
||||
second_extent.dispatch_threads_num[1] = 1080;
|
||||
second_extent.dispatch_threads_num[2] = 4;
|
||||
Check(ShaderGetIdCS(regs, dispatch_enabled, false) ==
|
||||
ShaderGetIdCS(regs, second_extent, false),
|
||||
"runtime dispatch extent created a compute shader variant");
|
||||
|
||||
mapped.scratch_size_dwords = 7;
|
||||
ShaderMapUserData(regs.cs_regs.data_addr, mapped);
|
||||
regs.cs_regs.lds_size = decode_lds_field(lds_896_rsrc2);
|
||||
@@ -10981,14 +11031,25 @@ void TestComputeLdsAllocationIdentity() {
|
||||
CheckSpirvBinaryValidates(append_result.spirv);
|
||||
}
|
||||
|
||||
void TestPixelProgramCacheDescriptorSetIdentity() {
|
||||
void TestPixelProgramCacheBindingIdentity() {
|
||||
const uint32_t shader_01[] = {0xbf810000u};
|
||||
const uint32_t shader_10[] = {0xbf810000u};
|
||||
HW::ShaderRegisters sh{};
|
||||
|
||||
auto check_transition = [&](const uint32_t *shader, uint64_t checksum,
|
||||
bool first_has_vs_descriptors,
|
||||
bool second_has_vs_descriptors) {
|
||||
HW::PixelShaderInfo identity_regs{};
|
||||
ShaderPixelInputInfo no_depth_export{};
|
||||
auto depth_export = no_depth_export;
|
||||
depth_export.ps_depth_export_enable = true;
|
||||
Check(ShaderGetIdPS(identity_regs, no_depth_export, false) !=
|
||||
ShaderGetIdPS(identity_regs, depth_export, false),
|
||||
"pixel shader identity omitted depth-export semantics");
|
||||
auto shifted_push = no_depth_export;
|
||||
shifted_push.push_constant_offset = 36;
|
||||
Check(ShaderGetIdPS(identity_regs, no_depth_export, false) !=
|
||||
ShaderGetIdPS(identity_regs, shifted_push, false),
|
||||
"pixel shader identity omitted graphics push-bank placement");
|
||||
|
||||
auto check_cache_identity = [&](const uint32_t *shader, uint64_t checksum) {
|
||||
HW::PixelShaderInfo regs{};
|
||||
regs.ps_regs.data_addr = reinterpret_cast<uint64_t>(shader);
|
||||
regs.ps_regs.chksum = checksum;
|
||||
@@ -10996,33 +11057,120 @@ void TestPixelProgramCacheDescriptorSetIdentity() {
|
||||
mapped.code_size_bytes = sizeof(uint32_t);
|
||||
ShaderMapUserData(regs.ps_regs.data_addr, mapped);
|
||||
|
||||
auto compile = [&](bool has_vs_descriptors) {
|
||||
auto vs_program = std::make_shared<ShaderRecompiler::IR::Program>();
|
||||
if (has_vs_descriptors) {
|
||||
vs_program->bindings.descriptors.emplace_back();
|
||||
}
|
||||
ShaderVertexInputInfo vs_info{};
|
||||
vs_info.stage.program = std::move(vs_program);
|
||||
const std::array<Prospero::ColorComponentMapping, 8> identity_mappings{};
|
||||
ShaderPixelInputInfo ps_info{};
|
||||
std::span<const uint32_t> spirv;
|
||||
Check(ShaderCompileInfoPS(regs, sh, vs_info, identity_mappings, ps_info,
|
||||
spirv),
|
||||
"pixel program-cache transition failed to compile");
|
||||
const auto expected_set = has_vs_descriptors ? 1u : 0u;
|
||||
Check(ps_info.descriptor_set == expected_set &&
|
||||
ps_info.stage.program != nullptr &&
|
||||
ps_info.stage.program->bindings.descriptor_set == expected_set,
|
||||
"pixel program cache reused SPIR-V with the paired VS descriptor "
|
||||
"set");
|
||||
};
|
||||
const std::array<Prospero::ColorComponentMapping, 8> identity_mappings{};
|
||||
ShaderVertexInputInfo vertex_info{};
|
||||
ShaderPixelInputInfo first_info{};
|
||||
std::span<const uint32_t> first_spirv;
|
||||
Check(ShaderCompileInfoPS(regs, sh, vertex_info, identity_mappings, first_info,
|
||||
first_spirv),
|
||||
"pixel program-cache fixture failed to compile");
|
||||
|
||||
compile(first_has_vs_descriptors);
|
||||
compile(second_has_vs_descriptors);
|
||||
ShaderPixelInputInfo second_info{};
|
||||
std::span<const uint32_t> second_spirv;
|
||||
Check(ShaderCompileInfoPS(regs, sh, vertex_info, identity_mappings, second_info,
|
||||
second_spirv),
|
||||
"pixel program-cache lookup failed");
|
||||
Check(
|
||||
first_info.stage.program != nullptr &&
|
||||
second_info.stage.program == first_info.stage.program &&
|
||||
second_spirv.data() == first_spirv.data() &&
|
||||
second_spirv.size() == first_spirv.size(),
|
||||
"pixel program cache did not reuse an identical graphics placement");
|
||||
};
|
||||
|
||||
check_transition(shader_01, 0x91a27e6300000001ull, false, true);
|
||||
check_transition(shader_10, 0x91a27e6300000002ull, true, false);
|
||||
check_cache_identity(shader_01, 0x91a27e6300000001ull);
|
||||
check_cache_identity(shader_10, 0x91a27e6300000002ull);
|
||||
|
||||
const uint32_t push_shader[] = {
|
||||
EncodeVop1(0x01, 0, 0), EncodeVop1(0x01, 1, 1),
|
||||
EncodeVop1(0x01, 2, 2), EncodeVop1(0x01, 3, 3),
|
||||
EncodeExp0(0x00, 0xf), EncodeExp1(0, 1, 2, 3), 0xbf810000u,
|
||||
};
|
||||
HW::PixelShaderInfo push_regs{};
|
||||
push_regs.ps_regs.data_addr = reinterpret_cast<uint64_t>(push_shader);
|
||||
push_regs.ps_regs.chksum = 0x91a27e6300000003ull;
|
||||
push_regs.ps_regs.rsrc2.user_sgpr = 4;
|
||||
ShaderMappedData push_mapped{};
|
||||
push_mapped.code_size_bytes = sizeof(push_shader);
|
||||
ShaderMapUserData(push_regs.ps_regs.data_addr, push_mapped);
|
||||
HW::ShaderRegisters push_sh{};
|
||||
push_sh.target_output_mode[0] = 4;
|
||||
const std::array<Prospero::ColorComponentMapping, 8> mappings{};
|
||||
const auto MakeVertex = [](uint32_t push_size) {
|
||||
ShaderVertexInputInfo info{};
|
||||
auto program = std::make_shared<ShaderRecompiler::IR::Program>();
|
||||
program->stage = ShaderType::Vertex;
|
||||
program->bindings.push_constant_size = push_size;
|
||||
info.stage.program = std::move(program);
|
||||
return info;
|
||||
};
|
||||
const auto vertex_at_zero = MakeVertex(0);
|
||||
const auto vertex_at_36 = MakeVertex(36);
|
||||
ShaderPixelInputInfo at_zero{};
|
||||
ShaderPixelInputInfo at_36{};
|
||||
ShaderPixelInputInfo at_zero_again{};
|
||||
std::span<const uint32_t> spirv_at_zero;
|
||||
std::span<const uint32_t> spirv_at_36;
|
||||
std::span<const uint32_t> spirv_at_zero_again;
|
||||
Check(ShaderCompileInfoPS(push_regs, push_sh, vertex_at_zero, mappings,
|
||||
at_zero, spirv_at_zero) &&
|
||||
ShaderCompileInfoPS(push_regs, push_sh, vertex_at_36, mappings,
|
||||
at_36, spirv_at_36) &&
|
||||
ShaderCompileInfoPS(push_regs, push_sh, vertex_at_zero, mappings,
|
||||
at_zero_again, spirv_at_zero_again),
|
||||
"pixel program-cache placement fixture failed to compile");
|
||||
Check(at_zero.push_constant_offset == 0 &&
|
||||
at_36.push_constant_offset == 36 &&
|
||||
at_zero.stage.program != at_36.stage.program &&
|
||||
spirv_at_zero.data() != spirv_at_36.data() &&
|
||||
at_zero_again.stage.program == at_zero.stage.program &&
|
||||
spirv_at_zero_again.data() == spirv_at_zero.data() &&
|
||||
SpirvHasMemberDecorationValue(spirv_at_36, 35u, 36u),
|
||||
"pixel program cache did not partition and reuse graphics push placement");
|
||||
}
|
||||
|
||||
void TestGraphicsPushConstantPlacement() {
|
||||
using BindingKind = ShaderRecompiler::IR::DescriptorBindingKind;
|
||||
constexpr uint32_t OffsetDecoration = 35;
|
||||
const uint32_t shader[] = {
|
||||
EncodeVop1(0x01, 0, 0), EncodeVop1(0x01, 1, 1),
|
||||
EncodeVop1(0x01, 2, 2), EncodeVop1(0x01, 3, 3),
|
||||
EncodeExp0(0x00, 0xf), EncodeExp1(0, 1, 2, 3), 0xbf810000u,
|
||||
};
|
||||
const std::array<uint32_t, 4> user_data = {
|
||||
0x3e800000u, 0x3f000000u, 0x3f400000u, 0x3f800000u};
|
||||
ShaderPixelInputInfo pixel_info{};
|
||||
|
||||
auto options = MakeCompileOptions(ShaderType::Pixel);
|
||||
options.input_info.pixel = &pixel_info;
|
||||
options.user_data = user_data.data();
|
||||
options.user_data_count = static_cast<uint32_t>(user_data.size());
|
||||
options.push_constant_offset = 36;
|
||||
|
||||
ShaderRecompiler::CompileResult placed;
|
||||
std::string error;
|
||||
Check(ShaderRecompiler::TryRecompile(shader, options, placed, &error),
|
||||
error.c_str());
|
||||
Check(placed.program.bindings.push_constant_offset == 36 &&
|
||||
placed.program.bindings.push_constant_size == sizeof(user_data) &&
|
||||
ShaderRecompiler::IR::FindBinding(placed.program.bindings,
|
||||
BindingKind::UserData) == nullptr,
|
||||
"pixel push constants did not follow the vertex payload");
|
||||
Check(SpirvHasMemberDecorationValue(placed.spirv, OffsetDecoration, 36),
|
||||
"SPIR-V push block omitted the graphics-bank member offset");
|
||||
CheckSpirvBinaryValidates(placed.spirv);
|
||||
|
||||
options.push_constant_offset = 124;
|
||||
ShaderRecompiler::CompileResult spilled;
|
||||
error.clear();
|
||||
Check(ShaderRecompiler::TryRecompile(shader, options, spilled, &error),
|
||||
error.c_str());
|
||||
Check(spilled.program.bindings.push_constant_offset == 124 &&
|
||||
spilled.program.bindings.push_constant_size == 0 &&
|
||||
ShaderRecompiler::IR::FindBinding(spilled.program.bindings,
|
||||
BindingKind::UserData) != nullptr,
|
||||
"pixel data that crossed the graphics push bank did not spill");
|
||||
CheckSpirvBinaryValidates(spilled.spirv);
|
||||
}
|
||||
|
||||
void TestNewShaderRecompilerUnsupportedMemoryDecode() {
|
||||
@@ -11478,7 +11626,8 @@ int main() {
|
||||
TestGraphicsCreateInterpolantMapping();
|
||||
TestNewShaderRecompilerPixelPipelineEntry();
|
||||
TestComputeLdsAllocationIdentity();
|
||||
TestPixelProgramCacheDescriptorSetIdentity();
|
||||
TestPixelProgramCacheBindingIdentity();
|
||||
TestGraphicsPushConstantPlacement();
|
||||
TestNewShaderRecompilerUnsupportedMemoryDecode();
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user