Share sampler descriptor snapshots across native variants
This commit is contained in:
parent
8b0cc79acf
commit
7f158c656e
|
|
@ -791,7 +791,8 @@ void RenderExecutor::PrepareBindings(const ShaderStageRuntime& runtime,
|
|||
}
|
||||
prepared.samplers.reserve(program.info.samplers.size());
|
||||
for (uint32_t i = 0; i < program.info.samplers.size(); i++) {
|
||||
prepared.samplers.push_back(NativeSampler(m_context, program, i, snapshot.samplers[i]));
|
||||
prepared.samplers.push_back(NativeSampler(
|
||||
m_context, program, i, snapshot.samplers[program.info.samplers[i].snapshot_index]));
|
||||
}
|
||||
prepared.shader_data.reserve(program.bindings.ShaderDataDwords());
|
||||
for (const auto reg: program.bindings.user_data_registers) {
|
||||
|
|
|
|||
|
|
@ -321,7 +321,8 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer,
|
|||
static_cast<uint32_t>(r.TileMode()));
|
||||
}
|
||||
for (uint32_t i = 0; i < program.info.samplers.size(); i++) {
|
||||
const auto r = DecodeNativeDescriptor<ShaderSamplerResource>(resources.samplers[i]);
|
||||
const auto r = DecodeNativeDescriptor<ShaderSamplerResource>(
|
||||
resources.samplers[program.info.samplers[i].snapshot_index]);
|
||||
LOGF(" CS sampler[%u]: source=%u clamp=%u/%u/%u filter=%u/%u/%u mip=%u "
|
||||
"lod=%u-%u bias=%d\n",
|
||||
i, program.info.samplers[i].source, static_cast<uint32_t>(r.ClampX()),
|
||||
|
|
|
|||
|
|
@ -148,6 +148,8 @@ struct ImageResource {
|
|||
struct SamplerResource {
|
||||
uint32_t source = 0;
|
||||
uint32_t first_use_pc = 0;
|
||||
// Native filtering/border variants share the original sampler's runtime descriptor.
|
||||
uint32_t snapshot_index = 0;
|
||||
bool force_point_filtering = false;
|
||||
bool depth_compare = false;
|
||||
bool integer_border = false;
|
||||
|
|
|
|||
|
|
@ -109,8 +109,7 @@ Prospero::BufferFormat ImageConversionFormat(Prospero::BufferFormat format) {
|
|||
|
||||
enum class SamplerClass : uint8_t { Float, Integer, PointInteger };
|
||||
|
||||
template <typename Image>
|
||||
SamplerClass ClassifySampler(const Image& image) {
|
||||
SamplerClass ClassifySampler(const ImageResource& image) {
|
||||
if (image.numeric_class == Prospero::TextureNumericClass::Sint ||
|
||||
image.conversion_format != Prospero::BufferFormat::kInvalid) {
|
||||
return SamplerClass::PointInteger;
|
||||
|
|
@ -418,9 +417,6 @@ private:
|
|||
uint32_t count = 0;
|
||||
};
|
||||
|
||||
template <typename Images>
|
||||
bool BuildSamplerPlan(const ShaderInfo& base, const Images& images, SamplerPlan& plan);
|
||||
|
||||
static bool BuildResourceSpecialization(const ResourcePlan& program, ResourceSnapshot& snapshot,
|
||||
ResourceSpecialization& specialization) {
|
||||
for (uint32_t i = 0; i < specialization.images.size(); i++) {
|
||||
|
|
@ -563,30 +559,21 @@ static bool BuildResourceSpecialization(const ResourcePlan& program, ResourceSna
|
|||
}
|
||||
}
|
||||
}
|
||||
SamplerPlan sampler_plan;
|
||||
if (!BuildSamplerPlan(program.info, specialization.images, sampler_plan)) {
|
||||
return SpecializationFail("specialized sampler layout exceeds its resource limit");
|
||||
}
|
||||
for (uint32_t index = static_cast<uint32_t>(program.info.samplers.size());
|
||||
index < sampler_plan.sampler_count; index++) {
|
||||
snapshot.samplers.push_back(snapshot.samplers[sampler_plan.bindings[index].source]);
|
||||
}
|
||||
ImageRemap(specialization).Apply(snapshot.images);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Images>
|
||||
bool BuildSamplerPlan(const ShaderInfo& base, const Images& images, SamplerPlan& plan) {
|
||||
bool BuildSamplerPlan(const ShaderInfo& base, SamplerPlan& plan) {
|
||||
if (base.samplers.size() > plan.mapping.size()) {
|
||||
return false;
|
||||
}
|
||||
std::array<uint8_t, ShaderInfo::MaxSamplers> usage {};
|
||||
plan.sampler_count = static_cast<uint32_t>(base.samplers.size());
|
||||
for (const auto& pair: base.sampled_pairs) {
|
||||
if (pair.image >= images.size() || pair.sampler >= base.samplers.size()) {
|
||||
if (pair.image >= base.images.size() || pair.sampler >= base.samplers.size()) {
|
||||
return false;
|
||||
}
|
||||
usage[pair.sampler] |= 1u << static_cast<uint32_t>(ClassifySampler(images[pair.image]));
|
||||
usage[pair.sampler] |= 1u << static_cast<uint32_t>(ClassifySampler(base.images[pair.image]));
|
||||
}
|
||||
for (uint32_t index = 0; index < base.samplers.size(); index++) {
|
||||
auto& mapping = plan.mapping[index];
|
||||
|
|
@ -1134,7 +1121,7 @@ void ApplyResourceSpecialization(Program& program, const ResourceSpecialization&
|
|||
}
|
||||
|
||||
SamplerPlan sampler_plan;
|
||||
EXIT_IF(!BuildSamplerPlan(program.info, images, sampler_plan));
|
||||
EXIT_IF(!BuildSamplerPlan(program.info, sampler_plan));
|
||||
auto& samplers = program.info.samplers;
|
||||
auto& sampled_pairs = program.info.sampled_pairs;
|
||||
const auto original_sampler_count = samplers.size();
|
||||
|
|
@ -1144,6 +1131,7 @@ void ApplyResourceSpecialization(Program& program, const ResourceSpecialization&
|
|||
if (index >= original_sampler_count) {
|
||||
samplers.push_back(samplers[binding.source]);
|
||||
}
|
||||
samplers[index].snapshot_index = binding.source;
|
||||
samplers[index].force_point_filtering = binding.type == SamplerClass::PointInteger;
|
||||
samplers[index].integer_border = binding.type != SamplerClass::Float;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,29 +95,33 @@ Libs::Graphics::ShaderRecompiler::IR::ResourcePlan UserDataBufferPlan() {
|
|||
return ExtractResourcePlan(program);
|
||||
}
|
||||
|
||||
Libs::Graphics::ShaderRecompiler::IR::ResourcePlan MixedSamplerPlan() {
|
||||
Libs::Graphics::ShaderRecompiler::IR::Program MixedSamplerProgram() {
|
||||
using namespace Libs::Graphics::ShaderRecompiler::IR;
|
||||
Program program;
|
||||
program.stage = Libs::Graphics::ShaderType::Compute;
|
||||
program.srt_plan_complete = true;
|
||||
program.resource_tracking_complete = true;
|
||||
AddValueBlock(program);
|
||||
auto &block = AddValueBlock(program);
|
||||
|
||||
const auto AddSource = [&program](uint32_t dword_count, uint32_t first) {
|
||||
const auto AddSource = [&program](uint32_t dword_count) {
|
||||
DescriptorSource source;
|
||||
source.dword_count = dword_count;
|
||||
source.dwords[0] = Value(first);
|
||||
for (uint32_t i = 1; i < dword_count; i++) {
|
||||
for (uint32_t i = 0; i < dword_count; i++) {
|
||||
source.dwords[i] = Value(0u);
|
||||
}
|
||||
program.descriptor_sources.push_back(source);
|
||||
return static_cast<uint32_t>(program.descriptor_sources.size() - 1u);
|
||||
};
|
||||
|
||||
const auto image0 = AddSource(8, 0);
|
||||
const auto image1 = AddSource(8, 0);
|
||||
const auto sampler0 = AddSource(4, 0x11111111u);
|
||||
const auto sampler1 = AddSource(4, 0x22222222u);
|
||||
const auto image0 = AddSource(8);
|
||||
const auto image1 = AddSource(8);
|
||||
const auto sampler0 = AddSource(4);
|
||||
const auto sampler1 = AddSource(4);
|
||||
for (uint32_t index = 0; index < 2; ++index) {
|
||||
auto &value = block.AppendNewInst(
|
||||
ValueOpcode::GetUserData, {Value(static_cast<ScalarReg>(index))});
|
||||
program.descriptor_sources[sampler0 + index].dwords[0] = Value(&value);
|
||||
}
|
||||
program.info.images.push_back(
|
||||
{.source = image0,
|
||||
.resource_class = ImageResourceClass::Sampled,
|
||||
|
|
@ -137,7 +141,7 @@ Libs::Graphics::ShaderRecompiler::IR::ResourcePlan MixedSamplerPlan() {
|
|||
program.info.sampled_pairs.push_back({.image = 0, .sampler = 0});
|
||||
program.info.sampled_pairs.push_back({.image = 0, .sampler = 1});
|
||||
program.info.sampled_pairs.push_back({.image = 1, .sampler = 1});
|
||||
return ExtractResourcePlan(program);
|
||||
return program;
|
||||
}
|
||||
|
||||
void TestMappedSrtUsesDirectReaderByDefault() {
|
||||
|
|
@ -373,18 +377,35 @@ void TestFiniteImageRefreshReusesScalarReads() {
|
|||
"finite image refresh grew reusable resource storage after warmup");
|
||||
}
|
||||
|
||||
void TestMixedSamplerDuplicatesTheCorrectSnapshot() {
|
||||
void TestMixedSamplerVariantsShareRuntimeDescriptor() {
|
||||
using namespace Libs::Graphics::ShaderRecompiler::IR;
|
||||
auto plan = MixedSamplerPlan();
|
||||
auto program = MixedSamplerProgram();
|
||||
auto plan = ExtractResourcePlan(program);
|
||||
std::array<uint32_t, 2> user_data{0x11111111u, 0x22222222u};
|
||||
const SrtRuntime runtime{.user_data = user_data};
|
||||
ResourceSnapshot snapshot;
|
||||
ResourceSpecialization specialization;
|
||||
Check(MaterializeResources(plan, {}, snapshot, specialization),
|
||||
Check(MaterializeResources(plan, runtime, snapshot, specialization),
|
||||
"mixed sampler materialization failed");
|
||||
Check(snapshot.samplers.size() == 3,
|
||||
"mixed sampler materialization appended unrelated samplers");
|
||||
Check(snapshot.samplers[2] == snapshot.samplers[1] &&
|
||||
snapshot.samplers[2] != snapshot.samplers[0],
|
||||
"point sampler variant duplicated the wrong runtime descriptor");
|
||||
ApplyResourceSpecialization(program, specialization);
|
||||
const auto &samplers = program.info.samplers;
|
||||
Check(snapshot.samplers.size() == 2 && samplers.size() == 3 &&
|
||||
samplers[0].snapshot_index == 0 && samplers[1].snapshot_index == 1 &&
|
||||
samplers[2].snapshot_index == 1 &&
|
||||
samplers[0].source == plan.info.samplers[0].source &&
|
||||
samplers[1].source == plan.info.samplers[1].source &&
|
||||
samplers[2].source == samplers[1].source &&
|
||||
!samplers[1].force_point_filtering && samplers[2].force_point_filtering &&
|
||||
program.info.sampled_pairs[2].sampler == 2,
|
||||
"native sampler variants lost their source identity or binding order");
|
||||
const auto capacity = snapshot.samplers.capacity();
|
||||
user_data[1] = 0x33333333u;
|
||||
Check(MaterializeResources(plan, runtime, snapshot, specialization) &&
|
||||
snapshot.samplers.size() == 2 && snapshot.samplers.capacity() == capacity &&
|
||||
snapshot.samplers[samplers[0].snapshot_index].dwords[0] == user_data[0] &&
|
||||
snapshot.samplers[samplers[1].snapshot_index].dwords[0] == user_data[1] &&
|
||||
snapshot.samplers[samplers[2].snapshot_index].dwords[0] == user_data[1],
|
||||
"sampler variants retained stale or duplicated descriptors after refresh");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -410,7 +431,7 @@ int main() {
|
|||
TestWrittenDescriptorUsesStrictReaderOnce();
|
||||
TestFailedMaterializationRejectsStage();
|
||||
TestFiniteImageRefreshReusesScalarReads();
|
||||
TestMixedSamplerDuplicatesTheCorrectSnapshot();
|
||||
TestMixedSamplerVariantsShareRuntimeDescriptor();
|
||||
std::puts("ResourceMaterializationTests: all cases passed");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34690,7 +34690,11 @@ void CheckImageSamplerSpecialization() {
|
|||
mixed_sampler_program.info.sampled_pairs[2].sampler == 2u &&
|
||||
mixed_sampler_program.info.sampled_pairs[3].sampler == 1u &&
|
||||
mixed_sampler_program.memory_info[0].sampler == 2u &&
|
||||
mixed_sampler_snapshot.samplers.size() == 3u,
|
||||
mixed_sampler_snapshot.samplers.size() == 1u &&
|
||||
std::ranges::all_of(mixed_sampler_program.info.samplers,
|
||||
[](const auto& sampler) {
|
||||
return sampler.source == 4u && sampler.snapshot_index == 0u;
|
||||
}),
|
||||
"a shared float/unsigned/signed sampler lost its border or filtering "
|
||||
"class in the compiled bindings, instruction or descriptor snapshot");
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue