shader_recompiler: Implement data share append and consume operations (#814)

* shader_recompiler: Add more format swap modes

* texture_cache: Handle stencil texture reads

* emulator: Support loading font library

* readme: Add thanks section

* shader_recompiler: Constant buffers as integers

* shader_recompiler: Typed buffers as integers

* shader_recompiler: Separate thread bit scalars

* We can assume guest shader never mixes them with normal sgprs. This helps avoid errors where ssa could view an sgpr write dominating a thread bit read, due to how control flow is structurized, even though its not possible in actual control flow

* shader_recompiler: Implement data append/consume operations

* clang format

* buffer_cache: Simplify invalidation scheme

* video_core: Remove some invalidation remnants

* adjust
This commit is contained in:
TheTurtle 2024-09-07 00:14:51 +03:00 committed by GitHub
parent 649527a235
commit 13743b27fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 512 additions and 272 deletions

View file

@ -585,11 +585,10 @@ vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat nu
vk::Format AdjustColorBufferFormat(vk::Format base_format,
Liverpool::ColorBuffer::SwapMode comp_swap, bool is_vo_surface) {
ASSERT_MSG(comp_swap == Liverpool::ColorBuffer::SwapMode::Standard ||
comp_swap == Liverpool::ColorBuffer::SwapMode::Alternate,
"Unsupported component swap mode {}", static_cast<u32>(comp_swap));
const bool comp_swap_alt = comp_swap == Liverpool::ColorBuffer::SwapMode::Alternate;
const bool comp_swap_reverse = comp_swap == Liverpool::ColorBuffer::SwapMode::StandardReverse;
const bool comp_swap_alt_reverse =
comp_swap == Liverpool::ColorBuffer::SwapMode::AlternateReverse;
if (comp_swap_alt) {
switch (base_format) {
case vk::Format::eR8G8B8A8Unorm:
@ -605,6 +604,18 @@ vk::Format AdjustColorBufferFormat(vk::Format base_format,
default:
break;
}
} else if (comp_swap_reverse) {
switch (base_format) {
case vk::Format::eR8G8B8A8Unorm:
return vk::Format::eA8B8G8R8UnormPack32;
case vk::Format::eR8G8B8A8Srgb:
return is_vo_surface ? vk::Format::eA8B8G8R8UnormPack32
: vk::Format::eA8B8G8R8SrgbPack32;
default:
break;
}
} else if (comp_swap_alt_reverse) {
return base_format;
} else {
if (is_vo_surface && base_format == vk::Format::eR8G8B8A8Srgb) {
return vk::Format::eR8G8B8A8Unorm;

View file

@ -109,37 +109,42 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
u32 binding{};
for (const auto& desc : info->buffers) {
const auto vsharp = desc.GetSharp(*info);
const bool is_storage = desc.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 (desc.is_written) {
if (texture_cache.TouchMeta(address, true)) {
LOG_TRACE(Render_Vulkan, "Metadata update skipped");
return false;
}
bool is_storage = true;
if (desc.is_gds_buffer) {
auto* vk_buffer = buffer_cache.GetGdsBuffer();
buffer_infos.emplace_back(vk_buffer->Handle(), 0, vk_buffer->SizeBytes());
} else {
if (texture_cache.IsMeta(address)) {
LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a CS shader (buffer)");
const auto vsharp = desc.GetSharp(*info);
is_storage = desc.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 (desc.is_written) {
if (texture_cache.TouchMeta(address, true)) {
LOG_TRACE(Render_Vulkan, "Metadata update skipped");
return false;
}
} else {
if (texture_cache.IsMeta(address)) {
LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a CS shader (buffer)");
}
}
const u32 size = vsharp.GetSize();
const u32 alignment =
is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment();
const auto [vk_buffer, offset] =
buffer_cache.ObtainBuffer(address, size, desc.is_written);
const u32 offset_aligned = Common::AlignDown(offset, alignment);
const u32 adjust = offset - offset_aligned;
if (adjust != 0) {
ASSERT(adjust % 4 == 0);
push_data.AddOffset(binding, adjust);
}
buffer_infos.emplace_back(vk_buffer->Handle(), offset_aligned, size + adjust);
}
const u32 size = vsharp.GetSize();
if (desc.is_written) {
texture_cache.InvalidateMemory(address, size);
}
const u32 alignment =
is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment();
const auto [vk_buffer, offset] = buffer_cache.ObtainBuffer(address, size, desc.is_written);
const u32 offset_aligned = Common::AlignDown(offset, alignment);
const u32 adjust = offset - offset_aligned;
if (adjust != 0) {
ASSERT(adjust % 4 == 0);
push_data.AddOffset(binding, adjust);
}
buffer_infos.emplace_back(vk_buffer->Handle(), offset_aligned, size + adjust);
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding++,
@ -188,7 +193,7 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
buffer_barriers.emplace_back(*barrier);
}
if (desc.is_written) {
texture_cache.InvalidateMemory(address, size);
texture_cache.MarkWritten(address, size);
}
}
set_writes.push_back({

View file

@ -432,7 +432,7 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
buffer_barriers.emplace_back(*barrier);
}
if (desc.is_written) {
texture_cache.InvalidateMemory(address, size);
texture_cache.MarkWritten(address, size);
}
}
set_writes.push_back({

View file

@ -298,6 +298,16 @@ bool PipelineCache::RefreshGraphicsKey() {
return false;
}
static bool TessMissingLogged = false;
if (auto* pgm = regs.ProgramForStage(3);
regs.stage_enable.IsStageEnabled(3) && pgm->Address() != 0) {
if (!TessMissingLogged) {
LOG_WARNING(Render_Vulkan, "Tess pipeline compilation skipped");
TessMissingLogged = true;
}
return false;
}
std::tie(infos[i], modules[i], key.stage_hashes[i]) = GetProgram(stage, params, binding);
}
return true;

View file

@ -175,6 +175,10 @@ u64 Rasterizer::Flush() {
return current_tick;
}
void Rasterizer::Finish() {
scheduler.Finish();
}
void Rasterizer::BeginRendering() {
const auto& regs = liverpool->regs;
RenderState state;
@ -251,6 +255,17 @@ void Rasterizer::BeginRendering() {
scheduler.BeginRendering(state);
}
void Rasterizer::InlineDataToGds(u32 gds_offset, u32 value) {
buffer_cache.InlineDataToGds(gds_offset, value);
}
u32 Rasterizer::ReadDataFromGds(u32 gds_offset) {
auto* gds_buf = buffer_cache.GetGdsBuffer();
u32 value;
std::memcpy(&value, gds_buf->mapped_data.data() + gds_offset, sizeof(u32));
return value;
}
void Rasterizer::InvalidateMemory(VAddr addr, u64 size) {
buffer_cache.InvalidateMemory(addr, size);
texture_cache.InvalidateMemory(addr, size);

View file

@ -41,12 +41,15 @@ public:
void ScopeMarkerEnd();
void ScopedMarkerInsert(const std::string_view& str);
void InlineDataToGds(u32 gds_offset, u32 value);
u32 ReadDataFromGds(u32 gsd_offset);
void InvalidateMemory(VAddr addr, u64 size);
void MapMemory(VAddr addr, u64 size);
void UnmapMemory(VAddr addr, u64 size);
void CpSync();
u64 Flush();
void Finish();
private:
void BeginRendering();