shader: emit dynamic sample offsets with the enabled maintenance8 feature
This commit is contained in:
parent
652154aead
commit
460a196fca
|
|
@ -33,7 +33,7 @@ struct GraphicContext {
|
|||
// bool fp64_denorm_preserve = false; // Temporarily disabled.
|
||||
bool attachment_feedback_loop_enabled = false;
|
||||
bool provoking_vertex_last_enabled = false;
|
||||
bool depth_color_copy_enabled = false;
|
||||
bool maintenance8_enabled = false;
|
||||
bool supports_block_texel_view = false;
|
||||
bool mesh_shader_enabled = false;
|
||||
vk::PhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = {};
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ void DumpShaderOriginal(const char* stage_name, uint64_t shader_hash,
|
|||
}
|
||||
|
||||
bool ValidateShaderSpirv(const char* label, uint64_t shader_hash,
|
||||
const std::vector<uint32_t>& spirv) {
|
||||
const std::vector<uint32_t>& spirv, bool maintenance8_enabled) {
|
||||
if (!Config::ShaderValidationEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -160,7 +160,9 @@ bool ValidateShaderSpirv(const char* label, uint64_t shader_hash,
|
|||
static_cast<int>(position.column), static_cast<int>(position.index),
|
||||
message);
|
||||
});
|
||||
if (tools.Validate(spirv)) {
|
||||
spvtools::ValidatorOptions validator_options;
|
||||
validator_options.SetAllowOffsetTextureOperand(maintenance8_enabled);
|
||||
if (tools.Validate(spirv.data(), spirv.size(), validator_options)) {
|
||||
return true;
|
||||
}
|
||||
spvtools::SpirvTools disassembler(SPV_ENV_VULKAN_1_2);
|
||||
|
|
@ -296,14 +298,15 @@ struct PipelineCache::ProgramCache {
|
|||
std::span<const uint32_t> function_code) {
|
||||
auto result = ShaderRecompiler::CompileProgram(std::move(translated), options,
|
||||
specialization, push_data_start_dword);
|
||||
if (!ValidateShaderSpirv(options.dump_label, options.shader_hash, result.spirv)) {
|
||||
if (!ValidateShaderSpirv(options.dump_label, options.shader_hash, result.spirv,
|
||||
options.maintenance8_enabled)) {
|
||||
DumpShaderSpirv(stage_name, options.shader_hash, result.spirv);
|
||||
EXIT("%s failed hash=0x%016" PRIx64 ": SPIR-V validation failed\n", options.dump_label,
|
||||
options.shader_hash);
|
||||
}
|
||||
DumpShaderSpirv(stage_name, options.shader_hash, result.spirv);
|
||||
|
||||
const auto module = CompileSPV(result.spirv, device);
|
||||
const auto module = CompileSPV(result.spirv, graphics.device);
|
||||
EXIT_IF(module == nullptr);
|
||||
if (options.dump_ir) {
|
||||
LOGF("%s SPIR-V words=%" PRIu64 " wave_size=%u\n", options.dump_label,
|
||||
|
|
@ -384,6 +387,7 @@ struct PipelineCache::ProgramCache {
|
|||
}
|
||||
ShaderRecompiler::CompileOptions options;
|
||||
options.stage = stage;
|
||||
options.maintenance8_enabled = graphics.maintenance8_enabled;
|
||||
options.shader_hash = params.hash;
|
||||
options.user_data = user_data;
|
||||
options.back_code = params.back_code;
|
||||
|
|
@ -456,26 +460,26 @@ struct PipelineCache::ProgramCache {
|
|||
return permutation.handle;
|
||||
}
|
||||
|
||||
explicit ProgramCache(vk::Device device): device(device) {
|
||||
explicit ProgramCache(GraphicContext& graphics): graphics(graphics) {
|
||||
lookup_key.static_state.reserve(MaxStaticKeyWords);
|
||||
}
|
||||
~ProgramCache() {
|
||||
for (const auto& [key, entry]: programs) {
|
||||
(void)key;
|
||||
for (const auto& permutation: entry.permutations) {
|
||||
device.destroyShaderModule(permutation.handle.module, nullptr);
|
||||
graphics.device.destroyShaderModule(permutation.handle.module, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<ProgramKey, SourceEntry, ProgramKeyHash> programs;
|
||||
ProgramKey lookup_key;
|
||||
vk::Device device;
|
||||
GraphicContext& graphics;
|
||||
uint64_t next_shader_id = 0;
|
||||
};
|
||||
|
||||
PipelineCache::PipelineCache(GraphicContext& graphics)
|
||||
: m_graphics(graphics), m_program_cache(std::make_unique<ProgramCache>(graphics.device)) {
|
||||
: m_graphics(graphics), m_program_cache(std::make_unique<ProgramCache>(graphics)) {
|
||||
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
|
||||
InitializeDriverCache();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1038,7 +1038,7 @@ bool RenderExecutor::CopyDepthToColor(CommandBuffer& buffer, const DrawCallInfo&
|
|||
const auto& hw = buffer.GetRegisters();
|
||||
auto& depth = state.depth_info;
|
||||
auto& color = state.color_info[0];
|
||||
EXIT_NOT_IMPLEMENTED(!m_context.GetGraphics().depth_color_copy_enabled ||
|
||||
EXIT_NOT_IMPLEMENTED(!m_context.GetGraphics().maintenance8_enabled ||
|
||||
!Prospero::IsRectList(ucfg.GetPrimType()) ||
|
||||
draw.IsIndexed() || draw.index_count != 3 || draw.instance_count != 1 ||
|
||||
emit.first_vertex != 0 || emit.first_instance != 0 ||
|
||||
|
|
|
|||
|
|
@ -553,9 +553,9 @@ static vk::Device VulkanCreateDevice(GraphicContext& graphics,
|
|||
graphics.attachment_feedback_loop_enabled =
|
||||
feedback_extensions && feedback_layout.attachmentFeedbackLoopLayout &&
|
||||
feedback_dynamic.attachmentFeedbackLoopDynamicState;
|
||||
graphics.depth_color_copy_enabled = maintenance8_extension && maintenance8.maintenance8;
|
||||
LOGF("Vulkan depth/color copy support: %s\n",
|
||||
graphics.depth_color_copy_enabled ? "true" : "false");
|
||||
graphics.maintenance8_enabled = maintenance8_extension && maintenance8.maintenance8;
|
||||
LOGF("Vulkan maintenance8 support: %s\n",
|
||||
graphics.maintenance8_enabled ? "true" : "false");
|
||||
LOGF("Vulkan depth feedback support: %s\n",
|
||||
graphics.attachment_feedback_loop_enabled ? "true" : "false");
|
||||
if (graphics.mesh_shader_enabled) {
|
||||
|
|
@ -652,7 +652,7 @@ static vk::Device VulkanCreateDevice(GraphicContext& graphics,
|
|||
image_atomic_int64.sparseImageInt64Atomics = VK_FALSE;
|
||||
create_info.pNext = &image_atomic_int64;
|
||||
}
|
||||
if (graphics.depth_color_copy_enabled) {
|
||||
if (graphics.maintenance8_enabled) {
|
||||
maintenance8.pNext = const_cast<void*>(create_info.pNext);
|
||||
create_info.pNext = &maintenance8;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -885,7 +885,8 @@ CompileResult CompileProgram(TranslateResult translated, const CompileOptions& o
|
|||
|
||||
LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " SPIR-V EmitProgram\n",
|
||||
GetDumpLabel(options), StageName(ir.stage), ir.shader_hash);
|
||||
auto spirv = Spirv::EmitProgram(ir, options.input_info, push_data_start_dword);
|
||||
auto spirv = Spirv::EmitProgram(ir, options.input_info, push_data_start_dword,
|
||||
options.maintenance8_enabled);
|
||||
LOGF("%s phase end: stage=%s hash=0x%016" PRIx64 " SPIR-V EmitProgram words=%" PRIu64
|
||||
" elapsed_ms=%" PRIu64 "\n",
|
||||
GetDumpLabel(options), StageName(ir.stage), ir.shader_hash,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ struct CompileOptions {
|
|||
uint64_t shader_hash = 0;
|
||||
bool dump_ir = true;
|
||||
bool early_dump = false;
|
||||
bool maintenance8_enabled = false;
|
||||
const char* dump_label = nullptr;
|
||||
std::span<const uint32_t> user_data;
|
||||
std::span<const uint32_t> back_code;
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ void ValidateNativeProgram(const IR::Program& program, bool lds_storage) {
|
|||
} // namespace
|
||||
|
||||
std::vector<uint32_t> EmitProgram(IR::Program& program, ShaderStageInputInfo input_info,
|
||||
uint32_t push_data_start_dword) {
|
||||
uint32_t push_data_start_dword, bool maintenance8_enabled) {
|
||||
using namespace Emitter;
|
||||
|
||||
if (program.stage != ShaderType::Compute && program.stage != ShaderType::Vertex &&
|
||||
|
|
@ -215,7 +215,7 @@ std::vector<uint32_t> EmitProgram(IR::Program& program, ShaderStageInputInfo inp
|
|||
}
|
||||
IR::ValidateProgram(program, true);
|
||||
program.bindings = {.push_data_start_dword = push_data_start_dword};
|
||||
EmitterState state(program, input_info);
|
||||
EmitterState state(program, input_info, maintenance8_enabled);
|
||||
const auto* workgroup = ShaderWorkgroupInput(program.stage, input_info);
|
||||
state.lane_count =
|
||||
workgroup != nullptr && program.wave_size == 64u && workgroup->host_subgroup_size == 32u
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv {
|
|||
|
||||
// Resets and writes backend IDs and descriptor indices; do not emit the same program concurrently.
|
||||
std::vector<uint32_t> EmitProgram(IR::Program& program, ShaderStageInputInfo input_info,
|
||||
uint32_t push_data_start_dword = 0);
|
||||
uint32_t push_data_start_dword = 0,
|
||||
bool maintenance8_enabled = false);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Spirv
|
||||
|
||||
|
|
|
|||
|
|
@ -333,6 +333,7 @@ uint32_t PackedOffset(ValueEmitContext& ctx, IR::Value value, ImageDimension dim
|
|||
TypeI32Vector(ctx.state, components),
|
||||
std::span(values).first(components));
|
||||
}
|
||||
ctx.state.builder.RequireCapability(spv::CapabilityImageGatherExtended);
|
||||
mask |= spv::ImageOperandsOffsetMask;
|
||||
const auto packed = Unary(ctx.state, spv::OpBitcast, TypeI32(ctx.state), ctx.Def(value));
|
||||
for (uint32_t index = 0; index < components; index++) {
|
||||
|
|
@ -937,8 +938,8 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||
operand_count = 2;
|
||||
}
|
||||
if (layout.offset != NoImageComponent &&
|
||||
!offset_value.IsImmediate()) {
|
||||
ctx.Fail(inst, "has a nonconstant sample texel offset");
|
||||
!offset_value.IsImmediate() && !state.maintenance8_enabled) {
|
||||
ctx.Fail(inst, "requires maintenance8 for a dynamic sample texel offset");
|
||||
}
|
||||
const auto samplers = EmitImageSamplers(ctx, inst);
|
||||
const auto EmitSample = [&](uint32_t resource, uint32_t array_index) {
|
||||
|
|
|
|||
|
|
@ -73,9 +73,9 @@ struct ImageDefinition {
|
|||
};
|
||||
|
||||
struct EmitterState {
|
||||
EmitterState(IR::Program& program_, ShaderStageInputInfo input_info_)
|
||||
EmitterState(IR::Program& program_, ShaderStageInputInfo input_info_, bool maintenance8_enabled_)
|
||||
: builder(program_.stage == ShaderType::Mesh ? 0x00010400u : 0x00010300u),
|
||||
program(program_), input_info(input_info_) {
|
||||
program(program_), input_info(input_info_), maintenance8_enabled(maintenance8_enabled_) {
|
||||
if (ShaderWorkgroupInput(program.stage, input_info) != nullptr) {
|
||||
lds_storage_class = spv::StorageClassWorkgroup;
|
||||
}
|
||||
|
|
@ -88,6 +88,7 @@ struct EmitterState {
|
|||
Builder builder;
|
||||
IR::Program& program;
|
||||
ShaderStageInputInfo input_info;
|
||||
bool maintenance8_enabled;
|
||||
uint32_t void_type = 0;
|
||||
uint32_t bool_type = 0;
|
||||
uint32_t u32_type = 0;
|
||||
|
|
|
|||
|
|
@ -1429,7 +1429,9 @@ void ValidateSpirv(const char *shader_name, const std::vector<u32> &spirv) {
|
|||
messages += buffer;
|
||||
});
|
||||
|
||||
if (!tools.Validate(spirv)) {
|
||||
spvtools::ValidatorOptions options;
|
||||
options.SetAllowOffsetTextureOperand(true);
|
||||
if (!tools.Validate(spirv.data(), spirv.size(), options)) {
|
||||
Fail(shader_name, "SPIR-V validation", messages);
|
||||
}
|
||||
}
|
||||
|
|
@ -1648,6 +1650,7 @@ CompiledShader CompileCase(const TestCase &test, u32 host_subgroup_size = 64) {
|
|||
}
|
||||
ShaderRecompiler::CompileOptions options;
|
||||
options.stage = ShaderType::Compute;
|
||||
options.maintenance8_enabled = true;
|
||||
options.dump_ir = true;
|
||||
auto compute_info = test.compute_info;
|
||||
compute_info.host_subgroup_size = host_subgroup_size;
|
||||
|
|
@ -1717,7 +1720,8 @@ CompiledShader CompileCase(const TestCase &test, u32 host_subgroup_size = 64) {
|
|||
}
|
||||
result.program.shader_info_complete = false;
|
||||
ShaderRecompiler::IR::CollectShaderInfo(result.program, options.input_info);
|
||||
result.spirv = ShaderRecompiler::Spirv::EmitProgram(result.program, options.input_info);
|
||||
result.spirv = ShaderRecompiler::Spirv::EmitProgram(
|
||||
result.program, options.input_info, 0u, options.maintenance8_enabled);
|
||||
const auto shader_data = result.program.bindings.descriptor_counts[
|
||||
static_cast<size_t>(ShaderRecompiler::IR::DescriptorBindingKind::ShaderData)];
|
||||
Require(test.name, "binding layout",
|
||||
|
|
@ -1825,6 +1829,7 @@ CompiledShader CompileFragmentCase(const GraphicsCase &test) {
|
|||
|
||||
ShaderRecompiler::CompileOptions options;
|
||||
options.stage = ShaderType::Pixel;
|
||||
options.maintenance8_enabled = true;
|
||||
options.dump_ir = false;
|
||||
options.input_info.pixel = &pixel_info;
|
||||
options.user_data = user_data;
|
||||
|
|
@ -18712,6 +18717,7 @@ private:
|
|||
m_runtime_context.queue_family = m_queue_family;
|
||||
m_runtime_context.queue = m_queue;
|
||||
m_runtime_context.shader_image_int64_atomics_enabled = true;
|
||||
m_runtime_context.maintenance8_enabled = true;
|
||||
m_runtime_context.attachment_feedback_loop_enabled = m_rasterization_supported;
|
||||
m_runtime_context.provoking_vertex_last_enabled = m_rasterization_supported;
|
||||
const vk::PhysicalDeviceImageFormatInfo2 block_texel_view_info{
|
||||
|
|
@ -18859,9 +18865,11 @@ private:
|
|||
available_provoking_vertex.pNext = &available_feedback_dynamic;
|
||||
vk::PhysicalDeviceImageViewMinLodFeaturesEXT available_min_lod{};
|
||||
available_min_lod.pNext = &available_provoking_vertex;
|
||||
vk::PhysicalDeviceMaintenance8FeaturesKHR available_maintenance8{};
|
||||
available_maintenance8.pNext = &available_min_lod;
|
||||
vk::PhysicalDeviceFeatures2 available_features2{};
|
||||
available_features2.sType = vk::StructureType::ePhysicalDeviceFeatures2;
|
||||
available_features2.pNext = &available_min_lod;
|
||||
available_features2.pNext = &available_maintenance8;
|
||||
m_physical_device.getFeatures2(&available_features2);
|
||||
Require("VulkanHarness", "dispatch",
|
||||
available_features.shaderStorageImageWriteWithoutFormat == true,
|
||||
|
|
@ -18899,6 +18907,8 @@ private:
|
|||
"nonuniform storage buffer indexing is not supported");
|
||||
Require("VulkanHarness", "dispatch", available_min_lod.minLod == true,
|
||||
"image view minimum LOD is not supported");
|
||||
Require("VulkanHarness", "dispatch", available_maintenance8.maintenance8 == true,
|
||||
"maintenance8 dynamic image offsets are not supported");
|
||||
Require("VulkanHarness", "graphics", available_features12.shaderOutputLayer == true,
|
||||
"vertex layer output is not supported");
|
||||
m_rasterization_supported = available_features.fillModeNonSolid &&
|
||||
|
|
@ -18977,7 +18987,10 @@ private:
|
|||
min_lod.pNext = m_rasterization_supported
|
||||
? static_cast<void *>(&provoking_vertex)
|
||||
: static_cast<void *>(&derivatives);
|
||||
device_info.pNext = &min_lod;
|
||||
vk::PhysicalDeviceMaintenance8FeaturesKHR maintenance8{};
|
||||
maintenance8.maintenance8 = true;
|
||||
maintenance8.pNext = &min_lod;
|
||||
device_info.pNext = &maintenance8;
|
||||
vk::PhysicalDeviceFeatures device_features{};
|
||||
device_features.shaderStorageImageWriteWithoutFormat = true;
|
||||
device_features.shaderImageGatherExtended = true;
|
||||
|
|
@ -18994,6 +19007,7 @@ private:
|
|||
VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME,
|
||||
VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME,
|
||||
VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME,
|
||||
VK_KHR_MAINTENANCE_8_EXTENSION_NAME,
|
||||
VK_EXT_IMAGE_VIEW_MIN_LOD_EXTENSION_NAME};
|
||||
if (m_rasterization_supported) {
|
||||
device_extensions.push_back(VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME);
|
||||
|
|
@ -35228,6 +35242,88 @@ template <u32 wave_size> TestCase ImageSampleOffsetsReadFourNeighbors() {
|
|||
return test;
|
||||
}
|
||||
|
||||
void CheckDynamicSampleOffsets(VulkanHarness &vulkan, u32 wave_size) {
|
||||
using O = ShaderOpcode;
|
||||
TestCase test;
|
||||
test.name = wave_size == 32u ? "DynamicSampleOffsets32" : "DynamicSampleOffsets64";
|
||||
test.has_compute_info = test.has_user_data = true;
|
||||
test.compute_info.wave_size = wave_size;
|
||||
test.compute_info.host_subgroup_size = vulkan.SubgroupSize();
|
||||
test.compute_info.threads_num[0] = wave_size;
|
||||
test.compute_info.threads_num[1] = test.compute_info.threads_num[2] = 1u;
|
||||
test.compute_info.thread_ids_num = 1;
|
||||
test.user_data = MakeSampledTextureData(Prospero::BufferFormat::k32_32_32_32Float);
|
||||
test.user_data[2] = 7u | (7u << 14u);
|
||||
test.user_data[3] |= 1u << 16u;
|
||||
test.user_data[5] = 1u << 4u;
|
||||
test.user_data[50] = wave_size * sizeof(u32);
|
||||
// Read the offset selector from a texture, as the native shader does.
|
||||
test.code = {EncodeVop2(0x1b, 20, InlineU32(7), 0),
|
||||
EncodeVop2(0x16, 21, InlineU32(3), 0),
|
||||
EncodeVop2(0x1b, 21, InlineU32(1), 21),
|
||||
EncodeMimg0(0x00, 0x1), EncodeMimg1(4, 20),
|
||||
EncodeVop2(0x1b, 20, InlineU32(3), 4),
|
||||
EncodeVop2(0x16, 22, InlineU32(2), 4),
|
||||
EncodeVop2(0x1b, 22, InlineU32(3), 22)};
|
||||
for (u32 reg : {20u, 22u}) {
|
||||
test.code.push_back(EncodeVop2(0x25, reg, InlineU32(63), reg));
|
||||
test.code.push_back(EncodeVop2(0x1b, reg, InlineU32(63), reg));
|
||||
}
|
||||
test.code.push_back(EncodeVop2(0x1a, 22, InlineU32(8), 22));
|
||||
test.code.push_back(EncodeVop2(0x1c, 20, Vgpr(22), 20));
|
||||
AppendVMovLiteral(&test.code, 21, std::bit_cast<u32>(0.375f));
|
||||
AppendVMovLiteral(&test.code, 22, std::bit_cast<u32>(0.375f));
|
||||
AppendVMovLiteral(&test.code, 23, std::bit_cast<u32>(1.0f));
|
||||
test.code.push_back(EncodeMimg0(0x34, 0x1)); // SAMPLE_L_O: offset is applied at mip 1.
|
||||
test.code.push_back(EncodeMimg1(5, 20));
|
||||
AppendStoreVgprAtLaneDwordOffset(&test.code, 5, 0, 0);
|
||||
AppendEnd(&test.code);
|
||||
test.opcodes = {O::V_AND_B32, O::V_LSHRREV_B32, O::V_ADD_NC_U32, O::V_LSHLREV_B32,
|
||||
O::V_OR_B32, O::V_MOV_B32, O::IMAGE_LOAD, O::IMAGE_SAMPLE,
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.required_spirv = {"ImageGatherExtended", "Lod|Offset", "OpBitFieldSExtract %int"};
|
||||
test.forbidden_spirv = {"OpSwitch", "OpImageQuerySizeLod", "OpFDiv"};
|
||||
test.initial.assign(wave_size, 0xdeadbeefu);
|
||||
for (u32 lane = 0; lane < wave_size; ++lane)
|
||||
test.expected.push_back(std::bit_cast<u32>(float(100u + (lane & 15u))));
|
||||
auto compiled = CompileCase(test, vulkan.SubgroupSize());
|
||||
spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_2);
|
||||
std::string text;
|
||||
const auto halves = wave_size > vulkan.SubgroupSize() ? 2u : 1u;
|
||||
Require(test.name, "direct dynamic offset", tools.Disassemble(compiled.spirv, &text) &&
|
||||
CountText(text, "OpImageSampleExplicitLod") == halves &&
|
||||
CountText(text, "OpBitFieldSExtract %int") == 2u * halves,
|
||||
"dynamic offsets expanded samples or lost signed six-bit components");
|
||||
#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
|
||||
if (wave_size == 32u) {
|
||||
Require(test.name, "default feature gate", !ShaderRecompiler::CompileOptions{}.maintenance8_enabled,
|
||||
"maintenance8 must reflect the enabled device feature");
|
||||
ExpectFatal("DynamicSampleOffsetsRequireMaintenance8", [&] {
|
||||
ShaderRecompiler::Spirv::EmitProgram(compiled.program, {.compute = &test.compute_info});
|
||||
});
|
||||
}
|
||||
#endif
|
||||
auto base = MakeRgbaImage(8, 8);
|
||||
auto mip = MakeRgbaImage(4, 4);
|
||||
for (u32 selector = 0; selector < 16u; ++selector) {
|
||||
SetRgbaPixel(&base, 8, selector & 7u, selector >> 3u, 0x3f800000u | selector, 0, 0, 0);
|
||||
SetRgbaPixel(&mip, 4, selector & 3u, selector >> 2u,
|
||||
std::bit_cast<u32>(float(100u + selector)), 0, 0, 0);
|
||||
}
|
||||
auto texture = vulkan.CreateImageMips(test.name, 8, 8, vk::Format::eR32G32B32A32Sfloat,
|
||||
vk::ImageUsageFlagBits::eSampled, {base, mip}, 4u, vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
vk::ImageType::e2D, vk::ImageViewType::e2D, 1u);
|
||||
const auto sampler = vulkan.CreateSampler(test.name, 2u);
|
||||
auto output = vulkan.CreateStorageBuffer(test.name, test.initial, test.initial.size());
|
||||
vulkan.Dispatch(test, compiled, output, nullptr, &texture, nullptr, nullptr, sampler);
|
||||
CompareWords(test, "image-derived offsets -1..2 at mip 1", test.expected,
|
||||
vulkan.ReadBuffer(test.name, output, test.expected.size()));
|
||||
vulkan.DestroyBuffer(&output);
|
||||
vulkan.Device().destroySampler(sampler);
|
||||
vulkan.DestroyImage(&texture);
|
||||
std::printf("[compute] %-32s ok\n", test.name);
|
||||
}
|
||||
|
||||
TestCase ImageSampleA16CompareBiasRdna2AddressOrder() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
|
|
@ -43794,6 +43890,8 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--image-sample-offset-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
CheckDynamicSampleOffsets(vulkan, 32u);
|
||||
CheckDynamicSampleOffsets(vulkan, 64u);
|
||||
RunCase(&vulkan, ImageSampleOffsetsReadFourNeighbors<32>());
|
||||
RunCase(&vulkan, ImageSampleOffsetsReadFourNeighbors<64>());
|
||||
RunCase(&vulkan, ImageSampleA16OffsetKeepsTexelOffset32BitOnGpu<32>());
|
||||
|
|
@ -44463,6 +44561,8 @@ int main(int argc, char **argv) {
|
|||
CheckRuntimeBufferRecords(vulkan);
|
||||
CheckComputeThreadDimensions(vulkan);
|
||||
CheckIndirectImageKeySwitch(vulkan);
|
||||
CheckDynamicSampleOffsets(vulkan, 32u);
|
||||
CheckDynamicSampleOffsets(vulkan, 64u);
|
||||
CheckFiniteInlineSamplerPhi(vulkan);
|
||||
CheckWave64WholeWaveResults();
|
||||
CheckPs5GameExampleImageClearRuntimeShape();
|
||||
|
|
|
|||
Loading…
Reference in New Issue