video_core: Query storage flag with runtime state

This commit is contained in:
IndecisiveTurtle 2024-08-25 23:34:02 +03:00
parent 347096b78f
commit 5c1de381c4
6 changed files with 30 additions and 26 deletions

View File

@ -329,10 +329,11 @@ void EmitContext::DefinePushDataBlock() {
void EmitContext::DefineBuffers() {
boost::container::small_vector<Id, 8> type_ids;
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 Id data_type = (*data_types)[1];
const Id record_array_type{buffer.is_storage
? TypeRuntimeArray(data_type)
const Id record_array_type{is_storage ? TypeRuntimeArray(data_type)
: TypeArray(data_type, ConstU32(buffer.length))};
const Id struct_type{TypeStruct(record_array_type)};
if (std::ranges::find(type_ids, record_array_type.value, &Id::value) == type_ids.end()) {
@ -350,13 +351,13 @@ void EmitContext::DefineBuffers() {
}
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 pointer_type = TypePointer(storage_class, data_type);
const Id id{AddGlobalVariable(struct_pointer_type, storage_class)};
Decorate(id, spv::Decoration::Binding, binding);
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({
.id = id,

View File

@ -401,7 +401,6 @@ void Translator::EmitFetch(const GcnInst& inst) {
.dword_offset = attrib.dword_offset,
.length = buffer.num_records,
.used_types = IR::Type::F32,
.is_storage = true, // we may not fit into UBO with large meshes
.is_instance_data = true,
});
instance_buf_handle = s32(info.buffers.size() - 1);

View File

@ -220,7 +220,6 @@ public:
})};
auto& buffer = buffer_resources[index];
ASSERT(buffer.length == desc.length);
buffer.is_storage |= desc.is_storage;
buffer.used_types |= desc.used_types;
buffer.is_written |= desc.is_written;
return index;
@ -412,7 +411,6 @@ s32 TryHandleInlineCbuf(IR::Inst& inst, Info& info, Descriptors& descriptors,
.length = BufferLength(cbuf),
.used_types = BufferDataType(inst, cbuf.GetNumberFmt()),
.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* producer = handle->Arg(0).InstRecursive();
const auto sharp = TrackSharp(producer);
const bool is_store = IsBufferStore(inst);
buffer = info.ReadUd<AmdGpu::Buffer>(sharp.sgpr_base, sharp.dword_offset);
binding = descriptors.Add(BufferResource{
.sgpr_base = sharp.sgpr_base,
.dword_offset = sharp.dword_offset,
.length = BufferLength(buffer),
.used_types = BufferDataType(inst, buffer.GetNumberFmt()),
.is_storage = is_store || buffer.GetSize() > MaxUboSize,
.is_written = is_store,
.is_written = IsBufferStore(inst),
});
}

View File

@ -83,18 +83,22 @@ struct BufferResource {
AmdGpu::Buffer inline_cbuf;
AmdGpu::DataFormat dfmt;
AmdGpu::NumberFormat nfmt;
bool is_storage{};
bool is_instance_data{};
bool is_written{};
u64 GetKey(const Info& info) const {
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 {
const auto sharp = GetVsharp(info);
const u32 stride = sharp.GetStride();
u64 key = stride | (sharp.data_format << 14) | (sharp.num_format << 18);
if (!is_written) {
key <<= 1;
key |= (stride * sharp.num_records) > MaxUboSize;
key |= IsStorage(sharp);
}
return key;
}

View File

@ -24,9 +24,10 @@ ComputePipeline::ComputePipeline(const Instance& instance_, Scheduler& scheduler
u32 binding{};
boost::container::small_vector<vk::DescriptorSetLayoutBinding, 32> bindings;
for (const auto& buffer : info->buffers) {
const auto sharp = buffer.GetVsharp(*info);
bindings.push_back({
.binding = binding++,
.descriptorType = buffer.is_storage ? vk::DescriptorType::eStorageBuffer
.descriptorType = buffer.IsStorage(sharp) ? vk::DescriptorType::eStorageBuffer
: vk::DescriptorType::eUniformBuffer,
.descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eCompute,
@ -98,12 +99,13 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
for (const auto& buffer : info->buffers) {
const auto vsharp = buffer.GetVsharp(*info);
const bool is_storage = buffer.IsStorage(vsharp);
const VAddr address = vsharp.base_address;
// 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
// 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.
if (buffer.is_storage) {
if (is_storage) {
if (texture_cache.TouchMeta(address, true)) {
LOG_WARNING(Render_Vulkan, "Metadata update skipped");
return false;
@ -118,7 +120,7 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
texture_cache.InvalidateMemory(address, size, true);
}
const u32 alignment =
buffer.is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment();
is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment();
const auto [vk_buffer, offset] =
buffer_cache.ObtainBuffer(address, size, buffer.is_written);
const u32 offset_aligned = Common::AlignDown(offset, alignment);
@ -133,7 +135,7 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
.dstBinding = binding++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = buffer.is_storage ? vk::DescriptorType::eStorageBuffer
.descriptorType = is_storage ? vk::DescriptorType::eStorageBuffer
: vk::DescriptorType::eUniformBuffer,
.pBufferInfo = &buffer_infos.back(),
});

View File

@ -307,9 +307,10 @@ void GraphicsPipeline::BuildDescSetLayout() {
continue;
}
for (const auto& buffer : stage->buffers) {
const auto sharp = buffer.GetVsharp(*stage);
bindings.push_back({
.binding = binding++,
.descriptorType = buffer.is_storage ? vk::DescriptorType::eStorageBuffer
.descriptorType = buffer.IsStorage(sharp) ? vk::DescriptorType::eStorageBuffer
: vk::DescriptorType::eUniformBuffer,
.descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
@ -361,14 +362,15 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
}
for (const auto& buffer : stage->buffers) {
const auto vsharp = buffer.GetVsharp(*stage);
const bool is_storage = buffer.IsStorage(vsharp);
if (vsharp) {
const VAddr address = vsharp.base_address;
if (texture_cache.IsMeta(address)) {
LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a PS shader (buffer)");
}
const u32 size = vsharp.GetSize();
const u32 alignment = buffer.is_storage ? instance.StorageMinAlignment()
: instance.UniformMinAlignment();
const u32 alignment =
is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment();
const auto [vk_buffer, offset] =
buffer_cache.ObtainBuffer(address, size, buffer.is_written);
const u32 offset_aligned = Common::AlignDown(offset, alignment);
@ -386,7 +388,7 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
.dstBinding = binding++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = buffer.is_storage ? vk::DescriptorType::eStorageBuffer
.descriptorType = is_storage ? vk::DescriptorType::eStorageBuffer
: vk::DescriptorType::eUniformBuffer,
.pBufferInfo = &buffer_infos.back(),
});