video_core: Query storage flag with runtime state
This commit is contained in:
parent
347096b78f
commit
5c1de381c4
|
@ -329,11 +329,12 @@ void EmitContext::DefinePushDataBlock() {
|
||||||
void EmitContext::DefineBuffers() {
|
void EmitContext::DefineBuffers() {
|
||||||
boost::container::small_vector<Id, 8> type_ids;
|
boost::container::small_vector<Id, 8> type_ids;
|
||||||
for (u32 i = 0; const auto& buffer : info.buffers) {
|
for (u32 i = 0; const auto& buffer : info.buffers) {
|
||||||
|
const auto sharp = buffer.GetVsharp(info);
|
||||||
|
const bool is_storage = buffer.IsStorage(sharp);
|
||||||
const auto* data_types = True(buffer.used_types & IR::Type::F32) ? &F32 : &U32;
|
const auto* data_types = True(buffer.used_types & IR::Type::F32) ? &F32 : &U32;
|
||||||
const Id data_type = (*data_types)[1];
|
const Id data_type = (*data_types)[1];
|
||||||
const Id record_array_type{buffer.is_storage
|
const Id record_array_type{is_storage ? TypeRuntimeArray(data_type)
|
||||||
? TypeRuntimeArray(data_type)
|
: TypeArray(data_type, ConstU32(buffer.length))};
|
||||||
: TypeArray(data_type, ConstU32(buffer.length))};
|
|
||||||
const Id struct_type{TypeStruct(record_array_type)};
|
const Id struct_type{TypeStruct(record_array_type)};
|
||||||
if (std::ranges::find(type_ids, record_array_type.value, &Id::value) == type_ids.end()) {
|
if (std::ranges::find(type_ids, record_array_type.value, &Id::value) == type_ids.end()) {
|
||||||
Decorate(record_array_type, spv::Decoration::ArrayStride, 4);
|
Decorate(record_array_type, spv::Decoration::ArrayStride, 4);
|
||||||
|
@ -350,13 +351,13 @@ void EmitContext::DefineBuffers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto storage_class =
|
const auto storage_class =
|
||||||
buffer.is_storage ? spv::StorageClass::StorageBuffer : spv::StorageClass::Uniform;
|
is_storage ? spv::StorageClass::StorageBuffer : spv::StorageClass::Uniform;
|
||||||
const Id struct_pointer_type{TypePointer(storage_class, struct_type)};
|
const Id struct_pointer_type{TypePointer(storage_class, struct_type)};
|
||||||
const Id pointer_type = TypePointer(storage_class, data_type);
|
const Id pointer_type = TypePointer(storage_class, data_type);
|
||||||
const Id id{AddGlobalVariable(struct_pointer_type, storage_class)};
|
const Id id{AddGlobalVariable(struct_pointer_type, storage_class)};
|
||||||
Decorate(id, spv::Decoration::Binding, binding);
|
Decorate(id, spv::Decoration::Binding, binding);
|
||||||
Decorate(id, spv::Decoration::DescriptorSet, 0U);
|
Decorate(id, spv::Decoration::DescriptorSet, 0U);
|
||||||
Name(id, fmt::format("{}_{}", buffer.is_storage ? "ssbo" : "cbuf", buffer.sgpr_base));
|
Name(id, fmt::format("{}_{}", is_storage ? "ssbo" : "cbuf", buffer.sgpr_base));
|
||||||
|
|
||||||
buffers.push_back({
|
buffers.push_back({
|
||||||
.id = id,
|
.id = id,
|
||||||
|
|
|
@ -401,7 +401,6 @@ void Translator::EmitFetch(const GcnInst& inst) {
|
||||||
.dword_offset = attrib.dword_offset,
|
.dword_offset = attrib.dword_offset,
|
||||||
.length = buffer.num_records,
|
.length = buffer.num_records,
|
||||||
.used_types = IR::Type::F32,
|
.used_types = IR::Type::F32,
|
||||||
.is_storage = true, // we may not fit into UBO with large meshes
|
|
||||||
.is_instance_data = true,
|
.is_instance_data = true,
|
||||||
});
|
});
|
||||||
instance_buf_handle = s32(info.buffers.size() - 1);
|
instance_buf_handle = s32(info.buffers.size() - 1);
|
||||||
|
|
|
@ -220,7 +220,6 @@ public:
|
||||||
})};
|
})};
|
||||||
auto& buffer = buffer_resources[index];
|
auto& buffer = buffer_resources[index];
|
||||||
ASSERT(buffer.length == desc.length);
|
ASSERT(buffer.length == desc.length);
|
||||||
buffer.is_storage |= desc.is_storage;
|
|
||||||
buffer.used_types |= desc.used_types;
|
buffer.used_types |= desc.used_types;
|
||||||
buffer.is_written |= desc.is_written;
|
buffer.is_written |= desc.is_written;
|
||||||
return index;
|
return index;
|
||||||
|
@ -412,7 +411,6 @@ s32 TryHandleInlineCbuf(IR::Inst& inst, Info& info, Descriptors& descriptors,
|
||||||
.length = BufferLength(cbuf),
|
.length = BufferLength(cbuf),
|
||||||
.used_types = BufferDataType(inst, cbuf.GetNumberFmt()),
|
.used_types = BufferDataType(inst, cbuf.GetNumberFmt()),
|
||||||
.inline_cbuf = cbuf,
|
.inline_cbuf = cbuf,
|
||||||
.is_storage = IsBufferStore(inst) || cbuf.GetSize() > MaxUboSize,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,15 +422,13 @@ void PatchBufferInstruction(IR::Block& block, IR::Inst& inst, Info& info,
|
||||||
IR::Inst* handle = inst.Arg(0).InstRecursive();
|
IR::Inst* handle = inst.Arg(0).InstRecursive();
|
||||||
IR::Inst* producer = handle->Arg(0).InstRecursive();
|
IR::Inst* producer = handle->Arg(0).InstRecursive();
|
||||||
const auto sharp = TrackSharp(producer);
|
const auto sharp = TrackSharp(producer);
|
||||||
const bool is_store = IsBufferStore(inst);
|
|
||||||
buffer = info.ReadUd<AmdGpu::Buffer>(sharp.sgpr_base, sharp.dword_offset);
|
buffer = info.ReadUd<AmdGpu::Buffer>(sharp.sgpr_base, sharp.dword_offset);
|
||||||
binding = descriptors.Add(BufferResource{
|
binding = descriptors.Add(BufferResource{
|
||||||
.sgpr_base = sharp.sgpr_base,
|
.sgpr_base = sharp.sgpr_base,
|
||||||
.dword_offset = sharp.dword_offset,
|
.dword_offset = sharp.dword_offset,
|
||||||
.length = BufferLength(buffer),
|
.length = BufferLength(buffer),
|
||||||
.used_types = BufferDataType(inst, buffer.GetNumberFmt()),
|
.used_types = BufferDataType(inst, buffer.GetNumberFmt()),
|
||||||
.is_storage = is_store || buffer.GetSize() > MaxUboSize,
|
.is_written = IsBufferStore(inst),
|
||||||
.is_written = is_store,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,18 +83,22 @@ struct BufferResource {
|
||||||
AmdGpu::Buffer inline_cbuf;
|
AmdGpu::Buffer inline_cbuf;
|
||||||
AmdGpu::DataFormat dfmt;
|
AmdGpu::DataFormat dfmt;
|
||||||
AmdGpu::NumberFormat nfmt;
|
AmdGpu::NumberFormat nfmt;
|
||||||
bool is_storage{};
|
|
||||||
bool is_instance_data{};
|
bool is_instance_data{};
|
||||||
bool is_written{};
|
bool is_written{};
|
||||||
|
|
||||||
|
static constexpr size_t MaxUboSize = 65536;
|
||||||
|
|
||||||
|
bool IsStorage(AmdGpu::Buffer buffer) const noexcept {
|
||||||
|
return buffer.GetSize() > MaxUboSize || is_written;
|
||||||
|
}
|
||||||
|
|
||||||
u64 GetKey(const Info& info) const {
|
u64 GetKey(const Info& info) const {
|
||||||
static constexpr size_t MaxUboSize = 65536;
|
|
||||||
const auto sharp = GetVsharp(info);
|
const auto sharp = GetVsharp(info);
|
||||||
const u32 stride = sharp.GetStride();
|
const u32 stride = sharp.GetStride();
|
||||||
u64 key = stride | (sharp.data_format << 14) | (sharp.num_format << 18);
|
u64 key = stride | (sharp.data_format << 14) | (sharp.num_format << 18);
|
||||||
if (!is_written) {
|
if (!is_written) {
|
||||||
key <<= 1;
|
key <<= 1;
|
||||||
key |= (stride * sharp.num_records) > MaxUboSize;
|
key |= IsStorage(sharp);
|
||||||
}
|
}
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,11 @@ ComputePipeline::ComputePipeline(const Instance& instance_, Scheduler& scheduler
|
||||||
u32 binding{};
|
u32 binding{};
|
||||||
boost::container::small_vector<vk::DescriptorSetLayoutBinding, 32> bindings;
|
boost::container::small_vector<vk::DescriptorSetLayoutBinding, 32> bindings;
|
||||||
for (const auto& buffer : info->buffers) {
|
for (const auto& buffer : info->buffers) {
|
||||||
|
const auto sharp = buffer.GetVsharp(*info);
|
||||||
bindings.push_back({
|
bindings.push_back({
|
||||||
.binding = binding++,
|
.binding = binding++,
|
||||||
.descriptorType = buffer.is_storage ? vk::DescriptorType::eStorageBuffer
|
.descriptorType = buffer.IsStorage(sharp) ? vk::DescriptorType::eStorageBuffer
|
||||||
: vk::DescriptorType::eUniformBuffer,
|
: vk::DescriptorType::eUniformBuffer,
|
||||||
.descriptorCount = 1,
|
.descriptorCount = 1,
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
||||||
});
|
});
|
||||||
|
@ -98,12 +99,13 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
|
||||||
|
|
||||||
for (const auto& buffer : info->buffers) {
|
for (const auto& buffer : info->buffers) {
|
||||||
const auto vsharp = buffer.GetVsharp(*info);
|
const auto vsharp = buffer.GetVsharp(*info);
|
||||||
|
const bool is_storage = buffer.IsStorage(vsharp);
|
||||||
const VAddr address = vsharp.base_address;
|
const VAddr address = vsharp.base_address;
|
||||||
// Most of the time when a metadata is updated with a shader it gets cleared. It means we
|
// Most of the time when a metadata is updated with a shader it gets cleared. It means we
|
||||||
// can skip the whole dispatch and update the tracked state instead. Also, it is not
|
// can skip the whole dispatch and update the tracked state instead. Also, it is not
|
||||||
// intended to be consumed and in such rare cases (e.g. HTile introspection, CRAA) we will
|
// intended to be consumed and in such rare cases (e.g. HTile introspection, CRAA) we will
|
||||||
// need its full emulation anyways. For cases of metadata read a warning will be logged.
|
// need its full emulation anyways. For cases of metadata read a warning will be logged.
|
||||||
if (buffer.is_storage) {
|
if (is_storage) {
|
||||||
if (texture_cache.TouchMeta(address, true)) {
|
if (texture_cache.TouchMeta(address, true)) {
|
||||||
LOG_WARNING(Render_Vulkan, "Metadata update skipped");
|
LOG_WARNING(Render_Vulkan, "Metadata update skipped");
|
||||||
return false;
|
return false;
|
||||||
|
@ -118,7 +120,7 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
|
||||||
texture_cache.InvalidateMemory(address, size, true);
|
texture_cache.InvalidateMemory(address, size, true);
|
||||||
}
|
}
|
||||||
const u32 alignment =
|
const u32 alignment =
|
||||||
buffer.is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment();
|
is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment();
|
||||||
const auto [vk_buffer, offset] =
|
const auto [vk_buffer, offset] =
|
||||||
buffer_cache.ObtainBuffer(address, size, buffer.is_written);
|
buffer_cache.ObtainBuffer(address, size, buffer.is_written);
|
||||||
const u32 offset_aligned = Common::AlignDown(offset, alignment);
|
const u32 offset_aligned = Common::AlignDown(offset, alignment);
|
||||||
|
@ -133,8 +135,8 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
|
||||||
.dstBinding = binding++,
|
.dstBinding = binding++,
|
||||||
.dstArrayElement = 0,
|
.dstArrayElement = 0,
|
||||||
.descriptorCount = 1,
|
.descriptorCount = 1,
|
||||||
.descriptorType = buffer.is_storage ? vk::DescriptorType::eStorageBuffer
|
.descriptorType = is_storage ? vk::DescriptorType::eStorageBuffer
|
||||||
: vk::DescriptorType::eUniformBuffer,
|
: vk::DescriptorType::eUniformBuffer,
|
||||||
.pBufferInfo = &buffer_infos.back(),
|
.pBufferInfo = &buffer_infos.back(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -307,10 +307,11 @@ void GraphicsPipeline::BuildDescSetLayout() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (const auto& buffer : stage->buffers) {
|
for (const auto& buffer : stage->buffers) {
|
||||||
|
const auto sharp = buffer.GetVsharp(*stage);
|
||||||
bindings.push_back({
|
bindings.push_back({
|
||||||
.binding = binding++,
|
.binding = binding++,
|
||||||
.descriptorType = buffer.is_storage ? vk::DescriptorType::eStorageBuffer
|
.descriptorType = buffer.IsStorage(sharp) ? vk::DescriptorType::eStorageBuffer
|
||||||
: vk::DescriptorType::eUniformBuffer,
|
: vk::DescriptorType::eUniformBuffer,
|
||||||
.descriptorCount = 1,
|
.descriptorCount = 1,
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
|
.stageFlags = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
|
||||||
});
|
});
|
||||||
|
@ -361,14 +362,15 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
|
||||||
}
|
}
|
||||||
for (const auto& buffer : stage->buffers) {
|
for (const auto& buffer : stage->buffers) {
|
||||||
const auto vsharp = buffer.GetVsharp(*stage);
|
const auto vsharp = buffer.GetVsharp(*stage);
|
||||||
|
const bool is_storage = buffer.IsStorage(vsharp);
|
||||||
if (vsharp) {
|
if (vsharp) {
|
||||||
const VAddr address = vsharp.base_address;
|
const VAddr address = vsharp.base_address;
|
||||||
if (texture_cache.IsMeta(address)) {
|
if (texture_cache.IsMeta(address)) {
|
||||||
LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a PS shader (buffer)");
|
LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a PS shader (buffer)");
|
||||||
}
|
}
|
||||||
const u32 size = vsharp.GetSize();
|
const u32 size = vsharp.GetSize();
|
||||||
const u32 alignment = buffer.is_storage ? instance.StorageMinAlignment()
|
const u32 alignment =
|
||||||
: instance.UniformMinAlignment();
|
is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment();
|
||||||
const auto [vk_buffer, offset] =
|
const auto [vk_buffer, offset] =
|
||||||
buffer_cache.ObtainBuffer(address, size, buffer.is_written);
|
buffer_cache.ObtainBuffer(address, size, buffer.is_written);
|
||||||
const u32 offset_aligned = Common::AlignDown(offset, alignment);
|
const u32 offset_aligned = Common::AlignDown(offset, alignment);
|
||||||
|
@ -386,8 +388,8 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
|
||||||
.dstBinding = binding++,
|
.dstBinding = binding++,
|
||||||
.dstArrayElement = 0,
|
.dstArrayElement = 0,
|
||||||
.descriptorCount = 1,
|
.descriptorCount = 1,
|
||||||
.descriptorType = buffer.is_storage ? vk::DescriptorType::eStorageBuffer
|
.descriptorType = is_storage ? vk::DescriptorType::eStorageBuffer
|
||||||
: vk::DescriptorType::eUniformBuffer,
|
: vk::DescriptorType::eUniformBuffer,
|
||||||
.pBufferInfo = &buffer_infos.back(),
|
.pBufferInfo = &buffer_infos.back(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue