shader: centralize program compilation and permutation caching

This commit is contained in:
nmzik
2026-08-27 13:37:46 +02:00
parent 65871a53a6
commit c167375fe1
11 changed files with 716 additions and 1035 deletions
+15 -83
View File
@@ -42,6 +42,7 @@
#include "graphics/shader/recompiler/ir/passes/BindingLayout.h"
#include "graphics/shader/rectListShader.h"
#include "graphics/shader/shader.h"
#include "graphics/shader/shaderCompiler.h"
#include "kernel/eventQueue.h"
#include "kernel/memory.h"
#include "libs/agc.h"
@@ -1057,12 +1058,14 @@ void CheckRectListShaders() {
pixel.interpolator_settings[0] = 0x400u;
pixel.interpolator_settings[1] = 0;
pixel.stage.program = program;
HW::PixelShaderInfo ps_regs{};
const auto perspective_id = ShaderGetIdPS(ps_regs, pixel, false);
std::vector<uint32_t> perspective_specialization;
BuildStageStaticKey(pixel, perspective_specialization);
pixel.ps_no_perspective = true;
const auto no_perspective_id = ShaderGetIdPS(ps_regs, pixel, false);
std::vector<uint32_t> no_perspective_specialization;
BuildStageStaticKey(pixel, no_perspective_specialization);
pixel.ps_no_perspective = false;
Require(name, "pipeline identity", perspective_id != no_perspective_id,
Require(name, "pipeline identity",
perspective_specialization != no_perspective_specialization,
"pixel interpolation mode must participate in the shader and "
"pipeline key");
@@ -22508,83 +22511,12 @@ void CheckStorageTextureDepthTileUploadLayout() {
"1x1 R8_UINT depth tile lost its 64 KiB source footprint");
std::printf("[host] %-32s ok\n", "StorageTextureDepthTileUpload");
}
void CheckImageSpecializationId() {
std::array<u32, 1> code{};
HW::ComputeShaderInfo regs{};
regs.cs_regs.data_addr = reinterpret_cast<uint64_t>(code.data());
ShaderRecompiler::IR::ImageResource image;
image.kind = ShaderRecompiler::IR::ResourceKind::StorageImage;
image.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
const auto make_program = [](ShaderRecompiler::IR::ImageResource resource) {
ShaderRecompiler::IR::Program program;
program.binding_layout_complete = true;
program.info.images.push_back(std::move(resource));
return program;
};
auto rgb1_image = image;
rgb1_image.shader_swizzle = DstSel(4, 5, 6, 1);
auto converted_image = image;
converted_image.conversion_format =
Prospero::BufferFormat::k11_11_10UInt;
auto mip1_image = image;
mip1_image.mip_mode = ShaderRecompiler::IR::ImageMipMode::DynamicStorage;
auto mip3_image = mip1_image;
mip3_image.mip_count = 3;
auto array_image = image;
array_image.dimension =
ShaderRecompiler::Decoder::ImageDimension::Dim2DArray;
auto cube_image = array_image;
cube_image.cube = true;
const auto resources =
std::make_shared<const ShaderRecompiler::IR::ResourceSnapshot>();
ShaderComputeInputInfo identity_info;
identity_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
make_program(image));
identity_info.stage.resources = resources;
auto rgb1_info = identity_info;
rgb1_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
make_program(rgb1_image));
auto converted_info = identity_info;
converted_info.stage.program =
std::make_shared<const ShaderRecompiler::IR::Program>(
make_program(converted_image));
auto mip1_info = identity_info;
mip1_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
make_program(mip1_image));
auto mip3_info = identity_info;
mip3_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
make_program(mip3_image));
auto array_info = identity_info;
array_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
make_program(array_image));
auto cube_info = identity_info;
cube_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
make_program(cube_image));
const auto identity_id = ShaderGetIdCS(regs, identity_info, true);
const auto rgb1_id = ShaderGetIdCS(regs, rgb1_info, true);
const auto converted_id = ShaderGetIdCS(regs, converted_info, true);
const auto mip1_id = ShaderGetIdCS(regs, mip1_info, true);
const auto mip3_id = ShaderGetIdCS(regs, mip3_info, true);
const auto array_id = ShaderGetIdCS(regs, array_info, true);
const auto cube_id = ShaderGetIdCS(regs, cube_info, true);
Require("ImageSpecializationId", "pipeline cache key",
identity_id != rgb1_id &&
identity_id.ids.size() == rgb1_id.ids.size() &&
identity_id != converted_id &&
identity_id.ids.size() == converted_id.ids.size() &&
mip1_id != mip3_id && mip1_id.ids.size() == mip3_id.ids.size() &&
array_id != cube_id && array_id.ids.size() == cube_id.ids.size(),
"image conversion, swizzle, mip-count, or cube variants share a "
"pipeline ID");
void CheckImageSamplerSpecialization() {
ShaderSamplerResource filtered_sampler{};
filtered_sampler.fields[2] =
(1u << 20u) | (3u << 22u) | (2u << 24u) | (2u << 26u);
filtered_sampler.SetPointFiltering();
Require("ImageSpecializationId", "forced point sampler",
Require("ImageSamplerSpecialization", "forced point sampler",
filtered_sampler.XyMagFilter() == 0u &&
filtered_sampler.XyMinFilter() == 0u &&
filtered_sampler.ZFilter() == 1u &&
@@ -22594,7 +22526,7 @@ void CheckImageSpecializationId() {
ShaderSamplerResource base_mip_sampler{};
base_mip_sampler.fields[2] = (3u << 20u) | (1u << 22u) | (2u << 24u);
base_mip_sampler.SetPointFiltering();
Require("ImageSpecializationId", "base-mip point sampler",
Require("ImageSamplerSpecialization", "base-mip point sampler",
base_mip_sampler.XyMagFilter() == 0u &&
base_mip_sampler.XyMinFilter() == 0u &&
base_mip_sampler.ZFilter() == 1u &&
@@ -22632,12 +22564,12 @@ void CheckImageSpecializationId() {
sampler_descriptor.dword_count = 4;
mixed_sampler_snapshot.samplers.push_back(sampler_descriptor);
std::string specialization_error;
Require("ImageSpecializationId", "mixed sampler specialization",
Require("ImageSamplerSpecialization", "mixed sampler specialization",
ShaderRecompiler::IR::SpecializeResources(mixed_sampler_program,
mixed_sampler_snapshot,
&specialization_error),
specialization_error);
Require("ImageSpecializationId", "mixed sampler variant",
Require("ImageSamplerSpecialization", "mixed sampler variant",
mixed_sampler_program.info.samplers.size() == 2u &&
!mixed_sampler_program.info.samplers[0].force_point_filtering &&
mixed_sampler_program.info.samplers[1].force_point_filtering &&
@@ -22658,7 +22590,7 @@ void CheckImageSpecializationId() {
ShaderRecompiler::IR::ResourceSnapshot packed_atomic_snapshot;
packed_atomic_snapshot.images.push_back(packed_image_descriptor);
std::string atomic_error;
Require("ImageSpecializationId", "packed atomic rejection",
Require("ImageSamplerSpecialization", "packed atomic rejection",
!ShaderRecompiler::IR::SpecializeResources(
packed_atomic_program, packed_atomic_snapshot, &atomic_error) &&
atomic_error.find("unsupported format 34") != std::string::npos,
@@ -24389,7 +24321,7 @@ int main(int argc, char **argv) {
return 0;
}
if (argc == 2 && std::strcmp(argv[1], "--indirect-image-only") == 0) {
CheckImageSpecializationId();
CheckImageSamplerSpecialization();
CheckIndirectImageKeySwitch();
return 0;
}
@@ -24431,7 +24363,7 @@ int main(int argc, char **argv) {
CheckBasicStorageTextureDescriptor();
CheckStorageTextureLinearUploadLayout();
CheckStorageTextureDepthTileUploadLayout();
CheckImageSpecializationId();
CheckImageSamplerSpecialization();
CheckStandard64RenderTargetTileRoundTrip();
CheckStorageTextureVolumeUploadLayout();
CheckStorageTextureVolumeMipRegions();
+148 -86
View File
@@ -25,6 +25,7 @@
#include "graphics/shader/recompiler/ir/passes/SrtWalker.h"
#include "graphics/shader/recompiler/ir/passes/SsaRewrite.h"
#include "graphics/shader/shader.h"
#include "graphics/shader/shaderCompiler.h"
#include "libs/agc.h"
#include "spirv-tools/libspirv.hpp"
@@ -76,6 +77,46 @@ ShaderRecompiler::CompileOptions MakeCompileOptions(ShaderType stage) {
return options;
}
bool ReadHostTestMemory(void *, uint64_t address, uint32_t *value) {
if (address == 0 || value == nullptr) {
return false;
}
std::memcpy(value, reinterpret_cast<const void *>(address), sizeof(*value));
return true;
}
bool CompilePixelRuntime(const ShaderParams &params,
ShaderPixelInputInfo &input_info,
std::string *error) {
auto options = MakeCompileOptions(ShaderType::Pixel);
options.shader_hash = params.hash;
options.shader_base = params.Base();
options.user_data = params.user_data.data();
options.user_data_count = static_cast<uint32_t>(params.user_data.size());
options.scratch_dwords = input_info.scratch_size_dwords;
options.push_constant_offset = input_info.push_constant_offset;
options.read_specialization_memory = ReadHostTestMemory;
options.input_info.pixel = &input_info;
ShaderRecompiler::CompileResult result;
if (!ShaderRecompiler::TryRecompile(params.code, options, result, error)) {
return false;
}
input_info.stage.program =
std::make_shared<const ShaderRecompiler::IR::Program>(
std::move(result.program));
input_info.stage.resources =
std::make_shared<const ShaderRecompiler::IR::ResourceSnapshot>(
std::move(result.resources));
return true;
}
template <typename InputInfo>
std::vector<uint32_t> MakeStageStaticKey(const InputInfo &input_info) {
std::vector<uint32_t> key;
BuildStageStaticKey(input_info, key);
return key;
}
std::vector<uint32_t>
CfgInstructionCoverage(const ShaderRecompiler::CFG::Graph &graph,
size_t instruction_count) {
@@ -9107,7 +9148,7 @@ void TestNewShaderRecompilerAuxPositionExports() {
ShaderVertexInputInfo key0{};
ShaderVertexInputInfo key1{};
key1.pa_cl_vs_out_cntl = 1;
Check(ShaderGetIdVS(regs, key0, false) != ShaderGetIdVS(regs, key1, false),
Check(MakeStageStaticKey(key0) != MakeStageStaticKey(key1),
"PA_CL_VS_OUT_CNTL is absent from the vertex shader cache key");
}
@@ -10513,8 +10554,7 @@ void TestRenderTargetReverseExportMapping() {
reversed_info.target_export_mapping[0] = gr32.export_mapping;
HW::PixelShaderInfo regs{};
Check(ShaderGetIdPS(regs, identity_info, false) !=
ShaderGetIdPS(regs, reversed_info, false),
Check(MakeStageStaticKey(identity_info) != MakeStageStaticKey(reversed_info),
"pixel shader cache identity omitted the render-target export mapping");
regs.ps_regs.data_addr = reinterpret_cast<uint64_t>(shader);
@@ -10527,18 +10567,13 @@ void TestRenderTargetReverseExportMapping() {
mappings[0] = gr32.export_mapping;
ShaderPixelInputInfo compiled_info{};
ShaderVertexInputInfo vertex_info{};
std::span<const uint32_t> compiled_spirv;
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 "
PrepareProgram(regs, sh, vertex_info, mappings, compiled_info);
Check(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, vertex_info, mappings, compiled_info,
compiled_spirv) &&
compiled_info.target_export_mapping[0] == gr32.export_mapping,
PrepareProgram(regs, sh, vertex_info, mappings, compiled_info);
Check(compiled_info.target_export_mapping[0] == gr32.export_mapping,
"active reverse MRT mapping was lost before shader specialization");
}
@@ -11517,15 +11552,12 @@ void TestNewShaderRecompilerPixelPipelineEntry() {
ShaderMapUserData(regs.ps_regs.data_addr, mapped);
HW::ShaderRegisters sh{};
const std::array<Prospero::ColorComponentMapping, 8> mappings{};
ShaderVertexInputInfo vertex_info{};
ShaderPixelInputInfo input_info{};
std::vector<uint32_t> spirv;
Check(ShaderCompileSpirvPS(regs, sh, input_info, spirv),
"new pixel shader recompiler wrapper did not produce SPIR-V");
Check(!spirv.empty(),
"new pixel shader recompiler wrapper returned empty SPIR-V");
Check(spirv.front() == 0x07230203u,
"new pixel shader recompiler wrapper did not emit SPIR-V binary");
CheckSpirvBinaryValidates(spirv);
const auto params = PrepareProgram(regs, sh, vertex_info, mappings, input_info);
Check(params.hash == regs.ps_regs.chksum && params.code.data() == shader,
"pixel shader program parameters lost source identity");
const uint32_t vcc_load_shader[] = {
EncodeSMovB32(106, 27), EncodeSMovB32(107, 28), EncodeSmem0(0x02, 44, 53),
@@ -11551,10 +11583,10 @@ void TestNewShaderRecompilerPixelPipelineEntry() {
ShaderMapUserData(vcc_regs.ps_regs.data_addr, vcc_mapped);
ShaderPixelInputInfo vcc_input{};
std::vector<uint32_t> vcc_spirv;
Check(ShaderCompileSpirvPS(vcc_regs, sh, vcc_input, vcc_spirv),
"VCC raw-load pointer was lost");
CheckSpirvBinaryValidates(vcc_spirv);
const auto vcc_params =
PrepareProgram(vcc_regs, sh, vertex_info, mappings, vcc_input);
std::string error;
Check(CompilePixelRuntime(vcc_params, vcc_input, &error), error.c_str());
}
void TestComputeLdsAllocationIdentity() {
@@ -11577,19 +11609,28 @@ void TestComputeLdsAllocationIdentity() {
uint32_t expected_dwords) {
regs.cs_regs.lds_size = encoded_lds_size;
ShaderComputeInputInfo input_info{};
std::span<const uint32_t> spirv;
Check(ShaderCompileInfoCS(regs, sh, false, input_info, spirv),
"compute LDS allocation shader did not compile");
const auto params = PrepareProgram(regs, sh, input_info);
Check(input_info.lds_size_dwords == expected_dwords,
"COMPUTE_PGM_RSRC2 LDS allocation units were not decoded");
const std::vector<uint32_t> binary(spirv.begin(), spirv.end());
Check(MeasureSpirv(binary).workgroup_variables == 1u,
auto options = MakeCompileOptions(ShaderType::Compute);
options.shader_hash = params.hash;
options.shader_base = params.Base();
options.user_data = params.user_data.data();
options.user_data_count = static_cast<uint32_t>(params.user_data.size());
options.input_info.compute = &input_info;
options.wave_size = input_info.wave_size;
options.scratch_dwords = input_info.scratch_size_dwords;
ShaderRecompiler::CompileResult result;
std::string error;
Check(ShaderRecompiler::TryRecompile(shader, options, result, &error),
error.c_str());
Check(MeasureSpirv(result.spirv).workgroup_variables == 1u,
"LDS shader did not declare exactly one Workgroup variable");
Check(SpirvArrayLengthCount(binary, expected_dwords) == 1u,
Check(SpirvArrayLengthCount(result.spirv, expected_dwords) == 1u,
"SPIR-V workgroup array did not use the declared LDS allocation");
Check(SpirvUnsignedLessThanBoundCount(binary, expected_dwords) == 1u,
Check(SpirvUnsignedLessThanBoundCount(result.spirv, expected_dwords) == 1u,
"LDS bounds check did not use the declared allocation");
CheckSpirvBinaryValidates(binary);
CheckSpirvBinaryValidates(result.spirv);
return input_info;
};
@@ -11602,21 +11643,19 @@ void TestComputeLdsAllocationIdentity() {
};
const auto lds_1152 = compile(decode_lds_field(lds_1152_rsrc2), 1152u);
const auto lds_896 = compile(decode_lds_field(lds_896_rsrc2), 896u);
Check(ShaderGetIdCS(regs, lds_1152, true) !=
ShaderGetIdCS(regs, lds_896, true),
Check(MakeStageStaticKey(lds_1152) != MakeStageStaticKey(lds_896),
"compute pipeline identity omitted the LDS allocation");
auto split_wave = lds_896;
split_wave.needs_lds_barriers = true;
Check(ShaderGetIdCS(regs, lds_896, true) !=
ShaderGetIdCS(regs, split_wave, true),
Check(MakeStageStaticKey(lds_896) != MakeStageStaticKey(split_wave),
"compute shader identity omitted split-wave LDS synchronization");
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),
Check(MakeStageStaticKey(tg_size_disabled) !=
MakeStageStaticKey(tg_size_enabled),
"compute shader identity omitted TG_SIZE semantics");
auto dispatch_disabled = lds_896;
@@ -11625,32 +11664,42 @@ void TestComputeLdsAllocationIdentity() {
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");
Check(MakeStageStaticKey(dispatch_disabled) !=
MakeStageStaticKey(dispatch_enabled),
"dispatch-dimension mode did not select 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),
Check(MakeStageStaticKey(dispatch_enabled) ==
MakeStageStaticKey(second_extent),
"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);
ShaderComputeInputInfo scratch_info{};
std::span<const uint32_t> scratch_spirv;
Check(ShaderCompileInfoCS(regs, sh, false, scratch_info, scratch_spirv),
"compute scratch metadata shader did not compile");
const auto scratch_params = PrepareProgram(regs, sh, scratch_info);
Check(scratch_info.scratch_size_dwords == 7,
"AGC per-thread scratch size was not propagated");
Check(scratch_info.stage.program != nullptr &&
scratch_info.stage.program->scratch_dwords == 7,
auto scratch_options = MakeCompileOptions(ShaderType::Compute);
scratch_options.shader_hash = scratch_params.hash;
scratch_options.shader_base = scratch_params.Base();
scratch_options.user_data = scratch_params.user_data.data();
scratch_options.user_data_count =
static_cast<uint32_t>(scratch_params.user_data.size());
scratch_options.input_info.compute = &scratch_info;
scratch_options.wave_size = scratch_info.wave_size;
scratch_options.scratch_dwords = scratch_info.scratch_size_dwords;
ShaderRecompiler::CompileResult scratch_result;
std::string scratch_error;
Check(ShaderRecompiler::TryRecompile(scratch_params.code, scratch_options,
scratch_result, &scratch_error),
scratch_error.c_str());
Check(scratch_result.program.scratch_dwords == 7,
"AGC per-thread scratch size did not reach the compiler program");
Check(ShaderGetIdCS(regs, scratch_info, true) !=
ShaderGetIdCS(regs, lds_896, true),
Check(MakeStageStaticKey(scratch_info) != MakeStageStaticKey(lds_896),
"compute pipeline identity omitted the scratch allocation");
const uint32_t append_shader[] = {
@@ -11810,20 +11859,18 @@ void TestPixelProgramCacheBindingIdentity() {
const uint32_t shader_10[] = {0xbf810000u};
HW::ShaderRegisters sh{};
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),
Check(MakeStageStaticKey(no_depth_export) != MakeStageStaticKey(depth_export),
"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),
Check(MakeStageStaticKey(no_depth_export) != MakeStageStaticKey(shifted_push),
"pixel shader identity omitted graphics push-bank placement");
auto check_cache_identity = [&](const uint32_t *shader, uint64_t checksum) {
auto check_program_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;
@@ -11834,26 +11881,29 @@ void TestPixelProgramCacheBindingIdentity() {
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");
const auto first_params =
PrepareProgram(regs, sh, vertex_info, identity_mappings, first_info);
const auto first_key = MakeStageStaticKey(first_info);
std::string error;
Check(CompilePixelRuntime(first_params, first_info, &error), error.c_str());
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");
const auto second_params =
PrepareProgram(regs, sh, vertex_info, identity_mappings, second_info);
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");
first_params.hash == second_params.hash &&
first_key == MakeStageStaticKey(second_info) &&
first_info.stage.program != nullptr &&
MaterializeProgram(first_info.stage.program, second_params, second_info) &&
second_info.stage.program == first_info.stage.program,
"pixel program matching did not reuse an identical graphics placement");
return std::pair {first_params.hash, first_key};
};
check_cache_identity(shader_01, 0x91a27e6300000001ull);
check_cache_identity(shader_10, 0x91a27e6300000002ull);
const auto request_01 = check_program_identity(shader_01, 0);
const auto request_10 = check_program_identity(shader_10, 0);
Check(request_01 == request_10,
"relocated identical pixel programs did not share their source identity");
const uint32_t push_shader[] = {
EncodeVop1(0x01, 0, 0), EncodeVop1(0x01, 1, 1),
@@ -11883,24 +11933,36 @@ void TestPixelProgramCacheBindingIdentity() {
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");
const auto params_at_zero =
PrepareProgram(push_regs, push_sh, vertex_at_zero, mappings, at_zero);
const auto key_at_zero = MakeStageStaticKey(at_zero);
std::string error;
Check(CompilePixelRuntime(params_at_zero, at_zero, &error), error.c_str());
const auto params_at_36 =
PrepareProgram(push_regs, push_sh, vertex_at_36, mappings, at_36);
const auto key_at_36 = MakeStageStaticKey(at_36);
Check(CompilePixelRuntime(params_at_36, at_36, &error), error.c_str());
const auto params_at_zero_again =
PrepareProgram(push_regs, push_sh, vertex_at_zero, mappings,
at_zero_again);
auto shifted_options = MakeCompileOptions(ShaderType::Pixel);
shifted_options.input_info.pixel = &at_36;
shifted_options.push_constant_offset = at_36.push_constant_offset;
ShaderRecompiler::CompileResult shifted_result;
std::string shifted_error;
Check(ShaderRecompiler::TryRecompile(push_shader, shifted_options,
shifted_result, &shifted_error),
shifted_error.c_str());
Check(at_zero.push_constant_offset == 0 &&
at_36.push_constant_offset == 36 &&
key_at_zero != key_at_36 &&
MakeStageStaticKey(at_zero_again) == key_at_zero &&
at_zero.stage.program != at_36.stage.program &&
spirv_at_zero.data() != spirv_at_36.data() &&
MaterializeProgram(at_zero.stage.program, params_at_zero_again,
at_zero_again) &&
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");
SpirvHasMemberDecorationValue(shifted_result.spirv, 35u, 36u),
"pixel program matching did not partition and reuse graphics push placement");
}
void TestGraphicsPushConstantPlacement() {