mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-29 08:41:20 +00:00
graphics: refactoring #2
This commit is contained in:
1 parent
b51d4322cc
commit
0a5f78c727
137 files changed
+10230
-10893
No files matched your search
@@ -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, ©);
|
||||
vk_buffer.copyBuffer(src.buffer, dst.buffer, 1, ©);
|
||||
const vk::BufferMemoryBarrier after[] = {
|
||||
MakeDmaBarrier(dst, dst_offset, size, vk::AccessFlagBits::eTransferWrite,
|
||||
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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*>(¶ms);
|
||||
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
|
||||
|
||||
@@ -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, ®istered_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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user