graphics: refactoring #2

This commit is contained in:
nmzik committed 2026-07-21 07:37:52 +02:00
1 parent b51d4322cc
commit 0a5f78c727
137 files changed
+10230 -10893

No files matched your search

+111 -142
View File
@@ -7,6 +7,7 @@
#include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/objects/label.h"
#include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/renderer/resourceMutex.h"
#include "graphics/host_gpu/renderer/textureCache.h"
#include "graphics/host_gpu/transfer.h"
@@ -38,22 +39,20 @@ constexpr uint64_t AlignReadbackCopySize(uint64_t size) noexcept {
}
struct SharedVulkanBufferOwner {
explicit SharedVulkanBufferOwner(GraphicContext* context): ctx(context) {
EXIT_IF(ctx == nullptr);
}
explicit SharedVulkanBufferOwner(GraphicContext& graphics): graphics(graphics) {}
~SharedVulkanBufferOwner() {
if (buffer.buffer != nullptr) {
VulkanDeleteBuffer(ctx, &buffer);
graphics.DeleteBuffer(buffer);
}
}
GraphicContext* ctx = nullptr;
GraphicContext& graphics;
VulkanBuffer buffer;
};
std::shared_ptr<VulkanBuffer> MakeSharedVulkanBuffer(GraphicContext* ctx) {
auto owner = std::make_shared<SharedVulkanBufferOwner>(ctx);
std::shared_ptr<VulkanBuffer> MakeSharedVulkanBuffer() {
auto owner = std::make_shared<SharedVulkanBufferOwner>(GetRenderContext().GetGraphics());
return {owner, &owner->buffer};
}
@@ -149,21 +148,21 @@ bool PageOverlaps(uint64_t left, uint64_t left_size, uint64_t right, uint64_t ri
}
} // namespace
bool MergeOverlappingBufferCacheRange(BufferCacheRange* merged,
bool MergeOverlappingBufferCacheRange(BufferCacheRange& merged,
BufferCacheRange candidate) noexcept {
if (merged == nullptr || merged->address == 0 || merged->size == 0 || candidate.address == 0 ||
candidate.size == 0 || merged->size > UINT64_MAX - merged->address ||
if (merged.address == 0 || merged.size == 0 || candidate.address == 0 || candidate.size == 0 ||
merged.size > UINT64_MAX - merged.address ||
candidate.size > UINT64_MAX - candidate.address) {
EXIT("BufferCache: invalid overlap-merge range\n");
}
const auto merged_end = merged->address + merged->size;
const auto merged_end = merged.address + merged.size;
const auto candidate_end = candidate.address + candidate.size;
if (merged->address >= candidate_end || candidate.address >= merged_end) {
if (merged.address >= candidate_end || candidate.address >= merged_end) {
return false;
}
const auto address = std::min(merged->address, candidate.address);
const auto address = std::min(merged.address, candidate.address);
const auto end = std::max(merged_end, candidate_end);
*merged = {.address = address, .size = end - address};
merged = {.address = address, .size = end - address};
return true;
}
@@ -175,7 +174,6 @@ struct BufferCache::CachedBuffer {
uint64_t vaddr = 0;
uint64_t size = 0;
uint64_t queue_mask = 0;
GraphicContext* ctx = nullptr;
std::shared_ptr<VulkanBuffer> buffer;
};
@@ -220,10 +218,7 @@ struct BufferCache::ReadbackWorker {
}
}
void Prepare(GraphicContext* graphic_context) {
if (graphic_context == nullptr) {
EXIT("BufferCache: cannot prepare readback without a graphics context\n");
}
void Prepare() {
auto current = state.load(std::memory_order_acquire);
while (current == State::InitRequested ||
(current == State::Claimed &&
@@ -236,15 +231,11 @@ struct BufferCache::ReadbackWorker {
EXIT("BufferCache: cannot prepare a stopping readback worker, state=%u\n",
static_cast<uint32_t>(current));
}
if (ctx != graphic_context || command == nullptr || mapped == nullptr ||
readback.buffer == nullptr) {
if (command == nullptr || mapped == nullptr || readback.buffer == nullptr) {
EXIT("BufferCache: initialized readback worker has invalid resources, state=%u "
"ctx=%p requested=%p "
"command=%p mapped=%p buffer=%p\n",
static_cast<uint32_t>(current), static_cast<const void*>(ctx),
static_cast<const void*>(graphic_context),
static_cast<const void*>(command.get()), static_cast<const void*>(mapped),
static_cast<const void*>(readback.buffer));
static_cast<uint32_t>(current), static_cast<const void*>(command.get()),
static_cast<const void*>(mapped), static_cast<const void*>(readback.buffer));
}
return;
}
@@ -253,7 +244,6 @@ struct BufferCache::ReadbackWorker {
EXIT("BufferCache: readback prepare requires uninitialized state, state=%u\n",
static_cast<uint32_t>(expected));
}
ctx = graphic_context;
state.store(State::InitRequested, std::memory_order_release);
state.notify_all();
while ((current = state.load(std::memory_order_acquire)) != State::Idle) {
@@ -276,16 +266,15 @@ struct BufferCache::ReadbackWorker {
const bool submissions_prepaused_now = GraphicsRunSubmissionLockHeld() || command_thread;
const bool unsafe_gpu_lock = GraphicsRunGpuLockHeld() && !submissions_prepaused_now;
if (unsafe_gpu_lock || LabelInCallback() || g_cache_lock_owner != nullptr ||
ctx == nullptr || command == nullptr || mapped == nullptr ||
readback.buffer == nullptr) {
command == nullptr || mapped == nullptr || readback.buffer == nullptr) {
EXIT("BufferCache: unsafe readback request context, command_thread=%d "
"submission_lock=%d "
"gpu_lock=%d label_callback=%d cache_lock=%p ctx=%p command=%p mapped=%p "
"gpu_lock=%d label_callback=%d cache_lock=%p command=%p mapped=%p "
"buffer=%p\n",
command_thread, GraphicsRunSubmissionLockHeld(), GraphicsRunGpuLockHeld(),
LabelInCallback(), static_cast<const void*>(g_cache_lock_owner),
static_cast<const void*>(ctx), static_cast<const void*>(command.get()),
static_cast<const void*>(mapped), static_cast<const void*>(readback.buffer));
static_cast<const void*>(command.get()), static_cast<const void*>(mapped),
static_cast<const void*>(readback.buffer));
}
State expected = State::Idle;
while (!state.compare_exchange_weak(expected, State::Claimed, std::memory_order_acq_rel)) {
@@ -386,48 +375,46 @@ struct BufferCache::ReadbackWorker {
if (current == State::Stopping) {
command.reset();
if (mapped != nullptr) {
VulkanUnmapMemory(ctx, &readback.memory);
cache.m_graphics.UnmapMemory(readback.memory);
mapped = nullptr;
}
if (readback.buffer != nullptr) {
VulkanDeleteBuffer(ctx, &readback);
cache.m_graphics.DeleteBuffer(readback);
}
state.store(State::Stopped, std::memory_order_release);
state.notify_all();
return;
}
if (current == State::InitRequested) {
if (ctx == nullptr || command != nullptr || mapped != nullptr ||
readback.buffer != nullptr) {
EXIT("BufferCache: invalid resources before readback initialization, ctx=%p "
if (command != nullptr || mapped != nullptr || readback.buffer != nullptr) {
EXIT("BufferCache: invalid resources before readback initialization, "
"command=%p mapped=%p buffer=%p\n",
static_cast<const void*>(ctx), static_cast<const void*>(command.get()),
static_cast<const void*>(mapped),
static_cast<const void*>(command.get()), static_cast<const void*>(mapped),
static_cast<const void*>(readback.buffer));
}
const auto family = ctx->queues[GraphicContext::QUEUE_UTIL].family;
const auto family = cache.m_graphics.queues[GraphicContext::QUEUE_UTIL].family;
if (family == static_cast<uint32_t>(-1) ||
ctx->queues[GraphicContext::QUEUE_GFX].family != family) {
cache.m_graphics.queues[GraphicContext::QUEUE_GFX].family != family) {
EXIT("BufferCache: utility and graphics queues must share a valid family, "
"util=%u "
"gfx=%u\n",
family, ctx->queues[GraphicContext::QUEUE_GFX].family);
family, cache.m_graphics.queues[GraphicContext::QUEUE_GFX].family);
}
for (int i = GraphicContext::QUEUE_COMPUTE_START;
i < GraphicContext::QUEUE_COMPUTE_START + GraphicContext::QUEUE_COMPUTE_NUM;
i++) {
if (ctx->queues[i].family != family) {
if (cache.m_graphics.queues[i].family != family) {
EXIT("BufferCache: compute queue %d family mismatch, expected=%u "
"actual=%u\n",
i, family, ctx->queues[i].family);
i, family, cache.m_graphics.queues[i].family);
}
}
readback.usage = vk::BufferUsageFlagBits::eTransferDst;
readback.memory.property = vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent |
vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, READBACK_CAPACITY, &readback);
VulkanMapMemory(ctx, &readback.memory, &mapped);
cache.m_graphics.CreateBuffer(READBACK_CAPACITY, readback);
cache.m_graphics.MapMemory(readback.memory, mapped);
command = std::make_unique<CommandBuffer>(GraphicContext::QUEUE_UTIL);
state.store(State::Idle, std::memory_order_release);
state.notify_all();
@@ -528,7 +515,6 @@ struct BufferCache::ReadbackWorker {
BufferCache& cache;
std::atomic<State> state {State::Uninitialized};
GraphicContext* ctx = nullptr;
VulkanBuffer readback {};
void* mapped = nullptr;
std::unique_ptr<CommandBuffer> command;
@@ -542,8 +528,9 @@ struct BufferCache::ReadbackWorker {
std::thread thread;
};
BufferCache::BufferCache(PageManager& page_manager, ResourceMutex& resource_mutex)
: m_memory_tracker(page_manager), m_page_manager(page_manager),
BufferCache::BufferCache(GraphicContext& graphics, PageManager& page_manager,
ResourceMutex& resource_mutex)
: m_graphics(graphics), m_memory_tracker(page_manager), m_page_manager(page_manager),
m_resource_mutex(resource_mutex) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
m_readback = std::make_unique<ReadbackWorker>(*this);
@@ -563,7 +550,7 @@ BufferCache::~BufferCache() {
}
}
if (!m_buffers.empty()) {
Transfer::WaitForGraphicsIdle(m_buffers.begin()->second->ctx);
Transfer::WaitForGraphicsIdle();
}
m_buffers.clear();
}
@@ -629,8 +616,8 @@ void BufferCache::UnmapMemory(uint64_t vaddr, uint64_t size) {
const auto ranges = m_gpu_modified_ranges.Intersections(address, bytes);
for (const auto& range: ranges) {
std::vector<uint8_t> data(range.size);
Transfer::DownloadBuffer(cached->ctx, cached->buffer.get(),
range.address - begin, data.data(), range.size);
Transfer::DownloadBuffer(*cached->buffer, range.address - begin, data.data(),
range.size);
Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size());
downloaded += range.size;
}
@@ -659,19 +646,15 @@ void BufferCache::UnmapMemory(uint64_t vaddr, uint64_t size) {
}
}
std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* command,
GraphicContext* ctx, uint64_t vaddr,
uint64_t size, bool is_written,
bool is_read, bool is_formatted) {
if (command == nullptr || command->IsInvalid() || command->IsExecute() || ctx == nullptr ||
vaddr == 0 || size == 0 || size > UINT64_MAX - vaddr || command->GetQueue() < 0 ||
command->GetQueue() >= 64) {
EXIT("BufferCache: invalid buffer request, command=%p queue=%d ctx=%p addr=0x%016" PRIx64
BufferBinding BufferCache::ObtainBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size,
bool is_written, bool is_read, bool is_formatted) {
if (command.IsInvalid() || command.IsExecute() || vaddr == 0 || size == 0 ||
size > UINT64_MAX - vaddr || command.GetQueue() < 0 || command.GetQueue() >= 64) {
EXIT("BufferCache: invalid buffer request, queue=%d addr=0x%016" PRIx64
" size=0x%016" PRIx64 "\n",
static_cast<const void*>(command), command == nullptr ? -1 : command->GetQueue(),
static_cast<const void*>(ctx), vaddr, size);
command.GetQueue(), vaddr, size);
}
const auto queue = static_cast<uint32_t>(command->GetQueue());
const auto queue = static_cast<uint32_t>(command.GetQueue());
const auto queue_mask = uint64_t {1} << queue;
ValidateGpuAccess(vaddr, size, is_read, is_written);
const auto begin = AlignDown(vaddr);
@@ -688,13 +671,13 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
!texture_region.gpu_metadata_bytes) {
std::array<uint8_t, CACHING_PAGE_SIZE> guest_data;
if (Libs::LibKernel::Memory::TryReadBacking(vaddr, guest_data.data(), size)) {
VulkanBuffer* stream_buffer = nullptr;
vk::DeviceSize stream_offset = 0;
vk::DeviceSize stream_range = 0;
const auto stream_alignment = std::max<uint64_t>(ctx->StorageMinAlignment(), 16);
if (UploadHostData(command, ctx, guest_data.data(), size, stream_alignment,
&stream_buffer, &stream_offset, &stream_range)) {
return {stream_buffer, stream_offset};
VulkanBuffer* stream_buffer = nullptr;
vk::DeviceSize stream_offset = 0;
vk::DeviceSize stream_range = 0;
const auto stream_alignment = std::max<uint64_t>(m_graphics.StorageMinAlignment(), 16);
if (UploadHostData(command, guest_data.data(), size, stream_alignment, stream_buffer,
stream_offset, stream_range)) {
return {*stream_buffer, stream_offset};
}
}
}
@@ -728,7 +711,7 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
}
}
if (is_written) {
m_readback->Prepare(ctx);
m_readback->Prepare();
}
FaultSafeCacheLock lock(this, m_mutex);
@@ -749,7 +732,7 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
if (first != m_buffers.begin()) {
auto previous = std::prev(first);
if (MergeOverlappingBufferCacheRange(
&merged, {previous->second->vaddr, previous->second->size})) {
merged, {previous->second->vaddr, previous->second->size})) {
first = previous;
}
}
@@ -758,7 +741,7 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
break;
}
if (MergeOverlappingBufferCacheRange(
&merged, {candidate->second->vaddr, candidate->second->size})) {
merged, {candidate->second->vaddr, candidate->second->size})) {
overlaps.push_back(candidate);
}
}
@@ -766,11 +749,10 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
if (!overlaps.empty()) {
for (const auto& overlap: overlaps) {
auto& old = *overlap->second;
if (old.ctx != ctx || old.buffer == nullptr || old.buffer->buffer == nullptr) {
if (old.buffer == nullptr || old.buffer->buffer == nullptr) {
EXIT("BufferCache: invalid overlapping buffer owner, addr=0x%016" PRIx64
" size=0x%016" PRIx64 " owner_ctx=%p requested_ctx=%p buffer=%p\n",
old.vaddr, old.size, static_cast<const void*>(old.ctx),
static_cast<const void*>(ctx), static_cast<const void*>(old.buffer.get()));
" size=0x%016" PRIx64 " buffer=%p\n",
old.vaddr, old.size, static_cast<const void*>(old.buffer.get()));
}
if (!CanMergeBufferCacheQueueMask(old.queue_mask, queue)) {
EXIT("BufferCache: cross-queue overlap merge is unsupported, "
@@ -786,8 +768,8 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
},
[&]() noexcept {
for (const auto& [upload_vaddr, upload_size]: uploads) {
Transfer::UploadBuffer(ctx, Transfer::StagingBufferType::Vertex,
old.buffer.get(), upload_vaddr - old.vaddr,
Transfer::UploadBuffer(Transfer::StagingBufferType::Vertex, *old.buffer,
upload_vaddr - old.vaddr,
reinterpret_cast<const void*>(upload_vaddr),
upload_size);
}
@@ -797,16 +779,15 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
auto cached = std::make_unique<CachedBuffer>();
cached->vaddr = merged.address;
cached->size = merged.size;
cached->ctx = ctx;
cached->buffer = MakeSharedVulkanBuffer(ctx);
cached->buffer = MakeSharedVulkanBuffer();
cached->buffer->usage =
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst |
vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndexBuffer |
vk::BufferUsageFlagBits::eStorageBuffer;
cached->buffer->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
VulkanCreateBuffer(ctx, cached->size, cached->buffer.get());
m_graphics.CreateBuffer(cached->size, *cached->buffer);
if (!overlaps.empty()) {
auto vk_buffer = command->Handle();
auto vk_buffer = command.Handle();
std::vector<vk::BufferMemoryBarrier> before;
before.reserve(overlaps.size() + 1);
for (const auto& overlap: overlaps) {
@@ -854,7 +835,7 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eAllCommands,
vk::DependencyFlagBits::eByRegion, 0, nullptr, 1, &after, 0, nullptr);
for (const auto& overlap: overlaps) {
command->RetainResourceUntilFence(overlap->second->buffer);
command.RetainResourceUntilFence(overlap->second->buffer);
m_buffers.erase(overlap);
}
}
@@ -871,8 +852,8 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
},
[&]() noexcept {
for (const auto& [upload_vaddr, upload_size]: ranges) {
Transfer::UploadBuffer(ctx, Transfer::StagingBufferType::Vertex,
cached.buffer.get(), upload_vaddr - cached.vaddr,
Transfer::UploadBuffer(Transfer::StagingBufferType::Vertex, *cached.buffer,
upload_vaddr - cached.vaddr,
reinterpret_cast<const void*>(upload_vaddr), upload_size);
}
});
@@ -880,47 +861,46 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
m_gpu_modified_ranges.Add(vaddr, size);
}
cached.queue_mask |= queue_mask;
command->RetainResourceUntilFence(cached.buffer);
return {cached.buffer.get(), vaddr - cached.vaddr};
command.RetainResourceUntilFence(cached.buffer);
return {*cached.buffer, vaddr - cached.vaddr};
}
bool BufferCache::UploadHostData(CommandBuffer* command, GraphicContext* ctx, const void* src,
uint64_t size, uint64_t alignment, VulkanBuffer** out_buffer,
uint64_t* out_offset, uint64_t* out_range) {
if (command == nullptr || command->IsInvalid() || command->IsExecute() || ctx == nullptr) {
bool BufferCache::UploadHostData(CommandBuffer& command, const void* src, uint64_t size,
uint64_t alignment, VulkanBuffer*& out_buffer,
uint64_t& out_offset, uint64_t& out_range) {
if (command.IsInvalid() || command.IsExecute()) {
EXIT("BufferCache: host stream upload requires a recording command buffer\n");
}
return command->m_host_stream.Copy(ctx, src, size, alignment, out_buffer, out_offset,
out_range);
return command.m_host_stream.Copy(src, size, alignment, out_buffer, out_offset, out_range);
}
VulkanBuffer* BufferCache::ObtainNullBuffer(CommandBuffer* command, GraphicContext* ctx) {
if (command == nullptr || command->IsInvalid() || command->IsExecute() || ctx == nullptr) {
VulkanBuffer& BufferCache::ObtainNullBuffer(CommandBuffer& command) {
if (command.IsInvalid() || command.IsExecute()) {
EXIT("BufferCache: null buffer requires a graphics context\n");
}
FaultSafeCacheLock lock(this, m_mutex);
if (m_null_buffer == nullptr) {
// robustBufferAccess makes every fetch safe; TODO: Use a
// persistent 16-byte fallback when Vulkan null vertex descriptors are unavailable.
auto buffer = MakeSharedVulkanBuffer(ctx);
auto buffer = MakeSharedVulkanBuffer();
buffer->usage = vk::BufferUsageFlagBits::eStorageBuffer |
vk::BufferUsageFlagBits::eVertexBuffer |
vk::BufferUsageFlagBits::eIndexBuffer;
buffer->memory.property = vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent |
vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, 16, buffer.get());
m_graphics.CreateBuffer(16, *buffer);
void* data = nullptr;
VulkanMapMemory(ctx, &buffer->memory, &data);
m_graphics.MapMemory(buffer->memory, data);
std::memset(data, 0, 16);
VulkanUnmapMemory(ctx, &buffer->memory);
m_graphics.UnmapMemory(buffer->memory);
m_null_buffer = std::move(buffer);
}
// The buffer remains cache-persistent, while every recorded consumer keeps the allocation
// alive until its own fence even if an unrelated command processor resets the global cache.
command->RetainResourceUntilFence(m_null_buffer);
return m_null_buffer.get();
command.RetainResourceUntilFence(m_null_buffer);
return *m_null_buffer;
}
BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t size) {
@@ -949,8 +929,8 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
--owner;
auto& cached = *owner->second;
const auto offset = address - cached.vaddr;
if (offset > cached.size || bytes > cached.size - offset || cached.ctx == nullptr ||
cached.buffer == nullptr || cached.buffer->buffer == nullptr) {
if (offset > cached.size || bytes > cached.size - offset || cached.buffer == nullptr ||
cached.buffer->buffer == nullptr) {
EXIT("BufferCache: GPU image-source bytes have no containing native buffer\n");
}
return cached;
@@ -964,14 +944,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
vaddr, size, GraphicsRunIsCommandProcessorThread(),
GraphicsRunSubmissionLockHeld(), LabelInCallback());
}
std::vector<GraphicContext*> waited;
for (const auto& range: dirty_ranges) {
auto& owner = find_owner(range.address, range.size);
if (std::find(waited.begin(), waited.end(), owner.ctx) == waited.end()) {
Transfer::WaitForGraphicsIdle(owner.ctx);
waited.push_back(owner.ctx);
}
}
Transfer::WaitForGraphicsIdle();
auto backing_writes = ReserveBackingWrites(m_page_manager, dirty_ranges);
uint64_t downloaded = 0;
m_memory_tracker.ForEachDownloadRange<true>(
@@ -990,8 +963,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
auto& owner = find_owner(range.address, range.size);
const auto buffer_offset = range.address - owner.vaddr;
std::vector<uint8_t> data(range.size);
Transfer::DownloadBuffer(owner.ctx, owner.buffer.get(), buffer_offset,
data.data(), range.size);
Transfer::DownloadBuffer(*owner.buffer, buffer_offset, data.data(), range.size);
Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size());
downloaded += range.size;
}
@@ -1013,7 +985,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
if (offset > cached.size || size > cached.size - offset) {
return {nullptr, 0, vaddr, size, true, cpu_modified};
}
if (cached.ctx == nullptr || cached.buffer == nullptr || cached.buffer->buffer == nullptr) {
if (cached.buffer == nullptr || cached.buffer->buffer == nullptr) {
EXIT("BufferCache: containing image source is inconsistent\n");
}
if (cpu_modified) {
@@ -1025,8 +997,8 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
},
[&]() noexcept {
for (const auto& [address, bytes]: uploads) {
Transfer::UploadBuffer(cached.ctx, Transfer::StagingBufferType::Vertex,
cached.buffer.get(), address - cached.vaddr,
Transfer::UploadBuffer(Transfer::StagingBufferType::Vertex, *cached.buffer,
address - cached.vaddr,
reinterpret_cast<const void*>(address), bytes);
}
});
@@ -1047,15 +1019,14 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
}
namespace {
vk::BufferMemoryBarrier MakeDmaBarrier(VulkanBuffer* buffer, uint64_t offset, uint64_t size,
vk::BufferMemoryBarrier MakeDmaBarrier(VulkanBuffer& buffer, uint64_t offset, uint64_t size,
vk::AccessFlags source, vk::AccessFlags destination) {
if (buffer == nullptr || buffer->buffer == nullptr || size == 0 ||
offset > buffer->buffer_size || size > buffer->buffer_size - offset) {
if (buffer.buffer == nullptr || size == 0 || offset > buffer.buffer_size ||
size > buffer.buffer_size - offset) {
EXIT("BufferCache: invalid DMA barrier, buffer=%p handle=%p offset=0x%016" PRIx64
" size=0x%016" PRIx64 " buffer_size=0x%016" PRIx64 "\n",
static_cast<const void*>(buffer),
buffer == nullptr ? nullptr : static_cast<const void*>(buffer->buffer), offset, size,
buffer == nullptr ? 0 : buffer->buffer_size);
static_cast<const void*>(&buffer), static_cast<const void*>(buffer.buffer), offset,
size, buffer.buffer_size);
}
vk::BufferMemoryBarrier barrier {};
barrier.sType = vk::StructureType::eBufferMemoryBarrier;
@@ -1063,23 +1034,19 @@ vk::BufferMemoryBarrier MakeDmaBarrier(VulkanBuffer* buffer, uint64_t offset, ui
barrier.dstAccessMask = destination;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.buffer = buffer->buffer;
barrier.buffer = buffer.buffer;
barrier.offset = offset;
barrier.size = size;
return barrier;
}
vk::CommandBuffer GetDmaCommandBuffer(CommandBuffer* command) {
if (command == nullptr) {
EXIT("BufferCache: invalid DMA command buffer, command=%p\n",
static_cast<const void*>(command));
}
return command->Handle();
vk::CommandBuffer GetDmaCommandBuffer(CommandBuffer& command) {
return command.Handle();
}
} // namespace
void BufferCache::FillBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t vaddr,
uint64_t size, uint32_t value) {
void BufferCache::FillBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size,
uint32_t value) {
if ((vaddr & 3u) != 0 || (size & 3u) != 0) {
EXIT("BufferCache: fill range must be dword aligned, addr=0x%016" PRIx64
" size=0x%016" PRIx64 "\n",
@@ -1114,15 +1081,16 @@ void BufferCache::FillBuffer(CommandBuffer* command, GraphicContext* ctx, uint64
vaddr, size);
}
}
const auto [dst, dst_offset] = ObtainBuffer(command, ctx, vaddr, size, true, false);
EXIT_IF(command == nullptr);
const auto [dst, dst_offset] = ObtainBuffer(*command, vaddr, size, true, false);
const auto before = MakeDmaBarrier(
dst, dst_offset, size, vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
vk::AccessFlagBits::eTransferWrite);
const auto vk_buffer = GetDmaCommandBuffer(command);
const auto vk_buffer = GetDmaCommandBuffer(*command);
vk_buffer.pipelineBarrier(
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, 0, nullptr, 1, &before, 0, nullptr);
vk_buffer.fillBuffer(dst->buffer, dst_offset, size, value);
vk_buffer.fillBuffer(dst.buffer, dst_offset, size, value);
const auto after =
MakeDmaBarrier(dst, dst_offset, size, vk::AccessFlagBits::eTransferWrite,
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite);
@@ -1131,8 +1099,8 @@ void BufferCache::FillBuffer(CommandBuffer* command, GraphicContext* ctx, uint64
vk::DependencyFlagBits::eByRegion, 0, nullptr, 1, &after, 0, nullptr);
}
void BufferCache::CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t dst_vaddr,
uint64_t src_vaddr, uint64_t size) {
void BufferCache::CopyBuffer(CommandBuffer* command, uint64_t dst_vaddr, uint64_t src_vaddr,
uint64_t size) {
if (dst_vaddr == 0 || src_vaddr == 0 || size == 0 ||
((dst_vaddr | src_vaddr | size) & 3u) != 0 || size > UINT64_MAX - dst_vaddr ||
size > UINT64_MAX - src_vaddr ||
@@ -1195,10 +1163,11 @@ void BufferCache::CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64
src_vaddr, dst_vaddr, size);
}
}
const auto [src, src_offset] = ObtainBuffer(command, ctx, src_vaddr, size, false, true);
EXIT_IF(command == nullptr);
const auto [src, src_offset] = ObtainBuffer(*command, src_vaddr, size, false, true);
const auto [dst, dst_offset] =
ObtainBuffer(command, ctx, dst_vaddr, size, true, false, dst_image_transition);
if (src == dst && src_offset < dst_offset + size && dst_offset < src_offset + size) {
ObtainBuffer(*command, dst_vaddr, size, true, false, dst_image_transition);
if (&src == &dst && src_offset < dst_offset + size && dst_offset < src_offset + size) {
EXIT("BufferCache: resolved Vulkan copy ranges overlap, src_offset=0x%016" PRIx64
" dst_offset=0x%016" PRIx64 " size=0x%016" PRIx64 "\n",
src_offset, dst_offset, size);
@@ -1210,12 +1179,12 @@ void BufferCache::CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64
MakeDmaBarrier(src, src_offset, size, vk::AccessFlagBits::eMemoryWrite,
vk::AccessFlagBits::eTransferRead),
};
const auto vk_buffer = GetDmaCommandBuffer(command);
const auto vk_buffer = GetDmaCommandBuffer(*command);
vk_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, 0, nullptr, 2, before, 0, nullptr);
const vk::BufferCopy copy {src_offset, dst_offset, size};
vk_buffer.copyBuffer(src->buffer, dst->buffer, 1, &copy);
vk_buffer.copyBuffer(src.buffer, dst.buffer, 1, &copy);
const vk::BufferMemoryBarrier after[] = {
MakeDmaBarrier(dst, dst_offset, size, vk::AccessFlagBits::eTransferWrite,
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite),
+17 -13
View File
@@ -35,7 +35,12 @@ struct BufferCacheRange {
uint64_t size = 0;
};
[[nodiscard]] bool MergeOverlappingBufferCacheRange(BufferCacheRange* merged,
struct BufferBinding {
VulkanBuffer& buffer;
uint64_t offset;
};
[[nodiscard]] bool MergeOverlappingBufferCacheRange(BufferCacheRange& merged,
BufferCacheRange candidate) noexcept;
[[nodiscard]] bool CanMergeBufferCacheQueueMask(uint64_t queue_mask, uint32_t queue) noexcept;
@@ -46,27 +51,25 @@ public:
return vaddr & (CACHING_PAGE_SIZE - 1);
}
BufferCache(PageManager& page_manager, ResourceMutex& resource_mutex);
BufferCache(GraphicContext& graphics, PageManager& page_manager, ResourceMutex& resource_mutex);
~BufferCache();
KYTY_CLASS_NO_COPY(BufferCache);
[[nodiscard]] bool InvalidateMemory(PageFaultAccess access, uint64_t vaddr, uint64_t size,
PageFaultPhase phase) noexcept;
void UnmapMemory(uint64_t vaddr, uint64_t size);
[[nodiscard]] std::pair<VulkanBuffer*, uint64_t>
ObtainBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t vaddr, uint64_t size,
bool is_written = false, bool is_read = true, bool is_formatted = false);
[[nodiscard]] BufferBinding ObtainBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size,
bool is_written = false, bool is_read = true,
bool is_formatted = false);
// Emulator-owned, CPU-current scratch only. Guest ranges must use ObtainBuffer so page
// ownership is resolved before any CPU access.
[[nodiscard]] bool UploadHostData(CommandBuffer* command, GraphicContext* ctx, const void* src,
uint64_t size, uint64_t alignment, VulkanBuffer** out_buffer,
uint64_t* out_offset, uint64_t* out_range);
[[nodiscard]] VulkanBuffer* ObtainNullBuffer(CommandBuffer* command, GraphicContext* ctx);
[[nodiscard]] bool UploadHostData(CommandBuffer& command, const void* src, uint64_t size,
uint64_t alignment, VulkanBuffer*& out_buffer,
uint64_t& out_offset, uint64_t& out_range);
[[nodiscard]] VulkanBuffer& ObtainNullBuffer(CommandBuffer& command);
[[nodiscard]] BufferImageCopySource ObtainBufferForImage(uint64_t vaddr, uint64_t size);
void FillBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t vaddr, uint64_t size,
uint32_t value);
void CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t dst_vaddr,
uint64_t src_vaddr, uint64_t size);
void FillBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size, uint32_t value);
void CopyBuffer(CommandBuffer* command, uint64_t dst_vaddr, uint64_t src_vaddr, uint64_t size);
[[nodiscard]] bool HasPageOverlap(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool IsRegionCpuModified(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool IsRegionGpuModified(uint64_t vaddr, uint64_t size);
@@ -80,6 +83,7 @@ private:
struct CachedBuffer;
struct ReadbackWorker;
GraphicContext& m_graphics;
Common::Mutex m_mutex;
std::shared_ptr<VulkanBuffer> m_null_buffer;
// TODO: add LRU cache
@@ -25,15 +25,13 @@ namespace Libs::Graphics {
static std::atomic<uint32_t> g_render_color_log_count = 0;
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw,
RenderColorInfo* r, uint32_t render_target_slice_offset,
uint32_t render_target_slot, bool ignore_target_mask,
bool reuse_existing_render_texture) {
void ResolveRenderColorTarget(uint64_t submit_id, RenderCommandBuffer& buffer, RenderColorInfo& r,
uint32_t render_target_slice_offset, uint32_t render_target_slot,
bool ignore_target_mask, bool reuse_existing_render_texture) {
KYTY_PROFILER_FUNCTION();
const auto& hw = buffer.GetRegisters();
EXIT_IF(r == nullptr);
const auto rt_slot = (render_target_slot == UINT32_MAX ? render_target_first_bound_slot(hw)
const auto rt_slot = (render_target_slot == UINT32_MAX ? render_target_first_bound_slot(buffer)
: render_target_slot);
const auto& rt = hw.GetRenderTarget(rt_slot);
auto mask = render_target_mask_slot(hw.GetRenderTargetMask(), rt_slot);
@@ -41,8 +39,8 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
mask = 0x0f;
}
r->target_slot = rt_slot;
r->export_mapping = {};
r.target_slot = rt_slot;
r.export_mapping = {};
if (rt.base.addr == 0 || mask == 0) {
if (graphics_debug_dump_enabled()) {
@@ -58,17 +56,17 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
}
// No color output
r->type = RenderColorType::NoColorOutput;
r->base_addr = 0;
r->vulkan_buffer = nullptr;
r->vulkan_view = nullptr;
r->format = vk::Format::eUndefined;
r->extent = {};
r->base_mip_level = 0;
r->buffer_size = 0;
r->samples = 1;
r->color_clear_enable = false;
r->color_clear_value = {};
r.type = RenderColorType::NoColorOutput;
r.base_addr = 0;
r.vulkan_buffer = nullptr;
r.vulkan_view = nullptr;
r.format = vk::Format::eUndefined;
r.extent = {};
r.base_mip_level = 0;
r.buffer_size = 0;
r.samples = 1;
r.color_clear_enable = false;
r.color_clear_value = {};
return;
}
const auto samples = render_sample_count(rt.attrib.num_fragments);
@@ -88,7 +86,7 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
rt.view.base_array_slice_index, rt.view.last_array_slice_index,
render_target_slice_offset);
}
r->base_array_layer = view.base_layer;
r.base_array_layer = view.base_layer;
const uint32_t levels = rt.attrib2.num_mip_levels + 1u;
if (levels == 0 || levels > 16 || rt.view.current_mip_level >= levels) {
EXIT("unsupported render-target mip range: current=%u levels=%u\n",
@@ -113,8 +111,8 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
// SRGB clear words are still encoded as normalized component values.
// Fast color clears are metadata driven and must be handled explicitly when
// that metadata path is implemented; render-pass load must preserve contents.
r->color_clear_enable = false;
r->color_clear_value = {};
r.color_clear_enable = false;
r.color_clear_value = {};
uint32_t width = 0;
uint32_t height = 0;
@@ -189,9 +187,9 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
} else {
valid_layout =
levels == 1 ? TileGetRenderTargetSize(width, height, pitch, bytes_per_element,
&layout, rt.attrib.num_fragments)
layout, rt.attrib.num_fragments)
: TileGetRenderTargetMipLayout(width, height, pitch, bytes_per_element,
levels, &layout, nullptr, nullptr);
levels, layout, nullptr, nullptr);
}
if (!valid_layout) {
EXIT("unsupported render-target layout: %ux%u pitch=%u bytes=%u levels=%u\n", width,
@@ -257,23 +255,22 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
target.levels = levels;
target.layers = view.image_layers;
target.samples = samples;
auto* texture_cache = g_render_ctx->GetTextureCache();
auto* buffer_vulkan =
texture_cache->FindRenderTarget(buffer, g_render_ctx->GetGraphicCtx(), target);
r->type = RenderColorType::RenderTexture;
r->base_addr = rt.base.addr;
r->vulkan_buffer = buffer_vulkan;
r->vulkan_view = texture_cache->GetRenderTargetAttachmentView(
g_render_ctx->GetGraphicCtx(), buffer_vulkan, target.format, rt.view.current_mip_level,
view.base_layer, view.layer_count);
r->format = target.format;
r->extent = view_extent;
r->base_mip_level = rt.view.current_mip_level;
r->buffer_size = backing_size;
r->samples = samples;
r->export_mapping = target_format.export_mapping;
r->color_clear_enable = buffer_vulkan->initial_clear_pending;
r->color_clear_value = {};
auto& texture_cache = GetRenderContext().GetTextureCache();
auto& buffer_vulkan = texture_cache.FindRenderTarget(buffer, target);
r.type = RenderColorType::RenderTexture;
r.base_addr = rt.base.addr;
r.vulkan_buffer = &buffer_vulkan;
r.vulkan_view = texture_cache.GetRenderTargetAttachmentView(
buffer_vulkan, target.format, rt.view.current_mip_level, view.base_layer,
view.layer_count);
r.format = target.format;
r.extent = view_extent;
r.base_mip_level = rt.view.current_mip_level;
r.buffer_size = backing_size;
r.samples = samples;
r.export_mapping = target_format.export_mapping;
r.color_clear_enable = buffer_vulkan.initial_clear_pending;
r.color_clear_value = {};
} else {
if (samples != 1) {
EXIT("multisampled display render targets are unsupported\n");
@@ -305,16 +302,16 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
}
EXIT_NOT_IMPLEMENTED(video_image.size < size);
EXIT_NOT_IMPLEMENTED(video_image.pitch != pitch);
r->type = RenderColorType::DisplayBuffer;
r->base_addr = rt.base.addr;
r->vulkan_buffer = video_image.image;
r->vulkan_view = video_image.image->image_view[VulkanImage::VIEW_DEFAULT];
r->format = video_image.image->format;
r->extent = video_image.image->extent;
r->base_mip_level = 0;
r->buffer_size = video_image.size;
r->samples = 1;
r->export_mapping = target_format.export_mapping;
r.type = RenderColorType::DisplayBuffer;
r.base_addr = rt.base.addr;
r.vulkan_buffer = video_image.image;
r.vulkan_view = video_image.image->image_view[VulkanImage::VIEW_DEFAULT];
r.format = video_image.image->format;
r.extent = video_image.image->extent;
r.base_mip_level = 0;
r.buffer_size = video_image.size;
r.samples = 1;
r.export_mapping = target_format.export_mapping;
}
}
@@ -324,7 +321,7 @@ void MarkRenderTargetGpuWritten(const RenderColorInfo& target) {
if (with_color) {
if (target.type == RenderColorType::RenderTexture ||
target.type == RenderColorType::DisplayBuffer) {
g_render_ctx->GetTextureCache()->MarkGpuWritten(target.vulkan_buffer);
GetRenderContext().GetTextureCache().MarkGpuWritten(*target.vulkan_buffer);
} else {
EXIT("unknown writable render-color resource type\n");
}
@@ -9,13 +9,9 @@
namespace Libs::Graphics {
class CommandBuffer;
class RenderCommandBuffer;
struct VulkanImage;
namespace HW {
class Context;
} // namespace HW
enum class RenderColorType {
NoColorOutput,
DisplayBuffer,
@@ -39,8 +35,8 @@ struct RenderColorInfo {
vk::ClearColorValue color_clear_value {};
};
void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw,
RenderColorInfo* r, uint32_t render_target_slice_offset = 0,
void ResolveRenderColorTarget(uint64_t submit_id, RenderCommandBuffer& buffer, RenderColorInfo& r,
uint32_t render_target_slice_offset = 0,
uint32_t render_target_slot = UINT32_MAX,
bool ignore_target_mask = false,
bool reuse_existing_render_texture = false);
+75 -61
View File
@@ -23,8 +23,11 @@
#include <atomic>
#include <cstring>
#include <memory>
#include <mutex>
namespace Libs::Graphics {
static std::atomic<uint64_t> g_command_buffer_submit_seq = 0;
static bool g_render_initialized = false;
static std::mutex g_render_init_mutex;
static void RequireValidQueueId(int queue_id) {
EXIT_IF(queue_id < 0 || queue_id >= GraphicContext::QUEUES_NUM);
@@ -65,9 +68,18 @@ private:
std::array<VulkanCommandPool*, GraphicContext::QUEUES_NUM> m_pools {};
};
RenderContext* g_render_ctx = nullptr;
static RenderContext* g_render_ctx = nullptr;
static thread_local CommandPool g_command_pool;
bool HasRenderContext() noexcept {
return g_render_ctx != nullptr;
}
RenderContext& GetRenderContext() {
EXIT_IF(g_render_ctx == nullptr);
return *g_render_ctx;
}
FenceResourceRetainer::~FenceResourceRetainer() {
if (!m_resources.empty()) {
EXIT("fence resource retainer destroyed before release\n");
@@ -90,9 +102,9 @@ void FenceResourceRetainer::ReleaseAfterFence() noexcept {
}
void GraphicsRenderInit() {
EXIT_IF(g_render_ctx != nullptr);
g_render_ctx = new RenderContext;
std::scoped_lock lock(g_render_init_mutex);
EXIT_IF(g_render_initialized || g_render_ctx != nullptr);
g_render_initialized = true;
}
void GraphicsRenderReleaseThreadCommandPools() {
@@ -102,32 +114,43 @@ void GraphicsRenderReleaseThreadCommandPools() {
}
void GraphicsRenderCreateContext() {
EXIT_IF(g_render_ctx == nullptr);
std::scoped_lock lock(g_render_init_mutex);
EXIT_IF(!g_render_initialized);
if (g_render_ctx == nullptr) {
g_render_ctx = new RenderContext(WindowGetGraphicContext());
}
}
g_render_ctx->SetGraphicCtx(WindowGetGraphicContext());
void GraphicsRenderSetContext(RenderContext& context) {
std::scoped_lock lock(g_render_init_mutex);
EXIT_IF(!g_render_initialized || g_render_ctx != nullptr);
g_render_ctx = &context;
}
CommandBuffer::CommandBuffer(int queue)
: m_graphics(GetRenderContext().GetGraphics()), m_queue(queue), m_host_stream(m_graphics) {
Allocate();
}
void CommandPool::Create(int queue_id) {
RequireValidQueueId(queue_id);
EXIT_IF(g_render_ctx == nullptr);
auto* ctx = g_render_ctx->GetGraphicCtx();
auto*& pool = m_pools[queue_id];
auto& graphics = GetRenderContext().GetGraphics();
auto*& pool = m_pools[queue_id];
EXIT_IF(pool != nullptr);
EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr);
EXIT_IF(ctx->queues[queue_id].family == static_cast<uint32_t>(-1));
EXIT_IF(graphics.device == nullptr);
EXIT_IF(graphics.queues[queue_id].family == static_cast<uint32_t>(-1));
pool = new VulkanCommandPool;
vk::CommandPoolCreateInfo pool_info {};
pool_info.sType = vk::StructureType::eCommandPoolCreateInfo;
pool_info.pNext = nullptr;
pool_info.queueFamilyIndex = ctx->queues[queue_id].family;
pool_info.queueFamilyIndex = graphics.queues[queue_id].family;
pool_info.flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer;
const auto result = ctx->device.createCommandPool(&pool_info, nullptr, &pool->pool);
const auto result = graphics.device.createCommandPool(&pool_info, nullptr, &pool->pool);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || pool->pool == nullptr);
pool->buffers_count = 8;
@@ -142,7 +165,7 @@ void CommandPool::Create(int queue_id) {
alloc_info.level = vk::CommandBufferLevel::ePrimary;
alloc_info.commandBufferCount = pool->buffers_count;
if (ctx->device.allocateCommandBuffers(&alloc_info, pool->buffers.get()) !=
if (graphics.device.allocateCommandBuffers(&alloc_info, pool->buffers.get()) !=
vk::Result::eSuccess) {
EXIT("Can't allocate command buffers");
}
@@ -155,7 +178,7 @@ void CommandPool::Create(int queue_id) {
fence_info.pNext = nullptr;
fence_info.flags = vk::FenceCreateFlagBits::eSignaled;
if (ctx->device.createFence(&fence_info, nullptr, &pool->fences[i]) !=
if (graphics.device.createFence(&fence_info, nullptr, &pool->fences[i]) !=
vk::Result::eSuccess) {
EXIT("Can't create fence");
}
@@ -165,7 +188,7 @@ void CommandPool::Create(int queue_id) {
semaphore_info.pNext = nullptr;
semaphore_info.flags = {};
if (ctx->device.createSemaphore(&semaphore_info, nullptr, &pool->semaphores[i]) !=
if (graphics.device.createSemaphore(&semaphore_info, nullptr, &pool->semaphores[i]) !=
vk::Result::eSuccess) {
EXIT("Can't create semaphore");
}
@@ -177,21 +200,21 @@ void CommandPool::Create(int queue_id) {
}
void CommandPool::DeleteAll() {
auto* ctx = g_render_ctx->GetGraphicCtx();
auto& graphics = GetRenderContext().GetGraphics();
for (auto& pool: m_pools) {
if (pool != nullptr) {
EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr);
EXIT_IF(graphics.device == nullptr);
for (uint32_t i = 0; i < pool->buffers_count; i++) {
ctx->device.destroySemaphore(pool->semaphores[i], nullptr);
ctx->device.destroyFence(pool->fences[i], nullptr);
graphics.device.destroySemaphore(pool->semaphores[i], nullptr);
graphics.device.destroyFence(pool->fences[i], nullptr);
}
ctx->device.freeCommandBuffers(pool->pool, pool->buffers_count, pool->buffers.get());
graphics.device.freeCommandBuffers(pool->pool, pool->buffers_count,
pool->buffers.get());
ctx->device.destroyCommandPool(pool->pool, nullptr);
graphics.device.destroyCommandPool(pool->pool, nullptr);
delete pool;
pool = nullptr;
@@ -200,8 +223,6 @@ void CommandPool::DeleteAll() {
}
bool CommandBuffer::IsInvalid() const {
EXIT_IF(g_render_ctx == nullptr);
if (m_pool != nullptr) {
Common::LockGuard lock(m_pool->mutex);
@@ -255,10 +276,8 @@ void CommandBuffer::Free() {
EXIT_NOT_IMPLEMENTED(!IsInvalid());
}
void CommandBuffer::DeleteAfterFence(VulkanBuffer* buffer) {
EXIT_IF(buffer == nullptr);
m_delete_after_fence.push_back(buffer);
void CommandBuffer::DeleteAfterFence(VulkanBuffer& buffer) {
m_delete_after_fence.push_back(&buffer);
}
void CommandBuffer::RetainResourceUntilFence(std::shared_ptr<void> resource) {
@@ -268,15 +287,13 @@ void CommandBuffer::RetainResourceUntilFence(std::shared_ptr<void> resource) {
m_fence_resources.Retain(std::move(resource));
}
void CommandBuffer::RecycleDescriptorAfterFence(VulkanDescriptorSet* set) {
EXIT_IF(set == nullptr);
m_descriptor_sets_after_fence.push_back(set);
void CommandBuffer::RecycleDescriptorAfterFence(VulkanDescriptorSet& set) {
m_descriptor_sets_after_fence.push_back(&set);
}
void CommandBuffer::RecycleDescriptorsAfterFence() {
for (auto* set: m_descriptor_sets_after_fence) {
g_render_ctx->GetDescriptorCache()->Recycle(set);
GetRenderContext().GetDescriptorCache().Recycle(*set);
}
m_descriptor_sets_after_fence.clear();
}
@@ -351,12 +368,11 @@ void CommandBuffer::Submit(vk::Semaphore wait_semaphore, vk::PipelineStageFlags
submit_info.signalSemaphoreCount = has_signal ? 1u : 0u;
submit_info.pSignalSemaphores = has_signal ? &signal_semaphore : nullptr;
auto* ctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr);
const auto& queue = ctx->queues[m_queue];
auto& graphics = GetRenderContext().GetGraphics();
EXIT_IF(graphics.device == nullptr);
const auto& queue = graphics.queues[m_queue];
auto result = ctx->device.resetFences(1, &fence);
auto result = graphics.device.resetFences(1, &fence);
if (result != vk::Result::eSuccess) {
LOGF("vkResetFences failed before submit: %s (%d)\n", VulkanToString(result).c_str(),
static_cast<int>(result));
@@ -412,7 +428,7 @@ void CommandBuffer::WaitForFenceOnly() {
if (!m_execute || m_fence_waited) {
return;
}
auto device = g_render_ctx->GetGraphicCtx()->device;
auto device = GetRenderContext().GetGraphics().device;
auto result = device.waitForFences(1, &m_pool->fences[m_index], VK_TRUE, UINT64_MAX);
if (result != vk::Result::eSuccess) {
LOGF("vkWaitForFences failed: %s (%d), queue=%d index=%u submit_seq=%" PRIu64
@@ -456,21 +472,20 @@ void CommandBuffer::ReleaseResourcesAfterFence() {
void CommandBuffer::DeleteBuffersAfterFence() {
for (auto* buffer: m_delete_after_fence) {
VulkanDeleteBuffer(g_render_ctx->GetGraphicCtx(), buffer);
GetRenderContext().GetGraphics().DeleteBuffer(*buffer);
delete buffer;
}
m_delete_after_fence.clear();
}
void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorInfo* colors,
uint32_t requested_color_count, RenderDepthInfo* depth) const {
void CommandBuffer::BeginRenderPass(VulkanFramebuffer& framebuffer, RenderColorInfo* colors,
uint32_t requested_color_count, RenderDepthInfo& depth) const {
auto buffer = Handle();
EXIT_IF(framebuffer == nullptr);
EXIT_IF(colors == nullptr);
EXIT_IF(requested_color_count > RENDER_COLOR_ATTACHMENTS_MAX);
bool with_depth = (depth->format != vk::Format::eUndefined && depth->vulkan_buffer != nullptr);
bool with_depth = (depth.format != vk::Format::eUndefined && depth.vulkan_buffer != nullptr);
uint32_t color_count = 0;
for (uint32_t i = 0; i < requested_color_count; i++) {
if (colors[i].vulkan_buffer == nullptr) {
@@ -486,22 +501,22 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI
for (uint32_t i = 0; i < color_count; i++) {
clears[i].color = colors[i].color_clear_value;
}
clears[color_count].depthStencil = {depth->depth_clear_value, depth->stencil_clear_value};
clears[color_count].depthStencil = {depth.depth_clear_value, depth.stencil_clear_value};
vk::Extent2D extent = (with_color ? colors[0].extent : depth->vulkan_buffer->extent);
vk::Extent2D extent = (with_color ? colors[0].extent : depth.vulkan_buffer->extent);
vk::RenderPassBeginInfo render_pass_info {};
render_pass_info.sType = vk::StructureType::eRenderPassBeginInfo;
render_pass_info.pNext = nullptr;
render_pass_info.renderPass = framebuffer->render_pass;
render_pass_info.framebuffer = framebuffer->framebuffer;
render_pass_info.renderPass = framebuffer.render_pass;
render_pass_info.framebuffer = framebuffer.framebuffer;
render_pass_info.renderArea.offset = {0, 0};
render_pass_info.renderArea.extent = extent;
render_pass_info.clearValueCount = color_count + (with_depth ? 1u : 0u);
render_pass_info.pClearValues = clears;
for (uint32_t i = 0; i < color_count; i++) {
const auto color_initial_layout = framebuffer->color_layout[i];
const auto color_initial_layout = framebuffer.color_layout[i];
if (colors[i].vulkan_buffer->layout != color_initial_layout) {
if (graphics_debug_dump_enabled()) {
LOGF("BeginRenderPass: color%u initial barrier image=%p mem=%" PRIu64 " %s -> %s\n",
@@ -543,10 +558,9 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI
}
const auto depth_layout =
(with_depth && framebuffer != nullptr ? framebuffer->depth_layout
: vk::ImageLayout::eDepthStencilAttachmentOptimal);
with_depth ? framebuffer.depth_layout : vk::ImageLayout::eDepthStencilAttachmentOptimal;
if (with_depth && depth->vulkan_buffer->layout != depth_layout) {
if (with_depth && depth.vulkan_buffer->layout != depth_layout) {
vk::ImageMemoryBarrier image_memory_barrier {};
image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier;
image_memory_barrier.pNext = nullptr;
@@ -556,24 +570,24 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI
(depth_layout == vk::ImageLayout::eDepthStencilReadOnlyOptimal
? vk::AccessFlagBits::eMemoryRead
: vk::AccessFlagBits::eMemoryWrite);
image_memory_barrier.oldLayout = depth->vulkan_buffer->layout;
image_memory_barrier.oldLayout = depth.vulkan_buffer->layout;
image_memory_barrier.newLayout = depth_layout;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = depth->vulkan_buffer->image;
image_memory_barrier.image = depth.vulkan_buffer->image;
image_memory_barrier.subresourceRange.aspectMask =
ImageViewOps::DepthAspectMask(depth->vulkan_buffer->format);
ImageViewOps::DepthAspectMask(depth.vulkan_buffer->format);
image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = 1;
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = depth->vulkan_buffer->layers;
image_memory_barrier.subresourceRange.layerCount = depth.vulkan_buffer->layers;
buffer.pipelineBarrier(
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader,
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader,
vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
depth->vulkan_buffer->layout = image_memory_barrier.newLayout;
depth.vulkan_buffer->layout = image_memory_barrier.newLayout;
}
buffer.beginRenderPass(&render_pass_info, vk::SubpassContents::eInline);
@@ -586,8 +600,8 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI
}
}
if (with_depth) {
depth->vulkan_buffer->initial_depth_clear_pending = false;
depth->vulkan_buffer->initial_stencil_clear_pending = false;
depth.vulkan_buffer->initial_depth_clear_pending = false;
depth.vulkan_buffer->initial_stencil_clear_pending = false;
}
}
+13 -9
View File
@@ -25,8 +25,9 @@ static bool RenderTargetMaskHasMrt(uint32_t mask) {
return (mask & ~0x0fu) != 0;
}
static bool RenderTargetMaskHasBoundMrt(const HW::Context& hw) {
const auto mask = hw.GetRenderTargetMask();
static bool RenderTargetMaskHasBoundMrt(const RenderCommandBuffer& buffer) {
const auto& hw = buffer.GetRegisters();
const auto mask = hw.GetRenderTargetMask();
if (!RenderTargetMaskHasMrt(mask)) {
return false;
@@ -42,8 +43,9 @@ static bool RenderTargetMaskHasBoundMrt(const HW::Context& hw) {
return bound_targets > 1;
}
uint32_t render_target_first_bound_slot(const HW::Context& hw) {
const auto mask = hw.GetRenderTargetMask();
uint32_t render_target_first_bound_slot(const RenderCommandBuffer& buffer) {
const auto& hw = buffer.GetRegisters();
const auto mask = hw.GetRenderTargetMask();
for (uint32_t i = 0; i < 8; i++) {
if (render_target_mask_slot(mask, i) != 0 && hw.GetRenderTarget(i).base.addr != 0) {
return i;
@@ -1241,8 +1243,9 @@ ScissorRect calc_final_scissor(const HW::ScreenViewport& vp, const HW::ScanModeC
return ScissorRectClamp(final, extent.width, extent.height);
}
void hw_check(const HW::Context& hw) {
const auto rt_slot = render_target_first_bound_slot(hw);
void hw_check(const RenderCommandBuffer& buffer) {
const auto& hw = buffer.GetRegisters();
const auto rt_slot = render_target_first_bound_slot(buffer);
const auto& rt = hw.GetRenderTarget(rt_slot);
const auto& bc = hw.GetBlendControl(rt_slot);
const auto& bclr = hw.GetBlendColor();
@@ -1291,7 +1294,7 @@ void hw_check(const HW::Context& hw) {
AaCheck(aa, ac);
log_phase("done");
if (RenderTargetMaskHasBoundMrt(hw)) {
if (RenderTargetMaskHasBoundMrt(buffer)) {
LOGF("MRT render target mask: 0x%08" PRIx32 "\n", hw.GetRenderTargetMask());
for (uint32_t i = 0; i < 8; i++) {
const auto& mrt = hw.GetRenderTarget(i);
@@ -1312,8 +1315,9 @@ void hw_check(const HW::Context& hw) {
// EXIT_NOT_IMPLEMENTED(hw.GetStencilClearValue() != 0);
}
void hw_print(const HW::Context& hw) {
const auto rt_slot = render_target_first_bound_slot(hw);
void hw_print(const RenderCommandBuffer& buffer) {
const auto& hw = buffer.GetRegisters();
const auto rt_slot = render_target_first_bound_slot(buffer);
const auto& rt = hw.GetRenderTarget(rt_slot);
const auto& bc = hw.GetBlendControl(rt_slot);
const auto& bclr = hw.GetBlendColor();
+5 -3
View File
@@ -9,6 +9,8 @@
namespace Libs::Graphics {
class RenderCommandBuffer;
namespace HW {
class Context;
class Shader;
@@ -26,7 +28,7 @@ struct ScissorRect {
};
uint32_t render_target_mask_slot(uint32_t mask, uint32_t slot);
uint32_t render_target_first_bound_slot(const HW::Context& hw);
uint32_t render_target_first_bound_slot(const RenderCommandBuffer& buffer);
bool graphics_debug_dump_enabled();
void uc_print(const char* func, const HW::UserConfig& uc);
void uc_check(const HW::UserConfig& uc);
@@ -34,8 +36,8 @@ void sh_print(const char* func, const HW::Shader& uc);
void sh_check(const HW::Shader& uc);
std::vector<std::string> rt_print(const char* func, const HW::RenderTarget& rt);
bool RenderIsColorTileModeLinear(uint32_t tile_mode);
void hw_print(const HW::Context& hw);
void hw_check(const HW::Context& hw);
void hw_print(const RenderCommandBuffer& buffer);
void hw_check(const RenderCommandBuffer& buffer);
void LogDrawPhase(const char* draw_name, const char* phase);
ScissorRect calc_final_scissor(const HW::ScreenViewport& vp, const HW::ScanModeControl& smc,
vk::Extent2D extent);
@@ -61,20 +61,18 @@ static bool UsesStencilOpValue(uint8_t fail, uint8_t pass, uint8_t depth_fail) {
depth_fail == Prospero::GpuEnumValue(Prospero::StencilOp::kReplaceOp);
}
[[nodiscard]] static vk::Format ResolveHostDepthAttachmentFormat(GraphicContext* ctx,
const DepthFormatPolicy& policy,
[[nodiscard]] static vk::Format ResolveHostDepthAttachmentFormat(const RenderCommandBuffer& buffer,
const DepthFormatPolicy& policy,
bool has_stencil,
uint32_t samples) {
if (ctx == nullptr) {
return vk::Format::eUndefined;
}
auto& graphics = buffer.GetGraphics();
const auto required_samples = vulkan_sample_count(samples);
const auto supports = [&](vk::Format format) {
vk::ImageFormatProperties properties {};
return format != vk::Format::eUndefined &&
ctx->GetImageFormatProperties(format, vk::ImageType::e2D, vk::ImageTiling::eOptimal,
DepthTargetImageUsage(), vk::ImageCreateFlags {},
&properties) == vk::Result::eSuccess &&
graphics.GetImageFormatProperties(
format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, DepthTargetImageUsage(),
vk::ImageCreateFlags {}, &properties) == vk::Result::eSuccess &&
static_cast<bool>(properties.sampleCounts & required_samples);
};
if (!has_stencil) {
@@ -90,12 +88,10 @@ static bool UsesStencilOpValue(uint8_t fail, uint8_t pass, uint8_t depth_fail) {
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw,
RenderDepthInfo* r) {
void ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandBuffer& buffer, RenderDepthInfo& r) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(r == nullptr);
(void)submit_id;
(void)buffer;
const auto& hw = buffer.GetRegisters();
const auto& z = hw.GetDepthRenderTarget();
const auto& rc = hw.GetRenderControl();
const auto& dc = hw.GetDepthControl();
@@ -232,9 +228,8 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H
DepthFatal("unsupported depth/stencil format pair");
}
const auto ideal_format = DepthAttachmentFormat(*policy, has_stencil);
r->format = ResolveHostDepthAttachmentFormat(g_render_ctx->GetGraphicCtx(), *policy,
has_stencil, samples);
if (r->format == vk::Format::eUndefined) {
r.format = ResolveHostDepthAttachmentFormat(buffer, *policy, has_stencil, samples);
if (r.format == vk::Format::eUndefined) {
DepthFatal("no host depth/stencil format supports required usage for %s",
VulkanToString(ideal_format).c_str());
}
@@ -250,7 +245,7 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H
TileSizeAlign stencil_size {};
TileSizeAlign htile_size {};
if (!TileGetDepthSize(width, height, 0, z.z_info.format, z.stencil_info.format, has_htile,
&stencil_size, &htile_size, &depth_size, z.z_info.num_samples) ||
stencil_size, htile_size, depth_size, z.z_info.num_samples) ||
depth_size.align != 65536 || depth_size.size == 0 ||
(has_stencil != (stencil_size.align == 65536 && stencil_size.size != 0)) ||
(has_htile != (htile_size.align == 32768 && htile_size.size != 0))) {
@@ -277,41 +272,40 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H
(has_htile && htile_backing_size > TRACKER_ADDRESS_SIZE - z.htile_data_base_addr)) {
DepthFatal("layered depth backing range is invalid");
}
r->htile = has_htile;
r->width = width;
r->height = height;
r->samples = samples;
r->depth_buffer_size = depth_backing_size;
r->depth_buffer_vaddr = z.z_read_base_addr;
r->stencil_buffer_size = has_stencil ? stencil_backing_size : 0;
r->stencil_buffer_vaddr = has_stencil ? z.stencil_read_base_addr : 0;
r->htile_buffer_size = has_htile ? htile_backing_size : 0;
r->htile_buffer_vaddr = has_htile ? z.htile_data_base_addr : 0;
auto* cache = g_render_ctx->GetTextureCache();
r.htile = has_htile;
r.width = width;
r.height = height;
r.samples = samples;
r.depth_buffer_size = depth_backing_size;
r.depth_buffer_vaddr = z.z_read_base_addr;
r.stencil_buffer_size = has_stencil ? stencil_backing_size : 0;
r.stencil_buffer_vaddr = has_stencil ? z.stencil_read_base_addr : 0;
r.htile_buffer_size = has_htile ? htile_backing_size : 0;
r.htile_buffer_vaddr = has_htile ? z.htile_data_base_addr : 0;
auto& cache = GetRenderContext().GetTextureCache();
if (has_htile) {
cache->RegisterMeta(g_render_ctx->GetGraphicCtx(), r->htile_buffer_vaddr,
r->htile_buffer_size, view.image_layers);
cache.RegisterMeta(r.htile_buffer_vaddr, r.htile_buffer_size, view.image_layers);
}
if (has_htile && rc.depth_clear_enable && !cache->ClearMeta(z.htile_data_base_addr)) {
if (has_htile && rc.depth_clear_enable && !cache.ClearMeta(z.htile_data_base_addr)) {
DepthFatal("failed to acquire HTile metadata for a depth clear");
}
const bool meta_clear =
has_htile && cache->IsMetaCleared(z.htile_data_base_addr, z.depth_view.slice_start);
r->depth_clear_enable = rc.depth_clear_enable;
r->depth_meta_clear_enable = meta_clear;
r->depth_load_clear_enable = r->depth_clear_enable || r->depth_meta_clear_enable;
r->depth_clear_value = hw.GetDepthClearValue();
r->depth_test_enable = dc.z_enable;
r->depth_write_enable = dc.z_write_enable && !z.depth_view.depth_write_disable;
r->depth_compare_op = static_cast<vk::CompareOp>(dc.zfunc);
has_htile && cache.IsMetaCleared(z.htile_data_base_addr, z.depth_view.slice_start);
r.depth_clear_enable = rc.depth_clear_enable;
r.depth_meta_clear_enable = meta_clear;
r.depth_load_clear_enable = r.depth_clear_enable || r.depth_meta_clear_enable;
r.depth_clear_value = hw.GetDepthClearValue();
r.depth_test_enable = dc.z_enable;
r.depth_write_enable = dc.z_write_enable && !z.depth_view.depth_write_disable;
r.depth_compare_op = static_cast<vk::CompareOp>(dc.zfunc);
r->depth_bounds_test_enable = dc.depth_bounds_enable;
r->depth_min_bounds = hw.GetDepthBoundsMin();
r->depth_max_bounds = hw.GetDepthBoundsMax();
r.depth_bounds_test_enable = dc.depth_bounds_enable;
r.depth_min_bounds = hw.GetDepthBoundsMin();
r.depth_max_bounds = hw.GetDepthBoundsMax();
r->stencil_clear_enable = rc.stencil_clear_enable;
r->stencil_clear_value = hw.GetStencilClearValue();
r->stencil_test_enable = dc.stencil_enable;
r.stencil_clear_enable = rc.stencil_clear_enable;
r.stencil_clear_value = hw.GetStencilClearValue();
r.stencil_test_enable = dc.stencil_enable;
if (dc.stencil_enable) {
if (dc.stencilfunc > static_cast<uint8_t>(vk::CompareOp::eAlways) ||
(dc.backface_enable &&
@@ -323,40 +317,40 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H
sm.stencil_opval_bf != sm.stencil_testval_bf)) {
DepthFatal("unsupported stencil compare or replacement state");
}
r->stencil_static_front = {
r.stencil_static_front = {
ConvertStencilOp(sc.stencil_fail), ConvertStencilOp(sc.stencil_zpass),
ConvertStencilOp(sc.stencil_zfail), static_cast<vk::CompareOp>(dc.stencilfunc)};
r->stencil_dynamic_front = {sm.stencil_mask,
rc.stencil_clear_enable ? 0u : sm.stencil_writemask,
sm.stencil_testval};
r.stencil_dynamic_front = {sm.stencil_mask,
rc.stencil_clear_enable ? 0u : sm.stencil_writemask,
sm.stencil_testval};
if (dc.backface_enable) {
r->stencil_static_back = {ConvertStencilOp(sc.stencil_fail_bf),
ConvertStencilOp(sc.stencil_zpass_bf),
ConvertStencilOp(sc.stencil_zfail_bf),
static_cast<vk::CompareOp>(dc.stencilfunc_bf)};
r->stencil_dynamic_back = {sm.stencil_mask_bf,
rc.stencil_clear_enable ? 0u : sm.stencil_writemask_bf,
sm.stencil_testval_bf};
r.stencil_static_back = {ConvertStencilOp(sc.stencil_fail_bf),
ConvertStencilOp(sc.stencil_zpass_bf),
ConvertStencilOp(sc.stencil_zfail_bf),
static_cast<vk::CompareOp>(dc.stencilfunc_bf)};
r.stencil_dynamic_back = {sm.stencil_mask_bf,
rc.stencil_clear_enable ? 0u : sm.stencil_writemask_bf,
sm.stencil_testval_bf};
} else {
r->stencil_static_back = r->stencil_static_front;
r->stencil_dynamic_back = r->stencil_dynamic_front;
r.stencil_static_back = r.stencil_static_front;
r.stencil_dynamic_back = r.stencil_dynamic_front;
}
}
r->vaddr_num = has_stencil ? 2 : 1;
r->vaddr[0] = r->depth_buffer_vaddr;
r->size[0] = r->depth_buffer_size;
r.vaddr_num = has_stencil ? 2 : 1;
r.vaddr[0] = r.depth_buffer_vaddr;
r.size[0] = r.depth_buffer_size;
if (has_stencil) {
r->vaddr[1] = r->stencil_buffer_vaddr;
r->size[1] = r->stencil_buffer_size;
r.vaddr[1] = r.stencil_buffer_vaddr;
r.size[1] = r.stencil_buffer_size;
}
DepthTargetInfo info {};
info.address = r->depth_buffer_vaddr;
info.size = r->depth_buffer_size;
info.stencil_address = r->stencil_buffer_vaddr;
info.stencil_size = r->stencil_buffer_size;
info.htile_address = r->htile_buffer_vaddr;
info.htile_size = r->htile_buffer_size;
info.format = r->format;
info.address = r.depth_buffer_vaddr;
info.size = r.depth_buffer_size;
info.stencil_address = r.stencil_buffer_vaddr;
info.stencil_size = r.stencil_buffer_size;
info.htile_address = r.htile_buffer_vaddr;
info.htile_size = r.htile_buffer_size;
info.format = r.format;
info.guest_format = guest_format;
info.width = width;
info.height = height;
@@ -365,28 +359,28 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H
info.tile_mode = Prospero::GpuEnumValue(Prospero::TileMode::kDepth);
info.layers = view.image_layers;
info.samples = samples;
info.depth_load_clear = r->depth_load_clear_enable;
info.depth_load_clear = r.depth_load_clear_enable;
info.depth_access = depth_active;
info.stencil_load_clear = rc.stencil_clear_enable;
info.stencil_access =
r->stencil_clear_enable ||
(r->stencil_test_enable &&
(stencil_face_accesses_attachment(r->stencil_static_front, r->stencil_dynamic_front) ||
stencil_face_accesses_attachment(r->stencil_static_back, r->stencil_dynamic_back)));
r.stencil_clear_enable ||
(r.stencil_test_enable &&
(stencil_face_accesses_attachment(r.stencil_static_front, r.stencil_dynamic_front) ||
stencil_face_accesses_attachment(r.stencil_static_back, r.stencil_dynamic_back)));
info.stencil_htile_compressed =
has_stencil && has_htile && !z.stencil_info.tile_stencil_disable;
r->vulkan_buffer = cache->FindDepthTarget(buffer, g_render_ctx->GetGraphicCtx(), info);
r->vulkan_view = cache->GetDepthTargetAttachmentView(
g_render_ctx->GetGraphicCtx(), r->vulkan_buffer, view.base_layer, view.layer_count);
if (r->vulkan_buffer->initial_depth_clear_pending) {
r->depth_load_clear_enable = true;
r->depth_clear_value = 0.0f;
r.vulkan_buffer = &cache.FindDepthTarget(buffer, info);
r.vulkan_view =
cache.GetDepthTargetAttachmentView(*r.vulkan_buffer, view.base_layer, view.layer_count);
if (r.vulkan_buffer->initial_depth_clear_pending) {
r.depth_load_clear_enable = true;
r.depth_clear_value = 0.0f;
}
if (r->vulkan_buffer->initial_stencil_clear_pending) {
r->stencil_clear_enable = true;
r->stencil_clear_value = 0;
if (r.vulkan_buffer->initial_stencil_clear_pending) {
r.stencil_clear_enable = true;
r.stencil_clear_value = 0;
}
if (meta_clear && !cache->TouchMeta(z.htile_data_base_addr, z.depth_view.slice_start, false)) {
if (meta_clear && !cache.TouchMeta(z.htile_data_base_addr, z.depth_view.slice_start, false)) {
DepthFatal("failed to consume HTile clear state");
}
}
@@ -395,8 +389,8 @@ void MarkRenderTargetGpuWritten(const RenderDepthInfo& target) {
const bool with_depth =
target.format != vk::Format::eUndefined && target.vulkan_buffer != nullptr;
if (with_depth && !depth_attachment_read_only(&target)) {
g_render_ctx->GetTextureCache()->MarkGpuWritten(target.vulkan_buffer);
if (with_depth && !depth_attachment_read_only(target)) {
GetRenderContext().GetTextureCache().MarkGpuWritten(*target.vulkan_buffer);
}
}
@@ -9,13 +9,9 @@
namespace Libs::Graphics {
class CommandBuffer;
class RenderCommandBuffer;
struct DepthStencilVulkanImage;
namespace HW {
class Context;
} // namespace HW
inline constexpr bool depth_htile_stencil_acceleration_compatible(bool has_stencil, bool has_htile,
bool acceleration_disabled) {
return acceleration_disabled || (has_stencil && has_htile);
@@ -60,22 +56,20 @@ struct RenderDepthInfo {
int vaddr_num = 0;
};
inline bool depth_attachment_read_only(const RenderDepthInfo* depth) {
EXIT_IF(depth == nullptr);
inline bool depth_attachment_read_only(const RenderDepthInfo& depth) {
const bool stencil_write =
depth->stencil_test_enable &&
(depth->stencil_dynamic_front.writeMask != 0 || depth->stencil_dynamic_back.writeMask != 0);
return !depth->depth_load_clear_enable && !depth->stencil_clear_enable &&
!depth->depth_write_enable && !stencil_write;
depth.stencil_test_enable &&
(depth.stencil_dynamic_front.writeMask != 0 || depth.stencil_dynamic_back.writeMask != 0);
return !depth.depth_load_clear_enable && !depth.stencil_clear_enable &&
!depth.depth_write_enable && !stencil_write;
}
inline vk::ImageLayout depth_attachment_layout(const RenderDepthInfo* depth) {
inline vk::ImageLayout depth_attachment_layout(const RenderDepthInfo& depth) {
return depth_attachment_read_only(depth) ? vk::ImageLayout::eDepthStencilReadOnlyOptimal
: vk::ImageLayout::eDepthStencilAttachmentOptimal;
}
void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw,
RenderDepthInfo* r);
void ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandBuffer& buffer, RenderDepthInfo& r);
void MarkRenderTargetGpuWritten(const RenderDepthInfo& target);
} // namespace Libs::Graphics
@@ -76,13 +76,12 @@ std::vector<uint32_t> LayoutKey(DescriptorCache::Stage stage,
return key;
}
vk::ImageLayout SampledLayout(const VulkanImage* image) {
EXIT_IF(image == nullptr);
switch (image->layout) {
vk::ImageLayout SampledLayout(const VulkanImage& image) {
switch (image.layout) {
case vk::ImageLayout::eTransferDstOptimal:
case vk::ImageLayout::eTransferSrcOptimal:
case vk::ImageLayout::eColorAttachmentOptimal: return vk::ImageLayout::eGeneral;
default: return image->layout;
default: return image.layout;
}
}
@@ -103,9 +102,8 @@ vk::DescriptorImageInfo MakeDescriptorImageInfo(const DescriptorCache::TextureBi
} // namespace
vk::DescriptorSetLayout
DescriptorCache::GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stage,
DescriptorCache::GetDescriptorSetLayoutInternal(Stage stage,
const ShaderRecompiler::IR::Program& program) {
EXIT_IF(gctx == nullptr);
const auto key = LayoutKey(stage, program);
if (const auto found = m_descriptor_set_layouts.find(key);
found != m_descriptor_set_layouts.end()) {
@@ -127,15 +125,14 @@ DescriptorCache::GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stag
info.bindingCount = static_cast<uint32_t>(bindings.size());
info.pBindings = bindings.data();
vk::DescriptorSetLayout layout = nullptr;
const auto result = gctx->device.createDescriptorSetLayout(&info, nullptr, &layout);
const auto result = m_graphics.device.createDescriptorSetLayout(&info, nullptr, &layout);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || layout == nullptr);
m_descriptor_set_layouts.emplace(key, layout);
return layout;
}
void DescriptorCache::CreatePool(GraphicContext* gctx) {
void DescriptorCache::CreatePool() {
KYTY_PROFILER_FUNCTION();
EXIT_IF(gctx == nullptr);
constexpr uint32_t MaxSets = 512;
const vk::DescriptorPoolSize sizes[] = {
{vk::DescriptorType::eStorageBuffer,
@@ -152,7 +149,7 @@ void DescriptorCache::CreatePool(GraphicContext* gctx) {
info.maxSets = MaxSets;
const auto pool_id = static_cast<int>(m_pools.size());
auto& pool = m_pools.emplace_back();
const auto result = gctx->device.createDescriptorPool(&info, nullptr, &pool.pool);
const auto result = m_graphics.device.createDescriptorPool(&info, nullptr, &pool.pool);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || pool.pool == nullptr);
pool.next_free_pool = m_first_free_pool;
m_first_free_pool = pool_id;
@@ -161,10 +158,8 @@ void DescriptorCache::CreatePool(GraphicContext* gctx) {
VulkanDescriptorSet* DescriptorCache::Allocate(Stage stage,
const ShaderRecompiler::IR::Program& program) {
KYTY_PROFILER_FUNCTION();
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
Common::LockGuard lock(m_mutex);
const auto layout = GetDescriptorSetLayoutInternal(gctx, stage, program);
const auto layout = GetDescriptorSetLayoutInternal(stage, program);
EXIT_IF(layout == nullptr);
auto& free_sets = m_free_sets_by_layout[layout];
if (!free_sets.empty()) {
@@ -186,7 +181,8 @@ VulkanDescriptorSet* DescriptorCache::Allocate(Stage
info.descriptorPool = pool.pool;
info.descriptorSetCount = Batch;
info.pSetLayouts = layouts.data();
if (gctx->device.allocateDescriptorSets(&info, sets.data()) == vk::Result::eSuccess) {
if (m_graphics.device.allocateDescriptorSets(&info, sets.data()) ==
vk::Result::eSuccess) {
free_sets.reserve(free_sets.size() + Batch - 1u);
for (uint32_t i = 0; i + 1u < Batch; i++) {
free_sets.push_back(new VulkanDescriptorSet {sets[i], layout, pool_id});
@@ -196,18 +192,18 @@ VulkanDescriptorSet* DescriptorCache::Allocate(Stage
m_first_free_pool = pool.next_free_pool;
break;
}
CreatePool(gctx);
CreatePool();
}
return nullptr;
}
void DescriptorCache::Recycle(VulkanDescriptorSet* set) {
EXIT_IF(set == nullptr || set->set == nullptr || set->layout == nullptr);
void DescriptorCache::Recycle(VulkanDescriptorSet& set) {
EXIT_IF(set.set == nullptr || set.layout == nullptr);
Common::LockGuard lock(m_mutex);
m_free_sets_by_layout[set->layout].push_back(set);
m_free_sets_by_layout[set.layout].push_back(&set);
}
VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage stage,
VulkanDescriptorSet& DescriptorCache::GetDescriptor(Stage stage,
const ShaderRecompiler::IR::Program& program,
const NativeDescriptors& data) {
KYTY_PROFILER_FUNCTION();
@@ -215,8 +211,6 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage
data.images.size() != program.info.images.size() ||
data.samplers.size() != program.info.samplers.size() ||
data.addresses.size() != program.info.addresses.size());
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
auto* set = Allocate(stage, program);
EXIT_NOT_IMPLEMENTED(set == nullptr);
@@ -268,7 +262,7 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage
const auto& texture = data.images.at(resource);
image_infos.push_back(MakeDescriptorImageInfo(
texture,
IsSampledImage(binding.kind) ? SampledLayout(texture.image) : layout));
IsSampledImage(binding.kind) ? SampledLayout(*texture.image) : layout));
}
break;
}
@@ -281,17 +275,15 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage
}
writes.push_back(write);
}
gctx->device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0,
nullptr);
return set;
m_graphics.device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0,
nullptr);
return *set;
}
vk::DescriptorSetLayout
DescriptorCache::GetDescriptorSetLayout(Stage stage, const ShaderRecompiler::IR::Program& program) {
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
Common::LockGuard lock(m_mutex);
return GetDescriptorSetLayoutInternal(gctx, stage, program);
return GetDescriptorSetLayoutInternal(stage, program);
}
} // namespace Libs::Graphics
@@ -63,14 +63,16 @@ public:
BufferView user_data;
};
DescriptorCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
explicit DescriptorCache(GraphicContext& graphics): m_graphics(graphics) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
}
~DescriptorCache() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(DescriptorCache);
vk::DescriptorSetLayout GetDescriptorSetLayout(Stage stage,
const ShaderRecompiler::IR::Program& program);
void Recycle(VulkanDescriptorSet* set);
VulkanDescriptorSet* GetDescriptor(Stage stage, const ShaderRecompiler::IR::Program& program,
void Recycle(VulkanDescriptorSet& set);
VulkanDescriptorSet& GetDescriptor(Stage stage, const ShaderRecompiler::IR::Program& program,
const NativeDescriptors& descriptors);
private:
@@ -79,12 +81,12 @@ private:
int next_free_pool = -1;
};
void CreatePool(GraphicContext* gctx);
void CreatePool();
VulkanDescriptorSet* Allocate(Stage stage, const ShaderRecompiler::IR::Program& program);
vk::DescriptorSetLayout
GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stage,
const ShaderRecompiler::IR::Program& program);
GetDescriptorSetLayoutInternal(Stage stage, const ShaderRecompiler::IR::Program& program);
GraphicContext& m_graphics;
Common::Mutex m_mutex;
std::vector<Pool> m_pools;
int m_first_free_pool = -1;
@@ -93,7 +95,7 @@ private:
std::map<std::vector<uint32_t>, vk::DescriptorSetLayout> m_descriptor_set_layouts;
};
void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer,
void BindDescriptors(uint64_t submit_id, CommandBuffer& buffer,
vk::PipelineBindPoint pipeline_bind_point, vk::PipelineLayout layout,
const ShaderStageRuntime& runtime, vk::ShaderStageFlags vk_stage,
DescriptorCache::Stage stage);
+88 -151
View File
@@ -49,13 +49,10 @@ namespace Libs::Graphics {
using TextureVariant = DescriptorCache::TextureVariant;
static void BindNullStorageBuffer(CommandBuffer* cmd_buffer, BufferView* dst) {
EXIT_IF(cmd_buffer == nullptr || dst == nullptr);
dst->buffer =
g_render_ctx->GetBufferCache()->ObtainNullBuffer(cmd_buffer, g_render_ctx->GetGraphicCtx());
dst->offset = 0;
dst->range = 16;
static void BindNullStorageBuffer(CommandBuffer& cmd_buffer, BufferView& dst) {
dst.buffer = &GetRenderContext().GetBufferCache().ObtainNullBuffer(cmd_buffer);
dst.offset = 0;
dst.range = 16;
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
@@ -71,21 +68,19 @@ static const char* VulkanImageTypeName(VulkanImageType type) {
}
}
static int SampledArrayViewIndex(const VulkanImage* image, int view_index) {
EXIT_IF(image == nullptr);
static int SampledArrayViewIndex(const VulkanImage& image, int view_index) {
switch (view_index) {
case VulkanImage::VIEW_DEFAULT: return VulkanImage::VIEW_DEFAULT_ARRAY;
default: return view_index;
}
}
static int SelectSampledTextureArrayView(const VulkanImage* image, int base_view) {
static int SelectSampledTextureArrayView(const VulkanImage& image, int base_view) {
const int array_view = SampledArrayViewIndex(image, base_view);
if (image->image_view[array_view] == nullptr) {
if (image.image_view[array_view] == nullptr) {
EXIT("missing sampled array image view: image_type=%s base_view=%d array_view=%d "
"layers=%u\n",
VulkanImageTypeName(image->type), base_view, array_view, image->layers);
VulkanImageTypeName(image.type), base_view, array_view, image.layers);
}
return array_view;
}
@@ -108,14 +103,14 @@ static int TextureVariantDefaultView(TextureVariant variant) {
: VulkanImage::VIEW_DEFAULT;
}
static VulkanImage* GetDummySampledTexture(TextureVariant variant) {
return g_render_ctx->GetTextureCache()->GetDummySampledTexture(TextureVariantIsUint(variant),
TextureVariantIs3D(variant));
static VulkanImage& GetDummySampledTexture(TextureVariant variant) {
return GetRenderContext().GetTextureCache().GetDummySampledTexture(
TextureVariantIsUint(variant), TextureVariantIs3D(variant));
}
static VulkanImage* GetDummyStorageTexture(TextureVariant variant) {
return g_render_ctx->GetTextureCache()->GetDummyStorageTexture(TextureVariantIsUint(variant),
TextureVariantIs3D(variant));
static VulkanImage& GetDummyStorageTexture(TextureVariant variant) {
return GetRenderContext().GetTextureCache().GetDummyStorageTexture(
TextureVariantIsUint(variant), TextureVariantIs3D(variant));
}
static void CopyNativeDescriptor(const ShaderRecompiler::IR::DescriptorValue& source,
@@ -124,63 +119,11 @@ static void CopyNativeDescriptor(const ShaderRecompiler::IR::DescriptorValue& so
std::copy_n(source.dwords.begin(), destination.size(), destination.begin());
}
static BufferView NativeStorageBuffer(uint64_t submit_id, CommandBuffer* command_buffer,
static BufferView NativeStorageBuffer(uint64_t submit_id, CommandBuffer& command_buffer,
const ShaderBufferResource& descriptor,
const ShaderRecompiler::IR::BufferResource& resource) {
BufferView result;
// Regression
// Bind a null buffer when these four dwords are
// the tracked prefix of an active image sharp. Image validity is encoded by dword 3 bit 31.
/*if (resource.image_alias != ShaderRecompiler::IR::BufferResource::NoImageAlias &&
(descriptor.Type() & 2u) != 0) {
BindNullStorageBuffer(command_buffer, &result);
return result;
}
// Buffer TYPE is zero. A nonzero value means a buffer instruction received the first four
// dwords of an image sharp without a tracked image alias; support the known write-only path.
if (descriptor.Type() != 0) {
ShaderTextureResource texture {};
std::copy_n(descriptor.fields, 4, texture.fields);
const auto width = static_cast<uint32_t>(texture.Width5()) + 1u;
const auto height = static_cast<uint32_t>(texture.Height5()) + 1u;
const auto format = texture.Format();
const auto tile = texture.TileMode();
const auto type = texture.Type();
const auto address = texture.Base40();
const auto pitch = TileGetTexturePitch(format, width, 1, tile);
TileSizeAlign footprint {};
TileGetTextureTotalSize(format, width, height, 1, pitch, 1, tile, false, &footprint);
const bool supported =
resource.formatted && resource.written && !resource.read && !resource.atomic &&
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8UInt) &&
tile == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) &&
type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) &&
texture.DstSelXYZW() == DstSel(4, 5, 6, 7) && address != 0 && footprint.size != 0 &&
footprint.align == 65536;
if (!supported) {
EXIT("unsupported texture descriptor used as storage buffer: type=%u format=%u"
" tile=%u swizzle=0x%03x extent=%ux%u read=%d written=%d formatted=%d atomic=%d\n",
type, format, tile, texture.DstSelXYZW(), width, height, resource.read,
resource.written, resource.formatted, resource.atomic);
}
auto* ctx = g_render_ctx->GetGraphicCtx();
g_render_ctx->GetBufferCache()->ValidateGpuAccess(address, footprint.size, false, true);
auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer(
command_buffer, ctx, address, footprint.size, true, false, true);
const auto alignment = ctx->StorageMinAlignment();
if (alignment == 0 || binding.second % alignment != 0 ||
footprint.size > ctx->GetPhysicalDeviceProperties().limits.maxStorageBufferRange) {
EXIT("texture-backed storage buffer binding is unsupported: addr=0x%016" PRIx64
" size=0x%016" PRIx64 " offset=0x%016" PRIx64 " alignment=0x%016" PRIx64 "\n",
address, footprint.size, static_cast<uint64_t>(binding.second),
static_cast<uint64_t>(alignment));
}
result.buffer = binding.first;
result.offset = binding.second;
result.range = footprint.size;
return result;
}*/
const auto address = descriptor.Base48();
const auto stride = descriptor.Stride();
const auto records = descriptor.NumRecords();
@@ -189,34 +132,35 @@ static BufferView NativeStorageBuffer(uint64_t submit_id, CommandBuffer* command
}
const auto size = stride != 0 ? static_cast<uint64_t>(stride) * records : records;
if (address == 0 || size == 0) {
BindNullStorageBuffer(command_buffer, &result);
BindNullStorageBuffer(command_buffer, result);
return result;
}
auto* const ctx = g_render_ctx->GetGraphicCtx();
const auto alignment = ctx->StorageMinAlignment();
if (alignment == 0 || size > ctx->GetPhysicalDeviceProperties().limits.maxStorageBufferRange ||
const auto& graphics = GetRenderContext().GetGraphics();
const auto alignment = graphics.StorageMinAlignment();
if (alignment == 0 ||
size > graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange ||
BufferCache::CACHING_PAGE_SIZE % alignment != 0) {
EXIT("storage buffer range or device alignment is unsupported\n");
}
(void)submit_id;
auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer(
command_buffer, ctx, address, size, resource.written, resource.read, resource.formatted);
if (binding.second % alignment != 0) {
auto binding = GetRenderContext().GetBufferCache().ObtainBuffer(
command_buffer, address, size, resource.written, resource.read, resource.formatted);
if (binding.offset % alignment != 0) {
EXIT("storage buffer binding is not device-aligned\n");
}
result.buffer = binding.first;
result.offset = binding.second;
result.buffer = &binding.buffer;
result.offset = binding.offset;
result.range = static_cast<vk::DeviceSize>(size);
return result;
}
static BufferView
NativeAddressBuffer(uint64_t submit_id, CommandBuffer* command_buffer,
NativeAddressBuffer(uint64_t submit_id, CommandBuffer& command_buffer,
const ShaderRecompiler::IR::AddressResource& resource,
const ShaderRecompiler::IR::ResourceSnapshot::Address& address) {
BufferView result;
if (address.binding_base == 0) {
BindNullStorageBuffer(command_buffer, &result);
BindNullStorageBuffer(command_buffer, result);
return result;
}
if (resource.written) {
@@ -224,26 +168,28 @@ NativeAddressBuffer(uint64_t submit_id, CommandBuffer* command_buffer,
}
const auto limit = resource.kind == ShaderRecompiler::IR::ResourceKind::Flat
? ShaderRecompiler::IR::FlatAddressWindowSize
: static_cast<uint64_t>(g_render_ctx->GetGraphicCtx()
->GetPhysicalDeviceProperties()
: static_cast<uint64_t>(GetRenderContext()
.GetGraphics()
.GetPhysicalDeviceProperties()
.limits.maxStorageBufferRange);
uint64_t size = 0;
const auto access = HostMemoryAccess::Mapped;
if (!HostMemoryQueryRange(address.binding_base, limit, access, &size)) {
if (!HostMemoryQueryRange(address.binding_base, limit, access, size)) {
EXIT("address resource is not host-accessible: base=0x%016" PRIx64 "\n",
address.binding_base);
}
auto* const ctx = g_render_ctx->GetGraphicCtx();
const auto alignment = ctx->StorageMinAlignment();
if (alignment == 0 || size > ctx->GetPhysicalDeviceProperties().limits.maxStorageBufferRange ||
const auto& graphics = GetRenderContext().GetGraphics();
const auto alignment = graphics.StorageMinAlignment();
if (alignment == 0 ||
size > graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange ||
BufferCache::GetBufferOffset(address.binding_base) % alignment != 0) {
EXIT("address resource range or alignment is unsupported\n");
}
(void)submit_id;
auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer(command_buffer, ctx,
address.binding_base, size);
result.buffer = binding.first;
result.offset = binding.second;
auto binding = GetRenderContext().GetBufferCache().ObtainBuffer(command_buffer,
address.binding_base, size);
result.buffer = &binding.buffer;
result.offset = binding.offset;
result.range = static_cast<vk::DeviceSize>(size);
return result;
}
@@ -529,7 +475,7 @@ void ValidateMetadataReuseTexture(const ShaderRecompiler::IR::ImageResource& res
}
static DescriptorCache::TextureBinding
NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
NativeTexture(uint64_t submit_id, CommandBuffer& command_buffer,
const ShaderRecompiler::IR::ImageResource& resource,
const ShaderRecompiler::IR::DescriptorValue& value) {
ShaderTextureResource descriptor;
@@ -541,9 +487,9 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
ValidateStorageImageResource(resource);
}
if (descriptor.IsNull()) {
return storage ? DescriptorCache::TextureBinding {GetDummyStorageTexture(variant),
return storage ? DescriptorCache::TextureBinding {&GetDummyStorageTexture(variant),
TextureVariantDefaultView(variant)}
: DescriptorCache::TextureBinding {GetDummySampledTexture(variant),
: DescriptorCache::TextureBinding {&GetDummySampledTexture(variant),
TextureVariantDefaultView(variant)};
}
const auto address = descriptor.Base40();
@@ -578,13 +524,13 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
const auto swizzle = descriptor.DstSelXYZW();
TileSizeAlign size;
TileGetTextureTotalSize(format, width, height, depth, pitch, levels, tile,
type == Prospero::ImageType::kColor3D, &size);
type == Prospero::ImageType::kColor3D, size);
EXIT_NOT_IMPLEMENTED(size.size == 0 ||
(address & (static_cast<uint64_t>(size.align) - 1u)) != 0);
if (storage) {
ValidateStorageTexture(resource, descriptor, size.size);
g_render_ctx->GetBufferCache()->ValidateGpuAccess(address, size.size, resource.read,
resource.written);
GetRenderContext().GetBufferCache().ValidateGpuAccess(address, size.size, resource.read,
resource.written);
}
VulkanImage* image = nullptr;
@@ -594,11 +540,11 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
descriptor.MsaaDepth();
if (image == nullptr) {
if (check_depth) {
image = g_render_ctx->GetTextureCache()->FindDepthTargetByRange(command_buffer, address,
size.size, true);
image = GetRenderContext().GetTextureCache().FindDepthTargetByRange(
command_buffer, address, size.size, true);
} else {
image = g_render_ctx->GetTextureCache()->FindRenderTargetByRange(command_buffer,
address, size.size);
image = GetRenderContext().GetTextureCache().FindRenderTargetByRange(
command_buffer, address, size.size);
}
if (image != nullptr) {
if (check_depth) {
@@ -628,10 +574,9 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
static_cast<uint32_t>(resource.dimension), descriptor.Type(),
descriptor.BaseArray5(), image->layers);
}
image_view = g_render_ctx->GetTextureCache()->GetDepthTargetSampledView(
g_render_ctx->GetGraphicCtx(), static_cast<DepthStencilVulkanImage*>(image),
view_format, swizzle, 0, 1, depth_view.type, depth_view.base_layer,
depth_view.layer_count);
image_view = GetRenderContext().GetTextureCache().GetDepthTargetSampledView(
*static_cast<DepthStencilVulkanImage*>(image), view_format, swizzle, 0, 1,
depth_view.type, depth_view.base_layer, depth_view.layer_count);
}
} else {
if (!(storage ? IsSupportedStorageImageResource(resource)
@@ -657,23 +602,21 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
}
if (storage) {
view = SelectStorageColorView(image->format, view_format, swizzle);
image_view = g_render_ctx->GetTextureCache()->GetRenderTargetStorageView(
g_render_ctx->GetGraphicCtx(),
static_cast<RenderTextureVulkanImage*>(image), view_format, base_level,
image_view = GetRenderContext().GetTextureCache().GetRenderTargetStorageView(
*static_cast<RenderTextureVulkanImage*>(image), view_format, base_level,
view_levels, target_view.type, target_view.base_layer,
target_view.layer_count);
} else {
image_view = g_render_ctx->GetTextureCache()->GetSampledColorView(
g_render_ctx->GetGraphicCtx(), image, view_format, swizzle, base_level,
view_levels, target_view.type, target_view.base_layer,
target_view.layer_count);
image_view = GetRenderContext().GetTextureCache().GetSampledColorView(
*image, view_format, swizzle, base_level, view_levels, target_view.type,
target_view.base_layer, target_view.layer_count);
}
}
if (image != nullptr && image_view == nullptr && image->image_view[view] == nullptr) {
EXIT("required cached texture image view is missing\n");
}
if (storage && image != nullptr) {
g_render_ctx->GetTextureCache()->MarkGpuWritten(image);
GetRenderContext().GetTextureCache().MarkGpuWritten(*image);
}
}
}
@@ -701,7 +644,7 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
}
image = video.image;
view = VulkanImage::VIEW_STORAGE;
g_render_ctx->GetTextureCache()->MarkGpuWritten(image);
GetRenderContext().GetTextureCache().MarkGpuWritten(*image);
} else {
const bool exact =
IsSupportedSampledVideoOutView(resource, descriptor, *video.image) &&
@@ -721,15 +664,14 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
static_cast<uint32_t>(type), size.size, video.size, pitch, video.pitch);
}
image = video.image;
image_view = g_render_ctx->GetTextureCache()->GetSampledColorView(
g_render_ctx->GetGraphicCtx(), video.image, view_format, swizzle, 0, 1,
vk::ImageViewType::e2D, 0, 1);
image_view = GetRenderContext().GetTextureCache().GetSampledColorView(
*video.image, view_format, swizzle, 0, 1, vk::ImageViewType::e2D, 0, 1);
}
}
}
if (image == nullptr) {
auto* texture_cache = g_render_ctx->GetTextureCache();
const bool metadata_read = texture_cache->QueryRegion(address, size.size).metadata_pages;
auto& texture_cache = GetRenderContext().GetTextureCache();
const bool metadata_read = texture_cache.QueryRegion(address, size.size).metadata_pages;
if (storage && metadata_read) {
EXIT("storage texture overlaps surface metadata\n");
}
@@ -754,19 +696,15 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
info.type = descriptor.Type();
info.base_array = descriptor.BaseArray5();
if (storage) {
image = texture_cache->FindStorageTexture(command_buffer, g_render_ctx->GetGraphicCtx(),
info);
view = VulkanImage::VIEW_DEFAULT;
image_view = texture_cache->GetStorageTextureStorageView(
g_render_ctx->GetGraphicCtx(), static_cast<StorageTextureVulkanImage*>(image),
base_level);
image = &texture_cache.FindStorageTexture(command_buffer, info);
view = VulkanImage::VIEW_DEFAULT;
image_view = texture_cache.GetStorageTextureStorageView(
*static_cast<StorageTextureVulkanImage*>(image), base_level);
} else {
image = texture_cache->FindTexture(command_buffer, g_render_ctx->GetGraphicCtx(), info,
metadata_read);
image = &texture_cache.FindTexture(command_buffer, info, metadata_read);
if (image->type == VulkanImageType::StorageTexture) {
image_view = texture_cache->GetStorageTextureSampledView(
g_render_ctx->GetGraphicCtx(), static_cast<StorageTextureVulkanImage*>(image),
info);
image_view = texture_cache.GetStorageTextureSampledView(
*static_cast<StorageTextureVulkanImage*>(image), info);
}
}
}
@@ -774,7 +712,7 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
if (NeedsStaticSampledArrayView(resource.dimension ==
ShaderRecompiler::Decoder::ImageDimension::Dim2DArray,
image_view != nullptr)) {
view = SelectSampledTextureArrayView(image, view);
view = SelectSampledTextureArrayView(*image, view);
}
return {image, view, image_view};
}
@@ -792,31 +730,31 @@ static vk::Sampler NativeSampler(const ShaderRecompiler::IR::Program& program, u
if (!depth_compare) {
descriptor.fields[0] &= ~(0x7u << 12u);
}
return g_render_ctx->GetSamplerCache()->GetSampler(descriptor);
return GetRenderContext().GetSamplerCache().GetSampler(descriptor);
}
static BufferView NativeUpload(CommandBuffer* command_buffer, std::span<const uint32_t> data) {
static BufferView NativeUpload(CommandBuffer& command_buffer, std::span<const uint32_t> data) {
EXIT_IF(data.empty());
BufferView result;
EXIT_IF(!g_render_ctx->GetBufferCache()->UploadHostData(
command_buffer, g_render_ctx->GetGraphicCtx(), data.data(), data.size_bytes(), 256,
&result.buffer, &result.offset, &result.range));
EXIT_IF(!GetRenderContext().GetBufferCache().UploadHostData(
command_buffer, data.data(), data.size_bytes(), 256, result.buffer, result.offset,
result.range));
return result;
}
void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer,
void BindDescriptors(uint64_t submit_id, CommandBuffer& buffer,
vk::PipelineBindPoint pipeline_bind_point, vk::PipelineLayout layout,
const ShaderStageRuntime& runtime, vk::ShaderStageFlags vk_stage,
DescriptorCache::Stage stage) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(buffer == nullptr || !runtime);
EXIT_IF(!runtime);
const auto& program = *runtime.program;
const auto& snapshot = *runtime.resources;
std::string error;
if (!ShaderRecompiler::IR::ValidateResourceSpecialization(program, snapshot, &error)) {
EXIT("invalid native shader runtime snapshot: %s\n", error.c_str());
}
auto vk_buffer = buffer->Handle();
auto vk_buffer = buffer.Handle();
const auto shader_stages = ShaderPipelineStages(vk_stage);
DescriptorCache::NativeDescriptors descriptors;
@@ -864,9 +802,8 @@ void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer,
}
if (ShaderRecompiler::IR::FindBinding(
program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::Gds) != nullptr) {
descriptors.gds.buffer =
g_render_ctx->GetGdsBuffer()->GetBuffer(g_render_ctx->GetGraphicCtx());
const auto barrier = MakeGdsDependency(*descriptors.gds.buffer);
descriptors.gds.buffer = &GetRenderContext().GetGdsBuffer().GetBuffer();
const auto barrier = MakeGdsDependency(*descriptors.gds.buffer);
vk_buffer.pipelineBarrier(
vk::PipelineStageFlagBits::eHost | vk::PipelineStageFlagBits::eTransfer |
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader,
@@ -880,14 +817,14 @@ void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer,
resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint) {
switch (image->type) {
case VulkanImageType::DepthStencil:
GraphicsRenderDepthStencilBarrier(vk_buffer, image);
GraphicsRenderDepthStencilBarrier(vk_buffer, *image);
break;
case VulkanImageType::RenderTexture:
case VulkanImageType::StorageTexture:
GraphicsRenderTextureBarrier(vk_buffer, image);
GraphicsRenderTextureBarrier(vk_buffer, *image);
break;
case VulkanImageType::VideoOut:
GraphicsRenderColorImageBarrier(vk_buffer, image, RENDER_COLOR_IMAGE_LAYOUT);
GraphicsRenderColorImageBarrier(vk_buffer, *image, RENDER_COLOR_IMAGE_LAYOUT);
break;
default: break;
}
@@ -901,11 +838,11 @@ void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer,
}
if (!program.bindings.descriptors.empty()) {
auto* set = g_render_ctx->GetDescriptorCache()->GetDescriptor(stage, program, descriptors);
EXIT_IF(set == nullptr);
auto& set =
GetRenderContext().GetDescriptorCache().GetDescriptor(stage, program, descriptors);
vk_buffer.bindDescriptorSets(pipeline_bind_point, layout, program.bindings.descriptor_set,
1, &set->set, 0, nullptr);
buffer->RecycleDescriptorAfterFence(set);
1, &set.set, 0, nullptr);
buffer.RecycleDescriptorAfterFence(set);
}
if (program.bindings.push_constant_size != 0) {
EXIT_IF(program.bindings.push_constant_size != user_data.size() * sizeof(uint32_t));
@@ -4,6 +4,8 @@
#include "graphics/host_gpu/renderer/image.h"
#include "graphics/host_gpu/transfer.h"
#include <algorithm>
namespace Libs::Graphics {
namespace {
@@ -16,15 +18,17 @@ namespace {
DummyTextureCache::~DummyTextureCache() {
Common::LockGuard lock(m_mutex);
if (m_ctx == nullptr) {
const auto populated = [](const auto& slots) {
return std::ranges::any_of(slots, [](const auto& slot) { return slot.image != nullptr; });
};
if (!populated(m_sampled) && !populated(m_storage)) {
return;
}
Transfer::WaitForGraphicsIdle(m_ctx);
const auto destroy = [this](auto& slots) {
Transfer::WaitForGraphicsIdle();
const auto destroy = [](auto& slots) {
for (auto& slot: slots) {
if (slot.image != nullptr) {
ImageOps::Destroy(m_ctx, slot.image);
ImageOps::Destroy(*slot.image);
slot.image = nullptr;
}
}
@@ -33,26 +37,15 @@ DummyTextureCache::~DummyTextureCache() {
destroy(m_storage);
}
VulkanImage* DummyTextureCache::Get(GraphicContext* ctx, Usage usage, bool uint_format,
bool image_3d) {
VulkanImage& DummyTextureCache::Get(Usage usage, bool uint_format, bool image_3d) {
Common::LockGuard lock(m_mutex);
if (ctx == nullptr) {
EXIT("TextureCache: dummy texture requires a graphics context\n");
}
if (m_ctx != nullptr && m_ctx != ctx) {
EXIT("TextureCache: dummy texture context changed, previous=%p current=%p usage=%u\n",
static_cast<const void*>(m_ctx), static_cast<const void*>(ctx),
static_cast<uint32_t>(usage));
}
m_ctx = ctx;
auto& slots = usage == Usage::Storage ? m_storage : m_sampled;
auto& slot = slots[DummyTextureIndex(uint_format, image_3d)];
auto& slots = usage == Usage::Storage ? m_storage : m_sampled;
auto& slot = slots[DummyTextureIndex(uint_format, image_3d)];
if (slot.image == nullptr) {
slot.image =
ImageOps::CreateDummyTexture(ctx, uint_format, image_3d, usage == Usage::Storage);
slot.image = ImageOps::CreateDummyTexture(uint_format, image_3d,
usage == Usage::Storage);
}
return slot.image;
return *slot.image;
}
} // namespace Libs::Graphics
@@ -18,8 +18,7 @@ public:
~DummyTextureCache();
KYTY_CLASS_NO_COPY(DummyTextureCache);
[[nodiscard]] VulkanImage* Get(GraphicContext* ctx, Usage usage, bool uint_format,
bool image_3d);
[[nodiscard]] VulkanImage& Get(Usage usage, bool uint_format, bool image_3d);
private:
struct Slot {
@@ -29,7 +28,6 @@ private:
Common::Mutex m_mutex;
std::array<Slot, 4> m_sampled {};
std::array<Slot, 4> m_storage {};
GraphicContext* m_ctx = nullptr;
};
} // namespace Libs::Graphics
@@ -15,17 +15,15 @@ namespace Libs::Graphics {
VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
uint32_t requested_color_count,
RenderDepthInfo* depth) {
RenderDepthInfo& depth) {
KYTY_PROFILER_FUNCTION();
Common::LockGuard lock(m_mutex);
EXIT_IF(colors == nullptr);
EXIT_IF(depth == nullptr);
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(requested_color_count > RENDER_COLOR_ATTACHMENTS_MAX);
bool with_depth = (depth->format != vk::Format::eUndefined && depth->vulkan_buffer != nullptr);
bool with_depth = (depth.format != vk::Format::eUndefined && depth.vulkan_buffer != nullptr);
bool with_color[RENDER_COLOR_ATTACHMENTS_MAX] = {};
uint32_t color_count = 0;
VulkanImage* first_color = nullptr;
@@ -58,16 +56,16 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
color_count++;
}
if (with_depth) {
if (depth->samples != depth->vulkan_buffer->samples) {
if (depth.samples != depth.vulkan_buffer->samples) {
EXIT("Framebuffer: depth attachment sample identity mismatch, requested=%u image=%u\n",
depth->samples, depth->vulkan_buffer->samples);
depth.samples, depth.vulkan_buffer->samples);
}
if (attachment_samples == 0) {
attachment_samples = depth->samples;
} else if (attachment_samples != depth->samples) {
attachment_samples = depth.samples;
} else if (attachment_samples != depth.samples) {
EXIT(
"Framebuffer: mixed color/depth sample counts are unsupported, color=%u depth=%u\n",
attachment_samples, depth->samples);
attachment_samples, depth.samples);
}
}
if (!with_depth && color_count == 0) {
@@ -87,29 +85,29 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
(with_depth && depth_layout == vk::ImageLayout::eDepthStencilReadOnlyOptimal);
if (with_depth && first_color != nullptr &&
(first_color_extent.width != depth->vulkan_buffer->extent.width ||
first_color_extent.height != depth->vulkan_buffer->extent.height)) {
(first_color_extent.width != depth.vulkan_buffer->extent.width ||
first_color_extent.height != depth.vulkan_buffer->extent.height)) {
static std::atomic<uint32_t> log_count {0};
if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) {
LOGF("Framebuffer: temporary: dropping mismatched PS5 depth attachment color=%ux%u "
"depth=%ux%u format=%s\n",
first_color_extent.width, first_color_extent.height,
depth->vulkan_buffer->extent.width, depth->vulkan_buffer->extent.height,
VulkanToString(depth->format).c_str());
depth.vulkan_buffer->extent.width, depth.vulkan_buffer->extent.height,
VulkanToString(depth.format).c_str());
}
depth->format = vk::Format::eUndefined;
depth->vulkan_buffer = nullptr;
depth->vulkan_view = nullptr;
depth->depth_test_enable = false;
depth->depth_write_enable = false;
depth->depth_bounds_test_enable = false;
depth->stencil_test_enable = false;
depth->depth_clear_enable = false;
depth->depth_load_clear_enable = false;
depth->stencil_clear_enable = false;
with_depth = false;
depth_layout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
depth_read_only = false;
depth.format = vk::Format::eUndefined;
depth.vulkan_buffer = nullptr;
depth.vulkan_view = nullptr;
depth.depth_test_enable = false;
depth.depth_write_enable = false;
depth.depth_bounds_test_enable = false;
depth.stencil_test_enable = false;
depth.depth_clear_enable = false;
depth.depth_load_clear_enable = false;
depth.stencil_clear_enable = false;
with_depth = false;
depth_layout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
depth_read_only = false;
}
for (auto& f: m_framebuffers) {
@@ -125,22 +123,21 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
(i < color_count && with_color[i] && colors[i].color_clear_enable) &&
f.color_layout[i] == color_layout[i];
}
if (color_match &&
f.depth_id == (with_depth ? depth->vulkan_buffer->memory.unique_id : 0) &&
f.depth_view == (with_depth ? depth->vulkan_view : nullptr) &&
f.depth_clear_enable == depth->depth_load_clear_enable &&
f.stencil_clear_enable == depth->stencil_clear_enable &&
if (color_match && f.depth_id == (with_depth ? depth.vulkan_buffer->memory.unique_id : 0) &&
f.depth_view == (with_depth ? depth.vulkan_view : nullptr) &&
f.depth_clear_enable == depth.depth_load_clear_enable &&
f.stencil_clear_enable == depth.stencil_clear_enable &&
f.depth_read_only == depth_read_only) {
return f.framebuffer;
}
}
EXIT_NOT_IMPLEMENTED(with_depth && first_color != nullptr &&
(first_color_extent.width != depth->vulkan_buffer->extent.width ||
first_color_extent.height != depth->vulkan_buffer->extent.height));
(first_color_extent.width != depth.vulkan_buffer->extent.width ||
first_color_extent.height != depth.vulkan_buffer->extent.height));
if (first_color == nullptr) {
first_color_extent = depth->vulkan_buffer->extent;
first_color_extent = depth.vulkan_buffer->extent;
}
auto* framebuffer = new VulkanFramebuffer;
@@ -152,10 +149,6 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
}
framebuffer->depth_layout = depth_layout;
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
vk::AttachmentDescription attachments[RENDER_COLOR_ATTACHMENTS_MAX + 1] = {};
for (uint32_t i = 0; i < color_count; i++) {
attachments[i].flags = {};
@@ -172,14 +165,14 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
const uint32_t depth_attachment = color_count;
attachments[depth_attachment].flags = {};
attachments[depth_attachment].format = depth->format;
attachments[depth_attachment].format = depth.format;
attachments[depth_attachment].samples = vulkan_sample_count(attachment_samples);
attachments[depth_attachment].loadOp =
(depth->depth_load_clear_enable ? vk::AttachmentLoadOp::eClear
: vk::AttachmentLoadOp::eLoad);
(depth.depth_load_clear_enable ? vk::AttachmentLoadOp::eClear
: vk::AttachmentLoadOp::eLoad);
attachments[depth_attachment].storeOp = vk::AttachmentStoreOp::eStore;
attachments[depth_attachment].stencilLoadOp =
(depth->stencil_clear_enable ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad);
(depth.stencil_clear_enable ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad);
attachments[depth_attachment].stencilStoreOp = vk::AttachmentStoreOp::eStore;
attachments[depth_attachment].initialLayout = depth_layout;
attachments[depth_attachment].finalLayout = depth_layout;
@@ -246,7 +239,7 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
render_pass_info.pDependencies = dependencies;
auto result =
gctx->device.createRenderPass(&render_pass_info, nullptr, &framebuffer->render_pass);
m_graphics.device.createRenderPass(&render_pass_info, nullptr, &framebuffer->render_pass);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
vk::Format color_formats[RENDER_COLOR_ATTACHMENTS_MAX] = {};
@@ -254,7 +247,7 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
color_formats[i] = colors[i].format;
}
framebuffer->render_pass_id = render_pass_compat_id(
color_count, color_formats, with_depth, depth->format, depth_layout, attachment_samples);
color_count, color_formats, with_depth, depth.format, depth_layout, attachment_samples);
EXIT_NOT_IMPLEMENTED(framebuffer->render_pass == nullptr);
@@ -266,10 +259,10 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
views[i] = colors[i].vulkan_view;
}
if (with_depth) {
if (depth->vulkan_view == nullptr) {
if (depth.vulkan_view == nullptr) {
EXIT("Framebuffer: depth attachment view is missing\n");
}
views[color_count] = depth->vulkan_view;
views[color_count] = depth.vulkan_view;
}
vk::FramebufferCreateInfo framebuffer_info {};
@@ -283,7 +276,8 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
framebuffer_info.height = first_color_extent.height;
framebuffer_info.layers = 1;
result = gctx->device.createFramebuffer(&framebuffer_info, nullptr, &framebuffer->framebuffer);
result =
m_graphics.device.createFramebuffer(&framebuffer_info, nullptr, &framebuffer->framebuffer);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
EXIT_NOT_IMPLEMENTED(framebuffer->framebuffer == nullptr);
@@ -298,10 +292,10 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
(i < color_count && with_color[i] && colors[i].color_clear_enable);
fnew.color_layout[i] = color_layout[i];
}
fnew.depth_id = (with_depth ? depth->vulkan_buffer->memory.unique_id : 0);
fnew.depth_view = (with_depth ? depth->vulkan_view : nullptr);
fnew.depth_clear_enable = depth->depth_load_clear_enable;
fnew.stencil_clear_enable = depth->stencil_clear_enable;
fnew.depth_id = (with_depth ? depth.vulkan_buffer->memory.unique_id : 0);
fnew.depth_view = (with_depth ? depth.vulkan_view : nullptr);
fnew.depth_clear_enable = depth.depth_load_clear_enable;
fnew.stencil_clear_enable = depth.stencil_clear_enable;
fnew.depth_read_only = depth_read_only;
bool updated = false;
@@ -321,28 +315,21 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
return framebuffer;
}
void FramebufferCache::FreeFramebufferByColor(VulkanImage* image) {
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(image == nullptr);
void FramebufferCache::FreeFramebufferByColor(VulkanImage& image) {
Common::LockGuard lock(m_mutex);
for (auto& f: m_framebuffers) {
bool uses_image = false;
for (auto image_id: f.image_id) {
if (image_id == image->memory.unique_id) {
if (image_id == image.memory.unique_id) {
uses_image = true;
break;
}
}
if (f.framebuffer != nullptr && uses_image) {
auto* gctx = g_render_ctx->GetGraphicCtx();
m_graphics.device.destroyFramebuffer(f.framebuffer->framebuffer, nullptr);
EXIT_IF(gctx == nullptr);
gctx->device.destroyFramebuffer(f.framebuffer->framebuffer, nullptr);
gctx->device.destroyRenderPass(f.framebuffer->render_pass, nullptr);
m_graphics.device.destroyRenderPass(f.framebuffer->render_pass, nullptr);
delete f.framebuffer;
@@ -351,21 +338,14 @@ void FramebufferCache::FreeFramebufferByColor(VulkanImage* image) {
}
}
void FramebufferCache::FreeFramebufferByDepth(DepthStencilVulkanImage* image) {
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(image == nullptr);
void FramebufferCache::FreeFramebufferByDepth(DepthStencilVulkanImage& image) {
Common::LockGuard lock(m_mutex);
for (auto& f: m_framebuffers) {
if (f.framebuffer != nullptr && f.depth_id == image->memory.unique_id) {
auto* gctx = g_render_ctx->GetGraphicCtx();
if (f.framebuffer != nullptr && f.depth_id == image.memory.unique_id) {
m_graphics.device.destroyFramebuffer(f.framebuffer->framebuffer, nullptr);
EXIT_IF(gctx == nullptr);
gctx->device.destroyFramebuffer(f.framebuffer->framebuffer, nullptr);
gctx->device.destroyRenderPass(f.framebuffer->render_pass, nullptr);
m_graphics.device.destroyRenderPass(f.framebuffer->render_pass, nullptr);
delete f.framebuffer;
@@ -50,14 +50,16 @@ inline uint64_t render_pass_compat_id(uint32_t color_count, const vk::Format* co
class FramebufferCache {
public:
FramebufferCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
explicit FramebufferCache(GraphicContext& graphics): m_graphics(graphics) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
}
~FramebufferCache() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(FramebufferCache);
VulkanFramebuffer* CreateFramebuffer(RenderColorInfo* colors, uint32_t color_count,
RenderDepthInfo* depth);
void FreeFramebufferByColor(VulkanImage* image);
void FreeFramebufferByDepth(DepthStencilVulkanImage* image);
RenderDepthInfo& depth);
void FreeFramebufferByColor(VulkanImage& image);
void FreeFramebufferByDepth(DepthStencilVulkanImage& image);
private:
struct Framebuffer {
@@ -73,6 +75,7 @@ private:
bool depth_read_only = false;
};
GraphicContext& m_graphics;
Common::Mutex m_mutex;
std::vector<Framebuffer> m_framebuffers;
};
+13 -16
View File
@@ -6,7 +6,7 @@
namespace Libs::Graphics {
void GdsBuffer::Init(GraphicContext* ctx) {
void GdsBuffer::Init() {
if (m_buffer == nullptr) {
m_buffer = std::make_unique<VulkanBuffer>();
@@ -14,57 +14,54 @@ void GdsBuffer::Init(GraphicContext* ctx) {
m_buffer->memory.property = vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent |
vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, DW_SIZE * 4, m_buffer.get());
m_graphics.CreateBuffer(DW_SIZE * 4, *m_buffer);
}
}
void GdsBuffer::Clear(GraphicContext* ctx, uint64_t dw_offset, uint32_t dw_num,
uint32_t clear_value) {
EXIT_IF(ctx == nullptr);
void GdsBuffer::Clear(uint64_t dw_offset, uint32_t dw_num, uint32_t clear_value) {
Common::LockGuard lock(m_mutex);
Init(ctx);
Init();
EXIT_NOT_IMPLEMENTED(dw_offset >= DW_SIZE);
EXIT_NOT_IMPLEMENTED(dw_offset + dw_num > DW_SIZE);
void* data = nullptr;
VulkanMapMemory(ctx, &m_buffer->memory, &data);
m_graphics.MapMemory(m_buffer->memory, data);
for (uint32_t i = 0; i < dw_num; i++) {
static_cast<uint32_t*>(data)[dw_offset + i] = clear_value;
}
VulkanUnmapMemory(ctx, &m_buffer->memory);
m_graphics.UnmapMemory(m_buffer->memory);
}
void GdsBuffer::Read(GraphicContext* ctx, uint32_t* dst, uint32_t dw_offset, uint32_t dw_size) {
void GdsBuffer::Read(uint32_t* dst, uint32_t dw_offset, uint32_t dw_size) {
EXIT_IF(dst == nullptr);
Common::LockGuard lock(m_mutex);
Init(ctx);
Init();
EXIT_NOT_IMPLEMENTED(dw_offset >= DW_SIZE);
EXIT_NOT_IMPLEMENTED(dw_offset + dw_size > DW_SIZE);
void* data = nullptr;
VulkanMapMemory(ctx, &m_buffer->memory, &data);
m_graphics.MapMemory(m_buffer->memory, data);
for (uint32_t i = 0; i < dw_size; i++) {
dst[i] = static_cast<uint32_t*>(data)[dw_offset + i];
}
VulkanUnmapMemory(ctx, &m_buffer->memory);
m_graphics.UnmapMemory(m_buffer->memory);
}
VulkanBuffer* GdsBuffer::GetBuffer(GraphicContext* ctx) {
VulkanBuffer& GdsBuffer::GetBuffer() {
Common::LockGuard lock(m_mutex);
Init(ctx);
Init();
return m_buffer.get();
return *m_buffer;
}
} // namespace Libs::Graphics
+8 -5
View File
@@ -13,20 +13,23 @@ namespace Libs::Graphics {
class GdsBuffer {
public:
GdsBuffer() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
explicit GdsBuffer(GraphicContext& graphics): m_graphics(graphics) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
}
~GdsBuffer() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(GdsBuffer);
void Clear(GraphicContext* ctx, uint64_t dw_offset, uint32_t dw_num, uint32_t clear_value);
void Read(GraphicContext* ctx, uint32_t* dst, uint32_t dw_offset, uint32_t dw_size);
void Clear(uint64_t dw_offset, uint32_t dw_num, uint32_t clear_value);
void Read(uint32_t* dst, uint32_t dw_offset, uint32_t dw_size);
VulkanBuffer* GetBuffer(GraphicContext* ctx);
VulkanBuffer& GetBuffer();
private:
static constexpr uint64_t DW_SIZE = 0x3000;
void Init(GraphicContext* ctx);
void Init();
GraphicContext& m_graphics;
Common::Mutex m_mutex;
std::unique_ptr<VulkanBuffer> m_buffer;
};
@@ -9,9 +9,9 @@
namespace Libs::Graphics {
GpuResourceManager::GpuResourceManager()
: m_page_manager(FaultThunk, this), m_buffer_cache(m_page_manager, m_resource_mutex),
m_texture_cache(m_page_manager, m_buffer_cache, m_resource_mutex) {
GpuResourceManager::GpuResourceManager(GraphicContext& graphics)
: m_page_manager(FaultThunk, this), m_buffer_cache(graphics, m_page_manager, m_resource_mutex),
m_texture_cache(graphics, m_page_manager, m_buffer_cache, m_resource_mutex) {
m_buffer_cache.SetTextureCache(m_texture_cache);
}
@@ -72,8 +72,7 @@ void GpuResourceManager::PrepareHostWrite(uint64_t vaddr, uint64_t size) {
}
const auto handle_range = [this, vaddr, size]() {
if (!m_page_manager.HandleWriteRange(vaddr, size)) {
EXIT("failed to prepare host write, addr=0x%016" PRIx64 " size=0x%016" PRIx64
"\n",
EXIT("failed to prepare host write, addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n",
vaddr, size);
}
};
@@ -113,22 +112,22 @@ void GpuResourceManager::UnmapMemory(uint64_t vaddr, uint64_t size, GpuAccess ac
m_page_manager.OnGpuUnmap(vaddr, size, access);
}
void GpuResourceManager::FillBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size,
void GpuResourceManager::FillBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size,
uint32_t value) {
if (g_render_ctx == nullptr || command == nullptr || command->IsInvalid()) {
if (command.IsInvalid()) {
EXIT("cannot fill a buffer without a valid render command context\n");
}
Common::LockGuard lock(g_render_ctx->GetMutex());
m_buffer_cache.FillBuffer(command, g_render_ctx->GetGraphicCtx(), vaddr, size, value);
Common::LockGuard lock(GetRenderContext().GetMutex());
m_buffer_cache.FillBuffer(&command, vaddr, size, value);
}
void GpuResourceManager::CopyBuffer(CommandBuffer* command, uint64_t dst_vaddr, uint64_t src_vaddr,
void GpuResourceManager::CopyBuffer(CommandBuffer& command, uint64_t dst_vaddr, uint64_t src_vaddr,
uint64_t size) {
if (g_render_ctx == nullptr || command == nullptr || command->IsInvalid()) {
if (command.IsInvalid()) {
EXIT("cannot copy a buffer without a valid render command context\n");
}
Common::LockGuard lock(g_render_ctx->GetMutex());
m_buffer_cache.CopyBuffer(command, g_render_ctx->GetGraphicCtx(), dst_vaddr, src_vaddr, size);
Common::LockGuard lock(GetRenderContext().GetMutex());
m_buffer_cache.CopyBuffer(&command, dst_vaddr, src_vaddr, size);
}
} // namespace Libs::Graphics
@@ -16,20 +16,20 @@ class CommandBuffer;
class GpuResourceManager {
public:
GpuResourceManager();
explicit GpuResourceManager(GraphicContext& graphics);
~GpuResourceManager();
KYTY_CLASS_NO_COPY(GpuResourceManager);
[[nodiscard]] BufferCache* GetBufferCache() { return &m_buffer_cache; }
[[nodiscard]] TextureCache* GetTextureCache() { return &m_texture_cache; }
[[nodiscard]] BufferCache& GetBufferCache() { return m_buffer_cache; }
[[nodiscard]] TextureCache& GetTextureCache() { return m_texture_cache; }
[[nodiscard]] bool HandleFault(PageFaultAccess access, uint64_t fault_vaddr) noexcept;
void PrepareHostWrite(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool IsMapped(uint64_t vaddr, uint64_t size) const noexcept;
void MapMemory(uint64_t vaddr, uint64_t size, GpuAccess access);
void UnmapMemory(uint64_t vaddr, uint64_t size, GpuAccess access);
void FillBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size, uint32_t value);
void CopyBuffer(CommandBuffer* command, uint64_t dst_vaddr, uint64_t src_vaddr, uint64_t size);
void FillBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size, uint32_t value);
void CopyBuffer(CommandBuffer& command, uint64_t dst_vaddr, uint64_t src_vaddr, uint64_t size);
private:
static bool FaultThunk(void* context, PageFaultAccess access, uint64_t vaddr, uint64_t size,
+88 -86
View File
@@ -50,15 +50,15 @@ TextureImageCreateParams MakeImageParams(const ImageInfo& info, bool storage) {
return params;
}
bool RenderTargetSupportsStorage(GraphicContext* ctx, vk::Format format,
bool RenderTargetSupportsStorage(vk::Format format,
vk::ImageCreateFlags flags) {
const auto compatible = SrgbStorageViewFormat(format);
const auto required_flags =
vk::ImageCreateFlagBits::eMutableFormat | vk::ImageCreateFlagBits::eExtendedUsage;
const bool compatible_views = (flags & required_flags) == required_flags;
return ImageViewOps::FormatSupportsStorage(ctx, format) ||
return ImageViewOps::FormatSupportsStorage(format) ||
(compatible_views && compatible != vk::Format::eUndefined &&
ImageViewOps::FormatSupportsStorage(ctx, compatible));
ImageViewOps::FormatSupportsStorage(compatible));
}
vk::ImageCreateFlags RenderTargetCreateFlags(vk::Format format) {
@@ -72,20 +72,21 @@ vk::ImageCreateFlags RenderTargetCreateFlags(vk::Format format) {
: vk::ImageCreateFlags {0};
}
vk::ImageUsageFlags RenderTargetUsage(GraphicContext* ctx, vk::Format format,
vk::ImageUsageFlags RenderTargetUsage(vk::Format format,
vk::ImageCreateFlags flags, uint32_t samples) {
auto& graphics = GetRenderContext().GetGraphics();
auto usage = static_cast<vk::ImageUsageFlags>(vk::ImageUsageFlagBits::eColorAttachment) |
static_cast<vk::ImageUsageFlags>(vk::ImageUsageFlagBits::eTransferSrc) |
static_cast<vk::ImageUsageFlags>(vk::ImageUsageFlagBits::eTransferDst);
if (samples == 1) {
usage |= vk::ImageUsageFlagBits::eSampled;
if (RenderTargetSupportsStorage(ctx, format, flags)) {
if (RenderTargetSupportsStorage(format, flags)) {
usage |= vk::ImageUsageFlagBits::eStorage;
}
}
vk::ImageFormatProperties properties {};
if (ctx->GetImageFormatProperties(format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, usage,
flags, &properties) != vk::Result::eSuccess ||
if (graphics.GetImageFormatProperties(format, vk::ImageType::e2D, vk::ImageTiling::eOptimal,
usage, flags, &properties) != vk::Result::eSuccess ||
!static_cast<bool>(properties.sampleCounts & vulkan_sample_count(samples))) {
EXIT("TextureCache: render-target format does not support required usage, format=%d "
"usage=0x%x samples=%u supported=0x%x\n",
@@ -146,44 +147,42 @@ uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element) {
return RenderTargetTransferFormatImpl(bytes_per_element);
}
GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info, bool storage,
vk::ComponentMapping* components) {
if (components == nullptr) {
EXIT("TextureCache: invalid texture component output\n");
}
GpuTextureVulkanImage* CreateTexture(const ImageInfo& info, bool storage,
vk::ComponentMapping& components) {
auto* image = storage ? static_cast<GpuTextureVulkanImage*>(new StorageTextureVulkanImage)
: new TextureVulkanImage;
*components = TextureCreateImage(ctx, image, MakeImageParams(info, storage));
components = TextureCreateImage(*image, MakeImageParams(info, storage));
return image;
}
void CreateTextureViews(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info,
bool storage, vk::ComponentMapping components) {
void CreateTextureViews(GpuTextureVulkanImage& image,
const ImageInfo& info, bool storage, vk::ComponentMapping components) {
if (storage) {
TextureCreateImageViews(ctx, image, components, info.type, 0, 0, 1, info.depth, false,
TextureCreateImageViews(image, components, info.type, 0, 0, 1, info.depth, false,
TextureFormatUsage::Sampled | TextureFormatUsage::Storage);
} else {
TextureCreateImageViews(ctx, image, components, info.type, info.base_array, info.base_level,
info.view_levels, info.depth, true, TextureFormatUsage::Sampled);
TextureCreateImageViews(image, components, info.type, info.base_array,
info.base_level, info.view_levels, info.depth, true,
TextureFormatUsage::Sampled);
}
}
void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* image,
void UploadRenderTargetLayers(RenderTextureVulkanImage& image,
const RenderTargetInfo& info, uint32_t base_layer,
uint32_t layer_count, bool refresh) {
if (info.layers == 0 || info.size % info.layers != 0 || layer_count == 0 ||
base_layer >= info.layers || layer_count > info.layers - base_layer || image == nullptr ||
base_layer >= image->layers || layer_count > image->layers - base_layer) {
base_layer >= info.layers || layer_count > info.layers - base_layer ||
base_layer >= image.layers || layer_count > image.layers - base_layer) {
EXIT("TextureCache: invalid render-target layer upload, base=%u count=%u "
"info_layers=%u image_layers=%u size=0x%016" PRIx64 "\n",
base_layer, layer_count, info.layers, image != nullptr ? image->layers : 0, info.size);
base_layer, layer_count, info.layers, image.layers, info.size);
}
if (info.samples != 1 || image->samples != 1) {
if (info.samples != 1 || image.samples != 1) {
EXIT("TextureCache: multisampled render-target upload is unsupported, samples=%u/%u\n",
info.samples, image->samples);
info.samples, image.samples);
}
if (refresh) {
Transfer::WaitForGraphicsIdle(ctx);
Transfer::WaitForGraphicsIdle();
}
const auto slice_size = info.size / info.layers;
const auto upload_size = slice_size * layer_count;
@@ -208,7 +207,7 @@ void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* ima
region.dst_layer += base_layer;
}
const auto source_address = info.address + slice_size * base_layer;
TextureUploadGuestImage(ctx, image, reinterpret_cast<const void*>(source_address),
TextureUploadGuestImage(image, reinterpret_cast<const void*>(source_address),
upload_size, regions, layout, format, info.width, info.height,
layer_count, info.levels, "TextureCache render target",
vk::ImageLayout::eGeneral);
@@ -222,21 +221,23 @@ void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* ima
"TextureCache render target");
auto regions = TextureBuildUploadRegions(layout, info.format, info.width, info.height, 1, 1,
true, false, TextureUploadDestination::MipLevels);
TextureUploadGuestImage(ctx, image, reinterpret_cast<const void*>(info.address), slice_size,
regions, layout, format, info.width, info.height, 1, 1,
TextureUploadGuestImage(image, reinterpret_cast<const void*>(info.address),
slice_size, regions, layout, format, info.width, info.height, 1, 1,
"TextureCache render target", vk::ImageLayout::eGeneral);
} else {
Transfer::UploadImage(ctx, image, reinterpret_cast<const void*>(info.address), slice_size,
info.pitch, vk::ImageLayout::eGeneral);
Transfer::UploadImage(image, reinterpret_cast<const void*>(info.address),
slice_size, info.pitch, vk::ImageLayout::eGeneral);
}
}
void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image,
void UploadRenderTarget(RenderTextureVulkanImage& image,
const RenderTargetInfo& info, bool refresh) {
UploadRenderTargetLayers(ctx, image, info, 0, info.layers, refresh);
UploadRenderTargetLayers(image, info, 0, info.layers, refresh);
}
RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTargetInfo& info) {
RenderTextureVulkanImage* CreateRenderTarget(
const RenderTargetInfo& info) {
auto& graphics = GetRenderContext().GetGraphics();
auto* image = new RenderTextureVulkanImage;
image->extent.width = info.width;
image->extent.height = info.height;
@@ -255,20 +256,21 @@ RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTa
create.format = info.format;
create.tiling = vk::ImageTiling::eOptimal;
create.initialLayout = vk::ImageLayout::eUndefined;
create.usage = RenderTargetUsage(ctx, info.format, create.flags, info.samples);
create.usage = RenderTargetUsage(info.format, create.flags, info.samples);
create.sharingMode = vk::SharingMode::eExclusive;
create.samples = vulkan_sample_count(info.samples);
image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
if (!VulkanCreateImage(ctx, create, image)) {
if (!graphics.CreateImage(create, *image)) {
EXIT("TextureCache: failed to create render target, addr=0x%016" PRIx64
" extent=%ux%u format=%d\n",
info.address, info.width, info.height, static_cast<int>(info.format));
}
ImageViewOps::CreateRenderTargetViews(ctx, image);
ImageViewOps::CreateRenderTargetViews(*image);
return image;
}
DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info) {
DepthStencilVulkanImage* CreateDepthTarget(const DepthTargetInfo& info) {
auto& graphics = GetRenderContext().GetGraphics();
vk::ImageCreateInfo create {};
create.sType = vk::StructureType::eImageCreateInfo;
create.imageType = vk::ImageType::e2D;
@@ -282,9 +284,9 @@ DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTarge
create.sharingMode = vk::SharingMode::eExclusive;
create.samples = vulkan_sample_count(info.samples);
vk::ImageFormatProperties properties {};
if (ctx->GetImageFormatProperties(info.format, vk::ImageType::e2D, vk::ImageTiling::eOptimal,
create.usage, vk::ImageCreateFlags {},
&properties) != vk::Result::eSuccess ||
if (graphics.GetImageFormatProperties(
info.format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, create.usage,
vk::ImageCreateFlags {}, &properties) != vk::Result::eSuccess ||
!static_cast<bool>(properties.sampleCounts & create.samples)) {
EXIT("TextureCache: depth format does not support required usage, format=%d usage=0x%x "
"samples=%u supported=0x%x\n",
@@ -302,16 +304,16 @@ DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTarge
image->layout = vk::ImageLayout::eUndefined;
image->compressed = false;
image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
if (!VulkanCreateImage(ctx, create, image)) {
if (!graphics.CreateImage(create, *image)) {
EXIT("TextureCache: failed to create depth target, addr=0x%016" PRIx64
" extent=%ux%u format=%d\n",
info.address, info.width, info.height, static_cast<int>(info.format));
}
ImageViewOps::CreateDepthViews(ctx, image);
ImageViewOps::CreateDepthViews(*image);
return image;
}
void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) {
void ValidateVideoOut(const VideoOutInfo& info) {
const auto compression =
ClassifyVideoOutCompression(info.compression != VideoOutCompression::Uncompressed,
info.metadata_address, info.dcc_control, 0);
@@ -320,23 +322,23 @@ void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) {
(info.metadata_address >= TRACKER_ADDRESS_SIZE ||
(info.metadata_address >= info.address &&
info.metadata_address < info.address + info.size));
if (ctx == nullptr || info.address == 0 || info.size == 0 ||
info.address >= TRACKER_ADDRESS_SIZE || info.size > TRACKER_ADDRESS_SIZE - info.address ||
(info.address & 0xffffu) != 0 || info.width == 0 || info.height == 0 ||
info.width > 16384 || info.height > 16384 || info.pitch < info.width ||
if (info.address == 0 || info.size == 0 || info.address >= TRACKER_ADDRESS_SIZE ||
info.size > TRACKER_ADDRESS_SIZE - info.address || (info.address & 0xffffu) != 0 ||
info.width == 0 || info.height == 0 || info.width > 16384 || info.height > 16384 ||
info.pitch < info.width ||
info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) ||
compression == VideoOutCompression::Unsupported || compression != info.compression ||
metadata_invalid || !IsSupportedVideoOutFormat(info)) {
EXIT("TextureCache: unsupported video-out surface, ctx=%p addr=0x%016" PRIx64
" size=0x%016" PRIx64 " metadata=0x%016" PRIx64 " dcc=0x%08" PRIx32
EXIT("TextureCache: unsupported video-out surface, addr=0x%016" PRIx64 " size=0x%016" PRIx64
" metadata=0x%016" PRIx64 " dcc=0x%08" PRIx32
" extent=%ux%u pitch=%u tile=%u guest_format=%u bpe=%u vk_format=%d\n",
static_cast<const void*>(ctx), info.address, info.size, info.metadata_address,
info.dcc_control, info.width, info.height, info.pitch, info.tile_mode,
info.guest_format, info.bytes_per_element, static_cast<int>(info.format));
info.address, info.size, info.metadata_address, info.dcc_control, info.width,
info.height, info.pitch, info.tile_mode, info.guest_format, info.bytes_per_element,
static_cast<int>(info.format));
}
TileSizeAlign exact {};
TileGetTextureTotalSize(info.guest_format, info.width, info.height, 1, info.pitch, 1,
info.tile_mode, false, &exact);
info.tile_mode, false, exact);
if (exact.align != 65536 || exact.size != info.size ||
TileGetTexturePitch(info.guest_format, info.width, 1, info.tile_mode) != info.pitch) {
EXIT("TextureCache: video-out tile layout mismatch, addr=0x%016" PRIx64
@@ -344,10 +346,11 @@ void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) {
" pitch=%u\n",
info.address, info.size, exact.size, exact.align, info.pitch);
}
(void)RenderTargetUsage(ctx, info.format, vk::ImageCreateFlags {}, 1);
(void)RenderTargetUsage(info.format, vk::ImageCreateFlags {}, 1);
}
VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) {
VideoOutVulkanImage* CreateVideoOut(const VideoOutInfo& info) {
auto& graphics = GetRenderContext().GetGraphics();
auto* image = new VideoOutVulkanImage;
image->extent.width = info.width;
image->extent.height = info.height;
@@ -363,20 +366,20 @@ VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& inf
create.tiling = vk::ImageTiling::eOptimal;
create.initialLayout = vk::ImageLayout::eUndefined;
create.flags = RenderTargetCreateFlags(info.format);
create.usage = RenderTargetUsage(ctx, info.format, create.flags, 1);
create.usage = RenderTargetUsage(info.format, create.flags, 1);
create.sharingMode = vk::SharingMode::eExclusive;
create.samples = vk::SampleCountFlagBits::e1;
image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
if (!VulkanCreateImage(ctx, create, image)) {
if (!graphics.CreateImage(create, *image)) {
EXIT("TextureCache: failed to create video-out image, addr=0x%016" PRIx64
" extent=%ux%u format=%d\n",
info.address, info.width, info.height, static_cast<int>(info.format));
}
ImageViewOps::CreateVideoOutViews(ctx, image);
ImageViewOps::CreateVideoOutViews(*image);
return image;
}
void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const VideoOutInfo& info,
void UploadVideoOut(VideoOutVulkanImage& image, const VideoOutInfo& info,
bool refresh) {
if (info.compression != VideoOutCompression::Uncompressed) {
EXIT("TextureCache: compressed video-out guest upload is unsupported, "
@@ -384,24 +387,24 @@ void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const Video
info.address, info.metadata_address, info.dcc_control);
}
if (refresh) {
Transfer::WaitForGraphicsIdle(ctx);
Transfer::WaitForGraphicsIdle();
}
image->layout = vk::ImageLayout::eUndefined;
image.layout = vk::ImageLayout::eUndefined;
if (!info.bgra16) {
auto layout =
TextureCalcUploadLayout(info.guest_format, info.width, info.height, 1, 1, info.pitch,
info.tile_mode, info.size, false, false, "VideoOut");
auto regions = TextureBuildUploadRegions(layout, info.format, info.width, info.height, 1, 1,
false, false, TextureUploadDestination::MipLevels);
TextureUploadGuestImage(ctx, image, reinterpret_cast<const void*>(info.address), info.size,
regions, layout, info.guest_format, info.width, info.height, 1, 1,
"VideoOut", vk::ImageLayout::eGeneral);
TextureUploadGuestImage(image, reinterpret_cast<const void*>(info.address),
info.size, regions, layout, info.guest_format, info.width,
info.height, 1, 1, "VideoOut", vk::ImageLayout::eGeneral);
return;
}
Transfer::ScratchBuffer scratch(info.size);
TileBlockLayout block {};
EXIT_NOT_IMPLEMENTED(
!TileGetBlockLayout(TileBlockFamily::RenderTarget64KB, info.bytes_per_element, &block));
!TileGetBlockLayout(TileBlockFamily::RenderTarget64KB, info.bytes_per_element, block));
const GpuTileInfo tile_info {block.family,
block.bytes_per_element,
0,
@@ -413,10 +416,10 @@ void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const Video
info.height,
1,
info.pitch};
GpuDetile(ctx, reinterpret_cast<const void*>(info.address), scratch.Data(), info.size,
GpuDetile(reinterpret_cast<const void*>(info.address), scratch.Data(), info.size,
info.size, std::span<const GpuTileInfo>(&tile_info, 1));
SwapVideoOutBgra16(scratch.Data(), info.size);
Transfer::UploadImage(ctx, image, scratch.Data(), info.size, info.pitch,
Transfer::UploadImage(image, scratch.Data(), info.size, info.pitch,
vk::ImageLayout::eGeneral);
}
@@ -427,7 +430,7 @@ void SwapVideoOutBgra16(void* data, uint64_t size) {
}
}
GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format, bool image_3d,
GpuTextureVulkanImage* CreateDummyTexture(bool uint_format, bool image_3d,
bool storage) {
auto* image = storage ? static_cast<GpuTextureVulkanImage*>(new StorageTextureVulkanImage)
: new TextureVulkanImage;
@@ -436,48 +439,47 @@ GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format,
auto owner = storage ? "DummyStorageTexture" : "DummySampledTexture";
auto params = MakeDummyTextureParams(uint_format, image_3d, usage, owner);
auto components = TextureCreateImage(ctx, image, params);
auto components = TextureCreateImage(*image, params);
static constexpr uint32_t zero = 0;
Transfer::UploadImage(ctx, image, &zero, sizeof(zero), 1, layout);
TextureCreateImageViews(ctx, image, components, params.type, 0, params.base_level,
Transfer::UploadImage(*image, &zero, sizeof(zero), 1, layout);
TextureCreateImageViews(*image, components, params.type, 0, params.base_level,
params.levels, params.depth, params.allow_cube_view, params.view_usage);
return image;
}
void Destroy(GraphicContext* ctx, VulkanImage* image) {
void Destroy(VulkanImage& image) {
auto& graphics = GetRenderContext().GetGraphics();
KYTY_PROFILER_BLOCK("TextureCache::DeleteImage");
EXIT_IF(ctx == nullptr || image == nullptr || g_render_ctx == nullptr);
switch (image->type) {
switch (image.type) {
case VulkanImageType::RenderTexture:
case VulkanImageType::VideoOut:
g_render_ctx->GetFramebufferCache()->FreeFramebufferByColor(image);
GetRenderContext().GetFramebufferCache().FreeFramebufferByColor(image);
break;
case VulkanImageType::DepthStencil:
g_render_ctx->GetFramebufferCache()->FreeFramebufferByDepth(
static_cast<DepthStencilVulkanImage*>(image));
GetRenderContext().GetFramebufferCache().FreeFramebufferByDepth(
static_cast<DepthStencilVulkanImage&>(image));
break;
case VulkanImageType::Texture:
case VulkanImageType::StorageTexture: break;
case VulkanImageType::Unknown: EXIT("cannot destroy an untyped Vulkan image\n");
}
ImageViewOps::DestroyViews(ctx, image);
VulkanDeleteImage(ctx, image);
ImageViewOps::DestroyViews(image);
graphics.DeleteImage(image);
switch (image->type) {
case VulkanImageType::Texture: delete static_cast<TextureVulkanImage*>(image); break;
switch (image.type) {
case VulkanImageType::Texture: delete &static_cast<TextureVulkanImage&>(image); break;
case VulkanImageType::StorageTexture:
delete static_cast<StorageTextureVulkanImage*>(image);
delete &static_cast<StorageTextureVulkanImage&>(image);
break;
case VulkanImageType::RenderTexture:
delete static_cast<RenderTextureVulkanImage*>(image);
delete &static_cast<RenderTextureVulkanImage&>(image);
break;
case VulkanImageType::DepthStencil:
delete static_cast<DepthStencilVulkanImage*>(image);
delete &static_cast<DepthStencilVulkanImage&>(image);
break;
case VulkanImageType::VideoOut: delete static_cast<VideoOutVulkanImage*>(image); break;
case VulkanImageType::VideoOut: delete &static_cast<VideoOutVulkanImage&>(image); break;
case VulkanImageType::Unknown: EXIT("cannot delete an untyped Vulkan image\n");
}
}
+14 -13
View File
@@ -100,33 +100,34 @@ private:
namespace ImageOps {
[[nodiscard]] GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info,
bool storage, vk::ComponentMapping* components);
void CreateTextureViews(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info,
bool storage, vk::ComponentMapping components);
[[nodiscard]] GpuTextureVulkanImage* CreateTexture(const ImageInfo& info,
bool storage, vk::ComponentMapping& components);
void CreateTextureViews(GpuTextureVulkanImage& image,
const ImageInfo& info, bool storage, vk::ComponentMapping components);
[[nodiscard]] RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx,
[[nodiscard]] RenderTextureVulkanImage* CreateRenderTarget(
const RenderTargetInfo& info);
[[nodiscard]] uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element);
void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* image,
void UploadRenderTargetLayers(RenderTextureVulkanImage& image,
const RenderTargetInfo& info, uint32_t base_layer,
uint32_t layer_count, bool refresh);
void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image,
void UploadRenderTarget(RenderTextureVulkanImage& image,
const RenderTargetInfo& info, bool refresh);
[[nodiscard]] DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx,
[[nodiscard]] DepthStencilVulkanImage* CreateDepthTarget(
const DepthTargetInfo& info);
void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info);
[[nodiscard]] VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info);
void ValidateVideoOut(const VideoOutInfo& info);
[[nodiscard]] VideoOutVulkanImage* CreateVideoOut(
const VideoOutInfo& info);
void SwapVideoOutBgra16(void* data, uint64_t size);
void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const VideoOutInfo& info,
void UploadVideoOut(VideoOutVulkanImage& image, const VideoOutInfo& info,
bool refresh);
[[nodiscard]] GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format,
[[nodiscard]] GpuTextureVulkanImage* CreateDummyTexture(bool uint_format,
bool image_3d, bool storage);
void Destroy(GraphicContext* ctx, VulkanImage* image);
void Destroy(VulkanImage& image);
} // namespace ImageOps
+61 -82
View File
@@ -316,13 +316,10 @@ inline constexpr std::array<VideoOutFormatPolicy, 6> VIDEO_OUT_FORMAT_POLICIES {
}};
[[nodiscard]] inline bool DecodeVideoOutPixelFormat(uint64_t pixel_format,
VideoOutPixelFormatInfo* info) {
if (info == nullptr) {
return false;
}
VideoOutPixelFormatInfo& info) {
for (const auto& policy: VIDEO_OUT_FORMAT_POLICIES) {
if (policy.pixel_format == pixel_format) {
*info = policy.info;
info = policy.info;
return true;
}
}
@@ -388,9 +385,8 @@ enum class BufferImageWrite : uint8_t {
[[nodiscard]] inline constexpr bool
HasGuestCurrentImageOwnership(bool image_gpu_modified, bool buffer_modified, bool cpu_dirty,
bool tracker_gpu_modified, bool same_context) noexcept {
return !image_gpu_modified && !buffer_modified && !cpu_dirty && !tracker_gpu_modified &&
same_context;
bool tracker_gpu_modified) noexcept {
return !image_gpu_modified && !buffer_modified && !cpu_dirty && !tracker_gpu_modified;
}
enum class StorageBufferRebind : uint8_t { Reuse, RefreshFromBacking, Unsupported };
@@ -398,11 +394,11 @@ enum class MetaImageOverlap : uint8_t { RetainSampled, RetireImage, Unsupported
[[nodiscard]] inline constexpr bool CanRetireGuestCurrentDepthForMetadataReuse(
bool depth_gpu_modified, bool depth_buffer_modified, bool depth_tracker_gpu_modified,
bool metadata_gpu_modified, bool metadata_tracker_gpu_modified, uint32_t metadata_clear_mask,
bool same_context) noexcept {
bool metadata_gpu_modified, bool metadata_tracker_gpu_modified,
uint32_t metadata_clear_mask) noexcept {
return !metadata_gpu_modified && !metadata_tracker_gpu_modified && metadata_clear_mask == 0 &&
HasGuestCurrentImageOwnership(depth_gpu_modified, depth_buffer_modified, false,
depth_tracker_gpu_modified, same_context);
depth_tracker_gpu_modified);
}
[[nodiscard]] inline constexpr uint32_t SelectImageBackingBaseLevel(bool storage,
@@ -493,12 +489,12 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
[[nodiscard]] inline MetaImageOverlap ClassifyMetaImageOverlap(bool sampled, bool writable_image,
bool gpu_modified,
bool buffer_modified, bool cpu_dirty,
bool same_context) {
bool buffer_modified,
bool cpu_dirty) {
if (sampled && !gpu_modified) {
return MetaImageOverlap::RetainSampled;
}
if (writable_image && !gpu_modified && !buffer_modified && !cpu_dirty && same_context) {
if (writable_image && !gpu_modified && !buffer_modified && !cpu_dirty) {
return MetaImageOverlap::RetireImage;
}
return MetaImageOverlap::Unsupported;
@@ -510,10 +506,7 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
}
[[nodiscard]] inline bool DecodePackedColorClear(vk::Format format, uint32_t packed,
vk::ClearColorValue* clear) {
if (clear == nullptr) {
return false;
}
vk::ClearColorValue& clear) {
vk::ClearColorValue next {};
const auto unorm8 = [](uint32_t value) { return static_cast<float>(value & 0xffu) / 255.0f; };
switch (format) {
@@ -555,32 +548,28 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
break;
default: return false;
}
*clear = next;
clear = next;
return true;
}
[[nodiscard]] inline bool DecodePackedStencilClear(uint32_t packed, uint8_t* clear) {
if (clear == nullptr) {
return false;
}
[[nodiscard]] inline bool DecodePackedStencilClear(uint32_t packed, uint8_t& clear) {
const auto value = static_cast<uint8_t>(packed);
if (packed != static_cast<uint32_t>(value) * 0x01010101u) {
return false;
}
*clear = value;
clear = value;
return true;
}
[[nodiscard]] inline bool DecodePackedDepthClear(vk::Format format, uint32_t packed, float* clear) {
if (clear == nullptr ||
(format != vk::Format::eD32Sfloat && format != vk::Format::eD32SfloatS8Uint)) {
[[nodiscard]] inline bool DecodePackedDepthClear(vk::Format format, uint32_t packed, float& clear) {
if (format != vk::Format::eD32Sfloat && format != vk::Format::eD32SfloatS8Uint) {
return false;
}
const auto value = std::bit_cast<float>(packed);
if (!std::isfinite(value) || value < 0.0f || value > 1.0f) {
return false;
}
*clear = value;
clear = value;
return true;
}
@@ -643,13 +632,11 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
[[nodiscard]] inline SampledOverlap ClassifySampledOverlap(const ImageInfo& requested,
const ImageInfo& cached,
bool cached_gpu_modified,
bool same_context) {
bool cached_gpu_modified) {
if (!ImagePageRangesOverlap(requested.address, requested.size, cached.address, cached.size)) {
return SampledOverlap::None;
}
return !cached_gpu_modified && same_context ? SampledOverlap::ReadOnlyAlias
: SampledOverlap::Unsupported;
return !cached_gpu_modified ? SampledOverlap::ReadOnlyAlias : SampledOverlap::Unsupported;
}
[[nodiscard]] inline bool IsRgba8SrgbReinterpretation(vk::Format cached,
@@ -702,7 +689,7 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
[[nodiscard]] inline StorageSampledOverlap ClassifyStorageSampledOverlap(
const ImageInfo& requested, const ImageInfo& cached, vk::Format requested_view_format,
vk::Format cached_image_format, bool cached_gpu_modified, bool cached_cpu_dirty,
bool same_context, bool exact_mip_subresource = false, bool cached_buffer_modified = false,
bool exact_mip_subresource = false, bool cached_buffer_modified = false,
bool tracker_gpu_modified = true) {
if (!ImagePageRangesOverlap(requested.address, requested.size, cached.address, cached.size)) {
return StorageSampledOverlap::None;
@@ -718,12 +705,11 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
(requested.format == cached.format && requested_view_format == cached_image_format) ||
IsRgba8SrgbReinterpretation(cached_image_format, requested_view_format) ||
IsR32UintFloatReinterpretation(cached_image_format, requested_view_format);
if (same_backing && compatible_format && cached_gpu_modified && !cached_cpu_dirty &&
same_context) {
if (same_backing && compatible_format && cached_gpu_modified && !cached_cpu_dirty) {
return StorageSampledOverlap::ExactImage;
}
if (exact_mip_subresource && cached_gpu_modified && tracker_gpu_modified &&
!cached_buffer_modified && !cached_cpu_dirty && same_context) {
!cached_buffer_modified && !cached_cpu_dirty) {
return StorageSampledOverlap::RetireStorage;
}
return StorageSampledOverlap::Unsupported;
@@ -866,8 +852,7 @@ ClassifyStorageBufferRebind(bool buffer_overlap, bool cached_gpu_modified,
[[nodiscard]] inline DepthOverlap
ClassifyStorageDepthOverlap(const ImageInfo& storage, bool storage_gpu_modified,
bool storage_buffer_modified, bool storage_cpu_dirty,
bool tracker_gpu_modified, bool same_context,
const DepthTargetInfo& depth) {
bool tracker_gpu_modified, const DepthTargetInfo& depth) {
const bool overlaps_depth =
ImageRangeOverlaps(storage.address, storage.size, depth.address, depth.size);
const bool overlaps_stencil =
@@ -876,21 +861,20 @@ ClassifyStorageDepthOverlap(const ImageInfo& storage, bool storage_gpu_modified,
if (!overlaps_depth && !overlaps_stencil) {
return DepthOverlap::None;
}
const bool guest_current =
HasGuestCurrentImageOwnership(storage_gpu_modified, storage_buffer_modified,
storage_cpu_dirty, tracker_gpu_modified, same_context);
const bool guest_current = HasGuestCurrentImageOwnership(
storage_gpu_modified, storage_buffer_modified, storage_cpu_dirty, tracker_gpu_modified);
const bool aspects_discarded =
(!overlaps_depth || !depth.depth_access) && (!overlaps_stencil || !depth.stencil_access);
return guest_current || (!storage_buffer_modified && !storage_cpu_dirty && same_context &&
aspects_discarded)
return guest_current || (!storage_buffer_modified && !storage_cpu_dirty && aspects_discarded)
? DepthOverlap::RetireStorage
: DepthOverlap::Unsupported;
}
[[nodiscard]] inline bool CanRetireGuestCurrentDepthForSampled(
const ImageInfo& sampled, const DepthTargetInfo& depth, bool depth_gpu_modified,
bool depth_buffer_modified, bool depth_tracker_gpu_modified, bool stencil_tracker_gpu_modified,
bool same_context) noexcept {
[[nodiscard]] inline bool
CanRetireGuestCurrentDepthForSampled(const ImageInfo& sampled, const DepthTargetInfo& depth,
bool depth_gpu_modified, bool depth_buffer_modified,
bool depth_tracker_gpu_modified,
bool stencil_tracker_gpu_modified) noexcept {
const bool overlaps_depth =
ImageRangeOverlaps(sampled.address, sampled.size, depth.address, depth.size);
const bool overlaps_stencil =
@@ -898,15 +882,15 @@ ClassifyStorageDepthOverlap(const ImageInfo& storage, bool storage_gpu_modified,
depth.stencil_address, depth.stencil_size);
return (overlaps_depth || overlaps_stencil) &&
HasGuestCurrentImageOwnership(depth_gpu_modified, depth_buffer_modified, false,
depth_tracker_gpu_modified || stencil_tracker_gpu_modified,
same_context);
depth_tracker_gpu_modified ||
stencil_tracker_gpu_modified);
}
[[nodiscard]] inline bool
CanRetireGuestCurrentSampledForDepth(const ImageInfo& sampled, const DepthTargetInfo& depth,
bool sampled_gpu_modified, bool sampled_buffer_modified,
bool sampled_cpu_dirty, bool tracker_gpu_modified,
bool same_context, bool guest_source_current) noexcept {
bool guest_source_current) noexcept {
const bool overlaps_depth =
ImageRangeOverlaps(sampled.address, sampled.size, depth.address, depth.size);
const bool overlaps_stencil =
@@ -914,11 +898,11 @@ CanRetireGuestCurrentSampledForDepth(const ImageInfo& sampled, const DepthTarget
depth.stencil_address, depth.stencil_size);
return (overlaps_depth || overlaps_stencil) && guest_source_current &&
HasGuestCurrentImageOwnership(sampled_gpu_modified, sampled_buffer_modified,
sampled_cpu_dirty, tracker_gpu_modified, same_context);
sampled_cpu_dirty, tracker_gpu_modified);
}
[[nodiscard]] inline RenderTargetOverlap
ClassifyRenderTargetOverlap(const ImageInfo& sampled, bool sampled_gpu_modified, bool same_context,
ClassifyRenderTargetOverlap(const ImageInfo& sampled, bool sampled_gpu_modified,
const RenderTargetInfo& target) {
if (!ImagePageRangesOverlap(sampled.address, sampled.size, target.address, target.size)) {
return RenderTargetOverlap::None;
@@ -926,15 +910,15 @@ ClassifyRenderTargetOverlap(const ImageInfo& sampled, bool sampled_gpu_modified,
if (!ImageRangeOverlaps(sampled.address, sampled.size, target.address, target.size)) {
return RenderTargetOverlap::None;
}
return !sampled_gpu_modified && same_context ? RenderTargetOverlap::RetireSampled
: RenderTargetOverlap::Unsupported;
return !sampled_gpu_modified ? RenderTargetOverlap::RetireSampled
: RenderTargetOverlap::Unsupported;
}
[[nodiscard]] inline RenderTargetOverlap
ClassifyStorageRenderTargetOverlap(const ImageInfo& storage, vk::Format storage_format,
bool storage_gpu_modified, bool storage_buffer_modified,
bool storage_cpu_dirty, bool tracker_gpu_modified,
bool same_context, const RenderTargetInfo& target) {
const RenderTargetInfo& target) {
if (!ImagePageRangesOverlap(storage.address, storage.size, target.address, target.size)) {
return RenderTargetOverlap::None;
}
@@ -950,11 +934,11 @@ ClassifyStorageRenderTargetOverlap(const ImageInfo& storage, vk::Format storage_
storage.type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) &&
storage.base_array == 0 && target.levels == 1 && target.layers == 1 && target.samples == 1;
if (exact_native_image && storage_gpu_modified && tracker_gpu_modified &&
!storage_buffer_modified && !storage_cpu_dirty && same_context) {
!storage_buffer_modified && !storage_cpu_dirty) {
return RenderTargetOverlap::PreserveStorage;
}
return HasGuestCurrentImageOwnership(storage_gpu_modified, storage_buffer_modified,
storage_cpu_dirty, tracker_gpu_modified, same_context)
storage_cpu_dirty, tracker_gpu_modified)
? RenderTargetOverlap::RetireStorage
: RenderTargetOverlap::Unsupported;
}
@@ -988,29 +972,28 @@ ClassifyStorageRenderTargetOverlap(const ImageInfo& storage, vk::Format storage_
[[nodiscard]] inline RenderTargetOverlap
ClassifySampledRenderTargetOverlap(const ImageInfo& sampled, const RenderTargetInfo& target,
bool target_buffer_modified, bool same_context) {
bool target_buffer_modified) {
if (!ImagePageRangesOverlap(sampled.address, sampled.size, target.address, target.size)) {
return RenderTargetOverlap::None;
}
if (!ImageRangeOverlaps(sampled.address, sampled.size, target.address, target.size)) {
return RenderTargetOverlap::None;
}
return same_context && !target_buffer_modified ? RenderTargetOverlap::RetireTarget
: RenderTargetOverlap::Unsupported;
return !target_buffer_modified ? RenderTargetOverlap::RetireTarget
: RenderTargetOverlap::Unsupported;
}
[[nodiscard]] inline StorageImageOverlap
ClassifyStorageImageOverlap(uint64_t requested_address, uint64_t requested_size,
uint64_t cached_address, uint64_t cached_size, bool sampled,
bool same_context, bool gpu_modified, bool buffer_modified,
bool tracker_gpu_modified) {
bool gpu_modified, bool buffer_modified, bool tracker_gpu_modified) {
if (!ImagePageRangesOverlap(requested_address, requested_size, cached_address, cached_size)) {
return StorageImageOverlap::None;
}
if (!ImageRangeOverlaps(requested_address, requested_size, cached_address, cached_size)) {
return StorageImageOverlap::PageNeighbor;
}
return sampled && same_context && !gpu_modified && !buffer_modified && !tracker_gpu_modified
return sampled && !gpu_modified && !buffer_modified && !tracker_gpu_modified
? StorageImageOverlap::RetireSampled
: StorageImageOverlap::Unsupported;
}
@@ -1068,8 +1051,7 @@ IsCompatibleDepthTargetBacking(const DepthTargetInfo& cached,
[[nodiscard]] inline RenderTargetOverlap
ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modified,
bool cached_buffer_modified, bool tracker_gpu_modified,
bool same_context, bool guest_source_current,
const RenderTargetInfo& requested) {
bool guest_source_current, const RenderTargetInfo& requested) {
if (!ImagePageRangesOverlap(cached.address, cached.size, requested.address, requested.size)) {
return RenderTargetOverlap::None;
}
@@ -1079,8 +1061,7 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
const bool expand = requested.layers > cached.layers &&
IsCompatibleRenderTargetBacking(requested, cached) &&
cached.format == requested.format;
if (expand && cached_gpu_modified && tracker_gpu_modified && !cached_buffer_modified &&
same_context) {
if (expand && cached_gpu_modified && tracker_gpu_modified && !cached_buffer_modified) {
return RenderTargetOverlap::ExpandTarget;
}
// A clean, page-isolated overlap is allocation-pool reuse, including a contained subrange.
@@ -1100,7 +1081,7 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
cached.size != requested.size || pool_storage_shape_changed;
return page_isolated && new_allocation && guest_source_current &&
HasGuestCurrentImageOwnership(cached_gpu_modified, cached_buffer_modified, false,
tracker_gpu_modified, same_context)
tracker_gpu_modified)
? RenderTargetOverlap::RetireTarget
: RenderTargetOverlap::Unsupported;
}
@@ -1108,7 +1089,6 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
[[nodiscard]] inline DepthOverlap ClassifyDepthTargetOverlap(const DepthTargetInfo& cached,
bool cached_gpu_modified,
bool cached_buffer_modified,
bool same_context,
const DepthTargetInfo& requested) {
const auto overlaps = [](uint64_t left, uint64_t left_size, uint64_t right, uint64_t right_size,
bool pages) {
@@ -1132,12 +1112,12 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
}
const bool expand =
requested.layers > cached.layers && IsCompatibleDepthTargetBacking(requested, cached);
if (expand && cached_gpu_modified && !cached_buffer_modified && same_context) {
if (expand && cached_gpu_modified && !cached_buffer_modified) {
return DepthOverlap::ExpandTarget;
}
const bool exact_discard =
requested.depth_load_clear && cached_gpu_modified && !cached_buffer_modified &&
same_context && cached.address == requested.address && cached.size == requested.size &&
cached.address == requested.address && cached.size == requested.size &&
cached.samples == requested.samples && cached.stencil_address == 0 &&
cached.stencil_size == 0 && cached.htile_address == 0 && cached.htile_size == 0 &&
requested.stencil_address == 0 && requested.stencil_size == 0 &&
@@ -1158,7 +1138,7 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
cached.bytes_per_element == requested.bytes_per_element &&
cached.tile_mode == requested.tile_mode && cached.layers == 1 &&
requested.layers == 1 && cached.samples == 1 && requested.samples == 1;
return exact_plane_rebind && same_shape && !cached_buffer_modified && same_context
return exact_plane_rebind && same_shape && !cached_buffer_modified
? DepthOverlap::RecreateTarget
: DepthOverlap::Unsupported;
}
@@ -1166,7 +1146,6 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
[[nodiscard]] inline bool CanRecreateDepthForRenderTarget(const DepthTargetInfo& depth,
bool gpu_modified, bool buffer_modified,
bool tracker_gpu_modified,
bool same_context,
bool guest_source_current,
const RenderTargetInfo& target) noexcept {
const bool exact_depth = depth.address == target.address && depth.size == target.size;
@@ -1189,15 +1168,16 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
const bool ownership_consistent = gpu_modified == tracker_gpu_modified && !buffer_modified;
const bool source_available =
((exact_depth || exact_stencil) && gpu_modified) || guest_source_current;
return same_context && ownership_consistent && source_available &&
return ownership_consistent && source_available &&
(exact_depth || exact_stencil || page_isolated_rebind) && depth.layers == 1 &&
target.levels == 1 && target.layers == 1 && depth.samples == 1 && target.samples == 1;
}
[[nodiscard]] inline bool
CanRecreateRenderTargetForDepth(const RenderTargetInfo& target, bool gpu_modified,
bool buffer_modified, bool tracker_gpu_modified, bool same_context,
bool guest_source_current, const DepthTargetInfo& depth) noexcept {
[[nodiscard]] inline bool CanRecreateRenderTargetForDepth(const RenderTargetInfo& target,
bool gpu_modified, bool buffer_modified,
bool tracker_gpu_modified,
bool guest_source_current,
const DepthTargetInfo& depth) noexcept {
const bool exact_depth = target.address == depth.address && target.size == depth.size;
const bool exact_stencil =
target.address == depth.stencil_address && target.size == depth.stencil_size;
@@ -1214,10 +1194,9 @@ CanRecreateRenderTargetForDepth(const RenderTargetInfo& target, bool gpu_modifie
depth.stencil_size % TRACKER_PAGE_SIZE == 0));
const bool source_available =
(gpu_modified && (exact_depth || exact_stencil)) || guest_source_current;
return gpu_modified == tracker_gpu_modified && !buffer_modified && same_context &&
source_available && (exact_depth || exact_stencil || page_isolated_rebind) &&
target.levels == 1 && target.layers == 1 && depth.layers == 1 && target.samples == 1 &&
depth.samples == 1;
return gpu_modified == tracker_gpu_modified && !buffer_modified && source_available &&
(exact_depth || exact_stencil || page_isolated_rebind) && target.levels == 1 &&
target.layers == 1 && depth.layers == 1 && target.samples == 1 && depth.samples == 1;
}
[[nodiscard]] inline bool RequiresMultisampleDepthRefresh(const DepthTargetInfo& info,
+132 -163
View File
@@ -2,6 +2,7 @@
#include "common/assert.h"
#include "graphics/host_gpu/objects/textureCommon.h"
#include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/renderer/textureCache.h"
#include <mutex>
@@ -10,19 +11,19 @@ namespace Libs::Graphics {
namespace {
void CreateView(GraphicContext* ctx, VulkanImage* image, int view_index,
void CreateView(VulkanImage& image, int view_index,
vk::ImageViewType view_type, vk::ImageAspectFlags aspect_mask,
vk::ComponentMapping components, uint32_t base_array_layer, uint32_t base_mip_level,
uint32_t layer_count, uint32_t level_count,
vk::Format view_format = vk::Format::eUndefined,
vk::ImageUsageFlags view_usage = {}) {
if (ctx == nullptr || image == nullptr || view_index < 0 ||
view_index >= VulkanImage::VIEW_MAX || image->image == nullptr ||
image->image_view[view_index] != nullptr) {
vk::ImageUsageFlags view_usage = {}) {
auto& graphics = GetRenderContext().GetGraphics();
if (view_index < 0 || view_index >= VulkanImage::VIEW_MAX ||
image.image_view[view_index] != nullptr) {
EXIT("invalid image-view creation target: image=%p index=%d current_view=%d\n",
static_cast<const void*>(image), view_index,
image != nullptr && view_index >= 0 && view_index < VulkanImage::VIEW_MAX &&
image->image_view[view_index] != nullptr);
static_cast<const void*>(&image), view_index,
view_index >= 0 && view_index < VulkanImage::VIEW_MAX &&
image.image_view[view_index] != nullptr);
}
vk::ImageViewUsageCreateInfo usage_info {};
@@ -32,9 +33,9 @@ void CreateView(GraphicContext* ctx, VulkanImage* image, int view_index,
vk::ImageViewCreateInfo create_info {};
create_info.sType = vk::StructureType::eImageViewCreateInfo;
create_info.pNext = view_usage ? &usage_info : nullptr;
create_info.image = image->image;
create_info.image = image.image;
create_info.viewType = view_type;
create_info.format = view_format != vk::Format::eUndefined ? view_format : image->format;
create_info.format = view_format != vk::Format::eUndefined ? view_format : image.format;
create_info.components = components;
create_info.subresourceRange.aspectMask = aspect_mask;
create_info.subresourceRange.baseArrayLayer = base_array_layer;
@@ -43,22 +44,22 @@ void CreateView(GraphicContext* ctx, VulkanImage* image, int view_index,
create_info.subresourceRange.levelCount = level_count;
const auto result =
ctx->device.createImageView(&create_info, nullptr, &image->image_view[view_index]);
if (result != vk::Result::eSuccess || image->image_view[view_index] == nullptr) {
graphics.device.createImageView(&create_info, nullptr, &image.image_view[view_index]);
if (result != vk::Result::eSuccess || image.image_view[view_index] == nullptr) {
EXIT("failed to create image view: result=%d image_format=%d view_format=%d index=%d\n",
static_cast<int>(result), static_cast<int>(image->format),
static_cast<int>(result), static_cast<int>(image.format),
static_cast<int>(create_info.format), view_index);
}
}
void CreateRenderTargetView(GraphicContext* ctx, VulkanImage* image, int index,
void CreateRenderTargetView(VulkanImage& image, int index,
vk::ComponentSwizzle r, vk::ComponentSwizzle g, vk::ComponentSwizzle b,
vk::ComponentSwizzle a, vk::ImageViewType type = vk::ImageViewType::e2D,
vk::Format view_format = vk::Format::eUndefined,
vk::ImageUsageFlags view_usage = {}, uint32_t level_count = 0) {
const auto layer_count = type == vk::ImageViewType::e2DArray ? image->layers : 1u;
CreateView(ctx, image, index, type, vk::ImageAspectFlagBits::eColor, {r, g, b, a}, 0, 0,
layer_count, level_count == 0 ? image->mip_levels : level_count, view_format,
const auto layer_count = type == vk::ImageViewType::e2DArray ? image.layers : 1u;
CreateView(image, index, type, vk::ImageAspectFlagBits::eColor, {r, g, b, a}, 0, 0,
layer_count, level_count == 0 ? image.mip_levels : level_count, view_format,
view_usage);
}
@@ -78,30 +79,31 @@ vk::ImageAspectFlags DepthAspectMask(vk::Format format) {
}
}
bool FormatSupportsStorage(GraphicContext* ctx, vk::Format format) {
const auto properties = ctx->GetFormatProperties(format);
bool FormatSupportsStorage(vk::Format format) {
auto& graphics = GetRenderContext().GetGraphics();
const auto properties = graphics.GetFormatProperties(format);
return static_cast<bool>(properties.optimalTilingFeatures &
vk::FormatFeatureFlagBits::eStorageImage);
}
void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* image) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT, vk::ComponentSwizzle::eIdentity,
void CreateRenderTargetViews(RenderTextureVulkanImage& image) {
CreateRenderTargetView(image, VulkanImage::VIEW_DEFAULT,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity);
if (image->layers > 1) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT_ARRAY,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity);
if (image.layers > 1) {
CreateRenderTargetView(image, VulkanImage::VIEW_DEFAULT_ARRAY,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ImageViewType::e2DArray);
}
if (image->samples == 1 && FormatSupportsStorage(ctx, image->format)) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_STORAGE,
if (image.samples == 1 && FormatSupportsStorage(image.format)) {
CreateRenderTargetView(image, VulkanImage::VIEW_STORAGE,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ImageViewType::e2D, vk::Format::eUndefined,
vk::ImageUsageFlags {}, 1);
if (image->layers > 1) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_STORAGE_ARRAY,
if (image.layers > 1) {
CreateRenderTargetView(image, VulkanImage::VIEW_STORAGE_ARRAY,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ImageViewType::e2DArray, vk::Format::eUndefined,
@@ -110,22 +112,21 @@ void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* imag
}
}
void CreateDepthViews(GraphicContext* ctx, DepthStencilVulkanImage* image) {
CreateView(ctx, image, VulkanImage::VIEW_DEFAULT, vk::ImageViewType::e2D,
DepthAspectMask(image->format),
void CreateDepthViews(DepthStencilVulkanImage& image) {
CreateView(image, VulkanImage::VIEW_DEFAULT, vk::ImageViewType::e2D,
DepthAspectMask(image.format),
{vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity},
0, 0, 1, 1);
}
void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT, vk::ComponentSwizzle::eIdentity,
void CreateVideoOutViews(VideoOutVulkanImage& image) {
CreateRenderTargetView(image, VulkanImage::VIEW_DEFAULT,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity);
if ((image->format == vk::Format::eR8G8B8A8Srgb ||
image->format == vk::Format::eB8G8R8A8Srgb) &&
FormatSupportsStorage(ctx, vk::Format::eR8G8B8A8Uint)) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_STORAGE,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity);
if ((image.format == vk::Format::eR8G8B8A8Srgb || image.format == vk::Format::eB8G8R8A8Srgb) &&
FormatSupportsStorage(vk::Format::eR8G8B8A8Uint)) {
CreateRenderTargetView(image, VulkanImage::VIEW_STORAGE,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ImageViewType::e2D, vk::Format::eR8G8B8A8Uint,
@@ -133,20 +134,18 @@ void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image) {
}
}
void DestroyViews(GraphicContext* ctx, VulkanImage* image) {
EXIT_IF(ctx == nullptr);
EXIT_IF(image == nullptr);
for (auto& cached: image->view_cache.views) {
void DestroyViews(VulkanImage& image) {
auto& graphics = GetRenderContext().GetGraphics();
for (auto& cached: image.view_cache.views) {
if (cached.view != nullptr) {
ctx->device.destroyImageView(cached.view, nullptr);
graphics.device.destroyImageView(cached.view, nullptr);
cached.view = nullptr;
}
}
image->view_cache.views.clear();
for (auto& view: image->image_view) {
image.view_cache.views.clear();
for (auto& view: image.image_view) {
if (view != nullptr) {
ctx->device.destroyImageView(view, nullptr);
graphics.device.destroyImageView(view, nullptr);
view = nullptr;
}
}
@@ -154,54 +153,45 @@ void DestroyViews(GraphicContext* ctx, VulkanImage* image) {
} // namespace ImageViewOps
vk::ImageView TextureCache::GetRenderTargetAttachmentView(GraphicContext* ctx,
RenderTextureVulkanImage* image,
vk::ImageView TextureCache::GetRenderTargetAttachmentView(RenderTextureVulkanImage& image,
vk::Format format, uint32_t level,
uint32_t base_layer,
uint32_t layer_count) {
if (ctx == nullptr || image == nullptr || image->image == nullptr ||
format == vk::Format::eUndefined || level >= image->mip_levels || level >= 16 ||
layer_count == 0 || base_layer >= image->layers ||
layer_count > image->layers - base_layer) {
if (image.format == vk::Format::eUndefined || level >= image.mip_levels || level >= 16 ||
layer_count == 0 || base_layer >= image.layers || layer_count > image.layers - base_layer) {
EXIT("TextureCache: invalid render-target attachment view, image=%p format=%d"
" level=%u image_levels=%u base_layer=%u layer_count=%u image_layers=%u\n",
static_cast<const void*>(image), static_cast<int>(format), level,
image != nullptr ? image->mip_levels : 0, base_layer, layer_count,
image != nullptr ? image->layers : 0);
static_cast<const void*>(&image), static_cast<int>(format), level, image.mip_levels,
base_layer, layer_count, image.layers);
}
if (format != image->format && !IsRgba8SrgbReinterpretation(image->format, format)) {
if (format != image.format && !IsRgba8SrgbReinterpretation(image.format, format)) {
EXIT("TextureCache: incompatible render-target attachment view, image_format=%d"
" view_format=%d level=%u\n",
static_cast<int>(image->format), static_cast<int>(format), level);
static_cast<int>(image.format), static_cast<int>(format), level);
}
return GetImageView(ctx, image,
{format,
layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray,
vk::ImageAspectFlagBits::eColor, level, 1, base_layer, layer_count,
DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eColorAttachment});
return GetImageView(
image, {format, layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray,
vk::ImageAspectFlagBits::eColor, level, 1, base_layer, layer_count,
DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eColorAttachment});
}
vk::ImageView TextureCache::GetDepthTargetAttachmentView(GraphicContext* ctx,
DepthStencilVulkanImage* image,
vk::ImageView TextureCache::GetDepthTargetAttachmentView(DepthStencilVulkanImage& image,
uint32_t base_layer,
uint32_t layer_count) {
if (ctx == nullptr || image == nullptr || image->image == nullptr || layer_count == 0 ||
base_layer >= image->layers || layer_count > image->layers - base_layer) {
if (layer_count == 0 || base_layer >= image.layers || layer_count > image.layers - base_layer) {
EXIT("TextureCache: invalid depth-target attachment view, image=%p base_layer=%u "
"layer_count=%u image_layers=%u\n",
static_cast<const void*>(image), base_layer, layer_count,
image != nullptr ? image->layers : 0);
static_cast<const void*>(&image), base_layer, layer_count, image.layers);
}
return GetImageView(
ctx, image,
{image->format, layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray,
ImageViewOps::DepthAspectMask(image->format), 0, 1, base_layer, layer_count,
DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eDepthStencilAttachment});
return GetImageView(image,
{image.format,
layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray,
ImageViewOps::DepthAspectMask(image.format), 0, 1, base_layer, layer_count,
DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eDepthStencilAttachment});
}
vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image,
const ImageViewInfo& info) {
vk::ImageView TextureCache::GetImageView(VulkanImage& image, const ImageViewInfo& info) {
const bool supported_type = info.type == vk::ImageViewType::e2D ||
info.type == vk::ImageViewType::e2DArray ||
info.type == vk::ImageViewType::e3D;
@@ -213,23 +203,22 @@ vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image
(info.type == vk::ImageViewType::e2D && info.layer_count == 1) ||
info.type == vk::ImageViewType::e2DArray ||
(info.type == vk::ImageViewType::e3D && info.base_layer == 0 && info.layer_count == 1);
if (ctx == nullptr || image == nullptr || image->image == nullptr ||
info.format == vk::Format::eUndefined || !info.aspect || info.level_count == 0 ||
info.base_level >= (image != nullptr ? image->mip_levels : 0) ||
info.level_count > image->mip_levels - info.base_level || info.layer_count == 0 ||
info.base_layer >= image->layers || info.layer_count > image->layers - info.base_layer ||
if (info.format == vk::Format::eUndefined || !info.aspect || info.level_count == 0 ||
info.base_level >= (image.mip_levels) ||
info.level_count > image.mip_levels - info.base_level || info.layer_count == 0 ||
info.base_layer >= image.layers || info.layer_count > image.layers - info.base_layer ||
!supported_type || !valid_shape || !supported_usage) {
EXIT("TextureCache: invalid dynamic image view, image=%p format=%d aspect=0x%x"
" swizzle=0x%03x mip=%u+%u layer=%u+%u type=%d usage=0x%x"
" image_levels=%u image_layers=%u\n",
static_cast<const void*>(image), static_cast<int>(info.format),
static_cast<const void*>(&image), static_cast<int>(info.format),
static_cast<vk::ImageAspectFlags::MaskType>(info.aspect), info.swizzle,
info.base_level, info.level_count, info.base_layer, info.layer_count,
static_cast<int>(info.type), static_cast<vk::ImageUsageFlags::MaskType>(info.usage),
image != nullptr ? image->mip_levels : 0, image != nullptr ? image->layers : 0);
image.mip_levels, image.layers);
}
auto& cache = image->view_cache;
auto& cache = image.view_cache;
std::lock_guard lock(cache.mutex);
for (const auto& cached: cache.views) {
if (cached.info == info) {
@@ -243,7 +232,7 @@ vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image
vk::ImageViewCreateInfo create {};
create.sType = vk::StructureType::eImageViewCreateInfo;
create.pNext = &usage;
create.image = image->image;
create.image = image.image;
create.viewType = info.type;
create.format = info.format;
create.components = info.usage == vk::ImageUsageFlagBits::eSampled
@@ -255,7 +244,7 @@ vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image
create.subresourceRange.baseArrayLayer = info.base_layer;
create.subresourceRange.layerCount = info.layer_count;
vk::ImageView view = nullptr;
const auto result = ctx->device.createImageView(&create, nullptr, &view);
const auto result = m_graphics.device.createImageView(&create, nullptr, &view);
if (result != vk::Result::eSuccess || view == nullptr) {
EXIT("TextureCache: failed to create dynamic image view, result=%d format=%d"
" aspect=0x%x swizzle=0x%03x mip=%u+%u layer=%u+%u type=%d usage=0x%x\n",
@@ -268,80 +257,68 @@ vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image
return view;
}
vk::ImageView TextureCache::GetDepthTargetSampledView(GraphicContext* ctx,
DepthStencilVulkanImage* image,
vk::ImageView TextureCache::GetDepthTargetSampledView(DepthStencilVulkanImage& image,
vk::Format view_format, uint32_t swizzle,
uint32_t base_level, uint32_t level_count,
vk::ImageViewType type, uint32_t base_layer,
uint32_t layer_count) {
if (ctx == nullptr || image == nullptr || image->image == nullptr ||
view_format == vk::Format::eUndefined ||
!IsSupportedSampledDepthView(image->format, view_format, swizzle)) {
if (view_format == vk::Format::eUndefined ||
!IsSupportedSampledDepthView(image.format, view_format, swizzle)) {
EXIT("TextureCache: invalid sampled depth-target view, image=%p image_format=%d"
" view_format=%d swizzle=0x%03x mip=%u+%u layer=%u+%u type=%d"
" image_levels=%u image_layers=%u\n",
static_cast<const void*>(image),
image != nullptr ? static_cast<int>(image->format)
: static_cast<int>(vk::Format::eUndefined),
static_cast<const void*>(&image), static_cast<int>(image.format),
static_cast<int>(view_format), swizzle, base_level, level_count, base_layer,
layer_count, static_cast<int>(type), image != nullptr ? image->mip_levels : 0,
image != nullptr ? image->layers : 0);
layer_count, static_cast<int>(type), image.mip_levels, image.layers);
}
return GetImageView(ctx, image,
{image->format, type, vk::ImageAspectFlagBits::eDepth, base_level,
level_count, base_layer, layer_count, swizzle});
return GetImageView(image, {image.format, type, vk::ImageAspectFlagBits::eDepth, base_level,
level_count, base_layer, layer_count, swizzle});
}
vk::ImageView TextureCache::GetSampledColorView(GraphicContext* ctx, VulkanImage* image,
vk::Format view_format, uint32_t swizzle,
uint32_t base_level, uint32_t level_count,
vk::ImageViewType type, uint32_t base_layer,
uint32_t layer_count) {
if (ctx == nullptr || image == nullptr || image->image == nullptr ||
view_format == vk::Format::eUndefined || base_level >= 16 ||
vk::ImageView TextureCache::GetSampledColorView(VulkanImage& image, vk::Format view_format,
uint32_t swizzle, uint32_t base_level,
uint32_t level_count, vk::ImageViewType type,
uint32_t base_layer, uint32_t layer_count) {
if (view_format == vk::Format::eUndefined || base_level >= 16 ||
(type != vk::ImageViewType::e2D && type != vk::ImageViewType::e2DArray) ||
!IsSupportedSampledColorView(image->format, view_format, swizzle)) {
!IsSupportedSampledColorView(image.format, view_format, swizzle)) {
EXIT("TextureCache: invalid sampled color view, image=%p swizzle=0x%03x"
" view_format=%d mip=%u+%u layer=%u+%u type=%d image_levels=%u image_layers=%u\n",
static_cast<const void*>(image), swizzle, static_cast<int>(view_format), base_level,
level_count, base_layer, layer_count, static_cast<int>(type),
image != nullptr ? image->mip_levels : 0, image != nullptr ? image->layers : 0);
static_cast<const void*>(&image), swizzle, static_cast<int>(view_format), base_level,
level_count, base_layer, layer_count, static_cast<int>(type), image.mip_levels,
image.layers);
}
const auto precreated_view = type == vk::ImageViewType::e2DArray
? VulkanImage::VIEW_DEFAULT_ARRAY
: VulkanImage::VIEW_DEFAULT;
const bool full_view =
base_level == 0 && level_count == image->mip_levels && base_layer == 0 &&
layer_count == (type == vk::ImageViewType::e2DArray ? image->layers : 1u);
if (view_format == image->format && swizzle == DstSel(4, 5, 6, 7) && full_view &&
image->image_view[precreated_view] != nullptr) {
return image->image_view[precreated_view];
const bool full_view = base_level == 0 && level_count == image.mip_levels && base_layer == 0 &&
layer_count == (type == vk::ImageViewType::e2DArray ? image.layers : 1u);
if (view_format == image.format && swizzle == DstSel(4, 5, 6, 7) && full_view &&
image.image_view[precreated_view] != nullptr) {
return image.image_view[precreated_view];
}
return GetImageView(ctx, image,
{view_format, type, vk::ImageAspectFlagBits::eColor, base_level,
level_count, base_layer, layer_count, swizzle});
return GetImageView(image, {view_format, type, vk::ImageAspectFlagBits::eColor, base_level,
level_count, base_layer, layer_count, swizzle});
}
vk::ImageView TextureCache::GetRenderTargetStorageView(GraphicContext* ctx,
RenderTextureVulkanImage* image,
vk::ImageView TextureCache::GetRenderTargetStorageView(RenderTextureVulkanImage& image,
vk::Format view_format, uint32_t base_level,
uint32_t level_count, vk::ImageViewType type,
uint32_t base_layer, uint32_t layer_count) {
if (ctx == nullptr || image == nullptr || image->image == nullptr ||
view_format == vk::Format::eUndefined ||
if (view_format == vk::Format::eUndefined ||
(type != vk::ImageViewType::e2D && type != vk::ImageViewType::e2DArray)) {
EXIT("TextureCache: invalid render-target storage view, image=%p view_format=%d"
" mip=%u+%u layer=%u+%u type=%d image_levels=%u image_layers=%u\n",
static_cast<const void*>(image), static_cast<int>(view_format), base_level,
level_count, base_layer, layer_count, static_cast<int>(type),
image != nullptr ? image->mip_levels : 0, image != nullptr ? image->layers : 0);
static_cast<const void*>(&image), static_cast<int>(view_format), base_level,
level_count, base_layer, layer_count, static_cast<int>(type), image.mip_levels,
image.layers);
}
const bool exact = view_format == image->format;
const bool compatible = view_format == BgraSrgbStorageViewFormat(image->format);
const bool exact = view_format == image.format;
const bool compatible = view_format == BgraSrgbStorageViewFormat(image.format);
if (!exact && !compatible) {
EXIT("TextureCache: incompatible render-target storage view, image_format=%d"
" view_format=%d base=%u count=%u\n",
static_cast<int>(image->format), static_cast<int>(view_format), base_level,
static_cast<int>(image.format), static_cast<int>(view_format), base_level,
level_count);
}
if (exact) {
@@ -349,44 +326,40 @@ vk::ImageView TextureCache::GetRenderTargetStorageView(GraphicContext*
: VulkanImage::VIEW_STORAGE;
const bool full_view =
base_level == 0 && level_count == 1 && base_layer == 0 &&
layer_count == (type == vk::ImageViewType::e2DArray ? image->layers : 1u);
if (full_view && image->image_view[index] != nullptr) {
return image->image_view[index];
layer_count == (type == vk::ImageViewType::e2DArray ? image.layers : 1u);
if (full_view && image.image_view[index] != nullptr) {
return image.image_view[index];
}
}
if (compatible && !ImageViewOps::FormatSupportsStorage(ctx, view_format)) {
if (compatible && !ImageViewOps::FormatSupportsStorage(view_format)) {
EXIT("TextureCache: compatible render-target storage format lacks storage support,"
" image_format=%d view_format=%d base=%u count=%u\n",
static_cast<int>(image->format), static_cast<int>(view_format), base_level,
static_cast<int>(image.format), static_cast<int>(view_format), base_level,
level_count);
}
return GetImageView(ctx, image,
{view_format, type, vk::ImageAspectFlagBits::eColor, base_level,
level_count, base_layer, layer_count, DstSel(4, 5, 6, 7),
vk::ImageUsageFlagBits::eStorage});
return GetImageView(image, {view_format, type, vk::ImageAspectFlagBits::eColor, base_level,
level_count, base_layer, layer_count, DstSel(4, 5, 6, 7),
vk::ImageUsageFlagBits::eStorage});
}
vk::ImageView TextureCache::GetStorageTextureSampledView(GraphicContext* ctx,
StorageTextureVulkanImage* image,
vk::ImageView TextureCache::GetStorageTextureSampledView(StorageTextureVulkanImage& image,
const ImageInfo& info) {
const auto shape =
SelectStorageSampledViewShape(info.type, info.depth, image != nullptr ? image->layers : 0);
if (ctx == nullptr || image == nullptr || image->image == nullptr ||
shape == StorageSampledViewShape::Unsupported || info.base_array != 0 ||
info.levels != image->mip_levels || info.base_level >= info.levels ||
const auto shape = SelectStorageSampledViewShape(info.type, info.depth, image.layers);
if (image.image == nullptr || shape == StorageSampledViewShape::Unsupported ||
info.base_array != 0 || info.levels != image.mip_levels || info.base_level >= info.levels ||
info.view_levels == 0 || info.base_level + info.view_levels > info.levels) {
EXIT("TextureCache: invalid sampled view of storage texture, image=%p type=%u depth=%u"
" base=%u levels=%u view_levels=%u image_levels=%u base_array=%u\n",
static_cast<const void*>(image), info.type, info.depth, info.base_level, info.levels,
info.view_levels, image != nullptr ? image->mip_levels : 0, info.base_array);
static_cast<const void*>(&image), info.type, info.depth, info.base_level, info.levels,
info.view_levels, image.mip_levels, info.base_array);
}
const auto view_format = TextureGetFormat(info.format);
if (view_format != image->format && !IsRgba8SrgbReinterpretation(image->format, view_format) &&
!IsR32UintFloatReinterpretation(image->format, view_format)) {
if (view_format != image.format && !IsRgba8SrgbReinterpretation(image.format, view_format) &&
!IsR32UintFloatReinterpretation(image.format, view_format)) {
EXIT("TextureCache: incompatible sampled view of storage texture, image_format=%d"
" view_format=%d swizzle=0x%03x\n",
static_cast<int>(image->format), static_cast<int>(view_format), info.swizzle);
static_cast<int>(image.format), static_cast<int>(view_format), info.swizzle);
}
vk::ImageViewType type = static_cast<vk::ImageViewType>(VK_IMAGE_VIEW_TYPE_MAX_ENUM);
@@ -398,26 +371,22 @@ vk::ImageView TextureCache::GetStorageTextureSampledView(GraphicContext*
EXIT("TextureCache: unsupported sampled storage-image view shape\n");
}
const auto layer_count = shape == StorageSampledViewShape::Image2DArray ? info.depth : 1u;
return GetImageView(ctx, image,
{view_format, type, vk::ImageAspectFlagBits::eColor, info.base_level,
info.view_levels, 0, layer_count, info.swizzle});
return GetImageView(image, {view_format, type, vk::ImageAspectFlagBits::eColor, info.base_level,
info.view_levels, 0, layer_count, info.swizzle});
}
vk::ImageView TextureCache::GetStorageTextureStorageView(GraphicContext* ctx,
StorageTextureVulkanImage* image,
vk::ImageView TextureCache::GetStorageTextureStorageView(StorageTextureVulkanImage& image,
uint32_t base_level) {
if (ctx == nullptr || image == nullptr || image->image == nullptr ||
base_level >= (image != nullptr ? image->mip_levels : 0)) {
if (image.image == nullptr || base_level >= (image.mip_levels)) {
EXIT("TextureCache: invalid storage-texture mip view, image=%p level=%u levels=%u\n",
static_cast<const void*>(image), base_level, image != nullptr ? image->mip_levels : 0);
static_cast<const void*>(&image), base_level, image.mip_levels);
}
if (base_level == 0) {
return image->image_view[VulkanImage::VIEW_DEFAULT];
return image.image_view[VulkanImage::VIEW_DEFAULT];
}
return GetImageView(ctx, image,
{image->format, vk::ImageViewType::e2D, vk::ImageAspectFlagBits::eColor,
base_level, 1, 0, 1, DstSel(4, 5, 6, 7),
vk::ImageUsageFlagBits::eStorage});
return GetImageView(image, {image.format, vk::ImageViewType::e2D,
vk::ImageAspectFlagBits::eColor, base_level, 1, 0, 1,
DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eStorage});
}
} // namespace Libs::Graphics
+5 -5
View File
@@ -216,12 +216,12 @@ ValidateStorageImageResource(const ShaderRecompiler::IR::ImageResource& resource
namespace ImageViewOps {
[[nodiscard]] vk::ImageAspectFlags DepthAspectMask(vk::Format format);
[[nodiscard]] bool FormatSupportsStorage(GraphicContext* ctx, vk::Format format);
[[nodiscard]] bool FormatSupportsStorage(vk::Format format);
void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* image);
void CreateDepthViews(GraphicContext* ctx, DepthStencilVulkanImage* image);
void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image);
void DestroyViews(GraphicContext* ctx, VulkanImage* image);
void CreateRenderTargetViews(RenderTextureVulkanImage& image);
void CreateDepthViews(DepthStencilVulkanImage& image);
void CreateVideoOutViews(VideoOutVulkanImage& image);
void DestroyViews(VulkanImage& image);
} // namespace ImageViewOps
@@ -8,6 +8,7 @@
#include "graphics/host_gpu/renderer/debug.h"
#include "graphics/host_gpu/renderer/depthRenderTarget.h"
#include "graphics/host_gpu/renderer/framebufferCache.h"
#include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h"
#include <atomic>
@@ -39,78 +40,77 @@ bool PipelineStaticParameters::operator==(const PipelineStaticParameters& other)
return std::memcmp(this, &other, sizeof(*this)) == 0;
}
PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
VulkanFramebuffer* framebuffer, RenderColorInfo* colors, uint32_t color_count,
RenderDepthInfo* depth, ShaderVertexInputInfo* vs_input_info, HW::Context* ctx,
HW::Shader* sh_ctx, ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology,
bool ps_active, std::span<const uint32_t> vs_spirv, std::span<const uint32_t> ps_spirv) {
PipelineCache::GraphicsPipeline& PipelineCache::CreateGraphicsPipeline(
VulkanFramebuffer& framebuffer, RenderColorInfo* colors, uint32_t color_count,
RenderDepthInfo& depth, ShaderVertexInputInfo& vs_input_info, RenderCommandBuffer& command,
ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology, bool ps_active,
std::span<const uint32_t> vs_spirv, std::span<const uint32_t> ps_spirv) {
KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Gfx)", profiler::colors::DeepOrangeA200);
EXIT_IF(framebuffer == nullptr);
EXIT_IF(depth == nullptr);
EXIT_IF(colors == nullptr);
EXIT_IF(color_count > RENDER_COLOR_ATTACHMENTS_MAX);
EXIT_IF(vs_spirv.empty());
EXIT_IF(ps_active && ps_spirv.empty());
Common::LockGuard lock(m_mutex);
auto& ctx = command.GetRegisters();
auto& sh_ctx = command.GetShaders();
const auto& vertex_info = sh_ctx->GetVs();
const auto& ps_regs = sh_ctx->GetPs();
const HW::BlendColor& bclr = ctx->GetBlendColor();
const auto& vertex_info = sh_ctx.GetVs();
const auto& ps_regs = sh_ctx.GetPs();
const HW::BlendColor& bclr = ctx.GetBlendColor();
uint32_t color_mask[RENDER_COLOR_ATTACHMENTS_MAX] = {};
for (uint32_t i = 0; i < color_count; i++) {
color_mask[i] = (colors[i].vulkan_buffer != nullptr
? colors[i].export_mapping.ApplyMask(render_target_mask_slot(
ctx->GetRenderTargetMask(), colors[i].target_slot))
ctx.GetRenderTargetMask(), colors[i].target_slot))
: 0);
}
const HW::ModeControl& mc = ctx->GetModeControl();
const HW::ModeControl& mc = ctx.GetModeControl();
auto vs_id = ShaderGetIdVS(&vertex_info, vs_input_info, true);
auto vs_id = ShaderGetIdVS(vertex_info, vs_input_info, true);
ShaderId ps_id {};
if (ps_active) {
ps_id = ShaderGetIdPS(&ps_regs, ps_input_info, true);
ps_id = ShaderGetIdPS(ps_regs, *ps_input_info, true);
}
PipelineStaticParameters static_params {};
GraphicsPipeline p {};
p.render_pass_id = framebuffer->render_pass_id;
p.render_pass_id = framebuffer.render_pass_id;
p.ps_shader_id = ps_id;
p.vs_shader_id = vs_id;
static_params.color_count = color_count;
if (ps_active && depth->depth_test_enable && ps_input_info->ps_execute_on_noop) {
if (ps_active && depth.depth_test_enable && ps_input_info->ps_execute_on_noop) {
static std::atomic<uint32_t> log_count {0};
if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) {
LOGF("Pipeline: temporary: accepting EXEC_ON_NOOP with depth test enabled\n");
}
}
const auto& clip_control = ctx->GetClipControl();
const auto& clip_control = ctx.GetClipControl();
EXIT_NOT_IMPLEMENTED(!clip_control.IsZClipModeRepresentable());
static_params.negative_one_to_one = !clip_control.dx_clip_space;
static_params.depth_clip_enable = clip_control.IsZClipEnabled();
static_params.topology = topology;
static_params.samples = framebuffer->samples;
static_params.samples = framebuffer.samples;
static_params.sample_shading_enable =
ps_active && framebuffer->samples > 1 && ps_input_info->ps_sample_shading;
if (static_params.sample_shading_enable &&
!g_render_ctx->GetGraphicCtx()->sample_rate_shading_enabled) {
ps_active && framebuffer.samples > 1 && ps_input_info->ps_sample_shading;
if (static_params.sample_shading_enable && !m_graphics.sample_rate_shading_enabled) {
EXIT("Pipeline: sample-rate shading is required but unsupported by the host\n");
}
static_params.with_depth =
(depth->format != vk::Format::eUndefined && depth->vulkan_buffer != nullptr);
static_params.depth_test_enable = depth->depth_test_enable;
static_params.depth_write_enable = (depth->depth_write_enable && !depth->depth_clear_enable);
static_params.depth_compare_op = depth->depth_compare_op;
static_params.depth_bounds_test_enable = depth->depth_bounds_test_enable;
static_params.depth_min_bounds = depth->depth_min_bounds;
static_params.depth_max_bounds = depth->depth_max_bounds;
static_params.stencil_test_enable = depth->stencil_test_enable;
static_params.stencil_front = depth->stencil_static_front;
static_params.stencil_back = depth->stencil_static_back;
(depth.format != vk::Format::eUndefined && depth.vulkan_buffer != nullptr);
static_params.depth_test_enable = depth.depth_test_enable;
static_params.depth_write_enable = (depth.depth_write_enable && !depth.depth_clear_enable);
static_params.depth_compare_op = depth.depth_compare_op;
static_params.depth_bounds_test_enable = depth.depth_bounds_test_enable;
static_params.depth_min_bounds = depth.depth_min_bounds;
static_params.depth_max_bounds = depth.depth_max_bounds;
static_params.stencil_test_enable = depth.stencil_test_enable;
static_params.stencil_front = depth.stencil_static_front;
static_params.stencil_back = depth.stencil_static_back;
for (uint32_t i = 0; i < RENDER_COLOR_ATTACHMENTS_MAX; i++) {
static_params.color_mask[i] = color_mask[i];
}
@@ -119,8 +119,8 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
static_params.face = mc.face;
for (uint32_t i = 0; i < color_count; i++) {
const auto& rt = ctx->GetRenderTarget(colors[i].target_slot);
const auto& bc = ctx->GetBlendControl(colors[i].target_slot);
const auto& rt = ctx.GetRenderTarget(colors[i].target_slot);
const auto& bc = ctx.GetBlendControl(colors[i].target_slot);
static_params.color_srcblend[i] = bc.color_srcblend;
static_params.color_comb_fcn[i] = bc.color_comb_fcn;
static_params.color_destblend[i] = bc.color_destblend;
@@ -145,13 +145,13 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
key.static_params = static_params;
if (auto iter = m_graphics_pipelines.find(key); iter != m_graphics_pipelines.end()) {
return iter->second.get();
return *iter->second;
}
if (graphics_debug_dump_enabled()) {
ShaderDbgDumpInputInfo(vs_input_info);
if (ps_active) {
ShaderDbgDumpInputInfo(ps_input_info);
ShaderDbgDumpInputInfo(*ps_input_info);
}
LOGF("PipelineTrace: shader binaries VS=0x%08" PRIx32 "/0x%08" PRIx32 " words=%" PRIu64
" PS=0x%08" PRIx32 "/0x%08" PRIx32 " words=%" PRIu64 "\n",
@@ -162,9 +162,9 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
auto cached = std::make_unique<GraphicsPipeline>(p);
LogPipelineTrace("CreatePipelineInternal begin", vs_id.hash0, vs_id.crc32, ps_id.hash0,
ps_id.crc32);
CreatePipelineInternal(cached.get(), framebuffer->render_pass, vs_input_info, vs_spirv,
ps_input_info, ps_spirv, static_params, vs_id.hash0, vs_id.crc32,
ps_id.hash0, ps_id.crc32, ps_active);
CreatePipelineInternal(*cached, framebuffer.render_pass, vs_input_info, vs_spirv, ps_input_info,
ps_spirv, static_params, vs_id.hash0, vs_id.crc32, ps_id.hash0,
ps_id.crc32, ps_active);
LogPipelineTrace("CreatePipelineInternal done", vs_id.hash0, vs_id.crc32, ps_id.hash0,
ps_id.crc32);
@@ -174,16 +174,15 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
auto [iter, inserted] = m_graphics_pipelines.emplace(std::move(key), std::move(cached));
EXIT_IF(!inserted);
return iter->second.get();
return *iter->second;
}
PipelineCache::ComputePipeline*
PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info,
const HW::ComputeShaderInfo* cs_regs,
PipelineCache::ComputePipeline&
PipelineCache::CreateComputePipeline(ShaderComputeInputInfo& input_info,
const HW::ComputeShaderInfo& cs_regs,
std::span<const uint32_t> cs_spirv) {
KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Compute)", profiler::colors::RedA100);
EXIT_IF(cs_regs == nullptr);
EXIT_IF(cs_spirv.empty());
Common::LockGuard lock(m_mutex);
@@ -197,7 +196,7 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info,
key.cs_shader_id = p.cs_shader_id;
if (auto iter = m_compute_pipelines.find(key); iter != m_compute_pipelines.end()) {
return iter->second.get();
return *iter->second;
}
if (graphics_debug_dump_enabled()) {
@@ -205,7 +204,7 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info,
}
auto cached = std::make_unique<ComputePipeline>(p);
CreatePipelineInternal(cached.get(), input_info, cs_spirv);
CreatePipelineInternal(*cached, input_info, cs_spirv);
EXIT_NOT_IMPLEMENTED(cached->pipeline == nullptr);
EXIT_NOT_IMPLEMENTED(cached->pipeline_layout == nullptr);
@@ -213,6 +212,6 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info,
auto [iter, inserted] = m_compute_pipelines.emplace(std::move(key), std::move(cached));
EXIT_IF(!inserted);
return iter->second.get();
return *iter->second;
}
} // namespace Libs::Graphics
+28 -23
View File
@@ -17,9 +17,11 @@
namespace Libs::Graphics {
struct GraphicContext;
struct RenderColorInfo;
struct RenderDepthInfo;
struct VulkanFramebuffer;
class RenderCommandBuffer;
namespace HW {
class Context;
@@ -76,7 +78,7 @@ static_assert(std::is_trivially_copyable_v<PipelineStaticParameters>);
static_assert(std::is_standard_layout_v<PipelineStaticParameters>);
static_assert(alignof(PipelineStaticParameters) == 1);
static_assert(sizeof(PipelineStaticParameters) ==
sizeof(float[3]) + sizeof(float[3]) + sizeof(bool) * 2 + sizeof(int[4]) +
sizeof(float[3]) + sizeof(float[3]) + sizeof(bool) * 2 + sizeof(int[4]) +
sizeof(vk::PrimitiveTopology) + sizeof(uint32_t) + sizeof(bool) * 4 +
sizeof(vk::CompareOp) + sizeof(bool) + sizeof(float) * 2 + sizeof(bool) +
sizeof(PipelineStencilStaticState) * 2 + sizeof(uint32_t) +
@@ -86,7 +88,9 @@ static_assert(sizeof(PipelineStaticParameters) ==
class PipelineCache {
public:
PipelineCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
explicit PipelineCache(GraphicContext& graphics): m_graphics(graphics) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
}
~PipelineCache() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(PipelineCache);
@@ -105,13 +109,13 @@ public:
ShaderId cs_shader_id;
};
GraphicsPipeline* CreateGraphicsPipeline(
VulkanFramebuffer* framebuffer, RenderColorInfo* colors, uint32_t color_count,
RenderDepthInfo* depth, ShaderVertexInputInfo* vs_input_info, HW::Context* ctx,
HW::Shader* sh_ctx, ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology,
bool ps_active, std::span<const uint32_t> vs_spirv, std::span<const uint32_t> ps_spirv);
ComputePipeline* CreateComputePipeline(ShaderComputeInputInfo* input_info,
const HW::ComputeShaderInfo* cs_regs,
GraphicsPipeline& CreateGraphicsPipeline(
VulkanFramebuffer& framebuffer, RenderColorInfo* colors, uint32_t color_count,
RenderDepthInfo& depth, ShaderVertexInputInfo& vs_input_info, RenderCommandBuffer& command,
ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology, bool ps_active,
std::span<const uint32_t> vs_spirv, std::span<const uint32_t> ps_spirv);
ComputePipeline& CreateComputePipeline(ShaderComputeInputInfo& input_info,
const HW::ComputeShaderInfo& cs_regs,
std::span<const uint32_t> cs_spirv);
private:
@@ -136,12 +140,12 @@ private:
};
struct PipelineKeyHash {
static void Mix(std::size_t* hash, std::size_t value) {
*hash ^= value + static_cast<std::size_t>(0x9e3779b97f4a7c15ull) + (*hash << 6u) +
(*hash >> 2u);
static void Mix(std::size_t& hash, std::size_t value) {
hash ^= value + static_cast<std::size_t>(0x9e3779b97f4a7c15ull) + (hash << 6u) +
(hash >> 2u);
}
static void MixShaderId(std::size_t* hash, const ShaderId& id) {
static void MixShaderId(std::size_t& hash, const ShaderId& id) {
Mix(hash, id.hash0);
Mix(hash, id.crc32);
Mix(hash, id.ids.size());
@@ -150,7 +154,7 @@ private:
}
}
static void MixStaticParams(std::size_t* hash, const PipelineStaticParameters& params) {
static void MixStaticParams(std::size_t& hash, const PipelineStaticParameters& params) {
const auto* bytes = reinterpret_cast<const uint8_t*>(&params);
for (std::size_t i = 0; i < sizeof(params); i++) {
Mix(hash, bytes[i]);
@@ -161,10 +165,10 @@ private:
struct GraphicsPipelineKeyHash {
std::size_t operator()(const GraphicsPipelineKey& key) const {
std::size_t hash = 0;
PipelineKeyHash::Mix(&hash, key.render_pass_id);
PipelineKeyHash::MixShaderId(&hash, key.vs_shader_id);
PipelineKeyHash::MixShaderId(&hash, key.ps_shader_id);
PipelineKeyHash::MixStaticParams(&hash, key.static_params);
PipelineKeyHash::Mix(hash, key.render_pass_id);
PipelineKeyHash::MixShaderId(hash, key.vs_shader_id);
PipelineKeyHash::MixShaderId(hash, key.ps_shader_id);
PipelineKeyHash::MixStaticParams(hash, key.static_params);
return hash;
}
};
@@ -172,11 +176,12 @@ private:
struct ComputePipelineKeyHash {
std::size_t operator()(const ComputePipelineKey& key) const {
std::size_t hash = 0;
PipelineKeyHash::MixShaderId(&hash, key.cs_shader_id);
PipelineKeyHash::MixShaderId(hash, key.cs_shader_id);
return hash;
}
};
GraphicContext& m_graphics;
std::unordered_map<GraphicsPipelineKey, std::unique_ptr<GraphicsPipeline>,
GraphicsPipelineKeyHash>
m_graphics_pipelines;
@@ -187,16 +192,16 @@ private:
void LogPipelineTrace(const char* phase, uint32_t vs_hash0, uint32_t vs_crc32, uint32_t ps_hash0,
uint32_t ps_crc32);
void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::RenderPass render_pass,
const ShaderVertexInputInfo* vs_input_info,
void CreatePipelineInternal(PipelineCache::GraphicsPipeline& pipeline, vk::RenderPass render_pass,
const ShaderVertexInputInfo& vs_input_info,
std::span<const uint32_t> vs_shader,
const ShaderPixelInputInfo* ps_input_info,
std::span<const uint32_t> ps_shader,
const PipelineStaticParameters& static_params, uint32_t vs_hash0,
uint32_t vs_crc32, uint32_t ps_hash0, uint32_t ps_crc32,
bool ps_active);
void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline,
const ShaderComputeInputInfo* input_info,
void CreatePipelineInternal(PipelineCache::ComputePipeline& pipeline,
const ShaderComputeInputInfo& input_info,
std::span<const uint32_t> cs_shader);
} // namespace Libs::Graphics
+36 -18
View File
@@ -33,6 +33,7 @@ struct VulkanFramebuffer;
struct RenderDepthInfo;
struct RenderColorInfo;
class BufferCache;
class RenderContext;
struct HtileClearTarget {
uint64_t address = 0;
@@ -68,7 +69,7 @@ private:
class CommandBuffer {
public:
explicit CommandBuffer(int queue): m_queue(queue) { Allocate(); }
explicit CommandBuffer(int queue);
~CommandBuffer() { Free(); }
KYTY_CLASS_NO_COPY(CommandBuffer);
@@ -85,17 +86,18 @@ public:
vk::Semaphore signal_semaphore);
void SetDebugInfo(uint32_t op, uint64_t submit_id, uint32_t arg0 = 0, uint32_t arg1 = 0,
uint32_t arg2 = 0, uint32_t arg3 = 0, uint64_t arg4 = 0);
void BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorInfo* colors,
uint32_t color_count, RenderDepthInfo* depth) const;
void BeginRenderPass(VulkanFramebuffer& framebuffer, RenderColorInfo* colors,
uint32_t color_count, RenderDepthInfo& depth) const;
void EndRenderPass() const;
void WaitForFenceOnly();
void WaitForFence();
void WaitForFenceAndReset();
void DeleteAfterFence(VulkanBuffer* buffer);
void DeleteAfterFence(VulkanBuffer& buffer);
void RetainResourceUntilFence(std::shared_ptr<void> resource);
void RecycleDescriptorAfterFence(VulkanDescriptorSet* set);
void RecycleDescriptorAfterFence(VulkanDescriptorSet& set);
[[nodiscard]] vk::CommandBuffer Handle() const;
[[nodiscard]] GraphicContext& GetGraphics() const noexcept { return m_graphics; }
[[nodiscard]] int GetQueue() const { return m_queue; }
[[nodiscard]] bool IsExecute() const { return m_execute; }
[[nodiscard]] uint64_t GetRecordingGeneration() const { return m_recording_generation; }
@@ -111,6 +113,7 @@ private:
void DeleteBuffersAfterFence();
void RecycleDescriptorsAfterFence();
GraphicContext& m_graphics;
VulkanCommandPool* m_pool = nullptr;
uint32_t m_index = static_cast<uint32_t>(-1);
int m_queue = -1;
@@ -131,34 +134,49 @@ private:
HostStreamBuffer m_host_stream;
};
void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx,
HW::UserConfig* ucfg, HW::Shader* sh_ctx, uint32_t index_type_and_size,
class RenderCommandBuffer final: public CommandBuffer {
public:
RenderCommandBuffer(int queue, HW::Context& registers, HW::UserConfig& user_config,
HW::Shader& shaders)
: CommandBuffer(queue), m_registers(registers), m_user_config(user_config),
m_shaders(shaders) {}
[[nodiscard]] HW::Context& GetRegisters() const noexcept { return m_registers; }
[[nodiscard]] HW::UserConfig& GetUserConfig() const noexcept { return m_user_config; }
[[nodiscard]] HW::Shader& GetShaders() const noexcept { return m_shaders; }
private:
HW::Context& m_registers;
HW::UserConfig& m_user_config;
HW::Shader& m_shaders;
};
void RenderDrawIndex(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_type_and_size,
uint32_t index_count, const void* index_addr, uint32_t flags, uint32_t type,
uint32_t instance_count = 1, uint32_t render_target_slice_offset = 0,
int32_t vertex_offset_add = 0, uint32_t first_instance = 0);
void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx,
HW::UserConfig* ucfg, HW::Shader* sh_ctx, uint32_t index_count,
void RenderDrawIndexAuto(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_count,
uint32_t flags, uint32_t render_target_slice_offset = 0,
uint32_t instance_count = 1, uint32_t first_vertex = 0,
uint32_t first_instance = 0);
void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx,
HW::Shader* sh_ctx, uint32_t thread_group_x, uint32_t thread_group_y,
uint32_t thread_group_z, uint32_t mode);
void RenderDispatchDirect(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t thread_group_x,
uint32_t thread_group_y, uint32_t thread_group_z, uint32_t mode);
void GraphicsRenderInit();
void GraphicsRenderCreateContext();
void GraphicsRenderSetContext(RenderContext& context);
void GraphicsRenderReleaseThreadCommandPools();
[[nodiscard]] bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t group_x,
uint32_t group_y, uint32_t group_z, uint32_t mode,
ShaderBufferResource* descriptor,
uint32_t* packed_clear, uint64_t* size);
ShaderBufferResource& descriptor,
uint32_t& packed_clear, uint64_t& size);
[[nodiscard]] bool ResolveHtileClearTarget(const HW::DepthRenderTarget& target,
uint64_t descriptor_size, HtileClearTarget* resolved);
uint64_t descriptor_size, HtileClearTarget& resolved);
void GraphicsRenderMemoryBarrier(CommandBuffer* buffer);
void GraphicsRenderTextureBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size);
void GraphicsRenderDepthStencilBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size);
void GraphicsRenderMemoryBarrier(CommandBuffer& buffer);
void GraphicsRenderTextureBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size);
void GraphicsRenderDepthStencilBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size);
} // namespace Libs::Graphics
@@ -51,11 +51,8 @@ static uint64_t BufferDescriptorSize(const ShaderBufferResource& descriptor) {
}
bool ResolveHtileClearTarget(const HW::DepthRenderTarget& z, uint64_t descriptor_size,
HtileClearTarget* resolved) {
if (resolved == nullptr) {
return false;
}
*resolved = {};
HtileClearTarget& resolved) {
resolved = {};
const bool has_stencil =
z.stencil_info.format != Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid);
const auto* depth_policy = FindDepthFormatPolicy(z.z_info.format);
@@ -112,7 +109,7 @@ bool ResolveHtileClearTarget(const HW::DepthRenderTarget& z, uint64_t descriptor
if (!descriptor_backed_state) {
return false;
}
*resolved = {.address = z.htile_data_base_addr, .size = descriptor_size};
resolved = {.address = z.htile_data_base_addr, .size = descriptor_size};
return true;
}
const uint32_t width = size_xy_valid ? static_cast<uint32_t>(z.size.x_max) + 1u : z.width;
@@ -124,10 +121,10 @@ bool ResolveHtileClearTarget(const HW::DepthRenderTarget& z, uint64_t descriptor
return false;
}
TileSizeAlign htile_size {};
if (!TileGetHtileSize(width, height, &htile_size) || htile_size.size != descriptor_size) {
if (!TileGetHtileSize(width, height, htile_size) || htile_size.size != descriptor_size) {
return false;
}
*resolved = {.address = z.htile_data_base_addr, .size = htile_size.size};
resolved = {.address = z.htile_data_base_addr, .size = htile_size.size};
return true;
}
@@ -154,9 +151,10 @@ static void ValidateFullHtileClearDispatch(const ShaderComputeInputInfo& input,
}
}
static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, const HW::Context& ctx,
uint32_t group_x, uint32_t group_y, uint32_t group_z,
uint32_t mode) {
static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input,
const RenderCommandBuffer& buffer, uint32_t group_x,
uint32_t group_y, uint32_t group_z, uint32_t mode) {
const auto& ctx = buffer.GetRegisters();
const auto& program = *input.stage.program;
const auto& resources = *input.stage.resources;
if (resources.buffers.size() != program.info.buffers.size()) {
@@ -164,7 +162,7 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
}
const auto& z = ctx.GetDepthRenderTarget();
const uint64_t meta_addr = z.htile_data_base_addr;
auto* cache = g_render_ctx->GetTextureCache();
auto& cache = GetRenderContext().GetTextureCache();
uint32_t current_references = 0;
uint32_t registered_writes = 0;
uint64_t described_meta_size = 0;
@@ -182,7 +180,7 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
// identifiable even when it is no longer the currently bound depth target.
TextureCache::MetaRangeInfo resolved_meta {};
if (resource.written &&
cache->ResolveMetaRange(descriptor.Base48(), descriptor_size, &resolved_meta)) {
cache.ResolveMetaRange(descriptor.Base48(), descriptor_size, resolved_meta)) {
registered_writes++;
registered_target = {.address = descriptor.Base48(), .size = descriptor_size};
registered_meta = resolved_meta;
@@ -197,7 +195,7 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
}
HtileClearTarget target {};
if (current_references != 0) {
if (!ResolveHtileClearTarget(z, described_meta_size, &target)) {
if (!ResolveHtileClearTarget(z, described_meta_size, target)) {
EXIT("unsupported HTile compute-clear target state: current=%u registered=%u "
"meta=0x%016" PRIx64 "+0x%016" PRIx64 " depth=0x%016" PRIx64 "/0x%016" PRIx64
" stencil=0x%016" PRIx64 "/0x%016" PRIx64
@@ -210,14 +208,14 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
z.slice_div64_minus1, z.z_info.format, z.stencil_info.format,
z.z_info.num_samples);
}
cache->RegisterMeta(g_render_ctx->GetGraphicCtx(), target.address, target.size);
if (!cache->ResolveMetaRange(target.address, target.size, &registered_meta)) {
cache.RegisterMeta(target.address, target.size);
if (!cache.ResolveMetaRange(target.address, target.size, registered_meta)) {
EXIT("failed to resolve registered HTile compute-clear range\n");
}
} else {
target = registered_target;
}
g_render_ctx->GetBufferCache()->ValidateGpuAccess(target.address, target.size, false, true);
GetRenderContext().GetBufferCache().ValidateGpuAccess(target.address, target.size, false, true);
uint32_t metadata_writes = 0;
ShaderBufferResource metadata_descriptor {};
@@ -245,20 +243,20 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
}
if (resource.written || !resource.read || resource.atomic || descriptor.Base48() == 0 ||
descriptor_size == 0 ||
cache->QueryRegion(descriptor.Base48(), descriptor_size).metadata_pages) {
cache.QueryRegion(descriptor.Base48(), descriptor_size).metadata_pages) {
EXIT("unsupported HTile clear side-buffer access\n");
}
g_render_ctx->GetBufferCache()->ValidateGpuAccess(descriptor.Base48(), descriptor_size,
true, false);
GetRenderContext().GetBufferCache().ValidateGpuAccess(descriptor.Base48(), descriptor_size,
true, false);
}
if (metadata_writes != 1) {
EXIT("HTile clear requires exactly one write-only metadata buffer, writes=%u\n",
metadata_writes);
}
ValidateFullHtileClearDispatch(input, metadata_descriptor, group_x, group_y, group_z, mode);
const bool recorded = registered_meta.full ? cache->ClearMeta(registered_meta.metadata_address)
: cache->TouchMeta(registered_meta.metadata_address,
registered_meta.slice, true);
const bool recorded = registered_meta.full ? cache.ClearMeta(registered_meta.metadata_address)
: cache.TouchMeta(registered_meta.metadata_address,
registered_meta.slice, true);
if (!recorded) {
EXIT("failed to record HTile compute clear\n");
}
@@ -267,11 +265,8 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t group_x,
uint32_t group_y, uint32_t group_z, uint32_t mode,
ShaderBufferResource* resolved_descriptor, uint32_t* resolved_clear,
uint64_t* resolved_size) {
if (resolved_descriptor == nullptr || resolved_clear == nullptr || resolved_size == nullptr) {
return false;
}
ShaderBufferResource& resolved_descriptor, uint32_t& resolved_clear,
uint64_t& resolved_size) {
const auto& program = *input.stage.program;
const auto& resources = *input.stage.resources;
if (program.info.buffers.size() != 1 || resources.buffers.size() != 1 ||
@@ -313,24 +308,24 @@ bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t grou
if (!full_dispatch || size == 0) {
return false;
}
*resolved_descriptor = descriptor;
*resolved_clear = clear;
*resolved_size = size;
resolved_descriptor = descriptor;
resolved_clear = clear;
resolved_size = size;
return true;
}
static bool TryConsumeComputeImageClear(const ShaderComputeInputInfo& input, CommandBuffer* command,
static bool TryConsumeComputeImageClear(const ShaderComputeInputInfo& input, CommandBuffer& command,
uint32_t group_x, uint32_t group_y, uint32_t group_z,
uint32_t mode) {
ShaderBufferResource descriptor;
uint32_t packed_clear = 0;
uint64_t size = 0;
if (!ResolveComputeImageClear(input, group_x, group_y, group_z, mode, &descriptor,
&packed_clear, &size)) {
if (!ResolveComputeImageClear(input, group_x, group_y, group_z, mode, descriptor, packed_clear,
size)) {
return false;
}
auto* cache = g_render_ctx->GetTextureCache();
if (!cache->ClearImageFromBuffer(command, descriptor.Base48(), size, packed_clear)) {
auto& cache = GetRenderContext().GetTextureCache();
if (!cache.ClearImageFromBuffer(command, descriptor.Base48(), size, packed_clear)) {
return false;
}
static std::atomic<uint32_t> logged_clears {0};
@@ -342,28 +337,26 @@ static bool TryConsumeComputeImageClear(const ShaderComputeInputInfo& input, Com
return true;
}
void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx,
HW::Shader* sh_ctx, uint32_t thread_group_x, uint32_t thread_group_y,
uint32_t thread_group_z, uint32_t mode) {
EXIT_IF(ctx == nullptr);
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
void RenderDispatchDirect(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t thread_group_x,
uint32_t thread_group_y, uint32_t thread_group_z, uint32_t mode) {
EXIT_IF(buffer.IsInvalid());
auto& ctx = buffer.GetRegisters();
auto& sh_ctx = buffer.GetShaders();
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::DispatchDirect), submit_id,
thread_group_x, thread_group_y, thread_group_z, mode,
sh_ctx != nullptr ? sh_ctx->GetCs().cs_regs.data_addr : 0);
buffer.SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::DispatchDirect), submit_id,
thread_group_x, thread_group_y, thread_group_z, mode,
sh_ctx.GetCs().cs_regs.data_addr);
Common::LockGuard lock(g_render_ctx->GetMutex());
Common::LockGuard lock(GetRenderContext().GetMutex());
if (sh_ctx->GetCs().cs_regs.data_addr == 0) {
if (sh_ctx.GetCs().cs_regs.data_addr == 0) {
LOGF("GraphicsRenderDispatchDirect: temporary: ignoring dispatch with null CS shader, "
"groups=%ux%ux%u mode=%u\n",
thread_group_x, thread_group_y, thread_group_z, mode);
return;
}
if (!ShaderAddressValid(sh_ctx->GetCs().cs_regs.data_addr)) {
if (!ShaderAddressValid(sh_ctx.GetCs().cs_regs.data_addr)) {
return;
}
@@ -380,17 +373,17 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context
LOGF("GraphicsRenderDispatchDirect: unknown dispatch initiator bits "
"mode=0x%08" PRIx32 " unknown=0x%08" PRIx32 " shader=0x%016" PRIx64
" groups=%ux%ux%u\n",
mode, unknown_mode_bits, sh_ctx->GetCs().cs_regs.data_addr, thread_group_x,
mode, unknown_mode_bits, sh_ctx.GetCs().cs_regs.data_addr, thread_group_x,
thread_group_y, thread_group_z);
}
}
const auto& cs_regs = sh_ctx->GetCs();
const auto& sh_regs = ctx->GetShaderRegisters();
const auto& cs_regs = sh_ctx.GetCs();
const auto& sh_regs = ctx.GetShaderRegisters();
ShaderComputeInputInfo input_info {};
std::span<const uint32_t> cs_shader;
if (!ShaderCompileInfoCS(&cs_regs, &sh_regs, &input_info, &cs_shader)) {
if (!ShaderCompileInfoCS(cs_regs, sh_regs, input_info, cs_shader)) {
EXIT("ShaderCompileInfoCS failed for dispatch with CS shader 0x%016" PRIx64 "\n",
cs_regs.cs_regs.data_addr);
}
@@ -408,8 +401,8 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context
(input_info.threads_num[0] * input_info.threads_num[1] * input_info.threads_num[2] >= 512);
const auto& program = *input_info.stage.program;
const auto& resources = *input_info.stage.resources;
if (TryConsumeComputeMetaClear(input_info, *ctx, thread_group_x, thread_group_y, thread_group_z,
mode)) {
if (TryConsumeComputeMetaClear(input_info, buffer, thread_group_x, thread_group_y,
thread_group_z, mode)) {
return;
}
if (TryConsumeComputeImageClear(input_info, buffer, thread_group_x, thread_group_y,
@@ -428,7 +421,7 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context
LOGF("GraphicsRenderDispatchDirect: frame=%u shader=0x%016" PRIx64
" groups=%ux%ux%u mode=0x%08" PRIx32 " local=%ux%ux%u "
"buffers=%zu textures=%zu sampled=%zu storage=%zu samplers=%zu push=%u\n",
frame_num, sh_ctx->GetCs().cs_regs.data_addr, thread_group_x, thread_group_y,
frame_num, sh_ctx.GetCs().cs_regs.data_addr, thread_group_x, thread_group_y,
thread_group_z, mode, input_info.threads_num[0], input_info.threads_num[1],
input_info.threads_num[2], program.info.buffers.size(), program.info.images.size(),
sampled_images, program.info.images.size() - sampled_images,
@@ -503,23 +496,23 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context
LOGF("GraphicsRenderDispatchDirect: skipping zero-sized dispatch groups=%ux%ux%u "
"mode=0x%08" PRIx32 " shader=0x%016" PRIx64 "\n",
thread_group_x, thread_group_y, thread_group_z, mode,
sh_ctx->GetCs().cs_regs.data_addr);
sh_ctx.GetCs().cs_regs.data_addr);
}
return;
}
for (;;) {
const auto recording_generation = buffer->GetRecordingGeneration();
auto vk_buffer = buffer->Handle();
auto* pipeline = g_render_ctx->GetPipelineCache()->CreateComputePipeline(
&input_info, &sh_ctx->GetCs(), cs_shader);
const auto recording_generation = buffer.GetRecordingGeneration();
auto vk_buffer = buffer.Handle();
auto& pipeline = GetRenderContext().GetPipelineCache().CreateComputePipeline(
input_info, sh_ctx.GetCs(), cs_shader);
vk_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline->pipeline);
vk_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline.pipeline);
BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eCompute,
pipeline->pipeline_layout, input_info.stage,
pipeline.pipeline_layout, input_info.stage,
vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute);
if (buffer->GetRecordingGeneration() != recording_generation) {
if (buffer.GetRecordingGeneration() != recording_generation) {
continue;
}
@@ -2,7 +2,6 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "graphics/presentation/window.h"
#include "kernel/pthread.h"
#include "libs/errno.h"
@@ -10,38 +9,11 @@
namespace Libs::Graphics {
void RenderContext::SetGraphicCtx(GraphicContext* ctx) {
EXIT_IF(ctx == nullptr);
Common::LockGuard lock(m_graphic_ctx_mutex);
m_graphic_ctx = ctx;
}
GraphicContext* RenderContext::GetGraphicCtx() {
{
Common::LockGuard lock(m_graphic_ctx_mutex);
if (m_graphic_ctx != nullptr) {
return m_graphic_ctx;
}
}
WindowWaitForGraphicInitialized();
auto* ctx = WindowGetGraphicContext();
LOGF("Graphic context initialized\n ctx = %p\n", static_cast<void*>(ctx));
EXIT_IF(ctx == nullptr);
GraphicContext* ret = nullptr;
{
Common::LockGuard lock(m_graphic_ctx_mutex);
if (m_graphic_ctx == nullptr) {
m_graphic_ctx = ctx;
}
ret = m_graphic_ctx;
}
return ret;
RenderContext::RenderContext(GraphicContext& graphics)
: m_graphics(graphics), m_pipeline_cache(graphics), m_descriptor_cache(graphics),
m_framebuffer_cache(graphics), m_sampler_cache(graphics), m_gds_buffer(graphics),
m_gpu_resources(graphics) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
}
void RenderContext::AddEopEq(LibKernel::EventQueue::KernelEqueue eq, int id) {
+13 -14
View File
@@ -23,22 +23,21 @@ constexpr int AGC_USER_INTERRUPT_EVENT = 0x1800;
class RenderContext {
public:
RenderContext() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
explicit RenderContext(GraphicContext& graphics);
~RenderContext() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(RenderContext);
void SetGraphicCtx(GraphicContext* ctx);
GraphicContext* GetGraphicCtx();
[[nodiscard]] GraphicContext& GetGraphics() const noexcept { return m_graphics; }
Common::Mutex& GetMutex() { return m_mutex; }
PipelineCache* GetPipelineCache() { return &m_pipeline_cache; }
DescriptorCache* GetDescriptorCache() { return &m_descriptor_cache; }
FramebufferCache* GetFramebufferCache() { return &m_framebuffer_cache; }
SamplerCache* GetSamplerCache() { return &m_sampler_cache; }
GdsBuffer* GetGdsBuffer() { return &m_gds_buffer; }
GpuResourceManager* GetGpuResources() { return &m_gpu_resources; }
BufferCache* GetBufferCache() { return m_gpu_resources.GetBufferCache(); }
TextureCache* GetTextureCache() { return m_gpu_resources.GetTextureCache(); }
PipelineCache& GetPipelineCache() { return m_pipeline_cache; }
DescriptorCache& GetDescriptorCache() { return m_descriptor_cache; }
FramebufferCache& GetFramebufferCache() { return m_framebuffer_cache; }
SamplerCache& GetSamplerCache() { return m_sampler_cache; }
GdsBuffer& GetGdsBuffer() { return m_gds_buffer; }
GpuResourceManager& GetGpuResources() { return m_gpu_resources; }
BufferCache& GetBufferCache() { return m_gpu_resources.GetBufferCache(); }
TextureCache& GetTextureCache() { return m_gpu_resources.GetTextureCache(); }
void AddEopEq(LibKernel::EventQueue::KernelEqueue eq, int id);
void DeleteEopEq(LibKernel::EventQueue::KernelEqueue eq, int id);
@@ -51,13 +50,12 @@ private:
uint32_t count = 0;
};
GraphicContext& m_graphics;
Common::Mutex m_mutex;
Common::Mutex m_graphic_ctx_mutex;
PipelineCache m_pipeline_cache;
DescriptorCache m_descriptor_cache;
FramebufferCache m_framebuffer_cache;
SamplerCache m_sampler_cache;
GraphicContext* m_graphic_ctx = nullptr;
GdsBuffer m_gds_buffer;
GpuResourceManager m_gpu_resources;
@@ -65,7 +63,8 @@ private:
std::vector<EopEqRegistration> m_eop_eqs;
};
extern RenderContext* g_render_ctx;
[[nodiscard]] bool HasRenderContext() noexcept;
[[nodiscard]] RenderContext& GetRenderContext();
} // namespace Libs::Graphics
+226 -261
View File
@@ -70,7 +70,7 @@ static std::atomic<uint32_t> g_mrt_state_log_count = 0;
static std::atomic<uint32_t> g_shader_stage_log_count = 0;
static std::atomic<uint32_t> g_framebuffer_skip_log_count = 0;
static bool ResolveColorTargets(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw,
static bool ResolveColorTargets(uint64_t submit_id, RenderCommandBuffer& buffer,
uint32_t render_target_slice_offset);
static const char* RenderColorTypeName(RenderColorType type) {
@@ -87,8 +87,10 @@ static bool IsDualSourceBlendFactor(uint32_t factor) {
}
static void LogFramebufferSkip(const char* draw_name, const RenderColorInfo& color,
const RenderDepthInfo& depth, const HW::Context* ctx,
const HW::UserConfig* ucfg, uint32_t index_count, uint32_t flags) {
const RenderDepthInfo& depth, const RenderCommandBuffer& buffer,
uint32_t index_count, uint32_t flags) {
const auto& ctx = buffer.GetRegisters();
const auto& ucfg = buffer.GetUserConfig();
if (!graphics_debug_dump_enabled()) {
return;
}
@@ -104,19 +106,17 @@ static void LogFramebufferSkip(const char* draw_name, const RenderColorInfo& col
" prim=%u index_count=%u flags=0x%08" PRIx32 "\n",
log_id, draw_name, RenderColorTypeName(color.type), color.base_addr, color.buffer_size,
color.vulkan_buffer != nullptr ? "yes" : "no", VulkanToString(depth.format).c_str(),
depth.vulkan_buffer != nullptr ? "yes" : "no", depth.vaddr_num,
ctx != nullptr ? ctx->GetRenderTargetMask() : 0, ucfg != nullptr ? ucfg->GetPrimType() : 0,
index_count, flags);
depth.vulkan_buffer != nullptr ? "yes" : "no", depth.vaddr_num, ctx.GetRenderTargetMask(),
ucfg.GetPrimType(), index_count, flags);
}
static void LogMrtState(const char* draw_name, const HW::Context* ctx,
static void LogMrtState(const char* draw_name, const RenderCommandBuffer& buffer,
const ShaderPixelInputInfo& ps_input_info) {
EXIT_IF(ctx == nullptr);
const auto& sh_regs = ctx->GetShaderRegisters();
const auto rt_mask = ctx->GetRenderTargetMask();
const auto& ctx = buffer.GetRegisters();
const auto& sh_regs = ctx.GetShaderRegisters();
const auto rt_mask = ctx.GetRenderTargetMask();
const auto cb_shader_mask = sh_regs.m_cbShaderMask;
const auto& bc0 = ctx->GetBlendControl(0);
const auto& bc0 = ctx.GetBlendControl(0);
bool interesting = rt_mask != 0x0f || (cb_shader_mask & ~0x0fu) != 0 ||
IsDualSourceBlendFactor(bc0.color_srcblend) ||
@@ -125,7 +125,7 @@ static void LogMrtState(const char* draw_name, const HW::Context* ctx,
IsDualSourceBlendFactor(bc0.alpha_destblend)));
for (uint32_t i = 1; i < 8; i++) {
const auto& rt = ctx->GetRenderTarget(i);
const auto& rt = ctx.GetRenderTarget(i);
if (rt.base.addr != 0 || ps_input_info.target_output_mode[i] != 0 ||
((rt_mask >> (i * 4u)) & 0x0fu) != 0 || ((cb_shader_mask >> (i * 4u)) & 0x0fu) != 0) {
interesting = true;
@@ -148,8 +148,8 @@ static void LogMrtState(const char* draw_name, const HW::Context* ctx,
bc0.separate_alpha_blend ? "true" : "false");
for (uint32_t i = 0; i < 8; i++) {
const auto& rt = ctx->GetRenderTarget(i);
const auto& bc = ctx->GetBlendControl(i);
const auto& rt = ctx.GetRenderTarget(i);
const auto& bc = ctx.GetBlendControl(i);
const auto ctm = (rt_mask >> (i * 4u)) & 0x0fu;
const auto csm = (cb_shader_mask >> (i * 4u)) & 0x0fu;
@@ -171,10 +171,11 @@ static void LogMrtState(const char* draw_name, const HW::Context* ctx,
}
static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& color,
const RenderDepthInfo& depth, const HW::Context* ctx,
const HW::UserConfig* ucfg,
const RenderDepthInfo& depth, const RenderCommandBuffer& buffer,
const ShaderPixelInputInfo& ps_input_info, uint32_t index_count,
uint32_t flags) {
const auto& ctx = buffer.GetRegisters();
const auto& ucfg = buffer.GetUserConfig();
if (color.type == RenderColorType::NoColorOutput) {
return;
}
@@ -184,13 +185,10 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
return;
}
EXIT_IF(ctx == nullptr);
EXIT_IF(ucfg == nullptr);
const auto& cc = ctx->GetColorControl();
const auto& bc = ctx->GetBlendControl(color.target_slot);
const auto& dc = ctx->GetDepthControl();
const auto& vp = ctx->GetScreenViewport();
const auto& cc = ctx.GetColorControl();
const auto& bc = ctx.GetBlendControl(color.target_slot);
const auto& dc = ctx.GetDepthControl();
const auto& vp = ctx.GetScreenViewport();
const auto& vp0 = vp.viewports[0];
const auto& ps_resources = ps_input_info.stage.program->info;
const auto sampled_images = std::count_if(
@@ -200,7 +198,7 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
});
vk::Extent2D extent = color.vulkan_buffer != nullptr ? color.extent : vk::Extent2D {};
auto sc = calc_final_scissor(vp, ctx->GetScanModeControl(), extent);
auto sc = calc_final_scissor(vp, ctx.GetScanModeControl(), extent);
LOGF(
"DrawTargetState[%u]: frame=%d %s target=%s addr=0x%010" PRIx64
@@ -210,8 +208,8 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
" depth_test=%s depth_write=%s depth_func=%u depth_clear=%s viewport=(%.1f,%.1f %.1fx%.1f) "
"scissor=(%d,%d)-(%d,%d)\n",
log_id, GraphicsRunGetFrameNum(), draw_name, RenderColorTypeName(color.type),
color.base_addr, extent.width, extent.height, ucfg->GetPrimType(), index_count, flags,
ctx->GetRenderTargetMask(), color.color_clear_enable ? "true" : "false",
color.base_addr, extent.width, extent.height, ucfg.GetPrimType(), index_count, flags,
ctx.GetRenderTargetMask(), color.color_clear_enable ? "true" : "false",
color.color_clear_value.float32[0], color.color_clear_value.float32[1],
color.color_clear_value.float32[2], color.color_clear_value.float32[3], cc.mode, cc.op,
bc.enable ? "true" : "false", bc.color_srcblend, bc.color_destblend, bc.color_comb_fcn,
@@ -223,7 +221,7 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
vp0.yoffset - vp0.yscale, vp0.xscale * 2.0f, vp0.yscale * 2.0f, sc.left, sc.top, sc.right,
sc.bottom);
LogMrtState(draw_name, ctx, ps_input_info);
LogMrtState(draw_name, buffer, ps_input_info);
}
static void LogDrawInputState(const RenderColorInfo& color,
@@ -305,11 +303,11 @@ static void LogDrawInputState(const RenderColorInfo& color,
}
}
static void VulkanCmdSetColorWriteEnableEXT(GraphicContext* ctx, vk::CommandBuffer command_buffer,
uint32_t attachment_count,
const vk::Bool32* p_color_write_enables) {
EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr);
static void VulkanCmdSetColorWriteEnableEXT(const RenderCommandBuffer& buffer,
vk::CommandBuffer command_buffer,
uint32_t attachment_count,
const vk::Bool32* p_color_write_enables) {
EXIT_IF(buffer.GetGraphics().device == nullptr);
if (VULKAN_HPP_DEFAULT_DISPATCHER.vkCmdSetColorWriteEnableEXT == nullptr) {
EXIT("vkCmdSetColorWriteEnableEXT not present\n");
@@ -317,11 +315,12 @@ static void VulkanCmdSetColorWriteEnableEXT(GraphicContext* ctx, vk::CommandBuff
command_buffer.setColorWriteEnableEXT(attachment_count, p_color_write_enables);
}
static PipelineDynamicParameters BuildGraphicsDynamicParams(const HW::Context& ctx,
const RenderColorInfo* colors,
uint32_t color_count,
const RenderDepthInfo& depth) {
static PipelineDynamicParameters BuildGraphicsDynamicParams(const RenderCommandBuffer& buffer,
const RenderColorInfo* colors,
uint32_t color_count,
const RenderDepthInfo& depth) {
EXIT_IF(colors == nullptr);
const auto& ctx = buffer.GetRegisters();
PipelineDynamicParameters ret {};
ret.color_write_count = color_count;
@@ -362,7 +361,7 @@ static PipelineDynamicParameters BuildGraphicsDynamicParams(const HW::Context&
return ret;
}
static void SetDynamicParams(vk::CommandBuffer vk_buffer,
static void SetDynamicParams(const RenderCommandBuffer& buffer, vk::CommandBuffer vk_buffer,
const PipelineDynamicParameters& dynamic_params) {
KYTY_PROFILER_FUNCTION();
@@ -414,14 +413,12 @@ static void SetDynamicParams(vk::CommandBuffer vk_buffer,
for (uint32_t i = 0; i < dynamic_params.color_write_count; i++) {
enable[i] = (dynamic_params.color_write_enable[i] ? VK_TRUE : VK_FALSE);
}
VulkanCmdSetColorWriteEnableEXT(g_render_ctx->GetGraphicCtx(), vk_buffer,
dynamic_params.color_write_count, enable);
VulkanCmdSetColorWriteEnableEXT(buffer, vk_buffer, dynamic_params.color_write_count, enable);
}
static bool DrawHasValidVertexShader(const HW::Shader* sh_ctx) {
EXIT_IF(sh_ctx == nullptr);
static bool DrawHasValidVertexShader(const HW::Shader& sh_ctx) {
const auto& vs = sh_ctx->GetVs();
const auto& vs = sh_ctx.GetVs();
return vs.gs_regs.chksum != 0 && ShaderAddressValid(vs.es_regs.data_addr);
}
@@ -432,16 +429,14 @@ static bool PixelShaderHasDepthOrCoverageSideEffects(const HW::ShaderRegisters&
db.shader_execute_on_noop;
}
static bool ShouldSkipGeShader(const HW::Context* ctx, const HW::UserConfig* ucfg,
const HW::Shader* sh_ctx) {
EXIT_IF(ctx == nullptr);
EXIT_IF(ucfg == nullptr);
EXIT_IF(sh_ctx == nullptr);
const auto& sh_regs = ctx->GetShaderRegisters();
const auto& ge_cntl = ucfg->GetGeControl();
const auto& vertex_info = sh_ctx->GetVs();
const auto stages = ctx->GetShaderStages();
static bool ShouldSkipGeShader(const RenderCommandBuffer& buffer) {
const auto& ctx = buffer.GetRegisters();
const auto& ucfg = buffer.GetUserConfig();
const auto& sh_ctx = buffer.GetShaders();
const auto& sh_regs = ctx.GetShaderRegisters();
const auto& ge_cntl = ucfg.GetGeControl();
const auto& vertex_info = sh_ctx.GetVs();
const auto stages = ctx.GetShaderStages();
const auto is_known_gs_out_prim_type = [](uint32_t value) {
switch (static_cast<Prospero::GsOutputPrimitiveType>(value)) {
@@ -511,11 +506,11 @@ struct DrawCallInfo {
uint32_t first_instance = 0;
};
static bool DrawHasActivePixelShader(const HW::Context* ctx, const HW::Shader* sh_ctx,
static bool DrawHasActivePixelShader(const RenderCommandBuffer& buffer,
const DrawRenderState& state, const DrawCallInfo& draw) {
EXIT_IF(ctx == nullptr);
EXIT_IF(sh_ctx == nullptr);
EXIT_IF(draw.name == nullptr);
const auto& ctx = buffer.GetRegisters();
const auto& sh_ctx = buffer.GetShaders();
const bool with_depth = (state.depth_info.format != vk::Format::eUndefined &&
state.depth_info.vulkan_buffer != nullptr);
@@ -523,8 +518,8 @@ static bool DrawHasActivePixelShader(const HW::Context* ctx, const HW::Shader* s
return true;
}
const auto& sh_regs = ctx->GetShaderRegisters();
const auto& ps = sh_ctx->GetPs();
const auto& sh_regs = ctx.GetShaderRegisters();
const auto& ps = sh_ctx.GetPs();
return ShaderAddressValid(ps.ps_regs.data_addr) &&
PixelShaderHasDepthOrCoverageSideEffects(sh_regs);
}
@@ -538,8 +533,9 @@ enum class CbColorMode : uint8_t {
DccDecompress = 6,
};
static bool ConsumeMetadataColorOperation(const HW::Context& ctx) {
const auto mode = ctx.GetColorControl().mode;
static bool ConsumeMetadataColorOperation(const RenderCommandBuffer& buffer) {
const auto& ctx = buffer.GetRegisters();
const auto mode = ctx.GetColorControl().mode;
// These AGC CB modes run color-buffer metadata/decompression operations. The shader is a
// dummy vehicle for the CB, and its exported color must not be applied as a normal draw.
// Kyty currently stores host images as expanded Vulkan images and does not track CMASK/DCC
@@ -570,176 +566,160 @@ static uint64_t VertexBufferDescriptorSize(const ShaderVertexInputBuffer& buffer
: buffer.num_records);
}
static void SetDrawDebugPhase(CommandBuffer* buffer, uint64_t submit_id, const DrawCallInfo& draw,
uint32_t phase) {
EXIT_IF(buffer == nullptr);
static void SetDrawDebugPhase(RenderCommandBuffer& buffer, uint64_t submit_id,
const DrawCallInfo& draw, uint32_t phase) {
EXIT_IF(draw.name == nullptr);
buffer->SetDebugInfo(static_cast<uint32_t>(draw.debug_op), submit_id, phase, draw.index_count,
draw.flags, draw.instance_count, draw.first_instance);
buffer.SetDebugInfo(static_cast<uint32_t>(draw.debug_op), submit_id, phase, draw.index_count,
draw.flags, draw.instance_count, draw.first_instance);
}
static bool GetDrawTopology(const HW::UserConfig* ucfg, bool auto_draw, bool use_ngg_rectlist_draw,
vk::PrimitiveTopology* topology) {
EXIT_IF(ucfg == nullptr);
EXIT_IF(topology == nullptr);
static bool GetDrawTopology(const HW::UserConfig& ucfg, bool auto_draw, bool use_ngg_rectlist_draw,
vk::PrimitiveTopology& topology) {
*topology = vk::PrimitiveTopology::ePointList;
topology = vk::PrimitiveTopology::ePointList;
switch (static_cast<Prospero::PrimitiveType>(ucfg->GetPrimType())) {
switch (static_cast<Prospero::PrimitiveType>(ucfg.GetPrimType())) {
case Prospero::PrimitiveType::kNone: return false;
case Prospero::PrimitiveType::kPointList:
*topology = vk::PrimitiveTopology::ePointList;
break;
case Prospero::PrimitiveType::kLineList:
*topology = vk::PrimitiveTopology::eLineList;
topology = vk::PrimitiveTopology::ePointList;
break;
case Prospero::PrimitiveType::kLineList: topology = vk::PrimitiveTopology::eLineList; break;
case Prospero::PrimitiveType::kLineStrip:
*topology = vk::PrimitiveTopology::eLineStrip;
topology = vk::PrimitiveTopology::eLineStrip;
break;
case Prospero::PrimitiveType::kTriList:
*topology = vk::PrimitiveTopology::eTriangleList;
topology = vk::PrimitiveTopology::eTriangleList;
break;
case Prospero::PrimitiveType::kTriFan:
*topology = vk::PrimitiveTopology::eTriangleFan;
topology = vk::PrimitiveTopology::eTriangleFan;
break;
case Prospero::PrimitiveType::kTriStrip:
*topology = vk::PrimitiveTopology::eTriangleStrip;
topology = vk::PrimitiveTopology::eTriangleStrip;
break;
case Prospero::PrimitiveType::kRectList:
*topology = (auto_draw && use_ngg_rectlist_draw ? vk::PrimitiveTopology::eTriangleStrip
: vk::PrimitiveTopology::eTriangleList);
topology = (auto_draw && use_ngg_rectlist_draw ? vk::PrimitiveTopology::eTriangleStrip
: vk::PrimitiveTopology::eTriangleList);
break;
case Prospero::PrimitiveType::kRectListLegacy:
if (!auto_draw) {
EXIT("unknown primitive type: %u\n", ucfg->GetPrimType());
EXIT("unknown primitive type: %u\n", ucfg.GetPrimType());
}
*topology = vk::PrimitiveTopology::eTriangleStrip;
topology = vk::PrimitiveTopology::eTriangleStrip;
break;
case Prospero::PrimitiveType::kQuadListLegacy:
*topology = vk::PrimitiveTopology::eTriangleFan;
topology = vk::PrimitiveTopology::eTriangleFan;
break;
default: EXIT("unknown primitive type: %u\n", ucfg->GetPrimType());
default: EXIT("unknown primitive type: %u\n", ucfg.GetPrimType());
}
return true;
}
static bool PrepareDrawRenderState(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx,
HW::UserConfig* ucfg, HW::Shader* sh_ctx,
static bool PrepareDrawRenderState(uint64_t submit_id, RenderCommandBuffer& buffer,
const DrawCallInfo& draw, uint32_t render_target_slice_offset,
bool skip_null_framebuffer, bool log_setup_phases,
DrawRenderState* state) {
EXIT_IF(buffer == nullptr);
EXIT_IF(ctx == nullptr);
EXIT_IF(ucfg == nullptr);
EXIT_IF(sh_ctx == nullptr);
DrawRenderState& state) {
EXIT_IF(draw.name == nullptr);
EXIT_IF(state == nullptr);
auto& ctx = buffer.GetRegisters();
if (log_setup_phases) {
LogDrawPhase(draw.name, "ResolveRenderDepthTarget");
}
ResolveRenderDepthTarget(submit_id, buffer, *ctx, &state->depth_info);
ResolveRenderDepthTarget(submit_id, buffer, state.depth_info);
if (ResolveColorTargets(submit_id, buffer, *ctx, render_target_slice_offset)) {
MarkRenderTargetGpuWritten(state->depth_info);
if (ResolveColorTargets(submit_id, buffer, render_target_slice_offset)) {
MarkRenderTargetGpuWritten(state.depth_info);
return false;
}
MarkRenderTargetGpuWritten(state->depth_info);
MarkRenderTargetGpuWritten(state.depth_info);
if (log_setup_phases) {
LogDrawPhase(draw.name, "ResolveRenderColorTarget");
}
for (uint32_t slot = 0; slot < RENDER_COLOR_ATTACHMENTS_MAX; slot++) {
if (slot == 0 || (render_target_mask_slot(ctx->GetRenderTargetMask(), slot) != 0 &&
ctx->GetRenderTarget(slot).base.addr != 0)) {
ResolveRenderColorTarget(submit_id, buffer, *ctx,
&state->color_info[state->color_count],
if (slot == 0 || (render_target_mask_slot(ctx.GetRenderTargetMask(), slot) != 0 &&
ctx.GetRenderTarget(slot).base.addr != 0)) {
ResolveRenderColorTarget(submit_id, buffer, state.color_info[state.color_count],
render_target_slice_offset, slot);
if (state->color_info[state->color_count].vulkan_buffer != nullptr) {
MarkRenderTargetGpuWritten(state->color_info[state->color_count]);
state->color_count++;
if (state.color_info[state.color_count].vulkan_buffer != nullptr) {
MarkRenderTargetGpuWritten(state.color_info[state.color_count]);
state.color_count++;
}
}
}
const bool with_depth = (state->depth_info.format != vk::Format::eUndefined &&
state->depth_info.vulkan_buffer != nullptr);
if (state->color_count == 0 && !with_depth) {
LogFramebufferSkip(draw.name, state->color_info[0], state->depth_info, ctx, ucfg,
const bool with_depth = (state.depth_info.format != vk::Format::eUndefined &&
state.depth_info.vulkan_buffer != nullptr);
if (state.color_count == 0 && !with_depth) {
LogFramebufferSkip(draw.name, state.color_info[0], state.depth_info, buffer,
draw.index_count, draw.flags);
return false;
}
state->ps_active = DrawHasActivePixelShader(ctx, sh_ctx, *state, draw);
state.ps_active = DrawHasActivePixelShader(buffer, state, draw);
if (log_setup_phases) {
LogDrawPhase(draw.name, "CreateFramebuffer");
}
state->framebuffer = g_render_ctx->GetFramebufferCache()->CreateFramebuffer(
state->color_info, state->color_count, &state->depth_info);
state.framebuffer = GetRenderContext().GetFramebufferCache().CreateFramebuffer(
state.color_info, state.color_count, state.depth_info);
if (state->framebuffer == nullptr && skip_null_framebuffer) {
LogFramebufferSkip(draw.name, state->color_info[0], state->depth_info, ctx, ucfg,
if (state.framebuffer == nullptr && skip_null_framebuffer) {
LogFramebufferSkip(draw.name, state.color_info[0], state.depth_info, buffer,
draw.index_count, draw.flags);
return false;
}
EXIT_NOT_IMPLEMENTED(state->framebuffer == nullptr);
EXIT_NOT_IMPLEMENTED(state->framebuffer->render_pass == nullptr);
EXIT_NOT_IMPLEMENTED(state.framebuffer == nullptr);
EXIT_NOT_IMPLEMENTED(state.framebuffer->render_pass == nullptr);
state->vk_buffer = buffer->Handle();
state.vk_buffer = buffer.Handle();
return true;
}
static void RefreshShaders(HW::Context* ctx, HW::Shader* sh_ctx, const DrawCallInfo& draw,
bool log_phases, DrawRenderState* state) {
EXIT_IF(ctx == nullptr);
EXIT_IF(sh_ctx == nullptr);
static void RefreshShaders(RenderCommandBuffer& buffer, const DrawCallInfo& draw, bool log_phases,
DrawRenderState& state) {
EXIT_IF(draw.name == nullptr);
EXIT_IF(state == nullptr);
auto& ctx = buffer.GetRegisters();
auto& sh_ctx = buffer.GetShaders();
const auto& vertex_shader_info = sh_ctx->GetVs();
const auto& pixel_shader_info = sh_ctx->GetPs();
const auto& shader_regs = ctx->GetShaderRegisters();
const auto& vertex_shader_info = sh_ctx.GetVs();
const auto& pixel_shader_info = sh_ctx.GetPs();
const auto& shader_regs = ctx.GetShaderRegisters();
state->vs_shader = {};
state->ps_shader = {};
state->ps_input_info = {};
state.vs_shader = {};
state.ps_shader = {};
state.ps_input_info = {};
std::array<Prospero::ColorComponentMapping, RENDER_COLOR_ATTACHMENTS_MAX>
target_export_mapping {};
for (uint32_t i = 0; i < state->color_count; i++) {
target_export_mapping[state->color_info[i].target_slot] =
state->color_info[i].export_mapping;
for (uint32_t i = 0; i < state.color_count; i++) {
target_export_mapping[state.color_info[i].target_slot] = state.color_info[i].export_mapping;
}
EXIT_IF(g_render_ctx == nullptr || g_render_ctx->GetGraphicCtx() == nullptr);
const auto lane_mask_mode = SelectGraphicsLaneMaskMode(*g_render_ctx->GetGraphicCtx(), 64u);
const auto lane_mask_mode = SelectGraphicsLaneMaskMode(64u);
if (log_phases) {
LogDrawPhase(draw.name, "ShaderCompileInfoVS");
}
if (!ShaderCompileInfoVS(&vertex_shader_info, &shader_regs, lane_mask_mode,
&state->vs_input_info, &state->vs_shader)) {
if (!ShaderCompileInfoVS(vertex_shader_info, shader_regs, lane_mask_mode, state.vs_input_info,
state.vs_shader)) {
EXIT("ShaderCompileInfoVS failed for draw %s\n", draw.name);
}
if (!state->ps_active) {
if (!state.ps_active) {
return;
}
if (log_phases) {
LogDrawPhase(draw.name, "ShaderCompileInfoPS");
}
if (!ShaderCompileInfoPS(&pixel_shader_info, &shader_regs, lane_mask_mode,
&state->vs_input_info, target_export_mapping, &state->ps_input_info,
&state->ps_shader)) {
if (!ShaderCompileInfoPS(pixel_shader_info, shader_regs, lane_mask_mode, state.vs_input_info,
target_export_mapping, state.ps_input_info, state.ps_shader)) {
EXIT("ShaderCompileInfoPS failed for draw %s\n", draw.name);
}
}
static void BindDrawVertexBuffers(uint64_t submit_id, CommandBuffer* buffer,
static void BindDrawVertexBuffers(uint64_t submit_id, RenderCommandBuffer& buffer,
const DrawCallInfo& draw, vk::CommandBuffer vk_buffer,
const ShaderVertexInputInfo& vs_input_info) {
EXIT_IF(buffer == nullptr);
EXIT_IF(draw.name == nullptr);
(void)submit_id;
@@ -752,13 +732,11 @@ static void BindDrawVertexBuffers(uint64_t submit_id, CommandBuffer* buffer,
vk::DeviceSize offset = 0;
if (size == 0) {
vertices = g_render_ctx->GetBufferCache()->ObtainNullBuffer(
buffer, g_render_ctx->GetGraphicCtx());
vertices = &GetRenderContext().GetBufferCache().ObtainNullBuffer(buffer);
} else {
auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer(
buffer, g_render_ctx->GetGraphicCtx(), addr, size);
vertices = binding.first;
offset = binding.second;
auto binding = GetRenderContext().GetBufferCache().ObtainBuffer(buffer, addr, size);
vertices = &binding.buffer;
offset = binding.offset;
}
EXIT_NOT_IMPLEMENTED(vertices == nullptr);
@@ -766,7 +744,7 @@ static void BindDrawVertexBuffers(uint64_t submit_id, CommandBuffer* buffer,
}
}
static void BindDrawIndexBuffer(CommandBuffer* buffer, vk::CommandBuffer vk_buffer,
static void BindDrawIndexBuffer(RenderCommandBuffer& buffer, vk::CommandBuffer vk_buffer,
const DrawIndexBufferSource& source) {
if (!source.enabled) {
return;
@@ -777,27 +755,24 @@ static void BindDrawIndexBuffer(CommandBuffer* buffer, vk::CommandBuffer vk_buff
vk::DeviceSize index_offset = 0;
if (source.host_data != nullptr) {
vk::DeviceSize range = 0;
if (!g_render_ctx->GetBufferCache()->UploadHostData(buffer, g_render_ctx->GetGraphicCtx(),
source.host_data, source.size, 16,
&index_buffer, &index_offset, &range)) {
if (!GetRenderContext().GetBufferCache().UploadHostData(
buffer, source.host_data, source.size, 16, index_buffer, index_offset, range)) {
EXIT("failed to upload host index buffer\n");
}
} else {
auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer(
buffer, g_render_ctx->GetGraphicCtx(), source.address, source.size);
index_buffer = binding.first;
index_offset = binding.second;
auto binding =
GetRenderContext().GetBufferCache().ObtainBuffer(buffer, source.address, source.size);
index_buffer = &binding.buffer;
index_offset = binding.offset;
}
EXIT_IF(index_buffer == nullptr);
vk_buffer.bindIndexBuffer(index_buffer->buffer, index_offset, source.type);
}
static void LogDrawStateIfNeeded(HW::Context* ctx, HW::UserConfig* ucfg, const DrawCallInfo& draw,
static void LogDrawStateIfNeeded(const RenderCommandBuffer& buffer, const DrawCallInfo& draw,
const DrawRenderState& state, bool always_log,
bool force_legacy_rect_log, uint32_t index_type_and_size,
const void* index_addr) {
EXIT_IF(ctx == nullptr);
EXIT_IF(ucfg == nullptr);
EXIT_IF(draw.name == nullptr);
if (!graphics_debug_dump_enabled()) {
@@ -809,7 +784,7 @@ static void LogDrawStateIfNeeded(HW::Context* ctx, HW::UserConfig* ucfg, const D
}
if (state.ps_active) {
LogDrawTargetState(draw.name, state.color_info[0], state.depth_info, ctx, ucfg,
LogDrawTargetState(draw.name, state.color_info[0], state.depth_info, buffer,
state.ps_input_info, draw.index_count, draw.flags);
}
LogDrawInputState(state.color_info[0], state.vs_input_info, index_type_and_size,
@@ -831,13 +806,12 @@ static bool IsHostExpandedRectListDrawSupported(const ShaderVertexInputInfo& vs_
return draw.index_count == 3 || draw.index_count == emit.draw_vertex_count;
}
static void EmitDrawPrimitives(const HW::UserConfig* ucfg, vk::CommandBuffer vk_buffer,
static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_buffer,
const ShaderVertexInputInfo& vs_input_info, const DrawCallInfo& draw,
const DrawEmitInfo& emit) {
EXIT_IF(ucfg == nullptr);
EXIT_IF(draw.name == nullptr);
switch (static_cast<Prospero::PrimitiveType>(ucfg->GetPrimType())) {
switch (static_cast<Prospero::PrimitiveType>(ucfg.GetPrimType())) {
case Prospero::PrimitiveType::kPointList:
case Prospero::PrimitiveType::kLineList:
case Prospero::PrimitiveType::kLineStrip:
@@ -865,7 +839,7 @@ static void EmitDrawPrimitives(const HW::UserConfig* ucfg, vk::CommandBuffer vk_
break;
case Prospero::PrimitiveType::kRectListLegacy:
if (emit.indexed) {
EXIT("unknown primitive type: %u\n", ucfg->GetPrimType());
EXIT("unknown primitive type: %u\n", ucfg.GetPrimType());
}
// Sarah
EXIT_NOT_IMPLEMENTED(!(draw.index_count == 3 && vs_input_info.buffers_num == 0));
@@ -883,67 +857,63 @@ static void EmitDrawPrimitives(const HW::UserConfig* ucfg, vk::CommandBuffer vk_
}
}
break;
default: EXIT("unknown primitive type: %u\n", ucfg->GetPrimType());
default: EXIT("unknown primitive type: %u\n", ucfg.GetPrimType());
}
}
static void ExecutePreparedDraw(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx,
HW::UserConfig* ucfg, HW::Shader* sh_ctx, const DrawCallInfo& draw,
DrawRenderState* state, vk::PrimitiveTopology topology,
const DrawEmitInfo& emit, const DrawIndexBufferSource& index_source,
bool log_pipeline_phase, bool set_bind_debug, bool set_auto_debug) {
EXIT_IF(buffer == nullptr);
EXIT_IF(ctx == nullptr);
EXIT_IF(ucfg == nullptr);
EXIT_IF(sh_ctx == nullptr);
static void ExecutePreparedDraw(uint64_t submit_id, RenderCommandBuffer& buffer,
const DrawCallInfo& draw, DrawRenderState& state,
vk::PrimitiveTopology topology, const DrawEmitInfo& emit,
const DrawIndexBufferSource& index_source, bool log_pipeline_phase,
bool set_bind_debug, bool set_auto_debug) {
EXIT_IF(draw.name == nullptr);
EXIT_IF(state == nullptr);
auto& ucfg = buffer.GetUserConfig();
for (;;) {
const auto recording_generation = buffer->GetRecordingGeneration();
const auto recording_generation = buffer.GetRecordingGeneration();
if (log_pipeline_phase) {
LogDrawPhase(draw.name, "CreatePipeline");
}
auto* pipeline = g_render_ctx->GetPipelineCache()->CreateGraphicsPipeline(
state->framebuffer, state->color_info, state->color_count, &state->depth_info,
&state->vs_input_info, ctx, sh_ctx, &state->ps_input_info, topology, state->ps_active,
state->vs_shader, state->ps_shader);
auto& pipeline = GetRenderContext().GetPipelineCache().CreateGraphicsPipeline(
*state.framebuffer, state.color_info, state.color_count, state.depth_info,
state.vs_input_info, buffer, &state.ps_input_info, topology, state.ps_active,
state.vs_shader, state.ps_shader);
if (set_bind_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x100u);
}
state->vk_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline->pipeline);
const auto dynamic_params = BuildGraphicsDynamicParams(
*ctx, state->color_info, state->color_count, state->depth_info);
SetDynamicParams(state->vk_buffer, dynamic_params);
state.vk_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.pipeline);
const auto dynamic_params = BuildGraphicsDynamicParams(buffer, state.color_info,
state.color_count, state.depth_info);
SetDynamicParams(buffer, state.vk_buffer, dynamic_params);
// EXIT_NOT_IMPLEMENTED(vs_input_info.buffers_num > 1);
BindDrawVertexBuffers(submit_id, buffer, draw, state->vk_buffer, state->vs_input_info);
BindDrawVertexBuffers(submit_id, buffer, draw, state.vk_buffer, state.vs_input_info);
LogDrawPhase(draw.name, "BindDescriptorsVS");
if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x200u);
}
BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics,
pipeline->pipeline_layout, state->vs_input_info.stage,
pipeline.pipeline_layout, state.vs_input_info.stage,
vk::ShaderStageFlagBits::eVertex, DescriptorCache::Stage::Vertex);
if (state->ps_active) {
if (state.ps_active) {
LogDrawPhase(draw.name, "BindDescriptorsPS");
if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x300u);
}
BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics,
pipeline->pipeline_layout, state->ps_input_info.stage,
pipeline.pipeline_layout, state.ps_input_info.stage,
vk::ShaderStageFlagBits::eFragment, DescriptorCache::Stage::Pixel);
}
if (buffer->GetRecordingGeneration() != recording_generation) {
if (buffer.GetRecordingGeneration() != recording_generation) {
continue;
}
// Index data may use this command buffer's host stream. Resolve it only after the other
// fault-capable bindings, and rebuild it whenever a fault reset changes the generation.
BindDrawIndexBuffer(buffer, state->vk_buffer, index_source);
if (buffer->GetRecordingGeneration() != recording_generation) {
BindDrawIndexBuffer(buffer, state.vk_buffer, index_source);
if (buffer.GetRecordingGeneration() != recording_generation) {
continue;
}
@@ -951,29 +921,29 @@ static void ExecutePreparedDraw(uint64_t submit_id, CommandBuffer* buffer, HW::C
if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x400u);
}
buffer->BeginRenderPass(state->framebuffer, state->color_info, state->color_count,
&state->depth_info);
buffer.BeginRenderPass(*state.framebuffer, state.color_info, state.color_count,
state.depth_info);
if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x500u);
}
EmitDrawPrimitives(ucfg, state->vk_buffer, state->vs_input_info, draw, emit);
EmitDrawPrimitives(ucfg, state.vk_buffer, state.vs_input_info, draw, emit);
if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x600u);
}
buffer->EndRenderPass();
buffer.EndRenderPass();
vk::PipelineStageFlags shader_write_stages = {};
if (HasShaderBufferWrites(state->vs_input_info.stage)) {
if (HasShaderBufferWrites(state.vs_input_info.stage)) {
shader_write_stages |= vk::PipelineStageFlagBits::eVertexShader;
}
if (state->ps_active) {
if (HasShaderBufferWrites(state->ps_input_info.stage)) {
if (state.ps_active) {
if (HasShaderBufferWrites(state.ps_input_info.stage)) {
shader_write_stages |= vk::PipelineStageFlagBits::eFragmentShader;
}
}
if (shader_write_stages) {
ShaderWriteBarrier(state->vk_buffer, shader_write_stages);
ShaderWriteBarrier(state.vk_buffer, shader_write_stages);
}
LogDrawPhase(draw.name, "EndRenderPass");
if (set_auto_debug) {
@@ -983,30 +953,27 @@ static void ExecutePreparedDraw(uint64_t submit_id, CommandBuffer* buffer, HW::C
}
}
void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx,
HW::UserConfig* ucfg, HW::Shader* sh_ctx, uint32_t index_type_and_size,
void RenderDrawIndex(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_type_and_size,
uint32_t index_count, const void* index_addr, uint32_t flags, uint32_t type,
uint32_t instance_count, uint32_t render_target_slice_offset,
int32_t vertex_offset_add, uint32_t first_instance) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr);
EXIT_IF(ucfg == nullptr);
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
EXIT_IF(buffer.IsInvalid());
auto& ucfg = buffer.GetUserConfig();
auto& sh_ctx = buffer.GetShaders();
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::DrawIndex), submit_id,
index_count, flags, type, instance_count,
reinterpret_cast<uint64_t>(index_addr));
buffer.SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::DrawIndex), submit_id,
index_count, flags, type, instance_count,
reinterpret_cast<uint64_t>(index_addr));
Common::LockGuard lock(g_render_ctx->GetMutex());
Common::LockGuard lock(GetRenderContext().GetMutex());
if (index_count == 0) {
return;
}
if (ConsumeMetadataColorOperation(*ctx)) {
if (ConsumeMetadataColorOperation(buffer)) {
return;
}
@@ -1014,14 +981,14 @@ void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx
return;
}
if (ShouldSkipGeShader(ctx, ucfg, sh_ctx)) {
if (ShouldSkipGeShader(buffer)) {
return;
}
if (graphics_debug_dump_enabled()) {
sh_print("GraphicsRenderDrawIndex():Shader:", *sh_ctx);
uc_print("GraphicsRenderDrawIndex():UserConfig:", *ucfg);
hw_print(*ctx);
sh_print("GraphicsRenderDrawIndex():Shader:", sh_ctx);
uc_print("GraphicsRenderDrawIndex():UserConfig:", ucfg);
hw_print(buffer);
LOGF("GraphicsRenderDrawIndex():Parameters:\n"
"\t index_type_and_size = 0x%08" PRIx32 "\n"
@@ -1037,14 +1004,14 @@ void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx
instance_count, render_target_slice_offset, static_cast<uint32_t>(vertex_offset_add),
first_instance);
}
sh_check(*sh_ctx);
sh_check(sh_ctx);
uc_check(*ucfg);
uc_check(ucfg);
hw_check(*ctx);
hw_check(buffer);
vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList;
if (!GetDrawTopology(ucfg, false, false, &topology)) {
if (!GetDrawTopology(ucfg, false, false, topology)) {
return;
}
@@ -1099,47 +1066,46 @@ void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx
index_source.type = index_type;
DrawRenderState state {};
if (!PrepareDrawRenderState(submit_id, buffer, ctx, ucfg, sh_ctx, draw,
render_target_slice_offset, false, true, &state)) {
if (!PrepareDrawRenderState(submit_id, buffer, draw, render_target_slice_offset, false, true,
state)) {
return;
}
RefreshShaders(ctx, sh_ctx, draw, true, &state);
RefreshShaders(buffer, draw, true, state);
LogDrawStateIfNeeded(ctx, ucfg, draw, state, true, false, index_type_and_size, index_addr);
LogDrawStateIfNeeded(buffer, draw, state, true, false, index_type_and_size, index_addr);
const auto vertex_offset =
ResolveVertexOffset(ucfg->GetIndexOffset(), state.vs_input_info) + vertex_offset_add;
ResolveVertexOffset(ucfg.GetIndexOffset(), state.vs_input_info) + vertex_offset_add;
DrawEmitInfo emit {};
emit.indexed = true;
emit.vertex_offset = vertex_offset;
ExecutePreparedDraw(submit_id, buffer, ctx, ucfg, sh_ctx, draw, &state, topology, emit,
index_source, true, true, false);
ExecutePreparedDraw(submit_id, buffer, draw, state, topology, emit, index_source, true, true,
false);
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx,
HW::UserConfig* ucfg, HW::Shader* sh_ctx, uint32_t index_count,
void RenderDrawIndexAuto(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_count,
uint32_t flags, uint32_t render_target_slice_offset,
uint32_t instance_count, uint32_t first_vertex, uint32_t first_instance) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ucfg == nullptr);
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(buffer == nullptr || buffer->IsInvalid());
EXIT_IF(buffer.IsInvalid());
auto& ucfg = buffer.GetUserConfig();
auto& sh_ctx = buffer.GetShaders();
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::DrawIndexAuto), submit_id,
index_count, flags, first_vertex, instance_count, first_instance);
buffer.SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::DrawIndexAuto), submit_id,
index_count, flags, first_vertex, instance_count, first_instance);
Common::LockGuard lock(g_render_ctx->GetMutex());
Common::LockGuard lock(GetRenderContext().GetMutex());
if (index_count == 0) {
return;
}
if (ConsumeMetadataColorOperation(*ctx)) {
if (ConsumeMetadataColorOperation(buffer)) {
return;
}
@@ -1147,14 +1113,14 @@ void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context*
return;
}
if (ShouldSkipGeShader(ctx, ucfg, sh_ctx)) {
if (ShouldSkipGeShader(buffer)) {
return;
}
if (graphics_debug_dump_enabled()) {
sh_print("GraphicsRenderDrawIndexAuto():Shader:", *sh_ctx);
uc_print("GraphicsRenderDrawIndexAuto():UserConfig:", *ucfg);
hw_print(*ctx);
sh_print("GraphicsRenderDrawIndexAuto():Shader:", sh_ctx);
uc_print("GraphicsRenderDrawIndexAuto():UserConfig:", ucfg);
hw_print(buffer);
LOGF("GraphicsRenderDrawIndexAuto():Parameters:\n"
"\t index_count = 0x%08" PRIx32 "\n"
@@ -1166,11 +1132,11 @@ void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context*
index_count, flags, render_target_slice_offset, instance_count, first_vertex,
first_instance);
}
sh_check(*sh_ctx);
sh_check(sh_ctx);
uc_check(*ucfg);
uc_check(ucfg);
hw_check(*ctx);
hw_check(buffer);
EXIT_NOT_IMPLEMENTED(flags != 0);
if (instance_count == 0) {
@@ -1182,50 +1148,50 @@ void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context*
instance_count, first_instance};
DrawRenderState state {};
if (!PrepareDrawRenderState(submit_id, buffer, ctx, ucfg, sh_ctx, draw,
render_target_slice_offset, true, false, &state)) {
if (!PrepareDrawRenderState(submit_id, buffer, draw, render_target_slice_offset, true, false,
state)) {
return;
}
vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList;
const bool use_ngg_rectlist_draw = Config::NggRectlistDrawEnabled();
if (!GetDrawTopology(ucfg, true, use_ngg_rectlist_draw, &topology)) {
if (!GetDrawTopology(ucfg, true, use_ngg_rectlist_draw, topology)) {
return;
}
const bool draw_prim7_as_ngg =
(use_ngg_rectlist_draw &&
ucfg->GetPrimType() == Prospero::GpuEnumValue(Prospero::PrimitiveType::kRectList));
ucfg.GetPrimType() == Prospero::GpuEnumValue(Prospero::PrimitiveType::kRectList));
RefreshShaders(ctx, sh_ctx, draw, false, &state);
RefreshShaders(buffer, draw, false, state);
if (draw_prim7_as_ngg && state.vs_input_info.buffers_num == 0 &&
state.vs_input_info.param_export_mask == 0 && state.ps_input_info.input_num != 0) {
if (graphics_debug_dump_enabled()) {
LOGF("DrawIndexAuto: skipping rect-list draw with no VS param exports and PS inputs: "
"ps_inputs=%u ps=0x%016" PRIx64 " es=0x%016" PRIx64 " gs=0x%016" PRIx64 "\n",
state.ps_input_info.input_num, sh_ctx->GetPs().ps_regs.chksum,
sh_ctx->GetVs().es_regs.data_addr, sh_ctx->GetVs().gs_regs.data_addr);
state.ps_input_info.input_num, sh_ctx.GetPs().ps_regs.chksum,
sh_ctx.GetVs().es_regs.data_addr, sh_ctx.GetVs().gs_regs.data_addr);
}
return;
}
LogDrawStateIfNeeded(ctx, ucfg, draw, state, false,
ucfg->GetPrimType() ==
LogDrawStateIfNeeded(buffer, draw, state, false,
ucfg.GetPrimType() ==
Prospero::GpuEnumValue(Prospero::PrimitiveType::kRectListLegacy),
0, nullptr);
const uint32_t draw_vertex_count = (draw_prim7_as_ngg ? 4u : index_count);
const auto vertex_offset = ResolveVertexOffset(ucfg->GetIndexOffset(), state.vs_input_info) +
static_cast<int32_t>(first_vertex);
DrawEmitInfo emit {};
const auto vertex_offset = ResolveVertexOffset(ucfg.GetIndexOffset(), state.vs_input_info) +
static_cast<int32_t>(first_vertex);
DrawEmitInfo emit {};
emit.draw_prim7_as_ngg = draw_prim7_as_ngg;
emit.draw_vertex_count = draw_vertex_count;
emit.first_vertex = static_cast<uint32_t>(vertex_offset);
DrawIndexBufferSource index_source {};
ExecutePreparedDraw(submit_id, buffer, ctx, ucfg, sh_ctx, draw, &state, topology, emit,
index_source, false, false, true);
ExecutePreparedDraw(submit_id, buffer, draw, state, topology, emit, index_source, false, false,
true);
}
bool IsSameColorResolveSubresource(const RenderColorInfo& src, const RenderColorInfo& dst) {
@@ -1235,8 +1201,7 @@ bool IsSameColorResolveSubresource(const RenderColorInfo& src, const RenderColor
ImageImageCopy MakeColorResolveCopy(const RenderColorInfo& src, const RenderColorInfo& dst,
uint32_t width, uint32_t height) {
ImageImageCopy region {};
region.src_image = src.vulkan_buffer;
ImageImageCopy region {*src.vulkan_buffer};
region.src_level = src.base_mip_level;
region.dst_level = dst.base_mip_level;
region.width = width;
@@ -1246,8 +1211,9 @@ ImageImageCopy MakeColorResolveCopy(const RenderColorInfo& src, const RenderColo
return region;
}
static bool ResolveColorTargets(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw,
static bool ResolveColorTargets(uint64_t submit_id, RenderCommandBuffer& buffer,
uint32_t render_target_slice_offset) {
const auto& hw = buffer.GetRegisters();
if (hw.GetColorControl().mode != 3) {
return false;
}
@@ -1260,9 +1226,8 @@ static bool ResolveColorTargets(uint64_t submit_id, CommandBuffer* buffer, const
RenderColorInfo src {};
RenderColorInfo dst {};
ResolveRenderColorTarget(submit_id, buffer, hw, &src, render_target_slice_offset, 0, true,
true);
ResolveRenderColorTarget(submit_id, buffer, hw, &dst, render_target_slice_offset, 1, true);
ResolveRenderColorTarget(submit_id, buffer, src, render_target_slice_offset, 0, true, true);
ResolveRenderColorTarget(submit_id, buffer, dst, render_target_slice_offset, 1, true);
if (src.vulkan_buffer == nullptr || dst.vulkan_buffer == nullptr ||
src.type == RenderColorType::NoColorOutput || dst.type == RenderColorType::NoColorOutput) {
return false;
@@ -1280,7 +1245,7 @@ static bool ResolveColorTargets(uint64_t submit_id, CommandBuffer* buffer, const
const std::array regions {MakeColorResolveCopy(src, dst, width, height)};
MarkRenderTargetGpuWritten(dst);
Transfer::CopyImage(buffer, regions, dst.vulkan_buffer, dst.vulkan_buffer->layout);
Transfer::CopyImage(buffer, regions, *dst.vulkan_buffer, dst.vulkan_buffer->layout);
return true;
}
@@ -28,13 +28,12 @@
namespace Libs::Graphics {
void GraphicsRenderMemoryBarrier(CommandBuffer* buffer) {
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
void GraphicsRenderMemoryBarrier(CommandBuffer& buffer) {
EXIT_IF(buffer.IsInvalid());
Common::LockGuard lock(g_render_ctx->GetMutex());
Common::LockGuard lock(GetRenderContext().GetMutex());
auto vk_buffer = buffer->Handle();
auto vk_buffer = buffer.Handle();
VulkanMemoryBarrier mem_barrier {};
mem_barrier.sType = vk::StructureType::eMemoryBarrier;
@@ -47,8 +46,7 @@ void GraphicsRenderMemoryBarrier(CommandBuffer* buffer) {
&mem_barrier, 0, nullptr, 0, nullptr);
}
void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image) {
EXIT_IF(image == nullptr);
void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image) {
vk::ImageMemoryBarrier image_memory_barrier {};
image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier;
@@ -57,16 +55,16 @@ void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage* imag
vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eTransferWrite |
vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eMemoryRead;
image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
image_memory_barrier.oldLayout = image->layout;
image_memory_barrier.oldLayout = image.layout;
image_memory_barrier.newLayout = RENDER_COLOR_IMAGE_LAYOUT;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = image->image;
image_memory_barrier.image = image.image;
image_memory_barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = image->layers;
image_memory_barrier.subresourceRange.layerCount = image.layers;
vk_buffer.pipelineBarrier(
vk::PipelineStageFlagBits::eColorAttachmentOutput |
@@ -76,21 +74,19 @@ void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage* imag
vk::PipelineStageFlagBits::eComputeShader,
vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
image->layout = image_memory_barrier.newLayout;
image.layout = image_memory_barrier.newLayout;
}
void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image,
void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image,
vk::ImageLayout new_layout) {
EXIT_IF(image == nullptr);
if (image->layout != new_layout) {
if (image->type == VulkanImageType::VideoOut &&
image->layout == vk::ImageLayout::eTransferDstOptimal) {
if (image.layout != new_layout) {
if (image.type == VulkanImageType::VideoOut &&
image.layout == vk::ImageLayout::eTransferDstOptimal) {
static std::atomic<uint32_t> log_count {0};
if (log_count.fetch_add(1, std::memory_order_relaxed) < 128) {
LOGF("GraphicsRenderColorImageBarrier: image=%p type=%d layout=%s -> %s\n",
VulkanHandleToPointer(image->image), static_cast<int>(image->type),
VulkanToString(image->layout).c_str(), VulkanToString(new_layout).c_str());
VulkanHandleToPointer(image.image), static_cast<int>(image.type),
VulkanToString(image.layout).c_str(), VulkanToString(new_layout).c_str());
}
}
vk::ImageMemoryBarrier image_memory_barrier {};
@@ -100,16 +96,16 @@ void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* i
vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eMemoryRead;
image_memory_barrier.dstAccessMask =
vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eMemoryRead;
image_memory_barrier.oldLayout = image->layout;
image_memory_barrier.oldLayout = image.layout;
image_memory_barrier.newLayout = new_layout;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = image->image;
image_memory_barrier.image = image.image;
image_memory_barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = image->layers;
image_memory_barrier.subresourceRange.layerCount = image.layers;
const auto stages = static_cast<vk::PipelineStageFlags>(
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader |
@@ -117,75 +113,72 @@ void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* i
vk_buffer.pipelineBarrier(stages, stages, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1,
&image_memory_barrier);
image->layout = image_memory_barrier.newLayout;
image.layout = image_memory_barrier.newLayout;
}
}
void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image,
void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image,
vk::ImageLayout new_layout) {
EXIT_IF(image == nullptr);
EXIT_IF(image->type != VulkanImageType::DepthStencil);
EXIT_IF(image.type != VulkanImageType::DepthStencil);
if (new_layout == vk::ImageLayout::eUndefined ||
new_layout == vk::ImageLayout::ePreinitialized) {
EXIT("invalid destination depth/stencil image layout: %s\n",
VulkanToString(new_layout).c_str());
}
if (image->layout == new_layout) {
if (image.layout == new_layout) {
return;
}
vk::ImageMemoryBarrier barrier {};
barrier.sType = vk::StructureType::eImageMemoryBarrier;
barrier.srcAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite;
barrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite;
barrier.oldLayout = image->layout;
barrier.oldLayout = image.layout;
barrier.newLayout = new_layout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image->image;
barrier.subresourceRange = {ImageViewOps::DepthAspectMask(image->format), 0,
VK_REMAINING_MIP_LEVELS, 0, image->layers};
barrier.image = image.image;
barrier.subresourceRange = {ImageViewOps::DepthAspectMask(image.format), 0,
VK_REMAINING_MIP_LEVELS, 0, image.layers};
const auto stages = static_cast<vk::PipelineStageFlags>(
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader |
vk::PipelineStageFlagBits::eTransfer);
vk_buffer.pipelineBarrier(stages, stages, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1,
&barrier);
image->layout = new_layout;
image.layout = new_layout;
}
void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image) {
EXIT_IF(image == nullptr);
void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image) {
EXIT_IF(image.type != VulkanImageType::DepthStencil);
EXIT_IF(image->type != VulkanImageType::DepthStencil);
auto* depth = static_cast<DepthStencilVulkanImage*>(image);
if (depth->compressed) {
auto& depth = static_cast<DepthStencilVulkanImage&>(image);
if (depth.compressed) {
static std::atomic<uint32_t> log_count {0};
if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) {
LOGF(
"DepthTexture: decompressing depth target for shader read format=%s extent=%ux%u\n",
VulkanToString(depth->format).c_str(), depth->extent.width, depth->extent.height);
VulkanToString(depth.format).c_str(), depth.extent.width, depth.extent.height);
}
depth->compressed = false;
depth.compressed = false;
}
if (image->layout != vk::ImageLayout::eDepthStencilReadOnlyOptimal) {
if (image.layout != vk::ImageLayout::eDepthStencilReadOnlyOptimal) {
vk::ImageMemoryBarrier image_memory_barrier {};
image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier;
image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask =
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite;
image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
image_memory_barrier.oldLayout = image->layout;
image_memory_barrier.oldLayout = image.layout;
image_memory_barrier.newLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = image->image;
image_memory_barrier.image = image.image;
image_memory_barrier.subresourceRange.aspectMask =
ImageViewOps::DepthAspectMask(image->format);
ImageViewOps::DepthAspectMask(image.format);
image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = image->layers;
image_memory_barrier.subresourceRange.layerCount = image.layers;
vk_buffer.pipelineBarrier(
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader |
@@ -194,37 +187,35 @@ void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage*
vk::PipelineStageFlagBits::eComputeShader,
vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
image->layout = image_memory_barrier.newLayout;
image.layout = image_memory_barrier.newLayout;
}
}
void GraphicsRenderTextureBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size) {
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
void GraphicsRenderTextureBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size) {
EXIT_IF(buffer.IsInvalid());
Common::LockGuard lock(g_render_ctx->GetMutex());
Common::LockGuard lock(GetRenderContext().GetMutex());
auto vk_buffer = buffer->Handle();
auto vk_buffer = buffer.Handle();
auto* native = g_render_ctx->GetTextureCache()->FindRenderTargetByRange(buffer, vaddr, size);
auto* native = GetRenderContext().GetTextureCache().FindRenderTargetByRange(buffer, vaddr, size);
if (native == nullptr) {
EXIT("render-target barrier range has no cached image\n");
}
GraphicsRenderTextureBarrier(vk_buffer, native);
GraphicsRenderTextureBarrier(vk_buffer, *native);
}
void GraphicsRenderDepthStencilBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size) {
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
void GraphicsRenderDepthStencilBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size) {
EXIT_IF(buffer.IsInvalid());
Common::LockGuard lock(g_render_ctx->GetMutex());
Common::LockGuard lock(GetRenderContext().GetMutex());
auto vk_buffer = buffer->Handle();
auto* native = g_render_ctx->GetTextureCache()->FindDepthTargetByRange(buffer, vaddr, size);
auto vk_buffer = buffer.Handle();
auto* native = GetRenderContext().GetTextureCache().FindDepthTargetByRange(buffer, vaddr, size);
if (native == nullptr) {
EXIT("depth-target barrier range has no cached image\n");
}
GraphicsRenderDepthStencilBarrier(vk_buffer, native);
GraphicsRenderDepthStencilBarrier(vk_buffer, *native);
}
} // namespace Libs::Graphics
@@ -7,12 +7,12 @@ namespace Libs::Graphics {
struct VulkanImage;
void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image);
void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image,
void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image);
void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image,
vk::ImageLayout new_layout);
void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image,
void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image,
vk::ImageLayout new_layout);
void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image);
void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image);
} // namespace Libs::Graphics
@@ -143,8 +143,7 @@ vk::Sampler SamplerCache::GetSampler(const ShaderSamplerResource& r) {
}
vk::Sampler vk_sampler = nullptr;
const auto result =
g_render_ctx->GetGraphicCtx()->device.createSampler(&sampler_info, nullptr, &vk_sampler);
const auto result = m_graphics.device.createSampler(&sampler_info, nullptr, &vk_sampler);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || vk_sampler == nullptr);
m_samplers.emplace(key, vk_sampler);
@@ -14,9 +14,13 @@
namespace Libs::Graphics {
struct GraphicContext;
class SamplerCache {
public:
SamplerCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
explicit SamplerCache(GraphicContext& graphics): m_graphics(graphics) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
}
~SamplerCache() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(SamplerCache);
@@ -37,6 +41,7 @@ private:
}
};
GraphicContext& m_graphics;
Common::Mutex m_mutex;
std::unordered_map<SamplerKey, vk::Sampler, SamplerKeyHash> m_samplers;
};
@@ -4,8 +4,13 @@
namespace Libs::Graphics {
ShaderLaneMaskMode SelectGraphicsLaneMaskMode(const GraphicContext& context,
uint32_t guest_wave_size) {
ShaderSubgroupCapabilities::ShaderSubgroupCapabilities(const GraphicContext& graphics)
: subgroup_size(graphics.subgroup_size), min_subgroup_size(graphics.min_subgroup_size),
max_subgroup_size(graphics.max_subgroup_size),
required_subgroup_size_stages(graphics.required_subgroup_size_stages),
subgroup_size_control_enabled(graphics.subgroup_size_control_enabled) {}
ShaderLaneMaskMode SelectGraphicsLaneMaskMode(uint32_t guest_wave_size) {
// A 64-wide guest wave can't assume the host GPU's lane layout matches
// GCN's. AMD RDNA also reports a 64-wide subgroup but uses a different
// lane/pixel layout, which corrupted rendering under "native wave" mode.
@@ -16,16 +21,16 @@ ShaderLaneMaskMode SelectGraphicsLaneMaskMode(const GraphicContext& context,
return ShaderLaneMaskMode::NativeWave;
}
ShaderSubgroupConfiguration ConfigureShaderSubgroup(const GraphicContext& context,
vk::ShaderStageFlagBits stage,
ShaderSubgroupConfiguration ConfigureShaderSubgroup(const ShaderSubgroupCapabilities& capabilities,
vk::ShaderStageFlagBits stage,
const ShaderRecompiler::IR::Program& program) {
const auto guest_wave_size = program.wave_size;
if (guest_wave_size != 32u && guest_wave_size != 64u) {
return {};
}
if (stage != vk::ShaderStageFlagBits::eCompute) {
const auto expected = SelectGraphicsLaneMaskMode(context, guest_wave_size);
if (program.lane_mask_mode != expected || (context.subgroup_size != guest_wave_size &&
const auto expected = SelectGraphicsLaneMaskMode(guest_wave_size);
if (program.lane_mask_mode != expected || (capabilities.subgroup_size != guest_wave_size &&
expected != ShaderLaneMaskMode::PerInvocation)) {
return {};
}
@@ -37,12 +42,13 @@ ShaderSubgroupConfiguration ConfigureShaderSubgroup(const GraphicContext&
if (program.lane_mask_mode != ShaderLaneMaskMode::NativeWave) {
return {};
}
if (context.subgroup_size == guest_wave_size) {
if (capabilities.subgroup_size == guest_wave_size) {
return {ShaderSubgroupMode::Natural, 0};
}
if (context.subgroup_size_control_enabled && (context.required_subgroup_size_stages & stage) &&
guest_wave_size >= context.min_subgroup_size &&
guest_wave_size <= context.max_subgroup_size) {
if (capabilities.subgroup_size_control_enabled &&
(capabilities.required_subgroup_size_stages & stage) &&
guest_wave_size >= capabilities.min_subgroup_size &&
guest_wave_size <= capabilities.max_subgroup_size) {
return {ShaderSubgroupMode::Controlled, guest_wave_size};
}
if (!ShaderRecompiler::Spirv::ProgramRequiresExactSubgroupSize(program)) {
@@ -19,11 +19,20 @@ struct ShaderSubgroupConfiguration {
uint32_t required_size = 0;
};
ShaderLaneMaskMode SelectGraphicsLaneMaskMode(const GraphicContext& context,
uint32_t guest_wave_size);
struct ShaderSubgroupCapabilities {
explicit ShaderSubgroupCapabilities(const GraphicContext& graphics);
ShaderSubgroupConfiguration ConfigureShaderSubgroup(const GraphicContext& context,
vk::ShaderStageFlagBits stage,
uint32_t subgroup_size = 0;
uint32_t min_subgroup_size = 0;
uint32_t max_subgroup_size = 0;
vk::ShaderStageFlags required_subgroup_size_stages;
bool subgroup_size_control_enabled = false;
};
ShaderLaneMaskMode SelectGraphicsLaneMaskMode(uint32_t guest_wave_size);
ShaderSubgroupConfiguration ConfigureShaderSubgroup(const ShaderSubgroupCapabilities& capabilities,
vk::ShaderStageFlagBits stage,
const ShaderRecompiler::IR::Program& program);
} // namespace Libs::Graphics
+227 -246
View File
@@ -25,62 +25,59 @@ namespace Libs::Graphics {
// IDK: maybe we can remove it?
constexpr uint32_t kTemporaryPs5BufferFormat121 = 121u;
static bool NarrowInputFormat(vk::Format* format, uint32_t* size, uint32_t used_components) {
EXIT_IF(format == nullptr);
EXIT_IF(size == nullptr);
if (used_components == 0 || used_components >= *size) {
static bool NarrowInputFormat(vk::Format& format, uint32_t& size, uint32_t used_components) {
if (used_components == 0 || used_components >= size) {
return false;
}
switch (*format) {
switch (format) {
case vk::Format::eR32G32B32A32Sfloat:
switch (used_components) {
case 1: *format = vk::Format::eR32Sfloat; break;
case 2: *format = vk::Format::eR32G32Sfloat; break;
case 3: *format = vk::Format::eR32G32B32Sfloat; break;
case 1: format = vk::Format::eR32Sfloat; break;
case 2: format = vk::Format::eR32G32Sfloat; break;
case 3: format = vk::Format::eR32G32B32Sfloat; break;
default: return false;
}
*size = used_components;
size = used_components;
return true;
case vk::Format::eR32G32B32Sfloat:
switch (used_components) {
case 1: *format = vk::Format::eR32Sfloat; break;
case 2: *format = vk::Format::eR32G32Sfloat; break;
case 1: format = vk::Format::eR32Sfloat; break;
case 2: format = vk::Format::eR32G32Sfloat; break;
default: return false;
}
*size = used_components;
size = used_components;
return true;
case vk::Format::eR16G16B16A16Sfloat:
switch (used_components) {
case 1: *format = vk::Format::eR16Sfloat; break;
case 2: *format = vk::Format::eR16G16Sfloat; break;
case 1: format = vk::Format::eR16Sfloat; break;
case 2: format = vk::Format::eR16G16Sfloat; break;
default: return false;
}
*size = used_components;
size = used_components;
return true;
case vk::Format::eR8G8B8A8Unorm:
switch (used_components) {
case 1: *format = vk::Format::eR8Unorm; break;
case 2: *format = vk::Format::eR8G8Unorm; break;
case 1: format = vk::Format::eR8Unorm; break;
case 2: format = vk::Format::eR8G8Unorm; break;
default: return false;
}
*size = used_components;
size = used_components;
return true;
case vk::Format::eR8G8B8A8Snorm:
if (used_components != 2) {
return false;
}
*format = vk::Format::eR8G8Snorm;
*size = 2;
format = vk::Format::eR8G8Snorm;
size = 2;
return true;
case vk::Format::eR8G8B8A8Uint:
switch (used_components) {
case 1: *format = vk::Format::eR8Uint; break;
case 2: *format = vk::Format::eR8G8Uint; break;
case 1: format = vk::Format::eR8Uint; break;
case 2: format = vk::Format::eR8G8Uint; break;
default: return false;
}
*size = used_components;
size = used_components;
return true;
default: break;
}
@@ -88,11 +85,8 @@ static bool NarrowInputFormat(vk::Format* format, uint32_t* size, uint32_t used_
return false;
}
static void GetInputFormat(const ShaderBufferResource& res, vk::Format* format, uint32_t* size,
static void GetInputFormat(const ShaderBufferResource& res, vk::Format& format, uint32_t& size,
uint32_t used_components) {
EXIT_IF(format == nullptr);
EXIT_IF(size == nullptr);
auto fmt = res.Format();
if (fmt == Prospero::GpuEnumValue(Prospero::VertexAttribFormat::k16_16SInt)) {
static bool logged_113 = false;
@@ -101,11 +95,11 @@ static void GetInputFormat(const ShaderBufferResource& res, vk::Format* format,
"vk::Format::eR32G32B32A32Sfloat\n");
logged_113 = true;
}
*format = vk::Format::eR32G32B32A32Sfloat;
*size = 4;
format = vk::Format::eR32G32B32A32Sfloat;
size = 4;
if (NarrowInputFormat(format, size, used_components)) {
LOGF("InputFormat: narrowing fmt=%u to %s for used_components=%u\n", fmt,
VulkanToString(*format).c_str(), used_components);
VulkanToString(format).c_str(), used_components);
}
return;
}
@@ -115,228 +109,228 @@ static void GetInputFormat(const ShaderBufferResource& res, vk::Format* format,
LOGF("InputFormat: accepting PS5 buffer format 121 as vk::Format::eR16G16Sfloat\n");
logged_121 = true;
}
*format = vk::Format::eR16G16Sfloat;
*size = 2;
format = vk::Format::eR16G16Sfloat;
size = 2;
if (NarrowInputFormat(format, size, used_components)) {
LOGF("InputFormat: narrowing fmt=%u to %s for used_components=%u\n", fmt,
VulkanToString(*format).c_str(), used_components);
VulkanToString(format).c_str(), used_components);
}
return;
}
switch (static_cast<Prospero::BufferFormat>(fmt)) {
case Prospero::BufferFormat::k32_32_32_32Float:
*format = vk::Format::eR32G32B32A32Sfloat;
*size = 4;
format = vk::Format::eR32G32B32A32Sfloat;
size = 4;
break;
case Prospero::BufferFormat::k32_32_32_32SInt:
*format = vk::Format::eR32G32B32A32Sint;
*size = 4;
format = vk::Format::eR32G32B32A32Sint;
size = 4;
break;
case Prospero::BufferFormat::k32_32_32_32UInt:
*format = vk::Format::eR32G32B32A32Uint;
*size = 4;
format = vk::Format::eR32G32B32A32Uint;
size = 4;
break;
case Prospero::BufferFormat::k32_32_32Float:
*format = vk::Format::eR32G32B32Sfloat;
*size = 3;
format = vk::Format::eR32G32B32Sfloat;
size = 3;
break;
case Prospero::BufferFormat::k32_32_32SInt:
*format = vk::Format::eR32G32B32Sint;
*size = 3;
format = vk::Format::eR32G32B32Sint;
size = 3;
break;
case Prospero::BufferFormat::k32_32_32UInt:
*format = vk::Format::eR32G32B32Uint;
*size = 3;
format = vk::Format::eR32G32B32Uint;
size = 3;
break;
case Prospero::BufferFormat::k16_16_16_16Float:
*format = vk::Format::eR16G16B16A16Sfloat;
*size = 4;
format = vk::Format::eR16G16B16A16Sfloat;
size = 4;
break;
case Prospero::BufferFormat::k16_16_16_16SInt:
*format = vk::Format::eR16G16B16A16Sint;
*size = 4;
format = vk::Format::eR16G16B16A16Sint;
size = 4;
break;
case Prospero::BufferFormat::k16_16_16_16UInt:
*format = vk::Format::eR16G16B16A16Uint;
*size = 4;
format = vk::Format::eR16G16B16A16Uint;
size = 4;
break;
case Prospero::BufferFormat::k16_16_16_16SScaled:
*format = vk::Format::eR16G16B16A16Sscaled;
*size = 4;
format = vk::Format::eR16G16B16A16Sscaled;
size = 4;
break;
case Prospero::BufferFormat::k16_16_16_16UScaled:
*format = vk::Format::eR16G16B16A16Uscaled;
*size = 4;
format = vk::Format::eR16G16B16A16Uscaled;
size = 4;
break;
case Prospero::BufferFormat::k16_16_16_16SNorm:
*format = vk::Format::eR16G16B16A16Snorm;
*size = 4;
format = vk::Format::eR16G16B16A16Snorm;
size = 4;
break;
case Prospero::BufferFormat::k16_16_16_16UNorm:
*format = vk::Format::eR16G16B16A16Unorm;
*size = 4;
format = vk::Format::eR16G16B16A16Unorm;
size = 4;
break;
case Prospero::BufferFormat::k32_32Float:
*format = vk::Format::eR32G32Sfloat;
*size = 2;
format = vk::Format::eR32G32Sfloat;
size = 2;
break;
case Prospero::BufferFormat::k32_32SInt:
*format = vk::Format::eR32G32Sint;
*size = 2;
format = vk::Format::eR32G32Sint;
size = 2;
break;
case Prospero::BufferFormat::k32_32UInt:
*format = vk::Format::eR32G32Uint;
*size = 2;
format = vk::Format::eR32G32Uint;
size = 2;
break;
case Prospero::BufferFormat::k8_8_8_8UInt:
*format = vk::Format::eR8G8B8A8Uint;
*size = 4;
format = vk::Format::eR8G8B8A8Uint;
size = 4;
break;
case Prospero::BufferFormat::k8_8_8_8SScaled:
*format = vk::Format::eR8G8B8A8Sscaled;
*size = 4;
format = vk::Format::eR8G8B8A8Sscaled;
size = 4;
break;
case Prospero::BufferFormat::k8_8_8_8UScaled:
*format = vk::Format::eR8G8B8A8Uscaled;
*size = 4;
format = vk::Format::eR8G8B8A8Uscaled;
size = 4;
break;
case Prospero::BufferFormat::k8_8_8_8SNorm:
*format = vk::Format::eR8G8B8A8Snorm;
*size = 4;
format = vk::Format::eR8G8B8A8Snorm;
size = 4;
break;
case Prospero::BufferFormat::k8_8_8_8UNorm:
*format = vk::Format::eR8G8B8A8Unorm;
*size = 4;
format = vk::Format::eR8G8B8A8Unorm;
size = 4;
break;
case Prospero::BufferFormat::k10_10_10_2UNorm:
*format = vk::Format::eA2B10G10R10UnormPack32;
*size = 4;
format = vk::Format::eA2B10G10R10UnormPack32;
size = 4;
break;
case Prospero::BufferFormat::k10_10_10_2SNorm:
*format = vk::Format::eA2B10G10R10SnormPack32;
*size = 4;
format = vk::Format::eA2B10G10R10SnormPack32;
size = 4;
break;
case Prospero::BufferFormat::k16_16Float:
*format = vk::Format::eR16G16Sfloat;
*size = 2;
format = vk::Format::eR16G16Sfloat;
size = 2;
break;
case Prospero::BufferFormat::k16_16SInt:
*format = vk::Format::eR16G16Sint;
*size = 2;
format = vk::Format::eR16G16Sint;
size = 2;
break;
case Prospero::BufferFormat::k16_16UInt:
*format = vk::Format::eR16G16Uint;
*size = 2;
format = vk::Format::eR16G16Uint;
size = 2;
break;
case Prospero::BufferFormat::k16_16SScaled:
*format = vk::Format::eR16G16Sscaled;
*size = 2;
format = vk::Format::eR16G16Sscaled;
size = 2;
break;
case Prospero::BufferFormat::k16_16UScaled:
*format = vk::Format::eR16G16Uscaled;
*size = 2;
format = vk::Format::eR16G16Uscaled;
size = 2;
break;
case Prospero::BufferFormat::k16_16SNorm:
*format = vk::Format::eR16G16Snorm;
*size = 2;
format = vk::Format::eR16G16Snorm;
size = 2;
break;
case Prospero::BufferFormat::k16_16UNorm:
*format = vk::Format::eR16G16Unorm;
*size = 2;
format = vk::Format::eR16G16Unorm;
size = 2;
break;
case Prospero::BufferFormat::k32Float:
*format = vk::Format::eR32Sfloat;
*size = 1;
format = vk::Format::eR32Sfloat;
size = 1;
break;
case Prospero::BufferFormat::k32SInt:
*format = vk::Format::eR32Sint;
*size = 1;
format = vk::Format::eR32Sint;
size = 1;
break;
case Prospero::BufferFormat::k32UInt:
*format = vk::Format::eR32Uint;
*size = 1;
format = vk::Format::eR32Uint;
size = 1;
break;
case Prospero::BufferFormat::k8_8SInt:
*format = vk::Format::eR8G8Sint;
*size = 2;
format = vk::Format::eR8G8Sint;
size = 2;
break;
case Prospero::BufferFormat::k8_8UInt:
*format = vk::Format::eR8G8Uint;
*size = 2;
format = vk::Format::eR8G8Uint;
size = 2;
break;
case Prospero::BufferFormat::k8_8SScaled:
*format = vk::Format::eR8G8Sscaled;
*size = 2;
format = vk::Format::eR8G8Sscaled;
size = 2;
break;
case Prospero::BufferFormat::k8_8UScaled:
*format = vk::Format::eR8G8Uscaled;
*size = 2;
format = vk::Format::eR8G8Uscaled;
size = 2;
break;
case Prospero::BufferFormat::k8_8SNorm:
*format = vk::Format::eR8G8Snorm;
*size = 2;
format = vk::Format::eR8G8Snorm;
size = 2;
break;
case Prospero::BufferFormat::k8_8UNorm:
*format = vk::Format::eR8G8Unorm;
*size = 2;
format = vk::Format::eR8G8Unorm;
size = 2;
break;
case Prospero::BufferFormat::k16Float:
*format = vk::Format::eR16Sfloat;
*size = 1;
format = vk::Format::eR16Sfloat;
size = 1;
break;
case Prospero::BufferFormat::k16SInt:
*format = vk::Format::eR16Sint;
*size = 1;
format = vk::Format::eR16Sint;
size = 1;
break;
case Prospero::BufferFormat::k16UInt:
*format = vk::Format::eR16Uint;
*size = 1;
format = vk::Format::eR16Uint;
size = 1;
break;
case Prospero::BufferFormat::k16SScaled:
*format = vk::Format::eR16Sscaled;
*size = 1;
format = vk::Format::eR16Sscaled;
size = 1;
break;
case Prospero::BufferFormat::k16UScaled:
*format = vk::Format::eR16Uscaled;
*size = 1;
format = vk::Format::eR16Uscaled;
size = 1;
break;
case Prospero::BufferFormat::k16SNorm:
*format = vk::Format::eR16Snorm;
*size = 1;
format = vk::Format::eR16Snorm;
size = 1;
break;
case Prospero::BufferFormat::k16UNorm:
*format = vk::Format::eR16Unorm;
*size = 1;
format = vk::Format::eR16Unorm;
size = 1;
break;
case Prospero::BufferFormat::k8SInt:
*format = vk::Format::eR8Sint;
*size = 1;
format = vk::Format::eR8Sint;
size = 1;
break;
case Prospero::BufferFormat::k8UInt:
*format = vk::Format::eR8Uint;
*size = 1;
format = vk::Format::eR8Uint;
size = 1;
break;
case Prospero::BufferFormat::k8SScaled:
*format = vk::Format::eR8Sscaled;
*size = 1;
format = vk::Format::eR8Sscaled;
size = 1;
break;
case Prospero::BufferFormat::k8UScaled:
*format = vk::Format::eR8Uscaled;
*size = 1;
format = vk::Format::eR8Uscaled;
size = 1;
break;
case Prospero::BufferFormat::k8SNorm:
*format = vk::Format::eR8Snorm;
*size = 1;
format = vk::Format::eR8Snorm;
size = 1;
break;
case Prospero::BufferFormat::k8UNorm:
*format = vk::Format::eR8Unorm;
*size = 1;
format = vk::Format::eR8Unorm;
size = 1;
break;
default:
EXIT("unknown format: fmt = %u\n", fmt);
*format = vk::Format::eUndefined;
*size = 4;
format = vk::Format::eUndefined;
size = 4;
break;
}
@@ -391,43 +385,39 @@ static vk::BlendOp GetBlendOp(uint32_t op) {
return vk::BlendOp::eAdd;
}
static void CreateLayout(vk::DescriptorSetLayout* set_layouts, uint32_t* set_layouts_num,
vk::PushConstantRange* push_constant_info,
uint32_t* push_constant_info_num,
static void CreateLayout(std::span<vk::DescriptorSetLayout> set_layouts, uint32_t& set_layouts_num,
std::span<vk::PushConstantRange> push_constant_info,
uint32_t& push_constant_info_num,
const ShaderRecompiler::IR::Program& program,
vk::ShaderStageFlags vk_stage, DescriptorCache::Stage stage) {
EXIT_IF(set_layouts == nullptr);
EXIT_IF(set_layouts_num == nullptr);
EXIT_IF(push_constant_info == nullptr);
EXIT_IF(push_constant_info_num == nullptr);
const auto& bindings = program.bindings;
const bool need_descriptor = !bindings.descriptors.empty();
if (bindings.push_constant_size != 0) {
auto index = *push_constant_info_num;
auto index = push_constant_info_num;
push_constant_info[index].stageFlags = vk_stage;
push_constant_info[index].offset = bindings.push_constant_offset;
push_constant_info[index].size = bindings.push_constant_size;
(*push_constant_info_num)++;
push_constant_info_num++;
}
if (need_descriptor) {
EXIT_IF(bindings.descriptor_set != *set_layouts_num);
EXIT_IF(bindings.descriptor_set != set_layouts_num);
set_layouts[*set_layouts_num] =
g_render_ctx->GetDescriptorCache()->GetDescriptorSetLayout(stage, program);
(*set_layouts_num)++;
set_layouts[set_layouts_num] =
GetRenderContext().GetDescriptorCache().GetDescriptorSetLayout(stage, program);
set_layouts_num++;
}
}
static void ConfigureSubgroupSize(const GraphicContext* gctx, vk::ShaderStageFlagBits vk_stage,
static void ConfigureSubgroupSize(vk::ShaderStageFlagBits vk_stage,
const ShaderRecompiler::IR::Program& program,
vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo* required,
vk::PipelineShaderStageCreateInfo* stage) {
EXIT_IF(gctx == nullptr || required == nullptr || stage == nullptr);
const auto config = ConfigureShaderSubgroup(*gctx, vk_stage, program);
vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo& required,
vk::PipelineShaderStageCreateInfo& stage) {
const auto& graphics = GetRenderContext().GetGraphics();
const auto config =
ConfigureShaderSubgroup(ShaderSubgroupCapabilities {graphics}, vk_stage, program);
switch (config.mode) {
case ShaderSubgroupMode::Natural: return;
case ShaderSubgroupMode::PerInvocationGraphics: {
@@ -453,33 +443,30 @@ static void ConfigureSubgroupSize(const GraphicContext* gctx, vk::ShaderStageFla
default:
EXIT("Vulkan cannot run %u-lane shader stage 0x%08x: default=%u min=%u max=%u "
"controlled_stages=0x%08x\n",
program.wave_size, static_cast<uint32_t>(vk_stage), gctx->subgroup_size,
gctx->min_subgroup_size, gctx->max_subgroup_size,
static_cast<vk::ShaderStageFlags::MaskType>(gctx->required_subgroup_size_stages));
program.wave_size, static_cast<uint32_t>(vk_stage), graphics.subgroup_size,
graphics.min_subgroup_size, graphics.max_subgroup_size,
static_cast<vk::ShaderStageFlags::MaskType>(
graphics.required_subgroup_size_stages));
}
required->sType = vk::StructureType::ePipelineShaderStageRequiredSubgroupSizeCreateInfo;
required->requiredSubgroupSize = config.required_size;
stage->pNext = required;
required.sType = vk::StructureType::ePipelineShaderStageRequiredSubgroupSizeCreateInfo;
required.requiredSubgroupSize = config.required_size;
stage.pNext = &required;
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::RenderPass render_pass,
const ShaderVertexInputInfo* vs_input_info,
void CreatePipelineInternal(PipelineCache::GraphicsPipeline& pipeline, vk::RenderPass render_pass,
const ShaderVertexInputInfo& vs_input_info,
std::span<const uint32_t> vs_shader,
const ShaderPixelInputInfo* ps_input_info,
std::span<const uint32_t> ps_shader,
const PipelineStaticParameters& static_params, uint32_t vs_hash0,
uint32_t vs_crc32, uint32_t ps_hash0, uint32_t ps_crc32,
bool ps_active) {
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(pipeline == nullptr);
EXIT_IF(render_pass == nullptr);
EXIT_IF(ps_active && ps_input_info == nullptr);
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
auto& graphics = GetRenderContext().GetGraphics();
vk::ShaderModule vert_shader_module = nullptr;
vk::ShaderModule frag_shader_module = nullptr;
@@ -492,7 +479,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
create_info.codeSize = vs_shader.size() * 4;
create_info.pCode = vs_shader.data();
auto result = gctx->device.createShaderModule(&create_info, nullptr, &vert_shader_module);
auto result = graphics.device.createShaderModule(&create_info, nullptr, &vert_shader_module);
if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreateShaderModule VS done result=%s module=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(vert_shader_module));
@@ -502,7 +489,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
if (ps_active) {
create_info.codeSize = ps_shader.size() * 4;
create_info.pCode = ps_shader.data();
result = gctx->device.createShaderModule(&create_info, nullptr, &frag_shader_module);
result = graphics.device.createShaderModule(&create_info, nullptr, &frag_shader_module);
if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreateShaderModule PS done result=%s module=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(frag_shader_module));
@@ -523,9 +510,9 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
vert_shader_stage_info.module = vert_shader_module;
vert_shader_stage_info.pName = "main";
vert_shader_stage_info.pSpecializationInfo = nullptr;
EXIT_IF(!vs_input_info->stage);
ConfigureSubgroupSize(gctx, vk::ShaderStageFlagBits::eVertex, *vs_input_info->stage.program,
&vert_subgroup_size, &vert_shader_stage_info);
EXIT_IF(!vs_input_info.stage);
ConfigureSubgroupSize(vk::ShaderStageFlagBits::eVertex, *vs_input_info.stage.program,
vert_subgroup_size, vert_shader_stage_info);
vk::PipelineShaderStageCreateInfo frag_shader_stage_info {};
vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo frag_subgroup_size {};
@@ -538,9 +525,8 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
frag_shader_stage_info.pSpecializationInfo = nullptr;
if (ps_active) {
EXIT_IF(!ps_input_info->stage);
ConfigureSubgroupSize(gctx, vk::ShaderStageFlagBits::eFragment,
*ps_input_info->stage.program, &frag_subgroup_size,
&frag_shader_stage_info);
ConfigureSubgroupSize(vk::ShaderStageFlagBits::eFragment, *ps_input_info->stage.program,
frag_subgroup_size, frag_shader_stage_info);
}
vk::PipelineShaderStageCreateInfo shader_stages[] = {vert_shader_stage_info,
@@ -550,8 +536,8 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
vk::VertexInputAttributeDescription input_attr[ShaderVertexInputInfo::RES_MAX];
vk::VertexInputBindingDescription input_desc[ShaderVertexInputInfo::RES_MAX];
for (int bi = 0; bi < vs_input_info->buffers_num; bi++) {
const auto& b = vs_input_info->buffers[bi];
for (int bi = 0; bi < vs_input_info.buffers_num; bi++) {
const auto& b = vs_input_info.buffers[bi];
input_desc[bi].binding = bi;
input_desc[bi].stride = b.stride;
input_desc[bi].inputRate =
@@ -564,11 +550,11 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
input_attr[index].offset = b.attr_offsets[ai];
uint32_t attr_size = 4;
auto registers_num = vs_input_info->resources_dst[index].registers_num;
auto used_components = (vs_input_info->resource_fetch_components[index] > 0
? vs_input_info->resource_fetch_components[index]
auto registers_num = vs_input_info.resources_dst[index].registers_num;
auto used_components = (vs_input_info.resource_fetch_components[index] > 0
? vs_input_info.resource_fetch_components[index]
: registers_num);
GetInputFormat(vs_input_info->resources[index], &input_attr[index].format, &attr_size,
GetInputFormat(vs_input_info.resources[index], input_attr[index].format, attr_size,
static_cast<uint32_t>(used_components));
if (graphics_debug_dump_enabled()) {
@@ -580,29 +566,29 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
" fetched_components=%u attr_size=%u swizzle=%u,%u,%u,%u\n",
log_id, index, input_attr[index].binding, input_attr[index].offset,
input_desc[bi].stride, static_cast<int>(input_attr[index].format),
static_cast<uint32_t>(vs_input_info->resources[index].Format()),
static_cast<uint32_t>(vs_input_info->resources_dst[index].register_start),
static_cast<uint32_t>(vs_input_info.resources[index].Format()),
static_cast<uint32_t>(vs_input_info.resources_dst[index].register_start),
static_cast<uint32_t>(registers_num),
static_cast<uint32_t>(used_components), attr_size,
static_cast<uint32_t>(vs_input_info->resources[index].DstSelX()),
static_cast<uint32_t>(vs_input_info->resources[index].DstSelY()),
static_cast<uint32_t>(vs_input_info->resources[index].DstSelZ()),
static_cast<uint32_t>(vs_input_info->resources[index].DstSelW()));
static_cast<uint32_t>(vs_input_info.resources[index].DstSelX()),
static_cast<uint32_t>(vs_input_info.resources[index].DstSelY()),
static_cast<uint32_t>(vs_input_info.resources[index].DstSelZ()),
static_cast<uint32_t>(vs_input_info.resources[index].DstSelW()));
}
}
if (vs_input_info->resources[index].OutOfBounds() != 0) {
if (vs_input_info.resources[index].OutOfBounds() != 0) {
static bool logged = false;
if (!logged) {
LOGF("VertexInput: temporary: accepting PS5 out-of-bounds behavior %" PRIu8
"\n",
vs_input_info->resources[index].OutOfBounds());
vs_input_info.resources[index].OutOfBounds());
logged = true;
}
}
EXIT_NOT_IMPLEMENTED(vs_input_info->resources[index].AddTid());
EXIT_NOT_IMPLEMENTED(vs_input_info->resources[index].SwizzleEnabled());
EXIT_NOT_IMPLEMENTED(vs_input_info.resources[index].AddTid());
EXIT_NOT_IMPLEMENTED(vs_input_info.resources[index].SwizzleEnabled());
auto log_unsupported_vertex_swizzle = [index, attr_size, registers_num](
uint32_t swizzle, uint32_t expected) {
@@ -619,14 +605,14 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
switch (registers_num) {
case 1: {
auto swizzle = vs_input_info->resources[index].DstSelX();
auto swizzle = vs_input_info.resources[index].DstSelX();
if (swizzle != DstSel(4)) {
log_unsupported_vertex_swizzle(swizzle, DstSel(4));
}
break;
}
case 2: {
auto swizzle = vs_input_info->resources[index].DstSelXY();
auto swizzle = vs_input_info.resources[index].DstSelXY();
auto expected = (attr_size == 1 ? DstSel(4, 0) : DstSel(4, 5));
if (swizzle != expected) {
log_unsupported_vertex_swizzle(swizzle, expected);
@@ -634,7 +620,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
break;
}
case 3: {
auto swizzle = vs_input_info->resources[index].DstSelXYZ();
auto swizzle = vs_input_info.resources[index].DstSelXYZ();
auto expected =
(attr_size == 1 ? DstSel(4, 0, 0)
: (attr_size == 2 ? DstSel(4, 5, 0) : DstSel(4, 5, 6)));
@@ -644,7 +630,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
break;
}
case 4: {
auto swizzle = vs_input_info->resources[index].DstSelXYZW();
auto swizzle = vs_input_info.resources[index].DstSelXYZW();
auto expected = DstSel(4, 5, 6, 7);
bool supported = false;
switch (attr_size) {
@@ -679,9 +665,9 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
vertex_input_info.sType = vk::StructureType::ePipelineVertexInputStateCreateInfo;
vertex_input_info.pNext = nullptr;
vertex_input_info.flags = {};
vertex_input_info.vertexBindingDescriptionCount = vs_input_info->buffers_num;
vertex_input_info.vertexBindingDescriptionCount = vs_input_info.buffers_num;
vertex_input_info.pVertexBindingDescriptions = input_desc;
vertex_input_info.vertexAttributeDescriptionCount = vs_input_info->resources_num;
vertex_input_info.vertexAttributeDescriptionCount = vs_input_info.resources_num;
vertex_input_info.pVertexAttributeDescriptions = input_attr;
vk::PipelineInputAssemblyStateCreateInfo input_assembly {};
@@ -833,13 +819,13 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
vk::PushConstantRange push_constant_info[2];
uint32_t push_constant_info_num = 0;
EXIT_IF(!vs_input_info->stage);
CreateLayout(set_layouts, &set_layouts_num, push_constant_info, &push_constant_info_num,
*vs_input_info->stage.program, vk::ShaderStageFlagBits::eVertex,
EXIT_IF(!vs_input_info.stage);
CreateLayout(set_layouts, set_layouts_num, push_constant_info, push_constant_info_num,
*vs_input_info.stage.program, vk::ShaderStageFlagBits::eVertex,
DescriptorCache::Stage::Vertex);
if (ps_active) {
EXIT_IF(!ps_input_info->stage);
CreateLayout(set_layouts, &set_layouts_num, push_constant_info, &push_constant_info_num,
CreateLayout(set_layouts, set_layouts_num, push_constant_info, push_constant_info_num,
*ps_input_info->stage.program, vk::ShaderStageFlagBits::eFragment,
DescriptorCache::Stage::Pixel);
}
@@ -854,7 +840,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
pipeline_layout_info.pPushConstantRanges =
push_constant_info_num > 0 ? push_constant_info : nullptr;
EXIT_IF(pipeline->pipeline_layout != nullptr);
EXIT_IF(pipeline.pipeline_layout != nullptr);
if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreatePipelineLayout begin VS=0x%08" PRIx32 "/0x%08" PRIx32
@@ -862,15 +848,15 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
"\n",
vs_hash0, vs_crc32, ps_hash0, ps_crc32, set_layouts_num, push_constant_info_num);
}
result = gctx->device.createPipelineLayout(&pipeline_layout_info, nullptr,
&pipeline->pipeline_layout);
result = graphics.device.createPipelineLayout(&pipeline_layout_info, nullptr,
&pipeline.pipeline_layout);
if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreatePipelineLayout done result=%s layout=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(pipeline->pipeline_layout));
VulkanToString(result).c_str(), static_cast<void*>(pipeline.pipeline_layout));
}
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
EXIT_NOT_IMPLEMENTED(pipeline->pipeline_layout == nullptr);
EXIT_NOT_IMPLEMENTED(pipeline.pipeline_layout == nullptr);
vk::PipelineDepthStencilStateCreateInfo depth_stencil_info {};
depth_stencil_info.sType = vk::StructureType::ePipelineDepthStencilStateCreateInfo;
@@ -927,13 +913,13 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
pipeline_info.pDepthStencilState = (static_params.with_depth ? &depth_stencil_info : nullptr);
pipeline_info.pColorBlendState = &color_blending;
pipeline_info.pDynamicState = &dynamic_state;
pipeline_info.layout = pipeline->pipeline_layout;
pipeline_info.layout = pipeline.pipeline_layout;
pipeline_info.renderPass = render_pass;
pipeline_info.subpass = 0;
pipeline_info.basePipelineHandle = nullptr;
pipeline_info.basePipelineIndex = -1;
EXIT_IF(pipeline->pipeline != nullptr);
EXIT_IF(pipeline.pipeline != nullptr);
if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreateGraphicsPipelines begin VS=0x%08" PRIx32 "/0x%08" PRIx32
@@ -946,32 +932,27 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
viewport.y, viewport.width, viewport.height, scissor.offset.x, scissor.offset.y,
scissor.extent.width, scissor.extent.height);
}
result = gctx->device.createGraphicsPipelines(nullptr, 1, &pipeline_info, nullptr,
&pipeline->pipeline);
result = graphics.device.createGraphicsPipelines(nullptr, 1, &pipeline_info, nullptr,
&pipeline.pipeline);
if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreateGraphicsPipelines done result=%s pipeline=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(pipeline->pipeline));
VulkanToString(result).c_str(), static_cast<void*>(pipeline.pipeline));
}
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
EXIT_NOT_IMPLEMENTED(pipeline->pipeline == nullptr);
EXIT_NOT_IMPLEMENTED(pipeline.pipeline == nullptr);
if (frag_shader_module != nullptr) {
gctx->device.destroyShaderModule(frag_shader_module, nullptr);
graphics.device.destroyShaderModule(frag_shader_module, nullptr);
}
gctx->device.destroyShaderModule(vert_shader_module, nullptr);
graphics.device.destroyShaderModule(vert_shader_module, nullptr);
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline,
const ShaderComputeInputInfo* input_info,
void CreatePipelineInternal(PipelineCache::ComputePipeline& pipeline,
const ShaderComputeInputInfo& input_info,
std::span<const uint32_t> cs_shader) {
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(pipeline == nullptr);
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
auto& graphics = GetRenderContext().GetGraphics();
vk::ShaderModule comp_shader_module = nullptr;
@@ -984,7 +965,7 @@ void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline,
create_info.pCode = cs_shader.data();
LOGF("PipelineTrace: vkCreateShaderModule CS begin words=%" PRIu64 "\n",
static_cast<uint64_t>(cs_shader.size()));
auto result = gctx->device.createShaderModule(&create_info, nullptr, &comp_shader_module);
auto result = graphics.device.createShaderModule(&create_info, nullptr, &comp_shader_module);
LOGF("PipelineTrace: vkCreateShaderModule CS done result=%s module=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(comp_shader_module));
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
@@ -1000,9 +981,9 @@ void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline,
comp_shader_stage_info.module = comp_shader_module;
comp_shader_stage_info.pName = "main";
comp_shader_stage_info.pSpecializationInfo = nullptr;
EXIT_IF(!input_info->stage);
ConfigureSubgroupSize(gctx, vk::ShaderStageFlagBits::eCompute, *input_info->stage.program,
&comp_subgroup_size, &comp_shader_stage_info);
EXIT_IF(!input_info.stage);
ConfigureSubgroupSize(vk::ShaderStageFlagBits::eCompute, *input_info.stage.program,
comp_subgroup_size, comp_shader_stage_info);
vk::DescriptorSetLayout set_layouts[1] = {};
uint32_t set_layouts_num = 0;
@@ -1010,9 +991,9 @@ void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline,
vk::PushConstantRange push_constant_info[1];
uint32_t push_constant_info_num = 0;
EXIT_IF(!input_info->stage);
CreateLayout(set_layouts, &set_layouts_num, push_constant_info, &push_constant_info_num,
*input_info->stage.program, vk::ShaderStageFlagBits::eCompute,
EXIT_IF(!input_info.stage);
CreateLayout(set_layouts, set_layouts_num, push_constant_info, push_constant_info_num,
*input_info.stage.program, vk::ShaderStageFlagBits::eCompute,
DescriptorCache::Stage::Compute);
vk::PipelineLayoutCreateInfo pipeline_layout_info {};
@@ -1025,39 +1006,39 @@ void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline,
pipeline_layout_info.pPushConstantRanges =
push_constant_info_num > 0 ? push_constant_info : nullptr;
EXIT_IF(pipeline->pipeline_layout != nullptr);
EXIT_IF(pipeline.pipeline_layout != nullptr);
LOGF("PipelineTrace: vkCreatePipelineLayout CS begin set_layouts=%u push_constants=%u\n",
set_layouts_num, push_constant_info_num);
result = gctx->device.createPipelineLayout(&pipeline_layout_info, nullptr,
&pipeline->pipeline_layout);
result = graphics.device.createPipelineLayout(&pipeline_layout_info, nullptr,
&pipeline.pipeline_layout);
LOGF("PipelineTrace: vkCreatePipelineLayout CS done result=%s layout=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(pipeline->pipeline_layout));
VulkanToString(result).c_str(), static_cast<void*>(pipeline.pipeline_layout));
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
EXIT_NOT_IMPLEMENTED(pipeline->pipeline_layout == nullptr);
EXIT_NOT_IMPLEMENTED(pipeline.pipeline_layout == nullptr);
vk::ComputePipelineCreateInfo info {};
info.sType = vk::StructureType::eComputePipelineCreateInfo;
info.pNext = nullptr;
info.flags = {};
info.stage = comp_shader_stage_info;
info.layout = pipeline->pipeline_layout;
info.layout = pipeline.pipeline_layout;
info.basePipelineHandle = nullptr;
info.basePipelineIndex = -1;
EXIT_IF(pipeline->pipeline != nullptr);
EXIT_IF(pipeline.pipeline != nullptr);
LOGF("PipelineTrace: vkCreateComputePipelines begin layout=%p\n",
static_cast<void*>(pipeline->pipeline_layout));
result = gctx->device.createComputePipelines(nullptr, 1, &info, nullptr, &pipeline->pipeline);
static_cast<void*>(pipeline.pipeline_layout));
result = graphics.device.createComputePipelines(nullptr, 1, &info, nullptr, &pipeline.pipeline);
LOGF("PipelineTrace: vkCreateComputePipelines done result=%s pipeline=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(pipeline->pipeline));
VulkanToString(result).c_str(), static_cast<void*>(pipeline.pipeline));
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
EXIT_NOT_IMPLEMENTED(pipeline->pipeline == nullptr);
EXIT_NOT_IMPLEMENTED(pipeline.pipeline == nullptr);
gctx->device.destroyShaderModule(comp_shader_module, nullptr);
graphics.device.destroyShaderModule(comp_shader_module, nullptr);
}
} // namespace Libs::Graphics
+17 -20
View File
@@ -16,21 +16,20 @@ namespace {
std::atomic<uint64_t> g_stream_buffer_count {0};
} // namespace
HostStreamBuffer::HostStreamBuffer() = default;
HostStreamBuffer::HostStreamBuffer(GraphicContext& graphics): m_graphics(graphics) {}
HostStreamBuffer::~HostStreamBuffer() {
Release();
}
void HostStreamBuffer::EnsureBuffer(GraphicContext* ctx) {
void HostStreamBuffer::EnsureBuffer() {
if (m_buffer != nullptr) {
if (m_ctx != ctx || m_mapped == nullptr) {
EXIT("host stream buffer changed graphics context\n");
if (m_mapped == nullptr) {
EXIT("host stream buffer lost its mapped storage\n");
}
return;
}
KYTY_PROFILER_BLOCK("HostStreamBuffer::create");
m_ctx = ctx;
m_buffer = std::make_unique<VulkanBuffer>();
m_buffer->usage = vk::BufferUsageFlagBits::eStorageBuffer |
vk::BufferUsageFlagBits::eVertexBuffer |
@@ -39,17 +38,16 @@ void HostStreamBuffer::EnsureBuffer(GraphicContext* ctx) {
m_buffer->memory.property = vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent |
vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, CAPACITY, m_buffer.get());
VulkanMapMemory(ctx, &m_buffer->memory, &m_mapped);
m_graphics.CreateBuffer(CAPACITY, *m_buffer);
m_graphics.MapMemory(m_buffer->memory, m_mapped);
const auto count = g_stream_buffer_count.fetch_add(1, std::memory_order_relaxed) + 1;
LOGF("HostStreamBuffer: created serial=%" PRIu64 " capacity=%" PRIu64 "\n", count, CAPACITY);
}
bool HostStreamBuffer::Copy(GraphicContext* ctx, const void* src, uint64_t size, uint64_t alignment,
VulkanBuffer** out_buffer, uint64_t* out_offset, uint64_t* out_range) {
bool HostStreamBuffer::Copy(const void* src, uint64_t size, uint64_t alignment,
VulkanBuffer*& out_buffer, uint64_t& out_offset, uint64_t& out_range) {
KYTY_PROFILER_FUNCTION();
if (ctx == nullptr || src == nullptr || out_buffer == nullptr || out_offset == nullptr ||
out_range == nullptr) {
if (src == nullptr) {
EXIT("invalid host stream upload\n");
}
std::lock_guard lock(m_mutex);
@@ -66,12 +64,12 @@ bool HostStreamBuffer::Copy(GraphicContext* ctx, const void* src, uint64_t size,
if (offset > CAPACITY || size > CAPACITY - offset) {
return false;
}
EnsureBuffer(ctx);
EnsureBuffer();
std::memcpy(static_cast<uint8_t*>(m_mapped) + offset, src, static_cast<size_t>(size));
m_offset = offset + size;
*out_buffer = m_buffer.get();
*out_offset = offset;
*out_range = size;
m_offset = offset + size;
out_buffer = m_buffer.get();
out_offset = offset;
out_range = size;
return true;
}
@@ -83,14 +81,13 @@ void HostStreamBuffer::Reset() noexcept {
void HostStreamBuffer::Release() noexcept {
std::lock_guard lock(m_mutex);
if (m_buffer != nullptr) {
if (m_ctx == nullptr || m_mapped == nullptr) {
if (m_mapped == nullptr) {
EXIT("invalid host stream buffer release state\n");
}
VulkanUnmapMemory(m_ctx, &m_buffer->memory);
VulkanDeleteBuffer(m_ctx, m_buffer.get());
m_graphics.UnmapMemory(m_buffer->memory);
m_graphics.DeleteBuffer(*m_buffer);
m_buffer.reset();
}
m_ctx = nullptr;
m_mapped = nullptr;
m_offset = 0;
}
@@ -18,17 +18,17 @@ struct VulkanBuffer;
// backend with scheduler watches will not change descriptor/render call sites.
class HostStreamBuffer final {
public:
HostStreamBuffer();
explicit HostStreamBuffer(GraphicContext& graphics);
~HostStreamBuffer();
KYTY_CLASS_NO_COPY(HostStreamBuffer);
[[nodiscard]] bool Copy(GraphicContext* ctx, const void* src, uint64_t size, uint64_t alignment,
VulkanBuffer** out_buffer, uint64_t* out_offset, uint64_t* out_range);
[[nodiscard]] bool Copy(const void* src, uint64_t size, uint64_t alignment,
VulkanBuffer*& out_buffer, uint64_t& out_offset, uint64_t& out_range);
void Reset() noexcept;
void Release() noexcept;
private:
void EnsureBuffer(GraphicContext* ctx);
void EnsureBuffer();
// Interim fence-scoped backend: one command processor's eight live command buffers reserve up
// to 128 MiB lazily. Additional active processors scale that aggregate until this backend is
@@ -36,7 +36,7 @@ private:
static constexpr uint64_t CAPACITY = 16ull * 1024ull * 1024ull;
mutable std::mutex m_mutex;
GraphicContext* m_ctx = nullptr;
GraphicContext& m_graphics;
std::unique_ptr<VulkanBuffer> m_buffer;
void* m_mapped = nullptr;
uint64_t m_offset = 0;
+43 -58
View File
@@ -24,8 +24,8 @@ constexpr int GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT = 0x00;
constexpr int GRAPHICS_EVENT_EOP = 0x40;
constexpr uint64_t GRAPHICS_REFERENCE_CLOCK_FREQUENCY = 100000000;
bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency, uint64_t* value) {
if (host_frequency == 0 || value == nullptr) {
bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency, uint64_t& value) {
if (host_frequency == 0) {
return false;
}
@@ -42,7 +42,7 @@ bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency, uint64_t*
if (whole_value > MAX_VALUE - fractional_value) {
return false;
}
*value = whole_value + fractional_value;
value = whole_value + fractional_value;
return true;
}
@@ -50,25 +50,22 @@ uint64_t ReadReferenceClock() {
const auto host_frequency = LibKernel::KernelGetTscFrequency();
const auto host_ticks = LibKernel::KernelReadTsc();
uint64_t value = 0;
if (!ScaleReferenceClock(host_ticks, host_frequency, &value)) {
if (!ScaleReferenceClock(host_ticks, host_frequency, value)) {
EXIT("cannot scale host clock, ticks=0x%016" PRIx64 " frequency=%" PRIu64 "\n", host_ticks,
host_frequency);
}
return value;
}
static void SubmitLabel(CommandBuffer* buffer, LabelCallback callback_1 = nullptr,
static void SubmitLabel(CommandBuffer& buffer, LabelCallback callback_1 = nullptr,
LabelCallback callback_2 = nullptr, const uint64_t* args = nullptr) {
auto* label = LabelCreate(g_render_ctx->GetGraphicCtx(), callback_1, callback_2, args);
LabelSet(buffer, label);
LabelDelete(label);
auto* label = LabelCreate(callback_1, callback_2, args);
LabelSet(buffer, *label);
LabelDelete(*label);
}
static bool CompleteDisplayBufferFlip(const uint64_t* args) {
if (g_render_ctx == nullptr || args == nullptr) {
EXIT("GPU flip completion has invalid state, render_ctx=%p args=%p\n",
static_cast<const void*>(g_render_ctx), static_cast<const void*>(args));
}
EXIT_IF(args == nullptr);
Presentation::DisplayBufferCompleteFlipFromGpu(args[0]);
return true;
}
@@ -90,20 +87,17 @@ enum class EndOfPipeWriteSize : uint32_t { Dword = 4, Qword = 8 };
enum class EndOfPipeWriteAction { Write, WriteBack, Interrupt, InterruptWriteBack };
static bool TriggerEopEventCallback(const uint64_t* args) {
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(args == nullptr);
g_render_ctx->TriggerEopEvent(static_cast<uint32_t>(args[0]));
GetRenderContext().TriggerEopEvent(static_cast<uint32_t>(args[0]));
return true;
}
static bool TriggerDefaultEopEventCallback(const uint64_t* /*args*/) {
EXIT_IF(g_render_ctx == nullptr);
g_render_ctx->TriggerEopEvent(0);
GetRenderContext().TriggerEopEvent(0);
return true;
}
static void ValidateEndOfPipeSignal(const EndOfPipeSignal& signal) {
EXIT_IF(g_render_ctx == nullptr);
if (signal.destination.has_value()) {
EXIT_IF(*signal.destination == 0);
}
@@ -121,13 +115,13 @@ static void RecordEndOfPipeSignal(const EndOfPipeSignal& signal) {
switch (signal.completion) {
case EndOfPipeCompletion::None: return;
case EndOfPipeCompletion::Interrupt:
SubmitLabel(signal.buffer, nullptr, TriggerEopEventCallback, args);
SubmitLabel(*signal.buffer, nullptr, TriggerEopEventCallback, args);
return;
case EndOfPipeCompletion::Flip:
SubmitLabel(signal.buffer, CompleteDisplayBufferFlip, nullptr, args);
SubmitLabel(*signal.buffer, CompleteDisplayBufferFlip, nullptr, args);
return;
case EndOfPipeCompletion::FlipAndInterrupt:
SubmitLabel(signal.buffer, CompleteDisplayBufferFlip, TriggerDefaultEopEventCallback,
SubmitLabel(*signal.buffer, CompleteDisplayBufferFlip, TriggerDefaultEopEventCallback,
args);
return;
}
@@ -149,7 +143,7 @@ static bool TriggersInterrupt(EndOfPipeWriteAction action) {
action == EndOfPipeWriteAction::InterruptWriteBack;
}
static void RecordEndOfPipeWrite(uint64_t submit_id, CommandBuffer* buffer, uint64_t destination,
static void RecordEndOfPipeWrite(uint64_t submit_id, CommandBuffer& buffer, uint64_t destination,
uint64_t value, EndOfPipeWriteSize size,
EndOfPipeWriteAction action, uint32_t context_id = 0) {
const auto width = static_cast<uint32_t>(size);
@@ -158,7 +152,7 @@ static void RecordEndOfPipeWrite(uint64_t submit_id, CommandBuffer* buffer, uint
const bool interrupt = TriggersInterrupt(action);
EndOfPipeSignal signal {
.buffer = buffer,
.buffer = &buffer,
.submit_id = submit_id,
.debug_operation = DebugOperation(action),
.debug_args = interrupt ? std::array {width, context_id, value_low, value_high}
@@ -179,21 +173,20 @@ void TriggerAgcUserInterrupt() {
}
void TriggerEopEvent(uint32_t context_id) {
EXIT_IF(g_render_ctx == nullptr);
g_render_ctx->TriggerEopEvent(context_id);
GetRenderContext().TriggerEopEvent(context_id);
}
void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr,
uint32_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::Write);
}
void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr,
uint32_t dw_offset, uint32_t dw_num) {
const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr);
RecordEndOfPipeSignal({
.buffer = buffer,
.buffer = &buffer,
.submit_id = submit_id,
.debug_operation = CommandBufferDebugOp::EopWrite,
.debug_args = {dw_offset, dw_num, 0, 0},
@@ -202,13 +195,13 @@ void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer* buffer, uint32_t*
});
}
void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr,
void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr,
uint64_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Write);
}
void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr,
void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr,
uint64_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), 0,
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Write);
@@ -218,7 +211,7 @@ void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer, uin
reinterpret_cast<uint64_t>(dst_gpu_addr), value);
}
void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer& buffer,
uint64_t* dst_gpu_addr, uint64_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), 0,
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::WriteBack);
@@ -228,19 +221,19 @@ void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer
reinterpret_cast<uint64_t>(dst_gpu_addr), value);
}
void WriteAtEndOfPipeWithWriteBack64(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithWriteBack64(uint64_t submit_id, CommandBuffer& buffer,
uint64_t* dst_gpu_addr, uint64_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::WriteBack);
}
void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer& buffer,
uint32_t* dst_gpu_addr, uint32_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::WriteBack);
}
void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer& buffer,
uint64_t* dst_gpu_addr, uint64_t value,
uint32_t context_id) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
@@ -248,7 +241,7 @@ void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer*
context_id);
}
void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer& buffer,
uint32_t* dst_gpu_addr, uint32_t value,
uint32_t context_id) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
@@ -256,24 +249,24 @@ void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer*
context_id);
}
void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer& buffer,
uint64_t* dst_gpu_addr, uint64_t value, uint32_t context_id) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Interrupt, context_id);
}
void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer& buffer,
uint32_t* dst_gpu_addr, uint32_t value, uint32_t context_id) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::Interrupt, context_id);
}
uint64_t PrepareDisplayBufferFlip(CommandBuffer* buffer, int handle, int index, int flip_mode,
uint64_t PrepareDisplayBufferFlip(CommandBuffer& buffer, int handle, int index, int flip_mode,
int64_t flip_arg) {
for (;;) {
uint64_t request_id = 0;
const auto result = Presentation::DisplayBufferSubmitFlipFromGpu(
buffer, handle, index, flip_mode, flip_arg, &request_id);
buffer, handle, index, flip_mode, flip_arg, request_id);
if (result == OK) {
EXIT_IF(request_id == 0);
return request_id;
@@ -287,13 +280,13 @@ uint64_t PrepareDisplayBufferFlip(CommandBuffer* buffer, int handle, int index,
}
}
void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuffer& buffer,
uint32_t* dst_gpu_addr, uint32_t value,
int handle, int index, int flip_mode,
int64_t flip_arg, uint64_t request_id) {
const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr);
RecordEndOfPipeSignal({
.buffer = buffer,
.buffer = &buffer,
.submit_id = submit_id,
.debug_operation = CommandBufferDebugOp::EopWriteBackFlip,
.debug_args = {static_cast<uint32_t>(handle), static_cast<uint32_t>(index),
@@ -305,12 +298,12 @@ void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuf
});
}
void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr,
uint32_t value, int handle, int index, int flip_mode,
int64_t flip_arg, uint64_t request_id) {
const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr);
RecordEndOfPipeSignal({
.buffer = buffer,
.buffer = &buffer,
.submit_id = submit_id,
.debug_operation = CommandBufferDebugOp::EopFlip,
.debug_args = {static_cast<uint32_t>(handle), static_cast<uint32_t>(index),
@@ -322,10 +315,10 @@ void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer* buffer, uint3
});
}
void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer* buffer, int handle, int index,
void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer& buffer, int handle, int index,
int flip_mode, int64_t flip_arg, uint64_t request_id) {
RecordEndOfPipeSignal({
.buffer = buffer,
.buffer = &buffer,
.submit_id = submit_id,
.debug_operation = CommandBufferDebugOp::EopOnlyFlip,
.debug_args = {static_cast<uint32_t>(handle), static_cast<uint32_t>(index),
@@ -336,8 +329,8 @@ void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer* buffer, int han
});
}
void TriggerEopEventAtEndOfPipe(CommandBuffer* buffer, uint32_t context_id) {
ValidateEndOfPipeSignal({.buffer = buffer});
void TriggerEopEventAtEndOfPipe(CommandBuffer& buffer, uint32_t context_id) {
ValidateEndOfPipeSignal({.buffer = &buffer});
uint64_t args[LABEL_ARGS_MAX] = {static_cast<uint64_t>(context_id)};
SubmitLabel(buffer, nullptr, TriggerEopEventCallback, args);
@@ -353,11 +346,10 @@ static void EopEventResetFunc(LibKernel::EventQueue::KernelEqueueEvent* event) {
static void EopEventDeleteFunc(LibKernel::EventQueue::KernelEqueue eq,
LibKernel::EventQueue::KernelEqueueEvent* event) {
EXIT_IF(event == nullptr);
EXIT_IF(g_render_ctx == nullptr);
EXIT_NOT_IMPLEMENTED(event->event.filter != LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS);
if (event->event.ident == GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT ||
event->event.ident == GRAPHICS_EVENT_EOP) {
g_render_ctx->DeleteEopEq(eq, static_cast<int>(event->event.ident));
GetRenderContext().DeleteEopEq(eq, static_cast<int>(event->event.ident));
}
}
@@ -377,8 +369,6 @@ static void EopEventTriggerFunc(LibKernel::EventQueue::KernelEqueueEvent* event,
}
int AddEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id, void* udata) {
EXIT_IF(g_render_ctx == nullptr);
LibKernel::EventQueue::KernelEqueueEvent event;
event.triggered = false;
event.event.ident = static_cast<uintptr_t>(id);
@@ -395,15 +385,13 @@ int AddEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id, void* udata) {
if (result == 0 &&
(id == GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT || id == GRAPHICS_EVENT_EOP)) {
g_render_ctx->AddEopEq(eq, id);
GetRenderContext().AddEopEq(eq, id);
}
return result;
}
int DeleteEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id) {
EXIT_IF(g_render_ctx == nullptr);
int result = LibKernel::EventQueue::KernelDeleteEvent(
eq, static_cast<uintptr_t>(id), LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS);
@@ -411,14 +399,11 @@ int DeleteEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id) {
}
void ReadGds(uint32_t* dst, uint32_t dw_offset, uint32_t dw_size) {
EXIT_IF(g_render_ctx == nullptr);
g_render_ctx->GetGdsBuffer()->Read(g_render_ctx->GetGraphicCtx(), dst, dw_offset, dw_size);
GetRenderContext().GetGdsBuffer().Read(dst, dw_offset, dw_size);
}
void DeleteBuffers() {
EXIT_IF(g_render_ctx == nullptr);
g_render_ctx->GetBufferCache()->ResetNullBuffer();
GetRenderContext().GetBufferCache().ResetNullBuffer();
}
} // namespace Libs::Graphics::Sync
+17 -17
View File
@@ -12,48 +12,48 @@ class CommandBuffer;
namespace Sync {
[[nodiscard]] bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency,
uint64_t* value);
uint64_t& value);
[[nodiscard]] uint64_t ReadReferenceClock();
void TriggerAgcUserInterrupt();
void TriggerEopEvent(uint32_t context_id);
void TriggerEopEventAtEndOfPipe(CommandBuffer* buffer, uint32_t context_id);
void TriggerEopEventAtEndOfPipe(CommandBuffer& buffer, uint32_t context_id);
void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr,
uint32_t value);
void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr,
void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr,
uint64_t value);
void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr,
uint32_t dw_offset, uint32_t dw_num);
void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr,
void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr,
uint64_t value);
void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer& buffer,
uint64_t* dst_gpu_addr, uint64_t value);
void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer& buffer,
uint32_t* dst_gpu_addr, uint32_t value);
void WriteAtEndOfPipeWithWriteBack64(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithWriteBack64(uint64_t submit_id, CommandBuffer& buffer,
uint64_t* dst_gpu_addr, uint64_t value);
void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer& buffer,
uint32_t* dst_gpu_addr, uint32_t value,
uint32_t context_id = 0);
void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer& buffer,
uint64_t* dst_gpu_addr, uint64_t value,
uint32_t context_id = 0);
void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer& buffer,
uint32_t* dst_gpu_addr, uint32_t value,
uint32_t context_id = 0);
void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer& buffer,
uint64_t* dst_gpu_addr, uint64_t value,
uint32_t context_id = 0);
[[nodiscard]] uint64_t PrepareDisplayBufferFlip(CommandBuffer* buffer, int handle, int index,
[[nodiscard]] uint64_t PrepareDisplayBufferFlip(CommandBuffer& buffer, int handle, int index,
int flip_mode, int64_t flip_arg);
void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer* buffer, int handle, int index,
void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer& buffer, int handle, int index,
int flip_mode, int64_t flip_arg, uint64_t request_id);
void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr,
uint32_t value, int handle, int index, int flip_mode,
int64_t flip_arg, uint64_t request_id);
void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuffer& buffer,
uint32_t* dst_gpu_addr, uint32_t value,
int handle, int index, int flip_mode,
int64_t flip_arg, uint64_t request_id);
File diff suppressed because it is too large. Load diff
+54 -61
View File
@@ -53,77 +53,71 @@ public:
bool full = false;
};
TextureCache(PageManager& page_manager, BufferCache& buffer_cache,
TextureCache(GraphicContext& graphics, PageManager& page_manager, BufferCache& buffer_cache,
ResourceMutex& resource_mutex);
~TextureCache();
KYTY_CLASS_NO_COPY(TextureCache);
[[nodiscard]] VulkanImage* FindTexture(CommandBuffer* command, GraphicContext* ctx,
const ImageInfo& info, bool metadata_read);
[[nodiscard]] StorageTextureVulkanImage*
FindStorageTexture(CommandBuffer* command, GraphicContext* ctx, const ImageInfo& info);
[[nodiscard]] RenderTextureVulkanImage*
FindRenderTarget(CommandBuffer* command, GraphicContext* ctx, const RenderTargetInfo& info);
[[nodiscard]] DepthStencilVulkanImage*
FindDepthTarget(CommandBuffer* command, GraphicContext* ctx, const DepthTargetInfo& info);
[[nodiscard]] VulkanImage& FindTexture(CommandBuffer& command, const ImageInfo& info,
bool metadata_read);
[[nodiscard]] StorageTextureVulkanImage& FindStorageTexture(CommandBuffer& command,
const ImageInfo& info);
[[nodiscard]] RenderTextureVulkanImage& FindRenderTarget(CommandBuffer& command,
const RenderTargetInfo& info);
[[nodiscard]] DepthStencilVulkanImage& FindDepthTarget(CommandBuffer& command,
const DepthTargetInfo& info);
[[nodiscard]] std::vector<VideoOutVulkanImage*>
RegisterVideoOutSurfaces(GraphicContext* ctx, const std::vector<VideoOutInfo>& infos);
void RefreshVideoOut(VideoOutVulkanImage* image, bool render_target = false);
void UnregisterVideoOutSurfaces(const std::vector<VideoOutVulkanImage*>& images);
[[nodiscard]] bool ClearImageFromBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size,
RegisterVideoOutSurfaces(const std::vector<VideoOutInfo>& infos);
void RefreshVideoOut(VideoOutVulkanImage& image, bool render_target = false);
void UnregisterVideoOutSurfaces(const std::vector<VideoOutVulkanImage*>& images);
[[nodiscard]] bool ClearImageFromBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size,
uint32_t packed_clear);
void MarkGpuWritten(VulkanImage* image);
void MarkGpuWritten(VulkanImage& image);
void PrepareHostWrite(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool InvalidateMemoryFromGPU(uint64_t vaddr, uint64_t size,
bool formatted_buffer_write = false);
[[nodiscard]] RenderTextureVulkanImage* FindRenderTargetByRange(CommandBuffer* command,
[[nodiscard]] RenderTextureVulkanImage* FindRenderTargetByRange(CommandBuffer& command,
uint64_t vaddr, uint64_t size);
[[nodiscard]] vk::ImageView GetRenderTargetAttachmentView(GraphicContext* ctx,
RenderTextureVulkanImage* image,
[[nodiscard]] vk::ImageView GetRenderTargetAttachmentView(RenderTextureVulkanImage& image,
vk::Format format, uint32_t level,
uint32_t base_layer,
uint32_t layer_count);
[[nodiscard]] vk::ImageView GetDepthTargetAttachmentView(GraphicContext* ctx,
DepthStencilVulkanImage* image,
[[nodiscard]] vk::ImageView GetDepthTargetAttachmentView(DepthStencilVulkanImage& image,
uint32_t base_layer,
uint32_t layer_count);
[[nodiscard]] vk::ImageView
GetDepthTargetSampledView(GraphicContext* ctx, DepthStencilVulkanImage* image,
vk::Format view_format, uint32_t swizzle, uint32_t base_level,
uint32_t level_count, vk::ImageViewType type, uint32_t base_layer,
uint32_t layer_count);
[[nodiscard]] vk::ImageView GetSampledColorView(GraphicContext* ctx, VulkanImage* image,
vk::Format view_format, uint32_t swizzle,
uint32_t base_level, uint32_t level_count,
vk::ImageViewType type, uint32_t base_layer,
uint32_t layer_count);
GetDepthTargetSampledView(DepthStencilVulkanImage& image, vk::Format view_format,
uint32_t swizzle, uint32_t base_level, uint32_t level_count,
vk::ImageViewType type, uint32_t base_layer, uint32_t layer_count);
[[nodiscard]] vk::ImageView GetSampledColorView(VulkanImage& image, vk::Format view_format,
uint32_t swizzle, uint32_t base_level,
uint32_t level_count, vk::ImageViewType type,
uint32_t base_layer, uint32_t layer_count);
[[nodiscard]] vk::ImageView
GetRenderTargetStorageView(GraphicContext* ctx, RenderTextureVulkanImage* image,
vk::Format view_format, uint32_t base_level, uint32_t level_count,
vk::ImageViewType type, uint32_t base_layer, uint32_t layer_count);
[[nodiscard]] vk::ImageView GetStorageTextureSampledView(GraphicContext* ctx,
StorageTextureVulkanImage* image,
GetRenderTargetStorageView(RenderTextureVulkanImage& image, vk::Format view_format,
uint32_t base_level, uint32_t level_count, vk::ImageViewType type,
uint32_t base_layer, uint32_t layer_count);
[[nodiscard]] vk::ImageView GetStorageTextureSampledView(StorageTextureVulkanImage& image,
const ImageInfo& info);
[[nodiscard]] vk::ImageView GetStorageTextureStorageView(GraphicContext* ctx,
StorageTextureVulkanImage* image,
[[nodiscard]] vk::ImageView GetStorageTextureStorageView(StorageTextureVulkanImage& image,
uint32_t base_level);
[[nodiscard]] DepthStencilVulkanImage*
FindDepthTargetByRange(CommandBuffer* command, uint64_t vaddr, uint64_t size,
FindDepthTargetByRange(CommandBuffer& command, uint64_t vaddr, uint64_t size,
bool allow_containing_sampled = false);
[[nodiscard]] RegionInfo QueryRegion(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool ResolveMetaRange(uint64_t vaddr, uint64_t size, MetaRangeInfo* info);
void RegisterMeta(GraphicContext* ctx, uint64_t vaddr, uint64_t size, uint32_t layers = 1);
[[nodiscard]] bool IsMeta(uint64_t vaddr);
[[nodiscard]] bool IsMetaRange(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool IsMetaCleared(uint64_t vaddr, uint32_t slice);
[[nodiscard]] bool ClearMeta(uint64_t vaddr);
[[nodiscard]] bool TouchMeta(uint64_t vaddr, uint32_t slice, bool is_clear);
[[nodiscard]] bool InvalidateMemory(PageFaultAccess access, uint64_t vaddr, uint64_t size,
PageFaultPhase phase) noexcept;
void UnmapMemory(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool ResolveMetaRange(uint64_t vaddr, uint64_t size, MetaRangeInfo& info);
void RegisterMeta(uint64_t vaddr, uint64_t size, uint32_t layers = 1);
[[nodiscard]] bool IsMeta(uint64_t vaddr);
[[nodiscard]] bool IsMetaRange(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool IsMetaCleared(uint64_t vaddr, uint32_t slice);
[[nodiscard]] bool ClearMeta(uint64_t vaddr);
[[nodiscard]] bool TouchMeta(uint64_t vaddr, uint32_t slice, bool is_clear);
[[nodiscard]] bool InvalidateMemory(PageFaultAccess access, uint64_t vaddr, uint64_t size,
PageFaultPhase phase) noexcept;
void UnmapMemory(uint64_t vaddr, uint64_t size);
VulkanImage* GetDummySampledTexture(bool uint_format, bool image_3d);
VulkanImage* GetDummyStorageTexture(bool uint_format, bool image_3d);
VulkanImage& GetDummySampledTexture(bool uint_format, bool image_3d);
VulkanImage& GetDummyStorageTexture(bool uint_format, bool image_3d);
private:
struct CachedImage;
@@ -135,20 +129,19 @@ private:
uint32_t clear_mask = 0;
bool gpu_modified = false;
};
[[nodiscard]] vk::ImageView GetImageView(GraphicContext* ctx, VulkanImage* image,
const ImageViewInfo& info);
[[nodiscard]] vk::ImageView GetImageView(VulkanImage& image, const ImageViewInfo& info);
[[nodiscard]] bool HasMetaOverlapLocked(uint64_t vaddr, uint64_t size) const;
[[nodiscard]] CachedImage* FindGpuReadbackPageCandidateLocked(uint64_t vaddr, uint64_t size);
void RequireNoMetaOverlapLocked(uint64_t vaddr, uint64_t size) const;
void ResolveImageMetadataOverlapsLocked(GraphicContext* ctx, uint64_t vaddr, uint64_t size);
void MarkSampledAliasesCpuDirtyLocked(uint64_t vaddr, uint64_t size);
void RetireSampledTargetAliases(GraphicContext* ctx, const ImageInfo& requested);
void ResolveStorageImageOverlaps(GraphicContext* ctx, const ImageInfo& requested);
void RetireStorageDepthAliasLocked(GraphicContext* ctx, const ImageInfo& requested);
void RegisterImageLocked(CachedImage& image);
void UnregisterImageLocked(CachedImage& image, bool release_tracking);
[[nodiscard]] VulkanImage* PublishImage(CommandBuffer* command,
std::shared_ptr<CachedImage> image);
void ResolveImageMetadataOverlapsLocked(uint64_t vaddr, uint64_t size);
void MarkSampledAliasesCpuDirtyLocked(uint64_t vaddr, uint64_t size);
void RetireSampledTargetAliases(const ImageInfo& requested);
void ResolveStorageImageOverlaps(const ImageInfo& requested);
void RetireStorageDepthAliasLocked(const ImageInfo& requested);
void RegisterImageLocked(CachedImage& image);
void UnregisterImageLocked(CachedImage& image, bool release_tracking);
[[nodiscard]] VulkanImage& PublishImage(CommandBuffer& command,
std::shared_ptr<CachedImage> image);
[[nodiscard]] std::vector<CachedImage*> FindImagesInRegionLocked(uint64_t vaddr, uint64_t size,
bool page_overlap);
void RequireRetirementIsolation(const std::vector<CachedImage*>& retire, const char* operation,
@@ -157,13 +150,13 @@ private:
const CachedImage* native_image_source = nullptr);
void RetireDepthMetadataLocked(const std::vector<CachedImage*>& retire,
uint64_t preserve_address = 0);
void MaterializeImagesToGuestLocked(GraphicContext* ctx,
const std::vector<std::shared_ptr<CachedImage>>& images);
void MaterializeImagesToGuestLocked(const std::vector<std::shared_ptr<CachedImage>>& images);
void SynchronizeColorImageToBufferLocked(CachedImage& cached, uint64_t write_address,
uint64_t write_size);
void SynchronizeDepthImageToBufferLocked(CachedImage& cached, uint64_t write_address,
uint64_t write_size);
GraphicContext& m_graphics;
std::unique_ptr<DummyTextureCache> m_dummy_textures;
TrackingSpinLock m_lock;
std::mutex m_fault_mutex;
+28 -29
View File
@@ -26,7 +26,7 @@ DepthTransfer MakeDepthTransfer(uint64_t size, uint32_t layers, uint32_t format,
EXIT_IF(size == 0 || layers == 0 || size % layers != 0);
TileBlockLayout block {};
EXIT_NOT_IMPLEMENTED(
!TileGetBlockLayout(TileBlockFamily::Depth64KB, bytes_per_element, &block) ||
!TileGetBlockLayout(TileBlockFamily::Depth64KB, bytes_per_element, block) ||
Prospero::NumBytesPerElement(format) != bytes_per_element);
const uint64_t slice_size = size / layers;
@@ -61,21 +61,20 @@ DepthTransfer MakeDepthTransfer(uint64_t size, uint32_t layers, uint32_t format,
return transfer;
}
void UploadDepth(GraphicContext* ctx, DepthStencilVulkanImage* image, uint64_t source_address,
uint64_t size, uint32_t layers, uint32_t format, uint32_t bytes_per_element,
uint32_t width, uint32_t height, uint32_t pitch, uint32_t base_layer,
void UploadDepth(DepthStencilVulkanImage& image, uint64_t source_address, uint64_t size,
uint32_t layers, uint32_t format, uint32_t bytes_per_element, uint32_t width,
uint32_t height, uint32_t pitch, uint32_t base_layer,
vk::ImageAspectFlags aspect) {
auto transfer = MakeDepthTransfer(size, layers, format, bytes_per_element, width, height, pitch,
base_layer, aspect);
Transfer::UploadTiledImage(ctx, image, reinterpret_cast<const void*>(source_address), size,
size, transfer.infos, transfer.regions,
Transfer::UploadTiledImage(image, reinterpret_cast<const void*>(source_address), size, size,
transfer.infos, transfer.regions,
vk::ImageLayout::eDepthStencilAttachmentOptimal);
}
template <uint32_t (*Encode)(uint16_t)>
void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source,
uint32_t base_layer) {
void UploadPromotedD16Depth(DepthStencilVulkanImage& image, const DepthTargetInfo& info,
const BufferImageCopySource& source, uint32_t base_layer) {
const uint64_t guest_slice_size = info.size / info.layers;
const uint64_t texels = static_cast<uint64_t>(info.pitch) * info.height;
const uint64_t host_slice_size = texels * sizeof(uint32_t);
@@ -86,7 +85,7 @@ void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage* image,
info.bytes_per_element, info.width, info.height, info.pitch,
base_layer, vk::ImageAspectFlagBits::eDepth);
std::vector<uint16_t> guest_linear(info.size / sizeof(uint16_t));
GpuDetile(ctx, reinterpret_cast<const void*>(source.address), guest_linear.data(), info.size,
GpuDetile(reinterpret_cast<const void*>(source.address), guest_linear.data(), info.size,
info.size, transfer.infos);
Transfer::ScratchBuffer host_linear(host_upload_size);
@@ -99,63 +98,63 @@ void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage* image,
}
transfer.regions[layer].offset = static_cast<uint32_t>(host_slice_size * layer);
}
Transfer::UploadImage(ctx, image, host_linear.Data(), host_upload_size, transfer.regions,
Transfer::UploadImage(image, host_linear.Data(), host_upload_size, transfer.regions,
vk::ImageLayout::eDepthStencilAttachmentOptimal);
}
} // namespace
void Tiler::DetileImage(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info,
void Tiler::DetileImage(GpuTextureVulkanImage& image, const ImageInfo& info,
const BufferImageCopySource& source, bool refresh, bool storage) const {
if (refresh) Transfer::WaitForGraphicsIdle(ctx);
if (refresh) Transfer::WaitForGraphicsIdle();
const bool array_texture = TextureIsLayeredTexture(info.type);
const bool volume_texture = TextureIs3DTexture(info.type);
auto layout = TextureCalcUploadLayout(
info.format, info.width, info.height, info.levels, info.depth, info.pitch, info.tile,
info.size, true, volume_texture, storage ? "StorageTextureCache" : "TextureCache");
auto regions = TextureBuildUploadRegions(layout, image->format, info.width, info.height,
auto regions = TextureBuildUploadRegions(layout, image.format, info.width, info.height,
info.depth, info.levels, array_texture, volume_texture,
TextureUploadDestination::MipLevels);
TextureUploadGuestImage(ctx, image, reinterpret_cast<const void*>(source.address), info.size,
TextureUploadGuestImage(image, reinterpret_cast<const void*>(source.address), info.size,
regions, layout, info.format, info.width, info.height, info.depth,
info.levels, storage ? "StorageTextureCache" : "TextureCache",
storage ? vk::ImageLayout::eGeneral
: vk::ImageLayout::eShaderReadOnlyOptimal);
}
void Tiler::DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source,
bool refresh, uint32_t base_layer) const {
EXIT_NOT_IMPLEMENTED(info.samples != 1 || image->samples != 1);
if (refresh) Transfer::WaitForGraphicsIdle(ctx);
void Tiler::DetileImage(DepthStencilVulkanImage& image, const DepthTargetInfo& info,
const BufferImageCopySource& source, bool refresh,
uint32_t base_layer) const {
EXIT_NOT_IMPLEMENTED(info.samples != 1 || image.samples != 1);
if (refresh) Transfer::WaitForGraphicsIdle();
if (DepthAspectTransferBytes(info.format) != info.bytes_per_element) {
switch (info.format) {
case vk::Format::eD24UnormS8Uint:
UploadPromotedD16Depth<EncodeD16AsD24>(ctx, image, info, source, base_layer);
UploadPromotedD16Depth<EncodeD16AsD24>(image, info, source, base_layer);
return;
case vk::Format::eD32SfloatS8Uint:
UploadPromotedD16Depth<EncodeD16AsD32>(ctx, image, info, source, base_layer);
UploadPromotedD16Depth<EncodeD16AsD32>(image, info, source, base_layer);
return;
default: EXIT_NOT_IMPLEMENTED(true);
}
}
UploadDepth(ctx, image, source.address, info.size, info.layers, info.guest_format,
UploadDepth(image, source.address, info.size, info.layers, info.guest_format,
info.bytes_per_element, info.width, info.height, info.pitch, base_layer,
vk::ImageAspectFlagBits::eDepth);
}
void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source,
bool refresh, uint32_t base_layer) const {
EXIT_NOT_IMPLEMENTED(info.samples != 1 || image->samples != 1);
if (refresh) Transfer::WaitForGraphicsIdle(ctx);
void Tiler::DetileStencil(DepthStencilVulkanImage& image, const DepthTargetInfo& info,
const BufferImageCopySource& source, bool refresh,
uint32_t base_layer) const {
EXIT_NOT_IMPLEMENTED(info.samples != 1 || image.samples != 1);
if (refresh) Transfer::WaitForGraphicsIdle();
const auto format = Prospero::GpuEnumValue(Prospero::BufferFormat::k8UInt);
const auto pitch = TileGetTexturePitch(format, info.width, 1,
Prospero::GpuEnumValue(Prospero::TileMode::kDepth));
UploadDepth(ctx, image, source.address, info.stencil_size, info.layers, format, 1, info.width,
UploadDepth(image, source.address, info.stencil_size, info.layers, format, 1, info.width,
info.height, pitch, base_layer, vk::ImageAspectFlagBits::eStencil);
}
+6 -8
View File
@@ -9,21 +9,19 @@ namespace Libs::Graphics {
struct DepthStencilVulkanImage;
struct GpuTextureVulkanImage;
struct GraphicContext;
class Tiler final {
public:
Tiler() = default;
KYTY_CLASS_NO_COPY(Tiler);
void DetileImage(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info,
void DetileImage(GpuTextureVulkanImage& image, const ImageInfo& info,
const BufferImageCopySource& source, bool refresh, bool storage) const;
void DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source, bool refresh,
void DetileImage(DepthStencilVulkanImage& image, const DepthTargetInfo& info,
const BufferImageCopySource& source, bool refresh,
uint32_t base_layer = 0) const;
void DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source,
bool refresh, uint32_t base_layer = 0) const;
void DetileStencil(DepthStencilVulkanImage& image, const DepthTargetInfo& info,
const BufferImageCopySource& source, bool refresh,
uint32_t base_layer = 0) const;
};
} // namespace Libs::Graphics