mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 11:26:56 +02:00
Refactor graphics #1
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
#include "graphics/host_gpu/renderer/render.h"
|
||||
#include "graphics/host_gpu/renderer/resourceMutex.h"
|
||||
#include "graphics/host_gpu/renderer/textureCache.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
#include "graphics/host_gpu/transfer.h"
|
||||
#include "graphics/host_gpu/vma.h"
|
||||
#include "kernel/memory.h"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
@@ -498,7 +499,7 @@ struct BufferCache::ReadbackWorker {
|
||||
" count=%u bytes=%u\n",
|
||||
page, range_count, data_offset);
|
||||
}
|
||||
auto vk_buffer = command->GetPool()->buffers[command->GetIndex()];
|
||||
auto vk_buffer = command->Handle();
|
||||
command->Begin();
|
||||
vk_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
|
||||
vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlags {},
|
||||
@@ -562,7 +563,7 @@ BufferCache::~BufferCache() {
|
||||
}
|
||||
}
|
||||
if (!m_buffers.empty()) {
|
||||
VulkanDeviceWaitIdle(m_buffers.begin()->second->ctx);
|
||||
Transfer::WaitForGraphicsIdle(m_buffers.begin()->second->ctx);
|
||||
}
|
||||
m_buffers.clear();
|
||||
}
|
||||
@@ -628,8 +629,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);
|
||||
UtilDownloadBuffer(cached->ctx, cached->buffer.get(), range.address - begin,
|
||||
data.data(), range.size);
|
||||
Transfer::DownloadBuffer(cached->ctx, cached->buffer.get(),
|
||||
range.address - begin, data.data(), range.size);
|
||||
Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size());
|
||||
downloaded += range.size;
|
||||
}
|
||||
@@ -781,10 +782,10 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
|
||||
},
|
||||
[&]() noexcept {
|
||||
for (const auto& [upload_vaddr, upload_size]: uploads) {
|
||||
UtilUploadBuffer(ctx, StagingBufferType::Vertex, old.buffer.get(),
|
||||
upload_vaddr - old.vaddr,
|
||||
reinterpret_cast<const void*>(upload_vaddr),
|
||||
upload_size);
|
||||
Transfer::UploadBuffer(ctx, Transfer::StagingBufferType::Vertex,
|
||||
old.buffer.get(), upload_vaddr - old.vaddr,
|
||||
reinterpret_cast<const void*>(upload_vaddr),
|
||||
upload_size);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -801,7 +802,7 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
|
||||
cached->buffer->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
|
||||
VulkanCreateBuffer(ctx, cached->size, cached->buffer.get());
|
||||
if (!overlaps.empty()) {
|
||||
auto vk_buffer = command->GetPool()->buffers[command->GetIndex()];
|
||||
auto vk_buffer = command->Handle();
|
||||
std::vector<vk::BufferMemoryBarrier> before;
|
||||
before.reserve(overlaps.size() + 1);
|
||||
for (const auto& overlap: overlaps) {
|
||||
@@ -866,9 +867,9 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
|
||||
},
|
||||
[&]() noexcept {
|
||||
for (const auto& [upload_vaddr, upload_size]: ranges) {
|
||||
UtilUploadBuffer(ctx, StagingBufferType::Vertex, cached.buffer.get(),
|
||||
upload_vaddr - cached.vaddr,
|
||||
reinterpret_cast<const void*>(upload_vaddr), upload_size);
|
||||
Transfer::UploadBuffer(ctx, Transfer::StagingBufferType::Vertex,
|
||||
cached.buffer.get(), upload_vaddr - cached.vaddr,
|
||||
reinterpret_cast<const void*>(upload_vaddr), upload_size);
|
||||
}
|
||||
});
|
||||
if (is_written) {
|
||||
@@ -963,7 +964,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
|
||||
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()) {
|
||||
VulkanDeviceWaitIdle(owner.ctx);
|
||||
Transfer::WaitForGraphicsIdle(owner.ctx);
|
||||
waited.push_back(owner.ctx);
|
||||
}
|
||||
}
|
||||
@@ -985,8 +986,8 @@ 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);
|
||||
UtilDownloadBuffer(owner.ctx, owner.buffer.get(), buffer_offset, data.data(),
|
||||
range.size);
|
||||
Transfer::DownloadBuffer(owner.ctx, owner.buffer.get(), buffer_offset,
|
||||
data.data(), range.size);
|
||||
Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size());
|
||||
downloaded += range.size;
|
||||
}
|
||||
@@ -1020,9 +1021,9 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
|
||||
},
|
||||
[&]() noexcept {
|
||||
for (const auto& [address, bytes]: uploads) {
|
||||
UtilUploadBuffer(cached.ctx, StagingBufferType::Vertex, cached.buffer.get(),
|
||||
address - cached.vaddr, reinterpret_cast<const void*>(address),
|
||||
bytes);
|
||||
Transfer::UploadBuffer(cached.ctx, Transfer::StagingBufferType::Vertex,
|
||||
cached.buffer.get(), address - cached.vaddr,
|
||||
reinterpret_cast<const void*>(address), bytes);
|
||||
}
|
||||
});
|
||||
if (uploads.empty()) {
|
||||
@@ -1065,16 +1066,11 @@ vk::BufferMemoryBarrier MakeDmaBarrier(VulkanBuffer* buffer, uint64_t offset, ui
|
||||
}
|
||||
|
||||
vk::CommandBuffer GetDmaCommandBuffer(CommandBuffer* command) {
|
||||
if (command == nullptr || command->IsInvalid() || command->GetPool() == nullptr ||
|
||||
command->GetIndex() >= command->GetPool()->buffers_count) {
|
||||
if (command == nullptr) {
|
||||
EXIT("BufferCache: invalid DMA command buffer, command=%p\n",
|
||||
static_cast<const void*>(command));
|
||||
}
|
||||
const auto vk_buffer = command->GetPool()->buffers[command->GetIndex()];
|
||||
if (vk_buffer == nullptr) {
|
||||
EXIT("BufferCache: DMA command buffer handle is null, index=%u\n", command->GetIndex());
|
||||
}
|
||||
return vk_buffer;
|
||||
return command->Handle();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -1308,27 +1304,10 @@ void BufferCache::SetTextureCache(TextureCache& texture_cache) {
|
||||
m_texture_cache = &texture_cache;
|
||||
}
|
||||
|
||||
// TODO: add LRU cache
|
||||
void BufferCache::RegisterForDelete(VulkanBuffer* buffer) {
|
||||
FaultSafeCacheLock lock(this, m_mutex);
|
||||
|
||||
m_delete_later.push_back(buffer);
|
||||
}
|
||||
|
||||
void BufferCache::DeleteAll(GraphicContext* ctx) {
|
||||
KYTY_PROFILER_BLOCK("BufferCache::DeleteAll");
|
||||
void BufferCache::ResetNullBuffer() {
|
||||
KYTY_PROFILER_BLOCK("BufferCache::ResetNullBuffer");
|
||||
|
||||
FaultSafeCacheLock lock(this, m_mutex);
|
||||
|
||||
for (auto* buffer: m_delete_later) {
|
||||
EXIT_IF(buffer == nullptr);
|
||||
EXIT_IF(buffer->buffer == nullptr);
|
||||
EXIT_IF(ctx == nullptr);
|
||||
|
||||
VulkanDeleteBuffer(ctx, buffer);
|
||||
delete buffer;
|
||||
}
|
||||
m_delete_later.clear();
|
||||
m_null_buffer.reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
@@ -75,16 +74,15 @@ public:
|
||||
void ValidateGpuAccess(uint64_t vaddr, uint64_t size, bool is_read, bool is_written) const;
|
||||
void SetTextureCache(TextureCache& texture_cache);
|
||||
|
||||
void RegisterForDelete(VulkanBuffer* buffer);
|
||||
void DeleteAll(GraphicContext* ctx);
|
||||
void ResetNullBuffer();
|
||||
|
||||
private:
|
||||
struct CachedBuffer;
|
||||
struct ReadbackWorker;
|
||||
|
||||
Common::Mutex m_mutex;
|
||||
std::vector<VulkanBuffer*> m_delete_later;
|
||||
std::shared_ptr<VulkanBuffer> m_null_buffer;
|
||||
Common::Mutex m_mutex;
|
||||
std::shared_ptr<VulkanBuffer> m_null_buffer;
|
||||
// TODO: add LRU cache
|
||||
std::map<uint64_t, std::unique_ptr<CachedBuffer>> m_buffers;
|
||||
std::unique_ptr<ReadbackWorker> m_readback;
|
||||
RangeSet m_gpu_modified_ranges;
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
#include "graphics/host_gpu/renderer/colorRenderTarget.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/profiler.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/threads.h"
|
||||
#include "graphics/guest_gpu/gpu_defs.h"
|
||||
#include "graphics/guest_gpu/hardwareContext.h"
|
||||
#include "graphics/guest_gpu/tile.h"
|
||||
@@ -16,264 +13,17 @@
|
||||
#include "graphics/host_gpu/renderer/framebufferCache.h"
|
||||
#include "graphics/host_gpu/renderer/render.h"
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
#include "graphics/host_gpu/transfer.h"
|
||||
#include "graphics/host_gpu/vulkanCommon.h"
|
||||
#include "graphics/presentation/displayBuffer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
static std::atomic<uint32_t> g_render_color_log_count = 0;
|
||||
|
||||
static float ColorClearUnorm(uint32_t value, uint32_t bits) {
|
||||
return static_cast<float>(value) / static_cast<float>((1u << bits) - 1u);
|
||||
}
|
||||
|
||||
static float ColorClearSnorm(uint32_t value, uint32_t bits) {
|
||||
const uint32_t mask = (1u << bits) - 1u;
|
||||
const uint32_t sign_bit = 1u << (bits - 1u);
|
||||
value &= mask;
|
||||
|
||||
auto signed_value = static_cast<int32_t>(value);
|
||||
if ((value & sign_bit) != 0) {
|
||||
signed_value = static_cast<int32_t>(value | ~mask);
|
||||
}
|
||||
|
||||
const auto denominator = static_cast<float>((1u << (bits - 1u)) - 1u);
|
||||
return std::max(-1.0f, static_cast<float>(signed_value) / denominator);
|
||||
}
|
||||
|
||||
static float ColorClearF16(uint32_t value) {
|
||||
const uint32_t sign = (value >> 15u) & 0x1u;
|
||||
const uint32_t exponent = (value >> 10u) & 0x1fu;
|
||||
const uint32_t mantissa = value & 0x3ffu;
|
||||
const float sign_mul = (sign != 0 ? -1.0f : 1.0f);
|
||||
|
||||
if (exponent == 0) {
|
||||
if (mantissa == 0) {
|
||||
return sign_mul * 0.0f;
|
||||
}
|
||||
return sign_mul * std::ldexp(static_cast<float>(mantissa), -24);
|
||||
}
|
||||
|
||||
if (exponent == 0x1fu) {
|
||||
return mantissa == 0 ? sign_mul * std::numeric_limits<float>::infinity()
|
||||
: std::numeric_limits<float>::quiet_NaN();
|
||||
}
|
||||
|
||||
return sign_mul *
|
||||
std::ldexp(static_cast<float>(0x400u | mantissa), static_cast<int>(exponent) - 25);
|
||||
}
|
||||
|
||||
[[maybe_unused]] static vk::ClearColorValue ColorClearValue(const HW::RenderTarget& rt) {
|
||||
const uint32_t c0 = rt.clear_word0.word0;
|
||||
const uint32_t c1 = rt.clear_word1.word1;
|
||||
|
||||
vk::ClearColorValue color {};
|
||||
|
||||
switch (static_cast<Prospero::ChannelType>(rt.info.channel_type)) {
|
||||
case Prospero::ChannelType::kUNorm:
|
||||
case Prospero::ChannelType::kSrgb:
|
||||
// SRGB clear words are still encoded as normalized component values.
|
||||
switch (static_cast<Prospero::ChannelLayout>(rt.info.format)) {
|
||||
case Prospero::ChannelLayout::k8:
|
||||
color.float32[0] = ColorClearUnorm(c0 & 0xffu, 8);
|
||||
color.float32[1] = 0.0f;
|
||||
color.float32[2] = 0.0f;
|
||||
color.float32[3] = 1.0f;
|
||||
break;
|
||||
case Prospero::ChannelLayout::k8_8:
|
||||
color.float32[0] = ColorClearUnorm(c0 & 0xffu, 8);
|
||||
color.float32[1] = ColorClearUnorm((c0 >> 8u) & 0xffu, 8);
|
||||
color.float32[2] = 0.0f;
|
||||
color.float32[3] = 1.0f;
|
||||
break;
|
||||
case Prospero::ChannelLayout::k8_8_8_8:
|
||||
color.float32[0] = ColorClearUnorm(c0 & 0xffu, 8);
|
||||
color.float32[1] = ColorClearUnorm((c0 >> 8u) & 0xffu, 8);
|
||||
color.float32[2] = ColorClearUnorm((c0 >> 16u) & 0xffu, 8);
|
||||
color.float32[3] = ColorClearUnorm((c0 >> 24u) & 0xffu, 8);
|
||||
if (rt.info.channel_order ==
|
||||
Prospero::GpuEnumValue(Prospero::ChannelOrder::kAlt)) {
|
||||
std::swap(color.float32[0], color.float32[2]);
|
||||
}
|
||||
break;
|
||||
case Prospero::ChannelLayout::k11_11_10:
|
||||
color.float32[0] = 0.0f;
|
||||
color.float32[1] = 0.0f;
|
||||
color.float32[2] = 0.0f;
|
||||
color.float32[3] = 1.0f;
|
||||
break;
|
||||
case Prospero::ChannelLayout::k10_10_10_2:
|
||||
color.float32[0] = ColorClearUnorm(c0 & 0x3ffu, 10);
|
||||
color.float32[1] = ColorClearUnorm((c0 >> 10u) & 0x3ffu, 10);
|
||||
color.float32[2] = ColorClearUnorm((c0 >> 20u) & 0x3ffu, 10);
|
||||
color.float32[3] = ColorClearUnorm((c0 >> 30u) & 0x3u, 2);
|
||||
if (rt.info.channel_order ==
|
||||
Prospero::GpuEnumValue(Prospero::ChannelOrder::kAlt)) {
|
||||
std::swap(color.float32[0], color.float32[2]);
|
||||
}
|
||||
break;
|
||||
case Prospero::ChannelLayout::k16_16:
|
||||
color.float32[0] = 0.0f;
|
||||
color.float32[1] = 0.0f;
|
||||
color.float32[2] = 0.0f;
|
||||
color.float32[3] = 1.0f;
|
||||
break;
|
||||
case Prospero::ChannelLayout::k32_32_32_32:
|
||||
color.float32[0] = 0.0f;
|
||||
color.float32[1] = 0.0f;
|
||||
color.float32[2] = 0.0f;
|
||||
color.float32[3] = 1.0f;
|
||||
break;
|
||||
default:
|
||||
EXIT("%s\n unsupported color clear format\n",
|
||||
Common::Concat(rt_print("RenderTarget", rt), "").c_str());
|
||||
}
|
||||
break;
|
||||
case Prospero::ChannelType::kSNorm:
|
||||
switch (static_cast<Prospero::ChannelLayout>(rt.info.format)) {
|
||||
case Prospero::ChannelLayout::k16_16:
|
||||
color.float32[0] = ColorClearSnorm(c0 & 0xffffu, 16);
|
||||
color.float32[1] = ColorClearSnorm((c0 >> 16u) & 0xffffu, 16);
|
||||
color.float32[2] = 0.0f;
|
||||
color.float32[3] = 1.0f;
|
||||
break;
|
||||
case Prospero::ChannelLayout::k8_8_8_8:
|
||||
color.float32[0] = ColorClearSnorm(c0 & 0xffu, 8);
|
||||
color.float32[1] = ColorClearSnorm((c0 >> 8u) & 0xffu, 8);
|
||||
color.float32[2] = ColorClearSnorm((c0 >> 16u) & 0xffu, 8);
|
||||
color.float32[3] = ColorClearSnorm((c0 >> 24u) & 0xffu, 8);
|
||||
if (rt.info.channel_order ==
|
||||
Prospero::GpuEnumValue(Prospero::ChannelOrder::kAlt)) {
|
||||
std::swap(color.float32[0], color.float32[2]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
EXIT("%s\n unsupported snorm color clear format\n",
|
||||
Common::Concat(rt_print("RenderTarget", rt), "").c_str());
|
||||
}
|
||||
break;
|
||||
case Prospero::ChannelType::kFloat:
|
||||
switch (static_cast<Prospero::ChannelLayout>(rt.info.format)) {
|
||||
case Prospero::ChannelLayout::k16:
|
||||
color.float32[0] = ColorClearF16(c0 & 0xffffu);
|
||||
color.float32[1] = 0.0f;
|
||||
color.float32[2] = 0.0f;
|
||||
color.float32[3] = 1.0f;
|
||||
break;
|
||||
case Prospero::ChannelLayout::k16_16:
|
||||
color.float32[0] = ColorClearF16(c0 & 0xffffu);
|
||||
color.float32[1] = ColorClearF16((c0 >> 16u) & 0xffffu);
|
||||
color.float32[2] = 0.0f;
|
||||
color.float32[3] = 1.0f;
|
||||
break;
|
||||
case Prospero::ChannelLayout::k16_16_16_16:
|
||||
color.float32[0] = ColorClearF16(c0 & 0xffffu);
|
||||
color.float32[1] = ColorClearF16((c0 >> 16u) & 0xffffu);
|
||||
color.float32[2] = ColorClearF16(c1 & 0xffffu);
|
||||
color.float32[3] = ColorClearF16((c1 >> 16u) & 0xffffu);
|
||||
if (rt.info.channel_order ==
|
||||
Prospero::GpuEnumValue(Prospero::ChannelOrder::kAlt)) {
|
||||
std::swap(color.float32[0], color.float32[2]);
|
||||
}
|
||||
break;
|
||||
case Prospero::ChannelLayout::k32:
|
||||
case Prospero::ChannelLayout::k11_11_10:
|
||||
case Prospero::ChannelLayout::k32_32_32_32:
|
||||
color.float32[0] = 0.0f;
|
||||
color.float32[1] = 0.0f;
|
||||
color.float32[2] = 0.0f;
|
||||
color.float32[3] = 1.0f;
|
||||
break;
|
||||
default:
|
||||
EXIT("%s\n unsupported float color clear format\n",
|
||||
Common::Concat(rt_print("RenderTarget", rt), "").c_str());
|
||||
}
|
||||
break;
|
||||
case Prospero::ChannelType::kUInt:
|
||||
case Prospero::ChannelType::kSInt:
|
||||
switch (static_cast<Prospero::ChannelLayout>(rt.info.format)) {
|
||||
case Prospero::ChannelLayout::k8:
|
||||
color.uint32[0] = c0;
|
||||
color.uint32[1] = 0;
|
||||
color.uint32[2] = 0;
|
||||
color.uint32[3] = 1;
|
||||
break;
|
||||
case Prospero::ChannelLayout::k16:
|
||||
color.uint32[0] = c0 & 0xffffu;
|
||||
color.uint32[1] = 0;
|
||||
color.uint32[2] = 0;
|
||||
color.uint32[3] = 1;
|
||||
break;
|
||||
case Prospero::ChannelLayout::k16_16:
|
||||
color.uint32[0] = c0 & 0xffffu;
|
||||
color.uint32[1] = (c0 >> 16u) & 0xffffu;
|
||||
color.uint32[2] = 0;
|
||||
color.uint32[3] = 1;
|
||||
break;
|
||||
case Prospero::ChannelLayout::k8_8_8_8:
|
||||
color.uint32[0] = c0 & 0xffu;
|
||||
color.uint32[1] = (c0 >> 8u) & 0xffu;
|
||||
color.uint32[2] = (c0 >> 16u) & 0xffu;
|
||||
color.uint32[3] = c0 >> 24u;
|
||||
if (rt.info.channel_order ==
|
||||
Prospero::GpuEnumValue(Prospero::ChannelOrder::kAlt)) {
|
||||
std::swap(color.uint32[0], color.uint32[2]);
|
||||
}
|
||||
break;
|
||||
case Prospero::ChannelLayout::k32_32:
|
||||
color.uint32[0] = c0;
|
||||
color.uint32[1] = c1;
|
||||
color.uint32[2] = 0;
|
||||
color.uint32[3] = 1;
|
||||
break;
|
||||
default:
|
||||
EXIT("%s\n unsupported integer color clear format\n",
|
||||
Common::Concat(rt_print("RenderTarget", rt), "").c_str());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
EXIT("%s\n unsupported color clear number type\n",
|
||||
Common::Concat(rt_print("RenderTarget", rt), "").c_str());
|
||||
}
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(
|
||||
c1 != 0 &&
|
||||
!(rt.info.channel_type == Prospero::GpuEnumValue(Prospero::ChannelType::kFloat) &&
|
||||
rt.info.format == Prospero::GpuEnumValue(Prospero::ChannelLayout::k16_16_16_16)) &&
|
||||
!((rt.info.channel_type == Prospero::GpuEnumValue(Prospero::ChannelType::kUInt) ||
|
||||
rt.info.channel_type == Prospero::GpuEnumValue(Prospero::ChannelType::kSInt)) &&
|
||||
rt.info.format == Prospero::GpuEnumValue(Prospero::ChannelLayout::k32_32)));
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static uint32_t RenderGetColorBpp(uint32_t dfmt) {
|
||||
switch (static_cast<Prospero::ChannelLayout>(dfmt)) {
|
||||
case Prospero::ChannelLayout::k8: return 8;
|
||||
case Prospero::ChannelLayout::k16:
|
||||
case Prospero::ChannelLayout::k8_8: return 16;
|
||||
case Prospero::ChannelLayout::k32:
|
||||
case Prospero::ChannelLayout::k16_16:
|
||||
case Prospero::ChannelLayout::k11_11_10:
|
||||
case Prospero::ChannelLayout::k10_10_10_2:
|
||||
case Prospero::ChannelLayout::k8_8_8_8: return 32;
|
||||
case Prospero::ChannelLayout::k32_32:
|
||||
case Prospero::ChannelLayout::k16_16_16_16: return 64;
|
||||
case Prospero::ChannelLayout::k32_32_32_32: return 128;
|
||||
case Prospero::ChannelLayout::k5_5_5_1:
|
||||
case Prospero::ChannelLayout::k4_4_4_4: return 16;
|
||||
default: EXIT("unsupported render-target channel layout: %u\n", dfmt);
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
@@ -369,6 +119,7 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
|
||||
|
||||
// CB_COLOR_CONTROL describes the color-buffer operation / ROP3 logic op.
|
||||
// ROP3 Copy is the normal color write path, not a render-target clear.
|
||||
// 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;
|
||||
@@ -394,9 +145,11 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
|
||||
EXIT("linear mipmapped render targets are unsupported\n");
|
||||
}
|
||||
|
||||
width = rt.attrib2.width + 1;
|
||||
height = rt.attrib2.height + 1;
|
||||
const auto bytes_per_element = RenderGetColorBpp(rt.info.format) / 8u;
|
||||
width = rt.attrib2.width + 1;
|
||||
height = rt.attrib2.height + 1;
|
||||
const auto target_format =
|
||||
TextureGetRenderTargetFormat(rt.info.format, rt.info.channel_type, rt.info.channel_order);
|
||||
const auto bytes_per_element = target_format.bytes_per_element;
|
||||
if (bytes_per_element == 0) {
|
||||
EXIT("render-target format has no valid element size\n");
|
||||
}
|
||||
@@ -497,18 +250,15 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
|
||||
}
|
||||
|
||||
if (render_to_texture) {
|
||||
const auto rt_format = TextureGetRenderTargetFormat(rt.info.format, rt.info.channel_type,
|
||||
rt.info.channel_order);
|
||||
|
||||
(void)reuse_existing_render_texture;
|
||||
RenderTargetInfo target {};
|
||||
target.address = rt.base.addr;
|
||||
target.size = backing_size;
|
||||
target.format = rt_format.format;
|
||||
target.format = target_format.format;
|
||||
target.width = width;
|
||||
target.height = height;
|
||||
target.pitch = pitch;
|
||||
target.bytes_per_element = rt_format.bytes_per_element;
|
||||
target.bytes_per_element = target_format.bytes_per_element;
|
||||
target.tile_mode = rt.attrib3.tile_mode;
|
||||
target.levels = levels;
|
||||
target.layers = view.image_layers;
|
||||
@@ -525,7 +275,7 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
|
||||
r->extent = view_extent;
|
||||
r->base_mip_level = rt.view.current_mip_level;
|
||||
r->buffer_size = backing_size;
|
||||
r->export_mapping = rt_format.export_mapping;
|
||||
r->export_mapping = target_format.export_mapping;
|
||||
} else {
|
||||
const auto layout = static_cast<Prospero::ChannelLayout>(rt.info.format);
|
||||
const auto type = static_cast<Prospero::ChannelType>(rt.info.channel_type);
|
||||
@@ -562,9 +312,7 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
|
||||
r->extent = video_image.image->extent;
|
||||
r->base_mip_level = 0;
|
||||
r->buffer_size = video_image.size;
|
||||
r->export_mapping = TextureGetRenderTargetFormat(rt.info.format, rt.info.channel_type,
|
||||
rt.info.channel_order)
|
||||
.export_mapping;
|
||||
r->export_mapping = target_format.export_mapping;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,19 +10,35 @@
|
||||
#include "graphics/host_gpu/renderer/depthRenderTarget.h"
|
||||
#include "graphics/host_gpu/renderer/descriptorCache.h"
|
||||
#include "graphics/host_gpu/renderer/framebufferCache.h"
|
||||
#include "graphics/host_gpu/renderer/imageView.h"
|
||||
#include "graphics/host_gpu/renderer/render.h"
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
#include "graphics/host_gpu/transfer.h"
|
||||
#include "graphics/host_gpu/vma.h"
|
||||
#include "graphics/host_gpu/vulkanCommon.h"
|
||||
#include "graphics/presentation/window.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
namespace Libs::Graphics {
|
||||
static std::atomic<uint64_t> g_command_buffer_submit_seq = 0;
|
||||
|
||||
static void RequireValidQueueId(int queue_id) {
|
||||
EXIT_IF(queue_id < 0 || queue_id >= GraphicContext::QUEUES_NUM);
|
||||
}
|
||||
|
||||
static void ResetNativeCommandBuffer(vk::CommandBuffer buffer) {
|
||||
EXIT_IF(buffer == nullptr);
|
||||
const auto result = buffer.reset(vk::CommandBufferResetFlagBits::eReleaseResources);
|
||||
if (result != vk::Result::eSuccess) {
|
||||
EXIT("failed to reset Vulkan command buffer: %s (%d)\n", VulkanToString(result).c_str(),
|
||||
static_cast<int>(result));
|
||||
}
|
||||
}
|
||||
|
||||
class CommandPool {
|
||||
public:
|
||||
CommandPool() = default;
|
||||
@@ -34,18 +50,19 @@ public:
|
||||
|
||||
KYTY_CLASS_NO_COPY(CommandPool);
|
||||
|
||||
VulkanCommandPool* GetPool(int id) {
|
||||
if (m_pool[id] == nullptr) {
|
||||
Create(id);
|
||||
VulkanCommandPool* GetPool(int queue_id) {
|
||||
RequireValidQueueId(queue_id);
|
||||
if (m_pools[queue_id] == nullptr) {
|
||||
Create(queue_id);
|
||||
}
|
||||
return m_pool[id];
|
||||
return m_pools[queue_id];
|
||||
}
|
||||
void DeleteAll();
|
||||
|
||||
private:
|
||||
void Create(int id);
|
||||
void Create(int queue_id);
|
||||
|
||||
VulkanCommandPool* m_pool[GraphicContext::QUEUES_NUM] = {};
|
||||
std::array<VulkanCommandPool*, GraphicContext::QUEUES_NUM> m_pools {};
|
||||
};
|
||||
|
||||
RenderContext* g_render_ctx = nullptr;
|
||||
@@ -90,28 +107,28 @@ void GraphicsRenderCreateContext() {
|
||||
g_render_ctx->SetGraphicCtx(WindowGetGraphicContext());
|
||||
}
|
||||
|
||||
void CommandPool::Create(int id) {
|
||||
auto* ctx = g_render_ctx->GetGraphicCtx();
|
||||
void CommandPool::Create(int queue_id) {
|
||||
RequireValidQueueId(queue_id);
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
|
||||
EXIT_IF(id < 0 || id >= GraphicContext::QUEUES_NUM);
|
||||
auto*& pool = m_pool[id];
|
||||
auto* ctx = g_render_ctx->GetGraphicCtx();
|
||||
auto*& pool = m_pools[queue_id];
|
||||
EXIT_IF(pool != nullptr);
|
||||
|
||||
EXIT_IF(ctx == nullptr);
|
||||
EXIT_IF(ctx->device == nullptr);
|
||||
EXIT_IF(ctx->queues[id].family == static_cast<uint32_t>(-1));
|
||||
EXIT_IF(ctx->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[id].family;
|
||||
pool_info.queueFamilyIndex = ctx->queues[queue_id].family;
|
||||
pool_info.flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer;
|
||||
|
||||
ctx->device.createCommandPool(&pool_info, nullptr, &pool->pool);
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(pool->pool == nullptr);
|
||||
const auto result = ctx->device.createCommandPool(&pool_info, nullptr, &pool->pool);
|
||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || pool->pool == nullptr);
|
||||
|
||||
pool->buffers_count = 8;
|
||||
pool->buffers = std::make_unique<vk::CommandBuffer[]>(pool->buffers_count);
|
||||
@@ -162,7 +179,7 @@ void CommandPool::Create(int id) {
|
||||
void CommandPool::DeleteAll() {
|
||||
auto* ctx = g_render_ctx->GetGraphicCtx();
|
||||
|
||||
for (auto& pool: m_pool) {
|
||||
for (auto& pool: m_pools) {
|
||||
if (pool != nullptr) {
|
||||
EXIT_IF(ctx == nullptr);
|
||||
EXIT_IF(ctx->device == nullptr);
|
||||
@@ -194,6 +211,14 @@ bool CommandBuffer::IsInvalid() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
vk::CommandBuffer CommandBuffer::Handle() const {
|
||||
EXIT_IF(IsInvalid());
|
||||
|
||||
const auto handle = m_pool->buffers[m_index];
|
||||
EXIT_IF(handle == nullptr);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void CommandBuffer::Allocate() {
|
||||
EXIT_IF(!IsInvalid());
|
||||
|
||||
@@ -204,7 +229,7 @@ void CommandBuffer::Allocate() {
|
||||
for (uint32_t i = 0; i < m_pool->buffers_count; i++) {
|
||||
if (!m_pool->busy[i]) {
|
||||
m_pool->busy[i] = true;
|
||||
m_pool->buffers[i].reset(vk::CommandBufferResetFlagBits::eReleaseResources);
|
||||
ResetNativeCommandBuffer(m_pool->buffers[i]);
|
||||
m_index = i;
|
||||
break;
|
||||
}
|
||||
@@ -223,9 +248,8 @@ void CommandBuffer::Free() {
|
||||
m_host_stream.Release();
|
||||
|
||||
m_pool->busy[m_index] = false;
|
||||
m_pool->buffers[m_index].reset(vk::CommandBufferResetFlagBits::eReleaseResources);
|
||||
RecycleDescriptorsAfterFence();
|
||||
m_fence_resources.ReleaseAfterFence();
|
||||
ResetNativeCommandBuffer(m_pool->buffers[m_index]);
|
||||
ReleaseResourcesAfterFence();
|
||||
m_index = static_cast<uint32_t>(-1);
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(!IsInvalid());
|
||||
@@ -258,9 +282,7 @@ void CommandBuffer::RecycleDescriptorsAfterFence() {
|
||||
}
|
||||
|
||||
void CommandBuffer::Begin() const {
|
||||
EXIT_IF(IsInvalid());
|
||||
|
||||
auto buffer = m_pool->buffers[m_index];
|
||||
auto buffer = Handle();
|
||||
|
||||
vk::CommandBufferBeginInfo begin_info {};
|
||||
begin_info.sType = vk::StructureType::eCommandBufferBeginInfo;
|
||||
@@ -274,9 +296,7 @@ void CommandBuffer::Begin() const {
|
||||
}
|
||||
|
||||
void CommandBuffer::End() const {
|
||||
EXIT_IF(IsInvalid());
|
||||
|
||||
auto buffer = m_pool->buffers[m_index];
|
||||
auto buffer = Handle();
|
||||
|
||||
auto result = buffer.end();
|
||||
|
||||
@@ -295,159 +315,48 @@ void CommandBuffer::SetDebugInfo(uint32_t op, uint64_t submit_id, uint32_t arg0,
|
||||
}
|
||||
|
||||
void CommandBuffer::Execute() {
|
||||
EXIT_IF(IsInvalid());
|
||||
EXIT_IF(m_execute);
|
||||
|
||||
auto buffer = m_pool->buffers[m_index];
|
||||
auto fence = m_pool->fences[m_index];
|
||||
|
||||
vk::SubmitInfo submit_info {};
|
||||
submit_info.sType = vk::StructureType::eSubmitInfo;
|
||||
submit_info.pNext = nullptr;
|
||||
submit_info.waitSemaphoreCount = 0;
|
||||
submit_info.pWaitSemaphores = nullptr;
|
||||
submit_info.pWaitDstStageMask = nullptr;
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = &buffer;
|
||||
submit_info.signalSemaphoreCount = 0;
|
||||
submit_info.pSignalSemaphores = nullptr;
|
||||
|
||||
EXIT_IF(m_queue < 0 || m_queue >= GraphicContext::QUEUES_NUM);
|
||||
|
||||
const auto& queue = g_render_ctx->GetGraphicCtx()->queues[m_queue];
|
||||
|
||||
auto result = g_render_ctx->GetGraphicCtx()->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));
|
||||
}
|
||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||
|
||||
if (queue.mutex != nullptr) {
|
||||
queue.mutex->Lock();
|
||||
}
|
||||
|
||||
if (Config::GraphicsDebugDumpEnabled()) {
|
||||
LOGF("vkQueueSubmit begin: queue=%d index=%u debug_op=%u debug_submit=%" PRIu64
|
||||
" args=%u,%u,%u,%u,0x%016" PRIx64 "\n",
|
||||
m_queue, m_index, m_debug_op, m_debug_submit_id, m_debug_arg0, m_debug_arg1,
|
||||
m_debug_arg2, m_debug_arg3, m_debug_arg4);
|
||||
}
|
||||
|
||||
result = queue.vk_queue.submit(1, &submit_info, fence);
|
||||
|
||||
if (queue.mutex != nullptr) {
|
||||
queue.mutex->Unlock();
|
||||
}
|
||||
|
||||
m_execute = true;
|
||||
m_fence_waited = false;
|
||||
m_submit_seq = g_command_buffer_submit_seq.fetch_add(1, std::memory_order_relaxed) + 1;
|
||||
|
||||
if (result != vk::Result::eSuccess) {
|
||||
LOGF("vkQueueSubmit failed: %s (%d), queue=%d index=%u submit_seq=%" PRIu64
|
||||
" debug_op=%u debug_submit=%" PRIu64 " args=%u,%u,%u,%u,0x%016" PRIx64 "\n",
|
||||
VulkanToString(result).c_str(), static_cast<int>(result), m_queue, m_index,
|
||||
m_submit_seq, m_debug_op, m_debug_submit_id, m_debug_arg0, m_debug_arg1, m_debug_arg2,
|
||||
m_debug_arg3, m_debug_arg4);
|
||||
}
|
||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||
Submit(nullptr, {}, nullptr);
|
||||
}
|
||||
|
||||
void CommandBuffer::ExecuteWithSemaphore(vk::Semaphore signal_semaphore) {
|
||||
EXIT_IF(IsInvalid());
|
||||
EXIT_IF(m_execute);
|
||||
|
||||
auto buffer = m_pool->buffers[m_index];
|
||||
auto fence = m_pool->fences[m_index];
|
||||
|
||||
if (signal_semaphore == nullptr) {
|
||||
signal_semaphore = m_pool->semaphores[m_index];
|
||||
}
|
||||
|
||||
vk::SubmitInfo submit_info {};
|
||||
submit_info.sType = vk::StructureType::eSubmitInfo;
|
||||
submit_info.pNext = nullptr;
|
||||
submit_info.waitSemaphoreCount = 0;
|
||||
submit_info.pWaitSemaphores = nullptr;
|
||||
submit_info.pWaitDstStageMask = nullptr;
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = &buffer;
|
||||
submit_info.signalSemaphoreCount = 1;
|
||||
submit_info.pSignalSemaphores = &signal_semaphore;
|
||||
|
||||
EXIT_IF(m_queue < 0 || m_queue >= GraphicContext::QUEUES_NUM);
|
||||
|
||||
const auto& queue = g_render_ctx->GetGraphicCtx()->queues[m_queue];
|
||||
|
||||
auto result = g_render_ctx->GetGraphicCtx()->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));
|
||||
}
|
||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||
|
||||
if (queue.mutex != nullptr) {
|
||||
queue.mutex->Lock();
|
||||
}
|
||||
|
||||
if (Config::GraphicsDebugDumpEnabled()) {
|
||||
LOGF("vkQueueSubmit begin: queue=%d index=%u signal_semaphore=%p debug_op=%u"
|
||||
" debug_submit=%" PRIu64 " args=%u,%u,%u,%u,0x%016" PRIx64 "\n",
|
||||
m_queue, m_index, static_cast<void*>(signal_semaphore), m_debug_op, m_debug_submit_id,
|
||||
m_debug_arg0, m_debug_arg1, m_debug_arg2, m_debug_arg3, m_debug_arg4);
|
||||
}
|
||||
|
||||
result = queue.vk_queue.submit(1, &submit_info, fence);
|
||||
|
||||
if (queue.mutex != nullptr) {
|
||||
queue.mutex->Unlock();
|
||||
}
|
||||
|
||||
m_execute = true;
|
||||
m_fence_waited = false;
|
||||
m_submit_seq = g_command_buffer_submit_seq.fetch_add(1, std::memory_order_relaxed) + 1;
|
||||
|
||||
if (result != vk::Result::eSuccess) {
|
||||
LOGF("vkQueueSubmit failed: %s (%d), queue=%d index=%u submit_seq=%" PRIu64
|
||||
" debug_op=%u debug_submit=%" PRIu64 " args=%u,%u,%u,%u,0x%016" PRIx64 "\n",
|
||||
VulkanToString(result).c_str(), static_cast<int>(result), m_queue, m_index,
|
||||
m_submit_seq, m_debug_op, m_debug_submit_id, m_debug_arg0, m_debug_arg1, m_debug_arg2,
|
||||
m_debug_arg3, m_debug_arg4);
|
||||
}
|
||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||
Submit(nullptr, {}, ResolveSignalSemaphore(signal_semaphore));
|
||||
}
|
||||
|
||||
void CommandBuffer::ExecuteWithSemaphore(vk::Semaphore wait_semaphore,
|
||||
vk::PipelineStageFlags wait_stage,
|
||||
vk::Semaphore signal_semaphore) {
|
||||
EXIT_IF(wait_semaphore == nullptr);
|
||||
Submit(wait_semaphore, wait_stage, ResolveSignalSemaphore(signal_semaphore));
|
||||
}
|
||||
|
||||
void CommandBuffer::Submit(vk::Semaphore wait_semaphore, vk::PipelineStageFlags wait_stage,
|
||||
vk::Semaphore signal_semaphore) {
|
||||
RequireValidQueueId(m_queue);
|
||||
EXIT_IF(IsInvalid());
|
||||
EXIT_IF(m_execute);
|
||||
EXIT_IF(wait_semaphore == nullptr);
|
||||
|
||||
auto buffer = m_pool->buffers[m_index];
|
||||
auto fence = m_pool->fences[m_index];
|
||||
|
||||
if (signal_semaphore == nullptr) {
|
||||
signal_semaphore = m_pool->semaphores[m_index];
|
||||
}
|
||||
const bool has_wait = wait_semaphore != nullptr;
|
||||
const bool has_signal = signal_semaphore != nullptr;
|
||||
auto buffer = Handle();
|
||||
auto fence = m_pool->fences[m_index];
|
||||
|
||||
vk::SubmitInfo submit_info {};
|
||||
submit_info.sType = vk::StructureType::eSubmitInfo;
|
||||
submit_info.pNext = nullptr;
|
||||
submit_info.waitSemaphoreCount = 1;
|
||||
submit_info.pWaitSemaphores = &wait_semaphore;
|
||||
submit_info.pWaitDstStageMask = &wait_stage;
|
||||
submit_info.waitSemaphoreCount = has_wait ? 1u : 0u;
|
||||
submit_info.pWaitSemaphores = has_wait ? &wait_semaphore : nullptr;
|
||||
submit_info.pWaitDstStageMask = has_wait ? &wait_stage : nullptr;
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = &buffer;
|
||||
submit_info.signalSemaphoreCount = 1;
|
||||
submit_info.pSignalSemaphores = &signal_semaphore;
|
||||
submit_info.signalSemaphoreCount = has_signal ? 1u : 0u;
|
||||
submit_info.pSignalSemaphores = has_signal ? &signal_semaphore : nullptr;
|
||||
|
||||
EXIT_IF(m_queue < 0 || m_queue >= GraphicContext::QUEUES_NUM);
|
||||
auto* ctx = g_render_ctx->GetGraphicCtx();
|
||||
EXIT_IF(ctx == nullptr);
|
||||
EXIT_IF(ctx->device == nullptr);
|
||||
const auto& queue = ctx->queues[m_queue];
|
||||
|
||||
const auto& queue = g_render_ctx->GetGraphicCtx()->queues[m_queue];
|
||||
|
||||
auto result = g_render_ctx->GetGraphicCtx()->device.resetFences(1, &fence);
|
||||
auto result = ctx->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));
|
||||
@@ -486,20 +395,16 @@ void CommandBuffer::ExecuteWithSemaphore(vk::Semaphore wait_semaphore,
|
||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||
}
|
||||
|
||||
vk::Semaphore CommandBuffer::ResolveSignalSemaphore(vk::Semaphore semaphore) const {
|
||||
if (semaphore != nullptr) {
|
||||
return semaphore;
|
||||
}
|
||||
EXIT_IF(IsInvalid());
|
||||
return m_pool->semaphores[m_index];
|
||||
}
|
||||
|
||||
void CommandBuffer::WaitForFence() {
|
||||
const bool was_executed = m_execute;
|
||||
WaitForFenceOnly();
|
||||
if (was_executed) {
|
||||
m_execute = false;
|
||||
m_fence_waited = false;
|
||||
RecycleDescriptorsAfterFence();
|
||||
m_fence_resources.ReleaseAfterFence();
|
||||
}
|
||||
for (auto* buffer: m_delete_after_fence) {
|
||||
VulkanDeleteBuffer(g_render_ctx->GetGraphicCtx(), buffer);
|
||||
delete buffer;
|
||||
}
|
||||
m_delete_after_fence.clear();
|
||||
FinalizeFence(false);
|
||||
}
|
||||
|
||||
void CommandBuffer::WaitForFenceOnly() {
|
||||
@@ -521,19 +426,35 @@ void CommandBuffer::WaitForFenceOnly() {
|
||||
}
|
||||
|
||||
void CommandBuffer::WaitForFenceAndReset() {
|
||||
FinalizeFence(true);
|
||||
}
|
||||
|
||||
void CommandBuffer::FinalizeFence(bool reset_recording) {
|
||||
const bool was_executed = m_execute;
|
||||
WaitForFenceOnly();
|
||||
if (was_executed) {
|
||||
m_execute = false;
|
||||
m_fence_waited = false;
|
||||
m_pool->buffers[m_index].reset(vk::CommandBufferResetFlagBits::eReleaseResources);
|
||||
m_recording_generation++;
|
||||
if (reset_recording) {
|
||||
ResetNativeCommandBuffer(m_pool->buffers[m_index]);
|
||||
m_recording_generation++;
|
||||
}
|
||||
}
|
||||
if (reset_recording) {
|
||||
m_host_stream.Reset();
|
||||
}
|
||||
m_host_stream.Reset();
|
||||
if (was_executed) {
|
||||
RecycleDescriptorsAfterFence();
|
||||
m_fence_resources.ReleaseAfterFence();
|
||||
ReleaseResourcesAfterFence();
|
||||
}
|
||||
DeleteBuffersAfterFence();
|
||||
}
|
||||
|
||||
void CommandBuffer::ReleaseResourcesAfterFence() {
|
||||
RecycleDescriptorsAfterFence();
|
||||
m_fence_resources.ReleaseAfterFence();
|
||||
}
|
||||
|
||||
void CommandBuffer::DeleteBuffersAfterFence() {
|
||||
for (auto* buffer: m_delete_after_fence) {
|
||||
VulkanDeleteBuffer(g_render_ctx->GetGraphicCtx(), buffer);
|
||||
delete buffer;
|
||||
@@ -543,9 +464,7 @@ void CommandBuffer::WaitForFenceAndReset() {
|
||||
|
||||
void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorInfo* colors,
|
||||
uint32_t requested_color_count, RenderDepthInfo* depth) const {
|
||||
EXIT_IF(IsInvalid());
|
||||
|
||||
auto buffer = m_pool->buffers[m_index];
|
||||
auto buffer = Handle();
|
||||
|
||||
EXIT_IF(framebuffer == nullptr);
|
||||
EXIT_IF(colors == nullptr);
|
||||
@@ -643,7 +562,7 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI
|
||||
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
image_memory_barrier.image = depth->vulkan_buffer->image;
|
||||
image_memory_barrier.subresourceRange.aspectMask =
|
||||
DepthStencilAspectMask(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;
|
||||
@@ -665,9 +584,7 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI
|
||||
}
|
||||
|
||||
void CommandBuffer::EndRenderPass() const {
|
||||
EXIT_IF(IsInvalid());
|
||||
|
||||
auto buffer = m_pool->buffers[m_index];
|
||||
auto buffer = Handle();
|
||||
|
||||
buffer.endRenderPass();
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "graphics/host_gpu/renderer/framebufferCache.h"
|
||||
#include "graphics/host_gpu/renderer/render.h"
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
#include "graphics/host_gpu/transfer.h"
|
||||
#include "graphics/host_gpu/vulkanCommon.h"
|
||||
#include "graphics/presentation/displayBuffer.h"
|
||||
|
||||
|
||||
@@ -102,15 +102,10 @@ vk::DescriptorImageInfo MakeDescriptorImageInfo(const DescriptorCache::TextureBi
|
||||
|
||||
} // namespace
|
||||
|
||||
void DescriptorCache::Init() {
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
vk::DescriptorSetLayout
|
||||
DescriptorCache::GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stage,
|
||||
const ShaderRecompiler::IR::Program& program) {
|
||||
EXIT_IF(gctx == nullptr);
|
||||
Init();
|
||||
const auto key = LayoutKey(stage, program);
|
||||
if (const auto found = m_descriptor_set_layouts.find(key);
|
||||
found != m_descriptor_set_layouts.end()) {
|
||||
@@ -132,8 +127,8 @@ DescriptorCache::GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stag
|
||||
info.bindingCount = static_cast<uint32_t>(bindings.size());
|
||||
info.pBindings = bindings.data();
|
||||
vk::DescriptorSetLayout layout = nullptr;
|
||||
gctx->device.createDescriptorSetLayout(&info, nullptr, &layout);
|
||||
EXIT_NOT_IMPLEMENTED(layout == nullptr);
|
||||
const auto result = gctx->device.createDescriptorSetLayout(&info, nullptr, &layout);
|
||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || layout == nullptr);
|
||||
m_descriptor_set_layouts.emplace(key, layout);
|
||||
return layout;
|
||||
}
|
||||
@@ -157,8 +152,8 @@ void DescriptorCache::CreatePool(GraphicContext* gctx) {
|
||||
info.maxSets = MaxSets;
|
||||
const auto pool_id = static_cast<int>(m_pools.size());
|
||||
auto& pool = m_pools.emplace_back();
|
||||
gctx->device.createDescriptorPool(&info, nullptr, &pool.pool);
|
||||
EXIT_NOT_IMPLEMENTED(pool.pool == nullptr);
|
||||
const auto result = gctx->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;
|
||||
}
|
||||
@@ -198,7 +193,6 @@ VulkanDescriptorSet* DescriptorCache::Allocate(Stage
|
||||
}
|
||||
return new VulkanDescriptorSet {sets.back(), layout, pool_id};
|
||||
}
|
||||
pool.free = false;
|
||||
m_first_free_pool = pool.next_free_pool;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -22,10 +22,6 @@ struct Program;
|
||||
class CommandBuffer;
|
||||
struct ShaderStageRuntime;
|
||||
|
||||
struct VulkanDescriptor {
|
||||
vk::DescriptorSet descriptor_set = nullptr;
|
||||
};
|
||||
|
||||
struct VulkanDescriptorSet {
|
||||
vk::DescriptorSet set = nullptr;
|
||||
vk::DescriptorSetLayout layout = nullptr;
|
||||
@@ -38,12 +34,6 @@ struct BufferView {
|
||||
vk::DeviceSize range = VK_WHOLE_SIZE;
|
||||
};
|
||||
|
||||
struct ShaderAddressWriteRange {
|
||||
VulkanBuffer* buffer = nullptr;
|
||||
uint64_t address = 0;
|
||||
uint64_t size = 0;
|
||||
};
|
||||
|
||||
class DescriptorCache {
|
||||
public:
|
||||
enum class Stage { Unknown, Vertex, Pixel, Compute };
|
||||
@@ -74,7 +64,7 @@ public:
|
||||
};
|
||||
|
||||
DescriptorCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
|
||||
virtual ~DescriptorCache() { KYTY_NOT_IMPLEMENTED; }
|
||||
~DescriptorCache() { KYTY_NOT_IMPLEMENTED; }
|
||||
KYTY_CLASS_NO_COPY(DescriptorCache);
|
||||
|
||||
vk::DescriptorSetLayout GetDescriptorSetLayout(Stage stage,
|
||||
@@ -87,10 +77,8 @@ private:
|
||||
struct Pool {
|
||||
vk::DescriptorPool pool = nullptr;
|
||||
int next_free_pool = -1;
|
||||
bool free = true;
|
||||
};
|
||||
|
||||
void Init();
|
||||
void CreatePool(GraphicContext* gctx);
|
||||
VulkanDescriptorSet* Allocate(Stage stage, const ShaderRecompiler::IR::Program& program);
|
||||
vk::DescriptorSetLayout
|
||||
@@ -103,17 +91,12 @@ private:
|
||||
std::unordered_map<vk::DescriptorSetLayout, std::vector<VulkanDescriptorSet*>>
|
||||
m_free_sets_by_layout;
|
||||
std::map<std::vector<uint32_t>, vk::DescriptorSetLayout> m_descriptor_set_layouts;
|
||||
bool m_initialized = false;
|
||||
};
|
||||
|
||||
const char* storage_usage_name(ShaderStorageUsage usage);
|
||||
vk::ImageAspectFlags DepthStencilAspectMask(vk::Format format);
|
||||
std::vector<ShaderAddressWriteRange> 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);
|
||||
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);
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
#include "graphics/host_gpu/renderer/renderTargetBarriers.h"
|
||||
#include "graphics/host_gpu/renderer/shaderResourceBarrier.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
#include "graphics/host_gpu/transfer.h"
|
||||
#include "graphics/host_gpu/vma.h"
|
||||
#include "graphics/host_gpu/vulkanCommon.h"
|
||||
#include "graphics/presentation/displayBuffer.h"
|
||||
@@ -34,9 +34,9 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <fmt/format.h>
|
||||
#include <limits>
|
||||
#include <span>
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
@@ -71,14 +71,6 @@ static const char* VulkanImageTypeName(VulkanImageType type) {
|
||||
}
|
||||
}
|
||||
|
||||
vk::ImageAspectFlags DepthStencilAspectMask(vk::Format format) {
|
||||
auto ret = static_cast<vk::ImageAspectFlags>(vk::ImageAspectFlagBits::eDepth);
|
||||
if (format == vk::Format::eD24UnormS8Uint || format == vk::Format::eD32SfloatS8Uint) {
|
||||
ret |= vk::ImageAspectFlagBits::eStencil;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int SampledArrayViewIndex(const VulkanImage* image, int view_index) {
|
||||
EXIT_IF(image == nullptr);
|
||||
|
||||
@@ -126,25 +118,10 @@ static VulkanImage* GetDummyStorageTexture(TextureVariant variant) {
|
||||
TextureVariantIs3D(variant));
|
||||
}
|
||||
|
||||
static ShaderBufferResource
|
||||
NativeBufferDescriptor(const ShaderRecompiler::IR::DescriptorValue& descriptor) {
|
||||
ShaderBufferResource result;
|
||||
std::copy_n(descriptor.dwords.begin(), std::size(result.fields), result.fields);
|
||||
return result;
|
||||
}
|
||||
|
||||
static ShaderTextureResource
|
||||
NativeTextureDescriptor(const ShaderRecompiler::IR::DescriptorValue& descriptor) {
|
||||
ShaderTextureResource result;
|
||||
std::copy_n(descriptor.dwords.begin(), std::size(result.fields), result.fields);
|
||||
return result;
|
||||
}
|
||||
|
||||
static ShaderSamplerResource
|
||||
NativeSamplerDescriptor(const ShaderRecompiler::IR::DescriptorValue& descriptor) {
|
||||
ShaderSamplerResource result;
|
||||
std::copy_n(descriptor.dwords.begin(), std::size(result.fields), result.fields);
|
||||
return result;
|
||||
static void CopyNativeDescriptor(const ShaderRecompiler::IR::DescriptorValue& source,
|
||||
std::span<uint32_t> destination) {
|
||||
EXIT_IF(source.dword_count != destination.size());
|
||||
std::copy_n(source.dwords.begin(), destination.size(), destination.begin());
|
||||
}
|
||||
|
||||
static BufferView NativeStorageBuffer(uint64_t submit_id, CommandBuffer* command_buffer,
|
||||
@@ -505,10 +482,11 @@ static DescriptorCache::TextureBinding
|
||||
NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
|
||||
const ShaderRecompiler::IR::ImageResource& resource,
|
||||
const ShaderRecompiler::IR::DescriptorValue& value) {
|
||||
auto descriptor = NativeTextureDescriptor(value);
|
||||
const bool storage = resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImage ||
|
||||
resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
||||
const auto variant = NativeTextureVariant(resource);
|
||||
ShaderTextureResource descriptor;
|
||||
CopyNativeDescriptor(value, descriptor.fields);
|
||||
const bool storage = resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImage ||
|
||||
resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint;
|
||||
const auto variant = NativeTextureVariant(resource);
|
||||
if (storage) {
|
||||
ValidateStorageImageResource(resource);
|
||||
}
|
||||
@@ -542,8 +520,7 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
|
||||
EXIT("sampled image numeric class mismatch: kind=%u format=%u addr=0x%016" PRIx64 "\n",
|
||||
static_cast<uint32_t>(resource.kind), format, address);
|
||||
}
|
||||
const auto view_format = TextureGetFormat(format, storage ? TextureFormatUsage::Storage
|
||||
: TextureFormatUsage::Sampled);
|
||||
const auto view_format = TextureGetFormat(format);
|
||||
const auto type = static_cast<Prospero::ImageType>(descriptor.Type());
|
||||
const auto target_view =
|
||||
ResolveTargetTextureView(resource, type, descriptor.BaseArray5(), depth);
|
||||
@@ -754,7 +731,8 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
|
||||
|
||||
static vk::Sampler NativeSampler(const ShaderRecompiler::IR::Program& program, uint32_t index,
|
||||
const ShaderRecompiler::IR::DescriptorValue& value) {
|
||||
auto descriptor = NativeSamplerDescriptor(value);
|
||||
ShaderSamplerResource descriptor;
|
||||
CopyNativeDescriptor(value, descriptor.fields);
|
||||
const bool depth_compare = std::any_of(program.info.sampled_pairs.begin(),
|
||||
program.info.sampled_pairs.end(), [&](const auto& pair) {
|
||||
return pair.sampler == index &&
|
||||
@@ -776,12 +754,10 @@ static BufferView NativeUpload(CommandBuffer* command_buffer, std::span<const ui
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<ShaderAddressWriteRange> 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) {
|
||||
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);
|
||||
const auto& program = *runtime.program;
|
||||
@@ -790,15 +766,16 @@ std::vector<ShaderAddressWriteRange> BindDescriptors(uint64_t submit_id, Command
|
||||
if (!ShaderRecompiler::IR::ValidateResourceSpecialization(program, snapshot, &error)) {
|
||||
EXIT("invalid native shader runtime snapshot: %s\n", error.c_str());
|
||||
}
|
||||
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()];
|
||||
auto vk_buffer = buffer->Handle();
|
||||
const auto shader_stages = ShaderPipelineStages(vk_stage);
|
||||
|
||||
DescriptorCache::NativeDescriptors descriptors;
|
||||
descriptors.buffers.reserve(program.info.buffers.size());
|
||||
for (uint32_t i = 0; i < program.info.buffers.size(); i++) {
|
||||
ShaderBufferResource descriptor;
|
||||
CopyNativeDescriptor(snapshot.buffers[i], descriptor.fields);
|
||||
descriptors.buffers.push_back(
|
||||
NativeStorageBuffer(submit_id, buffer, NativeBufferDescriptor(snapshot.buffers[i]),
|
||||
program.info.buffers[i]));
|
||||
NativeStorageBuffer(submit_id, buffer, descriptor, program.info.buffers[i]));
|
||||
}
|
||||
descriptors.images.reserve(program.info.images.size());
|
||||
for (uint32_t i = 0; i < program.info.images.size(); i++) {
|
||||
@@ -816,17 +793,9 @@ std::vector<ShaderAddressWriteRange> BindDescriptors(uint64_t submit_id, Command
|
||||
descriptors.samplers.push_back(NativeSampler(program, i, snapshot.samplers[i]));
|
||||
}
|
||||
descriptors.addresses.reserve(program.info.addresses.size());
|
||||
std::vector<ShaderAddressWriteRange> address_writes;
|
||||
for (uint32_t i = 0; i < program.info.addresses.size(); i++) {
|
||||
auto view = NativeAddressBuffer(submit_id, buffer, program.info.addresses[i],
|
||||
snapshot.addresses[i]);
|
||||
descriptors.addresses.push_back(view);
|
||||
if (program.info.addresses[i].written && snapshot.addresses[i].binding_base != 0) {
|
||||
EXIT_IF(view.buffer == nullptr || view.offset != 0 || view.range == VK_WHOLE_SIZE ||
|
||||
view.range == 0);
|
||||
address_writes.push_back({view.buffer, snapshot.addresses[i].binding_base,
|
||||
static_cast<uint64_t>(view.range)});
|
||||
}
|
||||
descriptors.addresses.push_back(NativeAddressBuffer(
|
||||
submit_id, buffer, program.info.addresses[i], snapshot.addresses[i]));
|
||||
}
|
||||
if (ShaderRecompiler::IR::FindBinding(
|
||||
program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::FlattenedSrt) !=
|
||||
@@ -893,7 +862,6 @@ std::vector<ShaderAddressWriteRange> BindDescriptors(uint64_t submit_id, Command
|
||||
vk_buffer.pushConstants(layout, vk_stage, program.bindings.push_constant_offset,
|
||||
program.bindings.push_constant_size, user_data.data());
|
||||
}
|
||||
return address_writes;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_DESCRIPTORS_H_
|
||||
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_DESCRIPTORS_H_
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "graphics/host_gpu/vulkanCommon.h"
|
||||
#include "graphics/shader/recompiler/ShaderIR.h"
|
||||
#include "graphics/shader/shaderBindings.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
struct VulkanImage;
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] T DecodeNativeDescriptor(const ShaderRecompiler::IR::DescriptorValue& value) {
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
static_assert(sizeof(T) % sizeof(uint32_t) == 0);
|
||||
T result {};
|
||||
EXIT_IF(value.dword_count < sizeof(result) / sizeof(uint32_t));
|
||||
std::memcpy(&result, value.dwords.data(), sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
struct TargetTextureViewInfo {
|
||||
vk::ImageViewType type = static_cast<vk::ImageViewType>(VK_IMAGE_VIEW_TYPE_MAX_ENUM);
|
||||
uint32_t base_layer = 0;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "graphics/host_gpu/renderer/image.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
#include "graphics/host_gpu/transfer.h"
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
@@ -20,11 +20,11 @@ DummyTextureCache::~DummyTextureCache() {
|
||||
return;
|
||||
}
|
||||
|
||||
VulkanDeviceWaitIdle(m_ctx);
|
||||
Transfer::WaitForGraphicsIdle(m_ctx);
|
||||
const auto destroy = [this](auto& slots) {
|
||||
for (auto& slot: slots) {
|
||||
if (slot.image != nullptr) {
|
||||
ImageOps::Destroy(m_ctx, slot.image, &slot.memory);
|
||||
ImageOps::Destroy(m_ctx, slot.image);
|
||||
slot.image = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -49,8 +49,8 @@ VulkanImage* DummyTextureCache::Get(GraphicContext* ctx, Usage usage, bool uint_
|
||||
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.memory);
|
||||
slot.image =
|
||||
ImageOps::CreateDummyTexture(ctx, uint_format, image_3d, usage == Usage::Storage);
|
||||
}
|
||||
return slot.image;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ public:
|
||||
private:
|
||||
struct Slot {
|
||||
GpuTextureVulkanImage* image = nullptr;
|
||||
VulkanMemory memory {};
|
||||
};
|
||||
|
||||
Common::Mutex m_mutex;
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "graphics/host_gpu/renderer/colorRenderTarget.h"
|
||||
#include "graphics/host_gpu/renderer/depthRenderTarget.h"
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
#include "graphics/host_gpu/vulkanCommon.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -108,6 +107,19 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
|
||||
}
|
||||
}
|
||||
|
||||
if (!with_depth && color_count == 0) {
|
||||
LOGF("Framebuffer: warning: no color or depth attachment\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
if (first_color == nullptr) {
|
||||
first_color_extent = depth->vulkan_buffer->extent;
|
||||
}
|
||||
|
||||
auto* framebuffer = new VulkanFramebuffer;
|
||||
framebuffer->render_pass = nullptr;
|
||||
framebuffer->framebuffer = nullptr;
|
||||
@@ -120,23 +132,6 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
|
||||
|
||||
EXIT_IF(gctx == nullptr);
|
||||
|
||||
if (!with_depth && color_count == 0) {
|
||||
LOGF("Framebuffer: warning: no color or depth attachment\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(!with_depth && color_count == 0);
|
||||
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));
|
||||
|
||||
if (first_color == nullptr) {
|
||||
first_color =
|
||||
CreateDummyBuffer(vk::Format::eB8G8R8A8Srgb, depth->vulkan_buffer->extent.width,
|
||||
depth->vulkan_buffer->extent.height);
|
||||
first_color_extent = first_color->extent;
|
||||
}
|
||||
|
||||
vk::AttachmentDescription attachments[RENDER_COLOR_ATTACHMENTS_MAX + 1] = {};
|
||||
for (uint32_t i = 0; i < color_count; i++) {
|
||||
attachments[i].flags = {};
|
||||
@@ -355,81 +350,4 @@ void FramebufferCache::FreeFramebufferByDepth(DepthStencilVulkanImage* image) {
|
||||
}
|
||||
}
|
||||
|
||||
VideoOutVulkanImage* FramebufferCache::CreateDummyBuffer(vk::Format format, uint32_t width,
|
||||
uint32_t height) {
|
||||
for (auto* b: m_dummy_buffers) {
|
||||
if (b->extent.width == width && b->extent.height == height && b->format == format) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
auto* ctx = g_render_ctx->GetGraphicCtx();
|
||||
|
||||
EXIT_IF(ctx == nullptr);
|
||||
|
||||
auto* vk_obj = new VideoOutVulkanImage;
|
||||
|
||||
vk_obj->extent.width = width;
|
||||
vk_obj->extent.height = height;
|
||||
vk_obj->format = format;
|
||||
vk_obj->image = nullptr;
|
||||
vk_obj->layout = vk::ImageLayout::eUndefined;
|
||||
|
||||
UtilResetImageViews(vk_obj);
|
||||
|
||||
vk::ImageCreateInfo image_info {};
|
||||
image_info.sType = vk::StructureType::eImageCreateInfo;
|
||||
image_info.pNext = nullptr;
|
||||
image_info.flags = {};
|
||||
image_info.imageType = vk::ImageType::e2D;
|
||||
image_info.extent.width = vk_obj->extent.width;
|
||||
image_info.extent.height = vk_obj->extent.height;
|
||||
image_info.extent.depth = 1;
|
||||
image_info.mipLevels = 1;
|
||||
image_info.arrayLayers = 1;
|
||||
image_info.format = vk_obj->format;
|
||||
image_info.tiling = vk::ImageTiling::eOptimal;
|
||||
image_info.initialLayout = vk_obj->layout;
|
||||
image_info.usage = vk::ImageUsageFlagBits::eColorAttachment;
|
||||
image_info.sharingMode = vk::SharingMode::eExclusive;
|
||||
image_info.samples = vk::SampleCountFlagBits::e1;
|
||||
|
||||
VulkanMemory mem;
|
||||
|
||||
mem.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
|
||||
|
||||
bool created = VulkanCreateImage(ctx, &image_info, vk_obj, &mem);
|
||||
EXIT_NOT_IMPLEMENTED(!created);
|
||||
|
||||
vk_obj->memory = mem;
|
||||
|
||||
vk::ImageViewCreateInfo create_info {};
|
||||
create_info.sType = vk::StructureType::eImageViewCreateInfo;
|
||||
create_info.pNext = nullptr;
|
||||
create_info.flags = {};
|
||||
create_info.image = vk_obj->image;
|
||||
create_info.viewType = vk::ImageViewType::e2D;
|
||||
create_info.format = vk_obj->format;
|
||||
create_info.components.r = vk::ComponentSwizzle::eIdentity;
|
||||
create_info.components.g = vk::ComponentSwizzle::eIdentity;
|
||||
create_info.components.b = vk::ComponentSwizzle::eIdentity;
|
||||
create_info.components.a = vk::ComponentSwizzle::eIdentity;
|
||||
create_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
|
||||
create_info.subresourceRange.baseArrayLayer = 0;
|
||||
create_info.subresourceRange.baseMipLevel = 0;
|
||||
create_info.subresourceRange.layerCount = 1;
|
||||
create_info.subresourceRange.levelCount = 1;
|
||||
|
||||
ctx->device.createImageView(&create_info, nullptr,
|
||||
&vk_obj->image_view[VulkanImage::VIEW_DEFAULT]);
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(vk_obj->image_view[VulkanImage::VIEW_DEFAULT] == nullptr);
|
||||
|
||||
UtilSetImageLayoutOptimal(vk_obj);
|
||||
|
||||
m_dummy_buffers.push_back(vk_obj);
|
||||
|
||||
return vk_obj;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
@@ -50,7 +50,7 @@ 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()); }
|
||||
virtual ~FramebufferCache() { KYTY_NOT_IMPLEMENTED; }
|
||||
~FramebufferCache() { KYTY_NOT_IMPLEMENTED; }
|
||||
KYTY_CLASS_NO_COPY(FramebufferCache);
|
||||
|
||||
VulkanFramebuffer* CreateFramebuffer(RenderColorInfo* colors, uint32_t color_count,
|
||||
@@ -59,8 +59,6 @@ public:
|
||||
void FreeFramebufferByDepth(DepthStencilVulkanImage* image);
|
||||
|
||||
private:
|
||||
VideoOutVulkanImage* CreateDummyBuffer(vk::Format format, uint32_t width, uint32_t height);
|
||||
|
||||
struct Framebuffer {
|
||||
VulkanFramebuffer* framebuffer = nullptr;
|
||||
uint64_t image_id[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
||||
@@ -74,9 +72,8 @@ private:
|
||||
bool depth_read_only = false;
|
||||
};
|
||||
|
||||
Common::Mutex m_mutex;
|
||||
std::vector<Framebuffer> m_framebuffers;
|
||||
std::vector<VideoOutVulkanImage*> m_dummy_buffers;
|
||||
Common::Mutex m_mutex;
|
||||
std::vector<Framebuffer> m_framebuffers;
|
||||
};
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "graphics/host_gpu/renderer/gdsBuffer.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
#include "graphics/host_gpu/transfer.h"
|
||||
#include "graphics/host_gpu/vma.h"
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Libs::Graphics {
|
||||
class GdsBuffer {
|
||||
public:
|
||||
GdsBuffer() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
|
||||
virtual ~GdsBuffer() { KYTY_NOT_IMPLEMENTED; }
|
||||
~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);
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
#include "graphics/host_gpu/renderer/framebufferCache.h"
|
||||
#include "graphics/host_gpu/renderer/imageView.h"
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
#include "graphics/host_gpu/transfer.h"
|
||||
#include "graphics/host_gpu/vma.h"
|
||||
#include "graphics/shader/shader.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -40,7 +41,7 @@ TextureImageCreateParams MakeImageParams(const ImageInfo& info, bool storage) {
|
||||
params.image_layout = TextureUploadDestination::MipLevels;
|
||||
params.allow_cube_view = !storage;
|
||||
params.compatible_format_views =
|
||||
storage && (IsRgba8SrgbViewFormat(TextureGetFormat(info.format, params.format_usage)) ||
|
||||
storage && (IsRgba8SrgbViewFormat(TextureGetFormat(info.format)) ||
|
||||
info.format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) ||
|
||||
info.format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float));
|
||||
params.owner = storage ? "StorageTextureCache" : "TextureCache";
|
||||
@@ -140,13 +141,13 @@ uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element) {
|
||||
}
|
||||
|
||||
GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info, bool storage,
|
||||
VulkanMemory* memory, vk::ComponentMapping* components) {
|
||||
vk::ComponentMapping* components) {
|
||||
if (components == nullptr) {
|
||||
EXIT("TextureCache: invalid texture component output\n");
|
||||
}
|
||||
auto* image = storage ? static_cast<GpuTextureVulkanImage*>(new StorageTextureVulkanImage)
|
||||
: new TextureVulkanImage;
|
||||
*components = TextureCreateImage(ctx, image, memory, MakeImageParams(info, storage));
|
||||
*components = TextureCreateImage(ctx, image, MakeImageParams(info, storage));
|
||||
return image;
|
||||
}
|
||||
|
||||
@@ -172,7 +173,7 @@ void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* ima
|
||||
base_layer, layer_count, info.layers, image != nullptr ? image->layers : 0, info.size);
|
||||
}
|
||||
if (refresh) {
|
||||
VulkanDeviceWaitIdle(ctx);
|
||||
Transfer::WaitForGraphicsIdle(ctx);
|
||||
}
|
||||
const auto slice_size = info.size / info.layers;
|
||||
const auto upload_size = slice_size * layer_count;
|
||||
@@ -204,16 +205,16 @@ void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* ima
|
||||
return;
|
||||
}
|
||||
if (info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) &&
|
||||
UtilBufferIsTiled(info.address, slice_size)) {
|
||||
UtilScratchBuffer scratch(slice_size);
|
||||
Transfer::GuestBufferIsTiled(info.address, slice_size)) {
|
||||
Transfer::ScratchBuffer scratch(slice_size);
|
||||
TileConvertTiledToLinearRenderTarget(
|
||||
scratch.Data(), reinterpret_cast<const void*>(info.address), info.width, info.height,
|
||||
info.pitch, info.bytes_per_element, slice_size);
|
||||
UtilFillImage(ctx, image, scratch.Data(), slice_size, info.pitch,
|
||||
vk::ImageLayout::eGeneral);
|
||||
Transfer::UploadImage(ctx, image, scratch.Data(), slice_size, info.pitch,
|
||||
vk::ImageLayout::eGeneral);
|
||||
} else {
|
||||
UtilFillImage(ctx, image, reinterpret_cast<const void*>(info.address), slice_size,
|
||||
info.pitch, vk::ImageLayout::eGeneral);
|
||||
Transfer::UploadImage(ctx, image, reinterpret_cast<const void*>(info.address), slice_size,
|
||||
info.pitch, vk::ImageLayout::eGeneral);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,8 +223,7 @@ void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image,
|
||||
UploadRenderTargetLayers(ctx, image, info, 0, info.layers, refresh);
|
||||
}
|
||||
|
||||
RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTargetInfo& info,
|
||||
VulkanMemory* memory) {
|
||||
RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTargetInfo& info) {
|
||||
auto* image = new RenderTextureVulkanImage;
|
||||
image->extent.width = info.width;
|
||||
image->extent.height = info.height;
|
||||
@@ -231,33 +231,30 @@ RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTa
|
||||
image->mip_levels = info.levels;
|
||||
image->layers = info.layers;
|
||||
image->layout = vk::ImageLayout::eUndefined;
|
||||
UtilResetImageViews(image);
|
||||
vk::ImageCreateInfo create {};
|
||||
create.sType = vk::StructureType::eImageCreateInfo;
|
||||
create.flags = RenderTargetCreateFlags(info.format);
|
||||
create.imageType = vk::ImageType::e2D;
|
||||
create.extent = {info.width, info.height, 1};
|
||||
create.mipLevels = info.levels;
|
||||
create.arrayLayers = info.layers;
|
||||
create.format = info.format;
|
||||
create.tiling = vk::ImageTiling::eOptimal;
|
||||
create.initialLayout = vk::ImageLayout::eUndefined;
|
||||
create.usage = RenderTargetUsage(ctx, info.format, create.flags);
|
||||
create.sharingMode = vk::SharingMode::eExclusive;
|
||||
create.samples = vk::SampleCountFlagBits::e1;
|
||||
memory->property = vk::MemoryPropertyFlagBits::eDeviceLocal;
|
||||
if (!VulkanCreateImage(ctx, &create, image, memory)) {
|
||||
create.sType = vk::StructureType::eImageCreateInfo;
|
||||
create.flags = RenderTargetCreateFlags(info.format);
|
||||
create.imageType = vk::ImageType::e2D;
|
||||
create.extent = {info.width, info.height, 1};
|
||||
create.mipLevels = info.levels;
|
||||
create.arrayLayers = info.layers;
|
||||
create.format = info.format;
|
||||
create.tiling = vk::ImageTiling::eOptimal;
|
||||
create.initialLayout = vk::ImageLayout::eUndefined;
|
||||
create.usage = RenderTargetUsage(ctx, info.format, create.flags);
|
||||
create.sharingMode = vk::SharingMode::eExclusive;
|
||||
create.samples = vk::SampleCountFlagBits::e1;
|
||||
image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
|
||||
if (!VulkanCreateImage(ctx, 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));
|
||||
}
|
||||
image->memory = *memory;
|
||||
ImageViewOps::CreateRenderTargetViews(ctx, image);
|
||||
return image;
|
||||
}
|
||||
|
||||
DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info,
|
||||
VulkanMemory* memory) {
|
||||
DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info) {
|
||||
vk::ImageCreateInfo create {};
|
||||
create.sType = vk::StructureType::eImageCreateInfo;
|
||||
create.imageType = vk::ImageType::e2D;
|
||||
@@ -278,22 +275,20 @@ DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTarge
|
||||
static_cast<int>(info.format),
|
||||
static_cast<vk::ImageUsageFlags::MaskType>(create.usage));
|
||||
}
|
||||
auto* image = new DepthStencilVulkanImage;
|
||||
image->extent.width = info.width;
|
||||
image->extent.height = info.height;
|
||||
image->guest_pitch = info.pitch;
|
||||
image->layers = info.layers;
|
||||
image->format = info.format;
|
||||
image->layout = vk::ImageLayout::eUndefined;
|
||||
image->compressed = false;
|
||||
UtilResetImageViews(image);
|
||||
memory->property = vk::MemoryPropertyFlagBits::eDeviceLocal;
|
||||
if (!VulkanCreateImage(ctx, &create, image, memory)) {
|
||||
auto* image = new DepthStencilVulkanImage;
|
||||
image->extent.width = info.width;
|
||||
image->extent.height = info.height;
|
||||
image->guest_pitch = info.pitch;
|
||||
image->layers = info.layers;
|
||||
image->format = info.format;
|
||||
image->layout = vk::ImageLayout::eUndefined;
|
||||
image->compressed = false;
|
||||
image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
|
||||
if (!VulkanCreateImage(ctx, 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));
|
||||
}
|
||||
image->memory = *memory;
|
||||
ImageViewOps::CreateDepthViews(ctx, image);
|
||||
return image;
|
||||
}
|
||||
@@ -334,34 +329,31 @@ void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) {
|
||||
(void)RenderTargetUsage(ctx, info.format, vk::ImageCreateFlags {});
|
||||
}
|
||||
|
||||
VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info,
|
||||
VulkanMemory* memory) {
|
||||
VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) {
|
||||
auto* image = new VideoOutVulkanImage;
|
||||
image->extent.width = info.width;
|
||||
image->extent.height = info.height;
|
||||
image->format = info.format;
|
||||
image->layout = vk::ImageLayout::eUndefined;
|
||||
UtilResetImageViews(image);
|
||||
vk::ImageCreateInfo create {};
|
||||
create.sType = vk::StructureType::eImageCreateInfo;
|
||||
create.imageType = vk::ImageType::e2D;
|
||||
create.extent = {info.width, info.height, 1};
|
||||
create.mipLevels = 1;
|
||||
create.arrayLayers = 1;
|
||||
create.format = info.format;
|
||||
create.tiling = vk::ImageTiling::eOptimal;
|
||||
create.initialLayout = vk::ImageLayout::eUndefined;
|
||||
create.flags = RenderTargetCreateFlags(info.format);
|
||||
create.usage = RenderTargetUsage(ctx, info.format, create.flags);
|
||||
create.sharingMode = vk::SharingMode::eExclusive;
|
||||
create.samples = vk::SampleCountFlagBits::e1;
|
||||
memory->property = vk::MemoryPropertyFlagBits::eDeviceLocal;
|
||||
if (!VulkanCreateImage(ctx, &create, image, memory)) {
|
||||
create.sType = vk::StructureType::eImageCreateInfo;
|
||||
create.imageType = vk::ImageType::e2D;
|
||||
create.extent = {info.width, info.height, 1};
|
||||
create.mipLevels = 1;
|
||||
create.arrayLayers = 1;
|
||||
create.format = info.format;
|
||||
create.tiling = vk::ImageTiling::eOptimal;
|
||||
create.initialLayout = vk::ImageLayout::eUndefined;
|
||||
create.flags = RenderTargetCreateFlags(info.format);
|
||||
create.usage = RenderTargetUsage(ctx, info.format, create.flags);
|
||||
create.sharingMode = vk::SharingMode::eExclusive;
|
||||
create.samples = vk::SampleCountFlagBits::e1;
|
||||
image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
|
||||
if (!VulkanCreateImage(ctx, 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));
|
||||
}
|
||||
image->memory = *memory;
|
||||
ImageViewOps::CreateVideoOutViews(ctx, image);
|
||||
return image;
|
||||
}
|
||||
@@ -374,10 +366,10 @@ void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const Video
|
||||
info.address, info.metadata_address, info.dcc_control);
|
||||
}
|
||||
if (refresh) {
|
||||
VulkanDeviceWaitIdle(ctx);
|
||||
Transfer::WaitForGraphicsIdle(ctx);
|
||||
}
|
||||
image->layout = vk::ImageLayout::eUndefined;
|
||||
UtilScratchBuffer scratch(info.size);
|
||||
Transfer::ScratchBuffer scratch(info.size);
|
||||
TileConvertTiledToLinearRenderTarget(
|
||||
scratch.Data(), reinterpret_cast<const void*>(info.address), info.width, info.height,
|
||||
info.pitch, info.bytes_per_element, info.size);
|
||||
@@ -387,16 +379,12 @@ void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const Video
|
||||
std::swap(pixels[i], pixels[i + 2]);
|
||||
}
|
||||
}
|
||||
UtilFillImage(ctx, image, scratch.Data(), info.size, info.pitch, vk::ImageLayout::eGeneral);
|
||||
Transfer::UploadImage(ctx, image, scratch.Data(), info.size, info.pitch,
|
||||
vk::ImageLayout::eGeneral);
|
||||
}
|
||||
|
||||
GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format, bool image_3d,
|
||||
bool storage, VulkanMemory* memory) {
|
||||
if (memory == nullptr || memory->allocation != nullptr) {
|
||||
EXIT("TextureCache: invalid dummy texture memory slot, slot=%p allocation=%p storage=%d\n",
|
||||
static_cast<const void*>(memory),
|
||||
memory == nullptr ? nullptr : static_cast<const void*>(memory->allocation), storage);
|
||||
}
|
||||
bool storage) {
|
||||
auto* image = storage ? static_cast<GpuTextureVulkanImage*>(new StorageTextureVulkanImage)
|
||||
: new TextureVulkanImage;
|
||||
auto usage = storage ? TextureFormatUsage::Storage : TextureFormatUsage::Sampled;
|
||||
@@ -404,69 +392,52 @@ 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, memory, params);
|
||||
auto components = TextureCreateImage(ctx, image, params);
|
||||
|
||||
static constexpr uint32_t zero = 0;
|
||||
UtilFillImage(ctx, image, &zero, sizeof(zero), 1, layout);
|
||||
Transfer::UploadImage(ctx, image, &zero, sizeof(zero), 1, layout);
|
||||
TextureCreateImageViews(ctx, 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, GpuTextureVulkanImage* image, VulkanMemory* memory) {
|
||||
KYTY_PROFILER_BLOCK("TextureCache::DeleteGpuTexture");
|
||||
void Destroy(GraphicContext* ctx, VulkanImage* image) {
|
||||
KYTY_PROFILER_BLOCK("TextureCache::DeleteImage");
|
||||
EXIT_IF(ctx == nullptr || image == nullptr || g_render_ctx == nullptr);
|
||||
|
||||
EXIT_IF(ctx == nullptr);
|
||||
EXIT_IF(image == nullptr);
|
||||
switch (image->type) {
|
||||
case VulkanImageType::RenderTexture:
|
||||
case VulkanImageType::VideoOut:
|
||||
g_render_ctx->GetFramebufferCache()->FreeFramebufferByColor(image);
|
||||
break;
|
||||
case VulkanImageType::DepthStencil:
|
||||
g_render_ctx->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, memory);
|
||||
VulkanDeleteImage(ctx, image);
|
||||
|
||||
switch (image->type) {
|
||||
case VulkanImageType::Texture: delete static_cast<TextureVulkanImage*>(image); break;
|
||||
case VulkanImageType::StorageTexture:
|
||||
delete static_cast<StorageTextureVulkanImage*>(image);
|
||||
break;
|
||||
default: EXIT("unsupported gpu texture image type: %d\n", static_cast<int>(image->type));
|
||||
case VulkanImageType::RenderTexture:
|
||||
delete static_cast<RenderTextureVulkanImage*>(image);
|
||||
break;
|
||||
case VulkanImageType::DepthStencil:
|
||||
delete static_cast<DepthStencilVulkanImage*>(image);
|
||||
break;
|
||||
case VulkanImageType::VideoOut: delete static_cast<VideoOutVulkanImage*>(image); break;
|
||||
case VulkanImageType::Unknown: EXIT("cannot delete an untyped Vulkan image\n");
|
||||
}
|
||||
}
|
||||
|
||||
void Destroy(GraphicContext* ctx, RenderTextureVulkanImage* image, VulkanMemory* memory) {
|
||||
KYTY_PROFILER_BLOCK("TextureCache::DeleteRenderTexture");
|
||||
|
||||
EXIT_IF(ctx == nullptr);
|
||||
EXIT_IF(image == nullptr);
|
||||
|
||||
g_render_ctx->GetFramebufferCache()->FreeFramebufferByColor(image);
|
||||
ImageViewOps::DestroyViews(ctx, image);
|
||||
VulkanDeleteImage(ctx, image, memory);
|
||||
delete image;
|
||||
}
|
||||
|
||||
void Destroy(GraphicContext* ctx, DepthStencilVulkanImage* image, VulkanMemory* memory) {
|
||||
KYTY_PROFILER_BLOCK("TextureCache::DeleteDepthStencil");
|
||||
|
||||
EXIT_IF(ctx == nullptr);
|
||||
EXIT_IF(image == nullptr);
|
||||
|
||||
g_render_ctx->GetFramebufferCache()->FreeFramebufferByDepth(image);
|
||||
ImageViewOps::DestroyViews(ctx, image);
|
||||
VulkanDeleteImage(ctx, image, memory);
|
||||
delete image;
|
||||
}
|
||||
|
||||
void Destroy(GraphicContext* ctx, VideoOutVulkanImage* image, VulkanMemory* memory) {
|
||||
KYTY_PROFILER_BLOCK("TextureCache::DeleteVideoOut");
|
||||
|
||||
EXIT_IF(ctx == nullptr);
|
||||
EXIT_IF(image == nullptr);
|
||||
|
||||
g_render_ctx->GetFramebufferCache()->FreeFramebufferByColor(image);
|
||||
ImageViewOps::DestroyViews(ctx, image);
|
||||
VulkanDeleteImage(ctx, image, memory);
|
||||
delete image;
|
||||
}
|
||||
|
||||
} // namespace ImageOps
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
@@ -15,7 +15,7 @@ struct GpuTextureVulkanImage;
|
||||
struct GraphicContext;
|
||||
struct RenderTextureVulkanImage;
|
||||
struct VideoOutVulkanImage;
|
||||
struct VulkanMemory;
|
||||
struct VulkanImage;
|
||||
|
||||
struct Image final: ImageInfo {
|
||||
Image& operator=(const ImageInfo& value) {
|
||||
@@ -101,37 +101,31 @@ private:
|
||||
namespace ImageOps {
|
||||
|
||||
[[nodiscard]] GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info,
|
||||
bool storage, VulkanMemory* memory,
|
||||
vk::ComponentMapping* components);
|
||||
bool storage, vk::ComponentMapping* components);
|
||||
void CreateTextureViews(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info,
|
||||
bool storage, vk::ComponentMapping components);
|
||||
|
||||
[[nodiscard]] RenderTextureVulkanImage*
|
||||
CreateRenderTarget(GraphicContext* ctx, const RenderTargetInfo& info, VulkanMemory* memory);
|
||||
[[nodiscard]] uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element);
|
||||
[[nodiscard]] RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx,
|
||||
const RenderTargetInfo& info);
|
||||
[[nodiscard]] uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element);
|
||||
void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* image,
|
||||
const RenderTargetInfo& info, uint32_t base_layer,
|
||||
uint32_t layer_count, bool refresh);
|
||||
void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image,
|
||||
const RenderTargetInfo& info, bool refresh);
|
||||
|
||||
[[nodiscard]] DepthStencilVulkanImage*
|
||||
CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info, VulkanMemory* memory);
|
||||
[[nodiscard]] DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx,
|
||||
const DepthTargetInfo& info);
|
||||
|
||||
void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info);
|
||||
[[nodiscard]] VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info,
|
||||
VulkanMemory* memory);
|
||||
[[nodiscard]] VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info);
|
||||
void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const VideoOutInfo& info,
|
||||
bool refresh);
|
||||
|
||||
[[nodiscard]] GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format,
|
||||
bool image_3d, bool storage,
|
||||
VulkanMemory* memory);
|
||||
bool image_3d, bool storage);
|
||||
|
||||
void Destroy(GraphicContext* ctx, GpuTextureVulkanImage* image, VulkanMemory* memory);
|
||||
void Destroy(GraphicContext* ctx, RenderTextureVulkanImage* image, VulkanMemory* memory);
|
||||
void Destroy(GraphicContext* ctx, DepthStencilVulkanImage* image, VulkanMemory* memory);
|
||||
void Destroy(GraphicContext* ctx, VideoOutVulkanImage* image, VulkanMemory* memory);
|
||||
void Destroy(GraphicContext* ctx, VulkanImage* image);
|
||||
|
||||
} // namespace ImageOps
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "common/assert.h"
|
||||
#include "graphics/host_gpu/objects/textureCommon.h"
|
||||
#include "graphics/host_gpu/renderer/textureCache.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
@@ -11,28 +10,72 @@ namespace Libs::Graphics {
|
||||
|
||||
namespace {
|
||||
|
||||
void CreateView(GraphicContext* ctx, 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) {
|
||||
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);
|
||||
}
|
||||
|
||||
vk::ImageViewUsageCreateInfo usage_info {};
|
||||
usage_info.sType = vk::StructureType::eImageViewUsageCreateInfo;
|
||||
usage_info.usage = view_usage;
|
||||
|
||||
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.viewType = view_type;
|
||||
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;
|
||||
create_info.subresourceRange.baseMipLevel = base_mip_level;
|
||||
create_info.subresourceRange.layerCount = layer_count;
|
||||
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) {
|
||||
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>(create_info.format), view_index);
|
||||
}
|
||||
}
|
||||
|
||||
void CreateRenderTargetView(GraphicContext* ctx, 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;
|
||||
UtilCreateImageView(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, view_usage);
|
||||
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,
|
||||
view_usage);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace ImageViewOps {
|
||||
|
||||
vk::ImageAspectFlags DepthAspectMask(vk::Format format) noexcept {
|
||||
auto aspects = vk::ImageAspectFlags {vk::ImageAspectFlagBits::eDepth};
|
||||
if (format == vk::Format::eD16UnormS8Uint || format == vk::Format::eD24UnormS8Uint ||
|
||||
format == vk::Format::eD32SfloatS8Uint) {
|
||||
aspects |= vk::ImageAspectFlagBits::eStencil;
|
||||
vk::ImageAspectFlags DepthAspectMask(vk::Format format) {
|
||||
switch (format) {
|
||||
case vk::Format::eD16Unorm:
|
||||
case vk::Format::eD32Sfloat: return vk::ImageAspectFlagBits::eDepth;
|
||||
case vk::Format::eD16UnormS8Uint:
|
||||
case vk::Format::eD24UnormS8Uint:
|
||||
case vk::Format::eD32SfloatS8Uint:
|
||||
return vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil;
|
||||
default: EXIT("unsupported depth/stencil image format: %d\n", static_cast<int>(format));
|
||||
}
|
||||
return aspects;
|
||||
}
|
||||
|
||||
bool FormatSupportsStorage(GraphicContext* ctx, vk::Format format) {
|
||||
@@ -68,11 +111,11 @@ void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* imag
|
||||
}
|
||||
|
||||
void CreateDepthViews(GraphicContext* ctx, DepthStencilVulkanImage* image) {
|
||||
UtilCreateImageView(ctx, 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);
|
||||
CreateView(ctx, 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) {
|
||||
@@ -338,7 +381,7 @@ vk::ImageView TextureCache::GetStorageTextureSampledView(GraphicContext*
|
||||
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);
|
||||
}
|
||||
const auto view_format = TextureGetFormat(info.format, TextureFormatUsage::Sampled);
|
||||
const auto view_format = TextureGetFormat(info.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"
|
||||
|
||||
@@ -215,7 +215,7 @@ ValidateStorageImageResource(const ShaderRecompiler::IR::ImageResource& resource
|
||||
|
||||
namespace ImageViewOps {
|
||||
|
||||
[[nodiscard]] vk::ImageAspectFlags DepthAspectMask(vk::Format format) noexcept;
|
||||
[[nodiscard]] vk::ImageAspectFlags DepthAspectMask(vk::Format format);
|
||||
[[nodiscard]] bool FormatSupportsStorage(GraphicContext* ctx, vk::Format format);
|
||||
|
||||
void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* image);
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_INTERNAL_H_
|
||||
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_INTERNAL_H_
|
||||
|
||||
#include "graphics/host_gpu/renderer/descriptorCache.h"
|
||||
#include "graphics/host_gpu/renderer/framebufferCache.h"
|
||||
#include "graphics/host_gpu/renderer/gdsBuffer.h"
|
||||
#include "graphics/host_gpu/renderer/pipelineCache.h"
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
#include "graphics/host_gpu/renderer/samplerCache.h"
|
||||
|
||||
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_INTERNAL_H_
|
||||
@@ -1,22 +1,16 @@
|
||||
#include "graphics/host_gpu/renderer/pipelineCache.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/emulatorConfig.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/profiler.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "graphics/guest_gpu/graphicsRun.h"
|
||||
#include "graphics/guest_gpu/hardwareContext.h"
|
||||
#include "graphics/host_gpu/renderer/colorRenderTarget.h"
|
||||
#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/renderContext.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <fmt/format.h>
|
||||
#include <span>
|
||||
#include <utility>
|
||||
|
||||
@@ -44,26 +38,6 @@ bool PipelineStaticParameters::operator==(const PipelineStaticParameters& other)
|
||||
return std::memcmp(this, &other, sizeof(*this)) == 0;
|
||||
}
|
||||
|
||||
void PipelineCache::DeletePipelineInternal(Pipeline* p) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(p == nullptr);
|
||||
EXIT_IF(p->pipeline == nullptr);
|
||||
EXIT_IF(p->pipeline_layout == nullptr);
|
||||
|
||||
DumpPipeline("delete", *p);
|
||||
|
||||
auto* gctx = g_render_ctx->GetGraphicCtx();
|
||||
|
||||
EXIT_IF(gctx == nullptr);
|
||||
|
||||
VulkanDeviceWaitIdle(gctx);
|
||||
gctx->device.destroyPipeline(p->pipeline, nullptr);
|
||||
gctx->device.destroyPipelineLayout(p->pipeline_layout, nullptr);
|
||||
|
||||
p->pipeline = nullptr;
|
||||
p->pipeline_layout = nullptr;
|
||||
}
|
||||
|
||||
PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
|
||||
VulkanFramebuffer* framebuffer, RenderColorInfo* colors, uint32_t color_count,
|
||||
RenderDepthInfo* depth, ShaderVertexInputInfo* vs_input_info, HW::Context* ctx,
|
||||
@@ -188,7 +162,6 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
|
||||
|
||||
auto [iter, inserted] = m_graphics_pipelines.emplace(std::move(key), std::move(cached));
|
||||
EXIT_IF(!inserted);
|
||||
DumpPipeline("create", *iter->second);
|
||||
|
||||
return iter->second.get();
|
||||
}
|
||||
@@ -231,69 +204,4 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info,
|
||||
|
||||
return iter->second.get();
|
||||
}
|
||||
|
||||
void PipelineCache::DeletePipeline(Pipeline* pipeline) {
|
||||
Common::LockGuard lock(m_mutex);
|
||||
|
||||
EXIT_IF(pipeline == nullptr);
|
||||
|
||||
for (auto iter = m_graphics_pipelines.begin(); iter != m_graphics_pipelines.end(); iter++) {
|
||||
if (iter->second.get() == pipeline) {
|
||||
DeletePipelineInternal(iter->second.get());
|
||||
m_graphics_pipelines.erase(iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto iter = m_compute_pipelines.begin(); iter != m_compute_pipelines.end(); iter++) {
|
||||
if (iter->second.get() == pipeline) {
|
||||
DeletePipelineInternal(iter->second.get());
|
||||
m_compute_pipelines.erase(iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EXIT_IF(true);
|
||||
}
|
||||
|
||||
void PipelineCache::DeleteAllPipelines() {
|
||||
Common::LockGuard lock(m_mutex);
|
||||
|
||||
for (auto& item: m_graphics_pipelines) {
|
||||
DeletePipelineInternal(item.second.get());
|
||||
}
|
||||
m_graphics_pipelines.clear();
|
||||
|
||||
for (auto& item: m_compute_pipelines) {
|
||||
DeletePipelineInternal(item.second.get());
|
||||
}
|
||||
m_compute_pipelines.clear();
|
||||
}
|
||||
|
||||
void PipelineCache::DumpToFile(Common::File* f, const Pipeline& p) {}
|
||||
|
||||
void PipelineCache::DumpPipeline(const char* action, const Pipeline& p) {
|
||||
EXIT_IF(action == nullptr);
|
||||
|
||||
static std::atomic_int dump_id = 0;
|
||||
|
||||
if (!Config::PipelineDumpEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Common::File f;
|
||||
const auto file_name =
|
||||
Config::GetPipelineDumpFolder() /
|
||||
fmt::format("{:04d}_{:04d}_pipeline_{}.log", GraphicsRunGetFrameNum(), dump_id++, action);
|
||||
Common::File::CreateDirectories(file_name.parent_path());
|
||||
f.Create(file_name);
|
||||
if (f.IsInvalid()) {
|
||||
auto file_name_text = Common::PathToString(file_name);
|
||||
LOGF_COLOR(Log::Color::BrightRed, "Can't create file: %s\n", file_name_text.c_str());
|
||||
return;
|
||||
}
|
||||
DumpToFile(&f, p);
|
||||
f.Close();
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "common/abi.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/common.h"
|
||||
#include "common/file.h"
|
||||
#include "common/threads.h"
|
||||
#include "graphics/host_gpu/renderer/renderTarget.h"
|
||||
#include "graphics/host_gpu/vulkanCommon.h"
|
||||
@@ -15,7 +14,6 @@
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
@@ -86,7 +84,7 @@ static_assert(sizeof(PipelineStaticParameters) ==
|
||||
class PipelineCache {
|
||||
public:
|
||||
PipelineCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
|
||||
virtual ~PipelineCache() { KYTY_NOT_IMPLEMENTED; }
|
||||
~PipelineCache() { KYTY_NOT_IMPLEMENTED; }
|
||||
KYTY_CLASS_NO_COPY(PipelineCache);
|
||||
|
||||
struct Pipeline {
|
||||
@@ -112,8 +110,6 @@ public:
|
||||
ComputePipeline* CreateComputePipeline(ShaderComputeInputInfo* input_info,
|
||||
const HW::ComputeShaderInfo* cs_regs,
|
||||
std::span<const uint32_t> cs_spirv);
|
||||
void DeletePipeline(Pipeline* pipeline);
|
||||
void DeleteAllPipelines();
|
||||
|
||||
private:
|
||||
struct GraphicsPipelineKey {
|
||||
@@ -178,10 +174,6 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
void DeletePipelineInternal(Pipeline* p);
|
||||
void DumpToFile(Common::File* f, const Pipeline& p);
|
||||
void DumpPipeline(const char* action, const Pipeline& p);
|
||||
|
||||
std::unordered_map<GraphicsPipelineKey, std::unique_ptr<GraphicsPipeline>,
|
||||
GraphicsPipelineKeyHash>
|
||||
m_graphics_pipelines;
|
||||
|
||||
@@ -69,7 +69,7 @@ private:
|
||||
class CommandBuffer {
|
||||
public:
|
||||
explicit CommandBuffer(int queue): m_queue(queue) { Allocate(); }
|
||||
virtual ~CommandBuffer() { Free(); }
|
||||
~CommandBuffer() { Free(); }
|
||||
|
||||
KYTY_CLASS_NO_COPY(CommandBuffer);
|
||||
|
||||
@@ -95,16 +95,21 @@ public:
|
||||
void RetainResourceUntilFence(std::shared_ptr<void> resource);
|
||||
void RecycleDescriptorAfterFence(VulkanDescriptorSet* set);
|
||||
|
||||
[[nodiscard]] uint32_t GetIndex() const { return m_index; }
|
||||
[[nodiscard]] int GetQueue() const { return m_queue; }
|
||||
VulkanCommandPool* GetPool() { return m_pool; }
|
||||
[[nodiscard]] bool IsExecute() const { return m_execute; }
|
||||
[[nodiscard]] vk::CommandBuffer Handle() const;
|
||||
[[nodiscard]] int GetQueue() const { return m_queue; }
|
||||
[[nodiscard]] bool IsExecute() const { return m_execute; }
|
||||
[[nodiscard]] uint64_t GetRecordingGeneration() const { return m_recording_generation; }
|
||||
|
||||
private:
|
||||
friend class BufferCache;
|
||||
|
||||
void RecycleDescriptorsAfterFence();
|
||||
void Submit(vk::Semaphore wait_semaphore, vk::PipelineStageFlags wait_stage,
|
||||
vk::Semaphore signal_semaphore);
|
||||
[[nodiscard]] vk::Semaphore ResolveSignalSemaphore(vk::Semaphore semaphore) const;
|
||||
void FinalizeFence(bool reset_recording);
|
||||
void ReleaseResourcesAfterFence();
|
||||
void DeleteBuffersAfterFence();
|
||||
void RecycleDescriptorsAfterFence();
|
||||
|
||||
VulkanCommandPool* m_pool = nullptr;
|
||||
uint32_t m_index = static_cast<uint32_t>(-1);
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
#include "graphics/host_gpu/objects/label.h"
|
||||
#include "graphics/host_gpu/renderer/depthRenderTarget.h"
|
||||
#include "graphics/host_gpu/renderer/descriptorCache.h"
|
||||
#include "graphics/host_gpu/renderer/descriptors.h"
|
||||
#include "graphics/host_gpu/renderer/framebufferCache.h"
|
||||
#include "graphics/host_gpu/renderer/imageInfo.h"
|
||||
#include "graphics/host_gpu/renderer/pipelineCache.h"
|
||||
#include "graphics/host_gpu/renderer/render.h"
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
#include "graphics/host_gpu/renderer/renderInternal.h"
|
||||
#include "graphics/host_gpu/renderer/shaderResourceBarrier.h"
|
||||
#include "graphics/host_gpu/renderer/shaderSubgroup.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
#include "graphics/host_gpu/transfer.h"
|
||||
#include "graphics/host_gpu/vulkanCommon.h"
|
||||
#include "graphics/shader/recompiler/ResourceMaterialization.h"
|
||||
#include "graphics/shader/recompiler/ShaderIR.h"
|
||||
@@ -528,15 +528,15 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context
|
||||
|
||||
for (;;) {
|
||||
const auto recording_generation = buffer->GetRecordingGeneration();
|
||||
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()];
|
||||
auto vk_buffer = buffer->Handle();
|
||||
auto* pipeline = g_render_ctx->GetPipelineCache()->CreateComputePipeline(
|
||||
&input_info, &sh_ctx->GetCs(), cs_shader);
|
||||
|
||||
vk_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline->pipeline);
|
||||
|
||||
const auto address_writes = BindDescriptors(
|
||||
submit_id, buffer, vk::PipelineBindPoint::eCompute, pipeline->pipeline_layout,
|
||||
input_info.stage, vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute);
|
||||
BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eCompute,
|
||||
pipeline->pipeline_layout, input_info.stage,
|
||||
vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute);
|
||||
if (buffer->GetRecordingGeneration() != recording_generation) {
|
||||
continue;
|
||||
}
|
||||
@@ -544,7 +544,6 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context
|
||||
vk_buffer.dispatch(thread_group_x, thread_group_y, thread_group_z);
|
||||
|
||||
bool has_storage_writes = HasShaderBufferWrites(input_info.stage);
|
||||
has_storage_writes = MarkShaderAddressWrites(address_writes) || has_storage_writes;
|
||||
has_storage_writes =
|
||||
std::any_of(
|
||||
program.info.images.begin(), program.info.images.end(),
|
||||
|
||||
@@ -19,8 +19,6 @@ void RenderContext::SetGraphicCtx(GraphicContext* ctx) {
|
||||
}
|
||||
|
||||
GraphicContext* RenderContext::GetGraphicCtx() {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
|
||||
{
|
||||
Common::LockGuard lock(m_graphic_ctx_mutex);
|
||||
if (m_graphic_ctx != nullptr) {
|
||||
|
||||
@@ -24,7 +24,7 @@ constexpr int AGC_USER_INTERRUPT_EVENT = 0x1800;
|
||||
class RenderContext {
|
||||
public:
|
||||
RenderContext() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
|
||||
virtual ~RenderContext() { KYTY_NOT_IMPLEMENTED; }
|
||||
~RenderContext() { KYTY_NOT_IMPLEMENTED; }
|
||||
KYTY_CLASS_NO_COPY(RenderContext);
|
||||
|
||||
void SetGraphicCtx(GraphicContext* ctx);
|
||||
|
||||
@@ -22,11 +22,9 @@
|
||||
#include "graphics/host_gpu/renderer/pipelineCache.h"
|
||||
#include "graphics/host_gpu/renderer/render.h"
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
#include "graphics/host_gpu/renderer/renderInternal.h"
|
||||
#include "graphics/host_gpu/renderer/renderVertex.h"
|
||||
#include "graphics/host_gpu/renderer/shaderResourceBarrier.h"
|
||||
#include "graphics/host_gpu/renderer/shaderSubgroup.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
#include "graphics/host_gpu/transfer.h"
|
||||
#include "graphics/host_gpu/vulkanCommon.h"
|
||||
#include "graphics/shader/recompiler/ResourceMaterialization.h"
|
||||
#include "graphics/shader/recompiler/ShaderIR.h"
|
||||
@@ -47,6 +45,25 @@
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
int32_t ResolveVertexOffset(uint32_t index_offset, const ShaderVertexInputInfo& vs_input_info) {
|
||||
if (index_offset != 0 || !vs_input_info.fetch_embedded) {
|
||||
return static_cast<int32_t>(index_offset);
|
||||
}
|
||||
|
||||
EXIT_IF(!vs_input_info.stage);
|
||||
const auto& program = *vs_input_info.stage.program;
|
||||
const auto& resources = *vs_input_info.stage.resources;
|
||||
if (program.info.vertex_offset_sgpr >= static_cast<int32_t>(program.user_data_base)) {
|
||||
const auto index =
|
||||
static_cast<uint32_t>(program.info.vertex_offset_sgpr) - program.user_data_base;
|
||||
if (index < resources.user_data.size()) {
|
||||
return static_cast<int32_t>(resources.user_data[index]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::atomic<uint32_t> g_draw_state_log_count = 0;
|
||||
static std::atomic<uint32_t> g_draw_input_log_count = 0;
|
||||
static std::atomic<uint32_t> g_mrt_state_log_count = 0;
|
||||
@@ -288,66 +305,6 @@ static void LogDrawInputState(const RenderColorInfo& color,
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] static void LogDrawTextureState(const char* draw_name,
|
||||
const RenderColorInfo& color,
|
||||
const ShaderPixelInputInfo& ps_input_info) {
|
||||
static std::atomic<uint32_t> log_count {0};
|
||||
const auto log_id = log_count.fetch_add(1, std::memory_order_relaxed);
|
||||
if (log_id >= 256) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& ps_program = *ps_input_info.stage.program;
|
||||
const auto& ps_resources = *ps_input_info.stage.resources;
|
||||
const auto sampled_images = std::count_if(
|
||||
ps_program.info.images.begin(), ps_program.info.images.end(), [](const auto& image) {
|
||||
return image.kind == ShaderRecompiler::IR::ResourceKind::Image ||
|
||||
image.kind == ShaderRecompiler::IR::ResourceKind::ImageUint;
|
||||
});
|
||||
LOGF("DrawTextureState[%u]: frame=%d %s target=%s addr=0x%010" PRIx64
|
||||
" textures=%zu sampled=%zu storage=%zu samplers=%zu\n",
|
||||
log_id, GraphicsRunGetFrameNum(), draw_name, RenderColorTypeName(color.type),
|
||||
color.base_addr, ps_program.info.images.size(), sampled_images,
|
||||
ps_program.info.images.size() - sampled_images, ps_program.info.samplers.size());
|
||||
|
||||
for (uint32_t i = 0; i < ps_program.info.images.size(); i++) {
|
||||
const auto& image = ps_program.info.images[i];
|
||||
const auto r = DecodeNativeDescriptor<ShaderTextureResource>(ps_resources.images[i]);
|
||||
LOGF("DrawTextureState[%u]: tex[%u] source=%u usage=%s sampled=%s "
|
||||
"addr=0x%010" PRIx64 " type=%u fmt=%u extent=%ux%u depth=%u levels=%u base_level=%u "
|
||||
"tile=%u swizzle=0x%03" PRIx32 " fields=%08" PRIx32 " %08" PRIx32 " %08" PRIx32
|
||||
" %08" PRIx32 " %08" PRIx32 " %08" PRIx32 " %08" PRIx32 " %08" PRIx32 "\n",
|
||||
log_id, i, image.source, image.written ? "read-write" : "read-only",
|
||||
(image.kind == ShaderRecompiler::IR::ResourceKind::Image ||
|
||||
image.kind == ShaderRecompiler::IR::ResourceKind::ImageUint)
|
||||
? "true"
|
||||
: "false",
|
||||
r.Base40(), static_cast<uint32_t>(r.Type()), static_cast<uint32_t>(r.Format()),
|
||||
static_cast<uint32_t>(r.Width5()) + 1u, static_cast<uint32_t>(r.Height5()) + 1u,
|
||||
static_cast<uint32_t>(r.Depth()) + 1u,
|
||||
std::max<uint32_t>(static_cast<uint32_t>(r.LastLevel()),
|
||||
static_cast<uint32_t>(r.MaxMip())) +
|
||||
1u,
|
||||
static_cast<uint32_t>(r.BaseLevel()), static_cast<uint32_t>(r.TileMode()),
|
||||
r.DstSelXYZW(), r.fields[0], r.fields[1], r.fields[2], r.fields[3], r.fields[4],
|
||||
r.fields[5], r.fields[6], r.fields[7]);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ps_program.info.samplers.size(); i++) {
|
||||
const auto& sampler = ps_program.info.samplers[i];
|
||||
const auto r = DecodeNativeDescriptor<ShaderSamplerResource>(ps_resources.samplers[i]);
|
||||
LOGF("DrawTextureState[%u]: samp[%u] source=%u clamp=%u/%u/%u filter=%u/%u/%u "
|
||||
"mip=%u lod=%u-%u"
|
||||
" bias=%d fields=%08" PRIx32 " %08" PRIx32 " %08" PRIx32 " %08" PRIx32 "\n",
|
||||
log_id, i, sampler.source, static_cast<uint32_t>(r.ClampX()),
|
||||
static_cast<uint32_t>(r.ClampY()), static_cast<uint32_t>(r.ClampZ()),
|
||||
static_cast<uint32_t>(r.XyMagFilter()), static_cast<uint32_t>(r.XyMinFilter()),
|
||||
static_cast<uint32_t>(r.ZFilter()), static_cast<uint32_t>(r.MipFilter()),
|
||||
static_cast<uint32_t>(r.MinLod()), static_cast<uint32_t>(r.MaxLod()),
|
||||
static_cast<int32_t>(r.LodBias()), r.fields[0], r.fields[1], r.fields[2], r.fields[3]);
|
||||
}
|
||||
}
|
||||
|
||||
static void VulkanCmdSetColorWriteEnableEXT(GraphicContext* ctx, vk::CommandBuffer command_buffer,
|
||||
uint32_t attachment_count,
|
||||
const vk::Bool32* p_color_write_enables) {
|
||||
@@ -730,7 +687,7 @@ static bool PrepareDrawRenderState(uint64_t submit_id, CommandBuffer* buffer, HW
|
||||
EXIT_NOT_IMPLEMENTED(state->framebuffer == nullptr);
|
||||
EXIT_NOT_IMPLEMENTED(state->framebuffer->render_pass == nullptr);
|
||||
|
||||
state->vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()];
|
||||
state->vk_buffer = buffer->Handle();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -851,8 +808,10 @@ static void LogDrawStateIfNeeded(HW::Context* ctx, HW::UserConfig* ucfg, const D
|
||||
return;
|
||||
}
|
||||
|
||||
LogDrawTargetState(draw.name, state.color_info[0], state.depth_info, ctx, ucfg,
|
||||
state.ps_input_info, draw.index_count, draw.flags);
|
||||
if (state.ps_active) {
|
||||
LogDrawTargetState(draw.name, state.color_info[0], state.depth_info, ctx, ucfg,
|
||||
state.ps_input_info, draw.index_count, draw.flags);
|
||||
}
|
||||
LogDrawInputState(state.color_info[0], state.vs_input_info, index_type_and_size,
|
||||
draw.index_count, index_addr);
|
||||
// LogDrawTextureState(draw.name, state.color_info[0], state.ps_input_info);
|
||||
@@ -965,21 +924,18 @@ static void ExecutePreparedDraw(uint64_t submit_id, CommandBuffer* buffer, HW::C
|
||||
if (set_auto_debug) {
|
||||
SetDrawDebugPhase(buffer, submit_id, draw, 0x200u);
|
||||
}
|
||||
const auto vs_address_writes =
|
||||
BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics,
|
||||
pipeline->pipeline_layout, state->vs_input_info.stage,
|
||||
vk::ShaderStageFlagBits::eVertex, DescriptorCache::Stage::Vertex);
|
||||
BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics,
|
||||
pipeline->pipeline_layout, state->vs_input_info.stage,
|
||||
vk::ShaderStageFlagBits::eVertex, DescriptorCache::Stage::Vertex);
|
||||
|
||||
std::vector<ShaderAddressWriteRange> ps_address_writes;
|
||||
if (state->ps_active) {
|
||||
LogDrawPhase(draw.name, "BindDescriptorsPS");
|
||||
if (set_auto_debug) {
|
||||
SetDrawDebugPhase(buffer, submit_id, draw, 0x300u);
|
||||
}
|
||||
ps_address_writes =
|
||||
BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics,
|
||||
pipeline->pipeline_layout, state->ps_input_info.stage,
|
||||
vk::ShaderStageFlagBits::eFragment, DescriptorCache::Stage::Pixel);
|
||||
BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics,
|
||||
pipeline->pipeline_layout, state->ps_input_info.stage,
|
||||
vk::ShaderStageFlagBits::eFragment, DescriptorCache::Stage::Pixel);
|
||||
}
|
||||
if (buffer->GetRecordingGeneration() != recording_generation) {
|
||||
continue;
|
||||
@@ -1008,15 +964,11 @@ static void ExecutePreparedDraw(uint64_t submit_id, CommandBuffer* buffer, HW::C
|
||||
}
|
||||
buffer->EndRenderPass();
|
||||
vk::PipelineStageFlags shader_write_stages = {};
|
||||
const bool vs_wrote_buffers = HasShaderBufferWrites(state->vs_input_info.stage);
|
||||
const bool vs_wrote_addresses = MarkShaderAddressWrites(vs_address_writes);
|
||||
if (vs_wrote_buffers || vs_wrote_addresses) {
|
||||
if (HasShaderBufferWrites(state->vs_input_info.stage)) {
|
||||
shader_write_stages |= vk::PipelineStageFlagBits::eVertexShader;
|
||||
}
|
||||
if (state->ps_active) {
|
||||
const bool ps_wrote_buffers = HasShaderBufferWrites(state->ps_input_info.stage);
|
||||
const bool ps_wrote_addresses = MarkShaderAddressWrites(ps_address_writes);
|
||||
if (ps_wrote_buffers || ps_wrote_addresses) {
|
||||
if (HasShaderBufferWrites(state->ps_input_info.stage)) {
|
||||
shader_write_stages |= vk::PipelineStageFlagBits::eFragmentShader;
|
||||
}
|
||||
}
|
||||
@@ -1328,7 +1280,7 @@ static bool ResolveColorTargets(uint64_t submit_id, CommandBuffer* buffer, const
|
||||
const std::array regions {MakeColorResolveCopy(src, dst, width, height)};
|
||||
|
||||
MarkRenderTargetGpuWritten(dst);
|
||||
UtilImageToImage(buffer, regions, dst.vulkan_buffer, dst.vulkan_buffer->layout);
|
||||
Transfer::CopyImage(buffer, regions, dst.vulkan_buffer, dst.vulkan_buffer->layout);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace Libs::Graphics {
|
||||
|
||||
struct ImageImageCopy;
|
||||
struct RenderColorInfo;
|
||||
struct ShaderVertexInputInfo;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
@@ -43,6 +44,8 @@ static_assert(sizeof(PipelineDynamicParameters) ==
|
||||
[[nodiscard]] ImageImageCopy MakeColorResolveCopy(const RenderColorInfo& src,
|
||||
const RenderColorInfo& dst, uint32_t width,
|
||||
uint32_t height);
|
||||
[[nodiscard]] int32_t ResolveVertexOffset(uint32_t index_offset,
|
||||
const ShaderVertexInputInfo& vs_input_info);
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_RENDERINTERNAL_H_
|
||||
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_RENDERINTERNAL_H_
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "graphics/shader/recompiler/ShaderIR.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
template <typename T>
|
||||
T DecodeNativeDescriptor(const ShaderRecompiler::IR::DescriptorValue& value) {
|
||||
T result {};
|
||||
EXIT_IF(value.dword_count < sizeof(result) / sizeof(uint32_t));
|
||||
std::memcpy(&result, value.dwords.data(), sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_RENDERINTERNAL_H_
|
||||
@@ -11,11 +11,11 @@
|
||||
#include "graphics/guest_gpu/tile.h"
|
||||
#include "graphics/host_gpu/graphicContext.h"
|
||||
#include "graphics/host_gpu/objects/textureCommon.h"
|
||||
#include "graphics/host_gpu/renderer/descriptorCache.h"
|
||||
#include "graphics/host_gpu/renderer/framebufferCache.h"
|
||||
#include "graphics/host_gpu/renderer/imageView.h"
|
||||
#include "graphics/host_gpu/renderer/render.h"
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
#include "graphics/host_gpu/transfer.h"
|
||||
#include "graphics/host_gpu/vulkanCommon.h"
|
||||
#include "graphics/presentation/displayBuffer.h"
|
||||
|
||||
@@ -34,7 +34,7 @@ void GraphicsRenderMemoryBarrier(CommandBuffer* buffer) {
|
||||
|
||||
Common::LockGuard lock(g_render_ctx->GetMutex());
|
||||
|
||||
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()];
|
||||
auto vk_buffer = buffer->Handle();
|
||||
|
||||
VulkanMemoryBarrier mem_barrier {};
|
||||
mem_barrier.sType = vk::StructureType::eMemoryBarrier;
|
||||
@@ -121,8 +121,6 @@ void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* i
|
||||
}
|
||||
}
|
||||
|
||||
vk::ImageAspectFlags DepthStencilAspectMask(vk::Format format);
|
||||
|
||||
void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image,
|
||||
vk::ImageLayout new_layout) {
|
||||
EXIT_IF(image == nullptr);
|
||||
@@ -144,9 +142,9 @@ void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanI
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = image->image;
|
||||
barrier.subresourceRange = {DepthStencilAspectMask(image->format), 0, VK_REMAINING_MIP_LEVELS,
|
||||
0, image->layers};
|
||||
const auto stages = static_cast<vk::PipelineStageFlags>(
|
||||
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,
|
||||
@@ -182,9 +180,10 @@ void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage*
|
||||
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.subresourceRange.aspectMask = DepthStencilAspectMask(image->format);
|
||||
image_memory_barrier.subresourceRange.baseMipLevel = 0;
|
||||
image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
|
||||
image_memory_barrier.subresourceRange.aspectMask =
|
||||
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;
|
||||
|
||||
@@ -205,7 +204,7 @@ void GraphicsRenderTextureBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_
|
||||
|
||||
Common::LockGuard lock(g_render_ctx->GetMutex());
|
||||
|
||||
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()];
|
||||
auto vk_buffer = buffer->Handle();
|
||||
|
||||
auto* native = g_render_ctx->GetTextureCache()->FindRenderTargetByRange(buffer, vaddr, size);
|
||||
if (native == nullptr) {
|
||||
@@ -220,7 +219,7 @@ void GraphicsRenderDepthStencilBarrier(CommandBuffer* buffer, uint64_t vaddr, ui
|
||||
|
||||
Common::LockGuard lock(g_render_ctx->GetMutex());
|
||||
|
||||
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()];
|
||||
auto vk_buffer = buffer->Handle();
|
||||
auto* native = g_render_ctx->GetTextureCache()->FindDepthTargetByRange(buffer, vaddr, size);
|
||||
if (native == nullptr) {
|
||||
EXIT("depth-target barrier range has no cached image\n");
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#include "graphics/host_gpu/renderer/renderVertex.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "graphics/shader/recompiler/ResourceMaterialization.h"
|
||||
#include "graphics/shader/recompiler/ShaderIR.h"
|
||||
#include "graphics/shader/shader.h"
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
int32_t ResolveVertexOffset(uint32_t index_offset, const ShaderVertexInputInfo& vs_input_info) {
|
||||
if (index_offset != 0 || !vs_input_info.fetch_embedded) {
|
||||
return static_cast<int32_t>(index_offset);
|
||||
}
|
||||
|
||||
EXIT_IF(!vs_input_info.stage);
|
||||
const auto& program = *vs_input_info.stage.program;
|
||||
const auto& resources = *vs_input_info.stage.resources;
|
||||
if (program.info.vertex_offset_sgpr >= static_cast<int32_t>(program.user_data_base)) {
|
||||
const auto index =
|
||||
static_cast<uint32_t>(program.info.vertex_offset_sgpr) - program.user_data_base;
|
||||
if (index < resources.user_data.size()) {
|
||||
return static_cast<int32_t>(resources.user_data[index]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
@@ -1,14 +0,0 @@
|
||||
#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_RENDERVERTEX_H_
|
||||
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_RENDERVERTEX_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
struct ShaderVertexInputInfo;
|
||||
|
||||
int32_t ResolveVertexOffset(uint32_t index_offset, const ShaderVertexInputInfo& vs_input_info);
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_RENDERVERTEX_H_
|
||||
@@ -143,8 +143,9 @@ vk::Sampler SamplerCache::GetSampler(const ShaderSamplerResource& r) {
|
||||
}
|
||||
|
||||
vk::Sampler vk_sampler = nullptr;
|
||||
g_render_ctx->GetGraphicCtx()->device.createSampler(&sampler_info, nullptr, &vk_sampler);
|
||||
EXIT_NOT_IMPLEMENTED(vk_sampler == nullptr);
|
||||
const auto result =
|
||||
g_render_ctx->GetGraphicCtx()->device.createSampler(&sampler_info, nullptr, &vk_sampler);
|
||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || vk_sampler == nullptr);
|
||||
|
||||
m_samplers.emplace(key, vk_sampler);
|
||||
return vk_sampler;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Libs::Graphics {
|
||||
class SamplerCache {
|
||||
public:
|
||||
SamplerCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
|
||||
virtual ~SamplerCache() { KYTY_NOT_IMPLEMENTED; }
|
||||
~SamplerCache() { KYTY_NOT_IMPLEMENTED; }
|
||||
KYTY_CLASS_NO_COPY(SamplerCache);
|
||||
|
||||
vk::Sampler GetSampler(const ShaderSamplerResource& r);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "graphics/host_gpu/renderer/shaderResourceBarrier.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "graphics/host_gpu/renderer/descriptorCache.h"
|
||||
#include "graphics/shader/shader.h"
|
||||
#include "graphics/shader/shaderBindings.h"
|
||||
|
||||
@@ -108,13 +107,6 @@ CollectShaderBufferWrites(const ShaderRecompiler::IR::Program& program,
|
||||
return writes;
|
||||
}
|
||||
|
||||
bool MarkShaderAddressWrites(const std::vector<ShaderAddressWriteRange>& writes) {
|
||||
if (!writes.empty()) {
|
||||
EXIT("shader address writes are unsupported\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasShaderBufferWrites(const ShaderStageRuntime& runtime) {
|
||||
EXIT_IF(!runtime);
|
||||
return !CollectShaderBufferWrites(*runtime.program, *runtime.resources).empty();
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
struct ShaderAddressWriteRange;
|
||||
struct ShaderStageRuntime;
|
||||
|
||||
struct ShaderBufferWriteRange {
|
||||
@@ -26,7 +25,6 @@ vk::BufferMemoryBarrier MakeGdsDependency(const VulkanBuffer& buffer);
|
||||
std::vector<ShaderBufferWriteRange>
|
||||
CollectShaderBufferWrites(const ShaderRecompiler::IR::Program& program,
|
||||
const ShaderRecompiler::IR::ResourceSnapshot& resources);
|
||||
bool MarkShaderAddressWrites(const std::vector<ShaderAddressWriteRange>& writes);
|
||||
bool HasShaderBufferWrites(const ShaderStageRuntime& runtime);
|
||||
void ShaderWriteBarrier(vk::CommandBuffer vk_buffer, vk::PipelineStageFlags source_stages);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/profiler.h"
|
||||
#include "graphics/host_gpu/graphicContext.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
#include "graphics/host_gpu/transfer.h"
|
||||
#include "graphics/host_gpu/vma.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
#include "kernel/pthread.h"
|
||||
#include "libs/errno.h"
|
||||
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
||||
namespace Libs::Graphics::Sync {
|
||||
|
||||
@@ -71,6 +73,104 @@ static bool CompleteDisplayBufferFlip(const uint64_t* args) {
|
||||
return true;
|
||||
}
|
||||
|
||||
enum class EndOfPipeCompletion { None, Interrupt, Flip, FlipAndInterrupt };
|
||||
|
||||
struct EndOfPipeSignal {
|
||||
CommandBuffer* buffer = nullptr;
|
||||
uint64_t submit_id = 0;
|
||||
CommandBufferDebugOp debug_operation = CommandBufferDebugOp::Unknown;
|
||||
std::array<uint32_t, 4> debug_args = {};
|
||||
uint64_t debug_data = 0;
|
||||
std::optional<uint64_t> destination;
|
||||
EndOfPipeCompletion completion = EndOfPipeCompletion::None;
|
||||
uint64_t completion_data = 0;
|
||||
};
|
||||
|
||||
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]));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TriggerDefaultEopEventCallback(const uint64_t* /*args*/) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
g_render_ctx->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);
|
||||
}
|
||||
EXIT_IF(signal.buffer == nullptr);
|
||||
(void)signal.buffer->Handle();
|
||||
}
|
||||
|
||||
static void RecordEndOfPipeSignal(const EndOfPipeSignal& signal) {
|
||||
ValidateEndOfPipeSignal(signal);
|
||||
signal.buffer->SetDebugInfo(static_cast<uint32_t>(signal.debug_operation), signal.submit_id,
|
||||
signal.debug_args[0], signal.debug_args[1], signal.debug_args[2],
|
||||
signal.debug_args[3], signal.debug_data);
|
||||
|
||||
const uint64_t args[LABEL_ARGS_MAX] = {signal.completion_data};
|
||||
switch (signal.completion) {
|
||||
case EndOfPipeCompletion::None: return;
|
||||
case EndOfPipeCompletion::Interrupt:
|
||||
SubmitLabel(signal.buffer, nullptr, TriggerEopEventCallback, args);
|
||||
return;
|
||||
case EndOfPipeCompletion::Flip:
|
||||
SubmitLabel(signal.buffer, CompleteDisplayBufferFlip, nullptr, args);
|
||||
return;
|
||||
case EndOfPipeCompletion::FlipAndInterrupt:
|
||||
SubmitLabel(signal.buffer, CompleteDisplayBufferFlip, TriggerDefaultEopEventCallback,
|
||||
args);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static CommandBufferDebugOp DebugOperation(EndOfPipeWriteAction action) {
|
||||
switch (action) {
|
||||
case EndOfPipeWriteAction::Write: return CommandBufferDebugOp::EopWrite;
|
||||
case EndOfPipeWriteAction::WriteBack:
|
||||
case EndOfPipeWriteAction::InterruptWriteBack: return CommandBufferDebugOp::EopWriteBack;
|
||||
case EndOfPipeWriteAction::Interrupt: return CommandBufferDebugOp::EopInterrupt;
|
||||
}
|
||||
EXIT("unsupported end-of-pipe write action\n");
|
||||
return CommandBufferDebugOp::Unknown;
|
||||
}
|
||||
|
||||
static bool TriggersInterrupt(EndOfPipeWriteAction action) {
|
||||
return action == EndOfPipeWriteAction::Interrupt ||
|
||||
action == EndOfPipeWriteAction::InterruptWriteBack;
|
||||
}
|
||||
|
||||
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);
|
||||
const auto value_low = static_cast<uint32_t>(value);
|
||||
const auto value_high = static_cast<uint32_t>(value >> 32u);
|
||||
const bool interrupt = TriggersInterrupt(action);
|
||||
|
||||
EndOfPipeSignal signal {
|
||||
.buffer = buffer,
|
||||
.submit_id = submit_id,
|
||||
.debug_operation = DebugOperation(action),
|
||||
.debug_args = interrupt ? std::array {width, context_id, value_low, value_high}
|
||||
: std::array {width, value_low, value_high, 0u},
|
||||
.debug_data = destination,
|
||||
.destination = destination,
|
||||
.completion = interrupt ? EndOfPipeCompletion::Interrupt : EndOfPipeCompletion::None,
|
||||
.completion_data = context_id != 0 ? context_id : value,
|
||||
};
|
||||
RecordEndOfPipeSignal(signal);
|
||||
}
|
||||
|
||||
void TriggerAgcUserInterrupt() {
|
||||
auto tsc = LibKernel::KernelReadTsc();
|
||||
auto result = LibKernel::EventQueue::KernelTriggerUserEventForAll(AGC_USER_INTERRUPT_EVENT,
|
||||
@@ -85,47 +185,33 @@ void TriggerEopEvent(uint32_t context_id) {
|
||||
|
||||
void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
|
||||
uint32_t value) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
EXIT_IF(buffer->IsInvalid());
|
||||
|
||||
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWrite), submit_id, 4, value,
|
||||
0, 0, reinterpret_cast<uint64_t>(dst_gpu_addr));
|
||||
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,
|
||||
uint32_t dw_offset, uint32_t dw_num) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
EXIT_IF(buffer->IsInvalid());
|
||||
|
||||
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWrite), submit_id,
|
||||
dw_offset, dw_num, 0, 0, reinterpret_cast<uint64_t>(dst_gpu_addr));
|
||||
const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr);
|
||||
RecordEndOfPipeSignal({
|
||||
.buffer = buffer,
|
||||
.submit_id = submit_id,
|
||||
.debug_operation = CommandBufferDebugOp::EopWrite,
|
||||
.debug_args = {dw_offset, dw_num, 0, 0},
|
||||
.debug_data = destination,
|
||||
.destination = destination,
|
||||
});
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr,
|
||||
uint64_t value) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
EXIT_IF(buffer->IsInvalid());
|
||||
|
||||
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWrite), submit_id, 8,
|
||||
static_cast<uint32_t>(value), static_cast<uint32_t>(value >> 32u), 0,
|
||||
reinterpret_cast<uint64_t>(dst_gpu_addr));
|
||||
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,
|
||||
uint64_t value) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
EXIT_IF(buffer->IsInvalid());
|
||||
|
||||
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWrite), submit_id, 8, 0, 0,
|
||||
0, reinterpret_cast<uint64_t>(dst_gpu_addr));
|
||||
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), 0,
|
||||
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Write);
|
||||
|
||||
LOGF_COLOR(Log::Color::BrightGreen,
|
||||
"EndOfPipe Signal!!! [0x%016" PRIx64 "] <- Clock: 0x%016" PRIx64 "\n",
|
||||
@@ -134,13 +220,8 @@ void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer, uin
|
||||
|
||||
void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint64_t* dst_gpu_addr, uint64_t value) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
EXIT_IF(buffer->IsInvalid());
|
||||
|
||||
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWriteBack), submit_id, 8, 0,
|
||||
0, 0, reinterpret_cast<uint64_t>(dst_gpu_addr));
|
||||
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), 0,
|
||||
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::WriteBack);
|
||||
|
||||
LOGF_COLOR(Log::Color::BrightGreen,
|
||||
"EndOfPipe Signal!!! [0x%016" PRIx64 "] <- Clock: 0x%016" PRIx64 "\n",
|
||||
@@ -149,115 +230,42 @@ void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer
|
||||
|
||||
void WriteAtEndOfPipeWithWriteBack64(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint64_t* dst_gpu_addr, uint64_t value) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
EXIT_IF(buffer->IsInvalid());
|
||||
|
||||
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWriteBack), submit_id, 8,
|
||||
static_cast<uint32_t>(value), static_cast<uint32_t>(value >> 32u), 0,
|
||||
reinterpret_cast<uint64_t>(dst_gpu_addr));
|
||||
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
|
||||
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::WriteBack);
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint32_t* dst_gpu_addr, uint32_t value) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
EXIT_IF(buffer->IsInvalid());
|
||||
|
||||
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWriteBack), submit_id, 4,
|
||||
value, 0, 0, reinterpret_cast<uint64_t>(dst_gpu_addr));
|
||||
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
|
||||
EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::WriteBack);
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint64_t* dst_gpu_addr, uint64_t value,
|
||||
uint32_t context_id) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
EXIT_IF(buffer->IsInvalid());
|
||||
|
||||
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWriteBack), submit_id, 8,
|
||||
context_id, static_cast<uint32_t>(value),
|
||||
static_cast<uint32_t>(value >> 32u),
|
||||
reinterpret_cast<uint64_t>(dst_gpu_addr));
|
||||
uint64_t args[LABEL_ARGS_MAX] = {context_id != 0 ? context_id : value};
|
||||
|
||||
SubmitLabel(
|
||||
buffer, nullptr,
|
||||
[](const uint64_t* args) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
g_render_ctx->TriggerEopEvent(static_cast<uint32_t>(args[0]));
|
||||
return true;
|
||||
},
|
||||
args);
|
||||
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
|
||||
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::InterruptWriteBack,
|
||||
context_id);
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint32_t* dst_gpu_addr, uint32_t value,
|
||||
uint32_t context_id) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
EXIT_IF(buffer->IsInvalid());
|
||||
|
||||
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWriteBack), submit_id, 4,
|
||||
context_id, value, 0, reinterpret_cast<uint64_t>(dst_gpu_addr));
|
||||
uint64_t args[LABEL_ARGS_MAX] = {context_id != 0 ? context_id : value};
|
||||
|
||||
SubmitLabel(
|
||||
buffer, nullptr,
|
||||
[](const uint64_t* args) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
g_render_ctx->TriggerEopEvent(static_cast<uint32_t>(args[0]));
|
||||
return true;
|
||||
},
|
||||
args);
|
||||
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
|
||||
EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::InterruptWriteBack,
|
||||
context_id);
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint64_t* dst_gpu_addr, uint64_t value, uint32_t context_id) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
EXIT_IF(buffer->IsInvalid());
|
||||
|
||||
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopInterrupt), submit_id, 8,
|
||||
context_id, static_cast<uint32_t>(value),
|
||||
static_cast<uint32_t>(value >> 32u),
|
||||
reinterpret_cast<uint64_t>(dst_gpu_addr));
|
||||
uint64_t args[LABEL_ARGS_MAX] = {context_id != 0 ? context_id : value};
|
||||
|
||||
SubmitLabel(
|
||||
buffer, nullptr,
|
||||
[](const uint64_t* args) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
g_render_ctx->TriggerEopEvent(static_cast<uint32_t>(args[0]));
|
||||
return true;
|
||||
},
|
||||
args);
|
||||
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,
|
||||
uint32_t* dst_gpu_addr, uint32_t value, uint32_t context_id) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
EXIT_IF(buffer->IsInvalid());
|
||||
|
||||
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopInterrupt), submit_id, 4,
|
||||
context_id, value, 0, reinterpret_cast<uint64_t>(dst_gpu_addr));
|
||||
uint64_t args[LABEL_ARGS_MAX] = {context_id != 0 ? context_id : value};
|
||||
|
||||
SubmitLabel(
|
||||
buffer, nullptr,
|
||||
[](const uint64_t* args) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
g_render_ctx->TriggerEopEvent(static_cast<uint32_t>(args[0]));
|
||||
return true;
|
||||
},
|
||||
args);
|
||||
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,
|
||||
@@ -283,69 +291,56 @@ void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuf
|
||||
uint32_t* dst_gpu_addr, uint32_t value,
|
||||
int handle, int index, int flip_mode,
|
||||
int64_t flip_arg, uint64_t request_id) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
EXIT_IF(buffer->IsInvalid());
|
||||
|
||||
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWriteBackFlip), submit_id,
|
||||
static_cast<uint32_t>(handle), static_cast<uint32_t>(index),
|
||||
static_cast<uint32_t>(flip_mode), value, static_cast<uint64_t>(flip_arg));
|
||||
const uint64_t args[LABEL_ARGS_MAX] = {request_id};
|
||||
SubmitLabel(
|
||||
buffer, CompleteDisplayBufferFlip,
|
||||
[](const uint64_t* /*args*/) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
g_render_ctx->TriggerEopEvent(0);
|
||||
return true;
|
||||
},
|
||||
args);
|
||||
const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr);
|
||||
RecordEndOfPipeSignal({
|
||||
.buffer = buffer,
|
||||
.submit_id = submit_id,
|
||||
.debug_operation = CommandBufferDebugOp::EopWriteBackFlip,
|
||||
.debug_args = {static_cast<uint32_t>(handle), static_cast<uint32_t>(index),
|
||||
static_cast<uint32_t>(flip_mode), value},
|
||||
.debug_data = static_cast<uint64_t>(flip_arg),
|
||||
.destination = destination,
|
||||
.completion = EndOfPipeCompletion::FlipAndInterrupt,
|
||||
.completion_data = request_id,
|
||||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
EXIT_IF(buffer->IsInvalid());
|
||||
|
||||
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopFlip), submit_id,
|
||||
static_cast<uint32_t>(handle), static_cast<uint32_t>(index),
|
||||
static_cast<uint32_t>(flip_mode), value, static_cast<uint64_t>(flip_arg));
|
||||
const uint64_t args[LABEL_ARGS_MAX] = {request_id};
|
||||
SubmitLabel(buffer, CompleteDisplayBufferFlip, nullptr, args);
|
||||
const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr);
|
||||
RecordEndOfPipeSignal({
|
||||
.buffer = buffer,
|
||||
.submit_id = submit_id,
|
||||
.debug_operation = CommandBufferDebugOp::EopFlip,
|
||||
.debug_args = {static_cast<uint32_t>(handle), static_cast<uint32_t>(index),
|
||||
static_cast<uint32_t>(flip_mode), value},
|
||||
.debug_data = static_cast<uint64_t>(flip_arg),
|
||||
.destination = destination,
|
||||
.completion = EndOfPipeCompletion::Flip,
|
||||
.completion_data = request_id,
|
||||
});
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer* buffer, int handle, int index,
|
||||
int flip_mode, int64_t flip_arg, uint64_t request_id) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
EXIT_IF(buffer->IsInvalid());
|
||||
|
||||
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopOnlyFlip), submit_id,
|
||||
static_cast<uint32_t>(handle), static_cast<uint32_t>(index),
|
||||
static_cast<uint32_t>(flip_mode), 0, static_cast<uint64_t>(flip_arg));
|
||||
|
||||
const uint64_t args[LABEL_ARGS_MAX] = {request_id};
|
||||
SubmitLabel(buffer, CompleteDisplayBufferFlip, nullptr, args);
|
||||
RecordEndOfPipeSignal({
|
||||
.buffer = buffer,
|
||||
.submit_id = submit_id,
|
||||
.debug_operation = CommandBufferDebugOp::EopOnlyFlip,
|
||||
.debug_args = {static_cast<uint32_t>(handle), static_cast<uint32_t>(index),
|
||||
static_cast<uint32_t>(flip_mode), 0},
|
||||
.debug_data = static_cast<uint64_t>(flip_arg),
|
||||
.completion = EndOfPipeCompletion::Flip,
|
||||
.completion_data = request_id,
|
||||
});
|
||||
}
|
||||
|
||||
void TriggerEopEventAtEndOfPipe(CommandBuffer* buffer, uint32_t context_id) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
EXIT_IF(buffer->IsInvalid());
|
||||
ValidateEndOfPipeSignal({.buffer = buffer});
|
||||
|
||||
uint64_t args[LABEL_ARGS_MAX] = {static_cast<uint64_t>(context_id)};
|
||||
|
||||
SubmitLabel(
|
||||
buffer, nullptr,
|
||||
[](const uint64_t* args) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
g_render_ctx->TriggerEopEvent(static_cast<uint32_t>(args[0]));
|
||||
return true;
|
||||
},
|
||||
args);
|
||||
SubmitLabel(buffer, nullptr, TriggerEopEventCallback, args);
|
||||
}
|
||||
|
||||
static void EopEventResetFunc(LibKernel::EventQueue::KernelEqueueEvent* event) {
|
||||
@@ -398,7 +393,8 @@ int AddEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id, void* udata) {
|
||||
|
||||
int result = LibKernel::EventQueue::KernelAddEvent(eq, event);
|
||||
|
||||
if (id == GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT || id == GRAPHICS_EVENT_EOP) {
|
||||
if (result == 0 &&
|
||||
(id == GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT || id == GRAPHICS_EVENT_EOP)) {
|
||||
g_render_ctx->AddEopEq(eq, id);
|
||||
}
|
||||
|
||||
@@ -422,7 +418,7 @@ void ReadGds(uint32_t* dst, uint32_t dw_offset, uint32_t dw_size) {
|
||||
|
||||
void DeleteBuffers() {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
g_render_ctx->GetBufferCache()->DeleteAll(g_render_ctx->GetGraphicCtx());
|
||||
g_render_ctx->GetBufferCache()->ResetNullBuffer();
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::Sync
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
#include "graphics/host_gpu/renderer/renderTargetBarriers.h"
|
||||
#include "graphics/host_gpu/renderer/resourceMutex.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
#include "graphics/host_gpu/transfer.h"
|
||||
#include "graphics/host_gpu/vulkanCommon.h"
|
||||
#include "kernel/memory.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -104,9 +105,8 @@ struct TextureCache::CachedImage {
|
||||
RenderTargetInfo target;
|
||||
DepthTargetInfo depth;
|
||||
VideoOutInfo video_out;
|
||||
GraphicContext* ctx = nullptr;
|
||||
VulkanImage* image = nullptr;
|
||||
VulkanMemory memory;
|
||||
GraphicContext* ctx = nullptr;
|
||||
VulkanImage* image = nullptr;
|
||||
bool gpu_modified = false;
|
||||
bool buffer_modified = false;
|
||||
bool stencil_initialized = false;
|
||||
@@ -119,21 +119,7 @@ struct TextureCache::CachedImage {
|
||||
static_cast<const void*>(ctx), static_cast<const void*>(image),
|
||||
static_cast<uint32_t>(kind), registered);
|
||||
}
|
||||
switch (kind) {
|
||||
case Kind::Texture:
|
||||
case Kind::StorageTexture:
|
||||
ImageOps::Destroy(ctx, static_cast<GpuTextureVulkanImage*>(image), &memory);
|
||||
break;
|
||||
case Kind::RenderTarget:
|
||||
ImageOps::Destroy(ctx, static_cast<RenderTextureVulkanImage*>(image), &memory);
|
||||
break;
|
||||
case Kind::DepthTarget:
|
||||
ImageOps::Destroy(ctx, static_cast<DepthStencilVulkanImage*>(image), &memory);
|
||||
break;
|
||||
case Kind::VideoOut:
|
||||
ImageOps::Destroy(ctx, static_cast<VideoOutVulkanImage*>(image), &memory);
|
||||
break;
|
||||
}
|
||||
ImageOps::Destroy(ctx, image);
|
||||
image = nullptr;
|
||||
}
|
||||
|
||||
@@ -465,10 +451,10 @@ struct TextureCache::ReadbackWorker {
|
||||
download.resize(info.size);
|
||||
std::fill(download.begin(), download.end(), 0);
|
||||
const auto regions =
|
||||
MakeLayeredImageBufferCopies(info.layers, slice_size, info.pitch, info.width,
|
||||
info.height, vk::ImageAspectFlagBits::eDepth);
|
||||
UtilFillBuffer(cached.ctx, download.data(), info.size, regions, cached.image,
|
||||
cached.image->layout);
|
||||
Transfer::MakeLayeredImageBufferCopies(info.layers, slice_size, info.pitch, info.width,
|
||||
info.height, vk::ImageAspectFlagBits::eDepth);
|
||||
Transfer::DownloadImage(cached.ctx, download.data(), info.size, regions, cached.image,
|
||||
cached.image->layout);
|
||||
guest.resize(info.size);
|
||||
cache.m_tiler.TileImage(guest.data(), download.data(), info);
|
||||
Libs::LibKernel::Memory::WriteBacking(info.address, guest.data(), info.size);
|
||||
@@ -478,11 +464,11 @@ struct TextureCache::ReadbackWorker {
|
||||
[[nodiscard]] ReadbackRange DownloadColorImage(CachedImage& cached) {
|
||||
const bool storage = cached.kind == CachedImage::Kind::StorageTexture;
|
||||
const bool target = cached.kind == CachedImage::Kind::RenderTarget;
|
||||
const auto info = storage ? MakeColorImageTransferInfo(
|
||||
cached.info, Prospero::SurfaceFormat(cached.info.format),
|
||||
Prospero::NumBytesPerElement(cached.info.format))
|
||||
: MakeColorImageTransferInfo(cached.target);
|
||||
const bool linear = info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kLinear);
|
||||
const auto info =
|
||||
storage ? MakeColorImageTransferInfo(cached.info, VulkanFormat(cached.info.format),
|
||||
Prospero::NumBytesPerElement(cached.info.format))
|
||||
: MakeColorImageTransferInfo(cached.target);
|
||||
const bool linear = info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kLinear);
|
||||
const bool tiled_target = target && IsTiledRenderTarget(cached.target);
|
||||
const bool tiled_storage =
|
||||
storage && info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget);
|
||||
@@ -520,10 +506,10 @@ struct TextureCache::ReadbackWorker {
|
||||
}
|
||||
download.resize(info.size);
|
||||
std::fill(download.begin(), download.end(), 0);
|
||||
const auto regions =
|
||||
MakeLayeredImageBufferCopies(layers, slice_size, info.pitch, info.width, info.height);
|
||||
UtilFillBuffer(cached.ctx, download.data(), info.size, regions, cached.image,
|
||||
cached.image->layout);
|
||||
const auto regions = Transfer::MakeLayeredImageBufferCopies(layers, slice_size, info.pitch,
|
||||
info.width, info.height);
|
||||
Transfer::DownloadImage(cached.ctx, download.data(), info.size, regions, cached.image,
|
||||
cached.image->layout);
|
||||
if (tiled_target || tiled_storage) {
|
||||
guest.resize(info.size);
|
||||
const RenderTargetInfo layout =
|
||||
@@ -959,7 +945,7 @@ void TextureCache::RetireSampledTargetAliases(GraphicContext* ctx, const ImageIn
|
||||
}
|
||||
RequireRetirementIsolation(retire, "sampled target", requested.address, requested.size);
|
||||
if (wait_idle) {
|
||||
VulkanDeviceWaitIdle(ctx);
|
||||
Transfer::WaitForGraphicsIdle(ctx);
|
||||
}
|
||||
for (auto* cached: retire) {
|
||||
if (!cached->gpu_modified) {
|
||||
@@ -1080,7 +1066,7 @@ void TextureCache::RetireStorageDepthAliasLocked(GraphicContext* ctx, const Imag
|
||||
if (selected == nullptr) {
|
||||
return;
|
||||
}
|
||||
VulkanDeviceWaitIdle(ctx);
|
||||
Transfer::WaitForGraphicsIdle(ctx);
|
||||
const auto transfer = m_readback->DownloadDepthTarget(*selected, false);
|
||||
m_memory_tracker.ForEachDownloadRange<true>(transfer.address, transfer.size,
|
||||
[](uint64_t, uint64_t) noexcept {});
|
||||
@@ -1091,7 +1077,7 @@ void TextureCache::RetireStorageDepthAliasLocked(GraphicContext* ctx, const Imag
|
||||
TextureCache::~TextureCache() {
|
||||
m_readback.reset();
|
||||
if (!m_images.empty()) {
|
||||
VulkanDeviceWaitIdle(m_images.front()->ctx);
|
||||
Transfer::WaitForGraphicsIdle(m_images.front()->ctx);
|
||||
}
|
||||
for (const auto& image: m_images) {
|
||||
UnregisterImageLocked(*image, false);
|
||||
@@ -1136,7 +1122,7 @@ VulkanImage* TextureCache::FindTexture(CommandBuffer* command, GraphicContext* c
|
||||
info.address, info.size, metadata_read);
|
||||
}
|
||||
std::shared_ptr<CachedImage> storage_match;
|
||||
const auto requested_view_format = TextureGetFormat(info.format, TextureFormatUsage::Sampled);
|
||||
const auto requested_view_format = TextureGetFormat(info.format);
|
||||
for (auto& cached: m_images) {
|
||||
if (cached->kind != CachedImage::Kind::StorageTexture) {
|
||||
continue;
|
||||
@@ -1266,7 +1252,7 @@ VulkanImage* TextureCache::FindTexture(CommandBuffer* command, GraphicContext* c
|
||||
cached->info = info;
|
||||
cached->ctx = ctx;
|
||||
vk::ComponentMapping components {};
|
||||
cached->image = ImageOps::CreateTexture(ctx, info, false, &cached->memory, &components);
|
||||
cached->image = ImageOps::CreateTexture(ctx, info, false, &components);
|
||||
m_memory_tracker.ForEachUploadRange(
|
||||
info.address, info.size, false, [](uint64_t, uint64_t) noexcept {},
|
||||
[&]() noexcept {
|
||||
@@ -1402,7 +1388,7 @@ StorageTextureVulkanImage* TextureCache::FindStorageTexture(CommandBuffer* com
|
||||
cached->info = info;
|
||||
cached->ctx = ctx;
|
||||
vk::ComponentMapping components {};
|
||||
cached->image = ImageOps::CreateTexture(ctx, info, true, &cached->memory, &components);
|
||||
cached->image = ImageOps::CreateTexture(ctx, info, true, &components);
|
||||
m_memory_tracker.ForEachUploadRange(
|
||||
info.address, info.size, true, [](uint64_t, uint64_t) noexcept {},
|
||||
[&]() noexcept {
|
||||
@@ -1610,7 +1596,7 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer*
|
||||
cached->kind = CachedImage::Kind::RenderTarget;
|
||||
cached->target = info;
|
||||
cached->ctx = ctx;
|
||||
cached->image = ImageOps::CreateRenderTarget(ctx, info, &cached->memory);
|
||||
cached->image = ImageOps::CreateRenderTarget(ctx, info);
|
||||
const bool preserve_native = native_image_source != nullptr;
|
||||
if (preserve_native) {
|
||||
command->RetainResourceUntilFence(native_image_source);
|
||||
@@ -1636,7 +1622,7 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer*
|
||||
regions.reserve(static_cast<size_t>(native_image_source->image->layers) *
|
||||
native_image_source->image->mip_levels);
|
||||
AppendLayerCopies(regions, native_image_source->image, vk::ImageAspectFlagBits::eColor);
|
||||
UtilImageToImage(command, regions, cached->image, RENDER_COLOR_IMAGE_LAYOUT);
|
||||
Transfer::CopyImage(command, regions, cached->image, RENDER_COLOR_IMAGE_LAYOUT);
|
||||
} else {
|
||||
m_memory_tracker.ForEachUploadRange(
|
||||
info.address, info.size, false, [](uint64_t, uint64_t) noexcept {},
|
||||
@@ -1885,7 +1871,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
|
||||
cached->depth = info;
|
||||
cached->ctx = ctx;
|
||||
cached->stencil_initialized = !has_stencil;
|
||||
cached->image = ImageOps::CreateDepthTarget(ctx, info, &cached->memory);
|
||||
cached->image = ImageOps::CreateDepthTarget(ctx, info);
|
||||
if (discarded_depth_source != nullptr) {
|
||||
command->RetainResourceUntilFence(discarded_depth_source);
|
||||
}
|
||||
@@ -1939,13 +1925,13 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
|
||||
AppendLayerCopies(regions, native_depth_source->image,
|
||||
vk::ImageAspectFlagBits::eStencil);
|
||||
}
|
||||
UtilImageToImage(command, regions, cached->image,
|
||||
vk::ImageLayout::eDepthStencilAttachmentOptimal);
|
||||
Transfer::CopyImage(command, regions, cached->image,
|
||||
vk::ImageLayout::eDepthStencilAttachmentOptimal);
|
||||
cached->gpu_modified = true;
|
||||
} else {
|
||||
if (sampled_depth_source != nullptr &&
|
||||
(sampled_depth_source->image->type != VulkanImageType::Texture ||
|
||||
sampled_depth_source->image->format != Prospero::SurfaceFormat(info.guest_format) ||
|
||||
sampled_depth_source->image->format != VulkanFormat(info.guest_format) ||
|
||||
sampled_depth_source->image->extent.width != info.width ||
|
||||
sampled_depth_source->image->extent.height != info.height)) {
|
||||
EXIT("TextureCache: sampled-depth native source is inconsistent\n");
|
||||
@@ -1967,11 +1953,11 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
|
||||
break;
|
||||
case DepthTransitionSource::Native:
|
||||
command->RetainResourceUntilFence(sampled_depth_source);
|
||||
UtilCopyImageWithBuffer(command, ctx, sampled_depth_source->image,
|
||||
vk::ImageAspectFlagBits::eColor, cached->image,
|
||||
vk::ImageAspectFlagBits::eDepth,
|
||||
info.bytes_per_element,
|
||||
vk::ImageLayout::eDepthStencilAttachmentOptimal);
|
||||
Transfer::CopyImageViaBuffer(
|
||||
command, ctx, sampled_depth_source->image,
|
||||
vk::ImageAspectFlagBits::eColor, cached->image,
|
||||
vk::ImageAspectFlagBits::eDepth, info.bytes_per_element,
|
||||
vk::ImageLayout::eDepthStencilAttachmentOptimal);
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -2036,7 +2022,7 @@ TextureCache::RegisterVideoOutSurfaces(GraphicContext* ctx,
|
||||
cached->kind = CachedImage::Kind::VideoOut;
|
||||
cached->video_out = info;
|
||||
cached->ctx = ctx;
|
||||
cached->image = ImageOps::CreateVideoOut(ctx, info, &cached->memory);
|
||||
cached->image = ImageOps::CreateVideoOut(ctx, info);
|
||||
if (info.compression == VideoOutCompression::Uncompressed) {
|
||||
m_memory_tracker.ForEachUploadRange(
|
||||
info.address, info.size, false, [](uint64_t, uint64_t) noexcept {},
|
||||
@@ -2147,7 +2133,7 @@ void TextureCache::UnregisterVideoOutSurfaces(const std::vector<VideoOutVulkanIm
|
||||
cached->Address(), cached->Size());
|
||||
}
|
||||
}
|
||||
VulkanDeviceWaitIdle(ctx);
|
||||
Transfer::WaitForGraphicsIdle(ctx);
|
||||
for (auto* cached: selected) {
|
||||
if (cached->gpu_modified) {
|
||||
m_memory_tracker.UnmarkRegionAsGpuModified(cached->Address(), cached->Size());
|
||||
@@ -2269,7 +2255,7 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer* command, uint64_t vaddr,
|
||||
image_cpu_modified);
|
||||
}
|
||||
|
||||
auto vk_buffer = command->GetPool()->buffers[command->GetIndex()];
|
||||
auto vk_buffer = command->Handle();
|
||||
if (aspect == ClearAspect::Color) {
|
||||
vk::ClearColorValue clear {};
|
||||
if (!DecodePackedColorClear(match->image->format, packed_clear, &clear)) {
|
||||
@@ -2438,7 +2424,7 @@ void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached, uint
|
||||
const auto& info = cached.info;
|
||||
target.address = info.address;
|
||||
target.size = info.size;
|
||||
target.format = Prospero::SurfaceFormat(info.format);
|
||||
target.format = VulkanFormat(info.format);
|
||||
target.width = info.width;
|
||||
target.height = info.height;
|
||||
target.pitch = info.pitch;
|
||||
@@ -2513,7 +2499,7 @@ void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached, uint
|
||||
// This is the CPU Tiler backend for the image-to-buffer synchronization seam.
|
||||
// The vectors and Vulkan staging allocation retain capacity; a future PS5 GPU tiler can replace
|
||||
// this block without changing alias classification or ownership transitions.
|
||||
VulkanDeviceWaitIdle(cached.ctx);
|
||||
Transfer::WaitForGraphicsIdle(cached.ctx);
|
||||
m_buffer_transition_linear.resize(target.size);
|
||||
std::fill(m_buffer_transition_linear.begin(), m_buffer_transition_linear.end(), 0);
|
||||
std::vector<ImageBufferCopy> regions;
|
||||
@@ -2533,11 +2519,11 @@ void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached, uint
|
||||
upload.dst_y, upload.dst_z, upload.aspect});
|
||||
}
|
||||
} else {
|
||||
regions = MakeLayeredImageBufferCopies(target.layers, slice_size, target.pitch,
|
||||
target.width, target.height);
|
||||
regions = Transfer::MakeLayeredImageBufferCopies(target.layers, slice_size, target.pitch,
|
||||
target.width, target.height);
|
||||
}
|
||||
UtilFillBuffer(cached.ctx, m_buffer_transition_linear.data(), target.size, regions,
|
||||
cached.image, cached.image->layout);
|
||||
Transfer::DownloadImage(cached.ctx, m_buffer_transition_linear.data(), target.size, regions,
|
||||
cached.image, cached.image->layout);
|
||||
if (storage) {
|
||||
m_buffer_transition_guest.resize(target.size);
|
||||
m_tiler.TileImage(m_buffer_transition_guest.data(), m_buffer_transition_linear.data(),
|
||||
@@ -2599,13 +2585,13 @@ void TextureCache::SynchronizeDepthImageToBufferLocked(CachedImage& cached, uint
|
||||
info.layers, static_cast<int>(info.format), info.guest_format, info.bytes_per_element,
|
||||
has_stencil, has_htile, cached.gpu_modified, cached.buffer_modified);
|
||||
}
|
||||
VulkanDeviceWaitIdle(cached.ctx);
|
||||
Transfer::WaitForGraphicsIdle(cached.ctx);
|
||||
m_buffer_transition_linear.resize(info.size);
|
||||
std::fill(m_buffer_transition_linear.begin(), m_buffer_transition_linear.end(), 0);
|
||||
const auto regions = MakeLayeredImageBufferCopies(1, info.size, info.pitch, info.width,
|
||||
info.height, vk::ImageAspectFlagBits::eDepth);
|
||||
UtilFillBuffer(cached.ctx, m_buffer_transition_linear.data(), info.size, regions, cached.image,
|
||||
cached.image->layout);
|
||||
const auto regions = Transfer::MakeLayeredImageBufferCopies(
|
||||
1, info.size, info.pitch, info.width, info.height, vk::ImageAspectFlagBits::eDepth);
|
||||
Transfer::DownloadImage(cached.ctx, m_buffer_transition_linear.data(), info.size, regions,
|
||||
cached.image, cached.image->layout);
|
||||
m_buffer_transition_guest.resize(info.size);
|
||||
m_tiler.TileImage(m_buffer_transition_guest.data(), m_buffer_transition_linear.data(), info);
|
||||
Libs::LibKernel::Memory::WriteBacking(info.address, m_buffer_transition_guest.data(),
|
||||
@@ -3169,7 +3155,7 @@ void TextureCache::UnmapMemory(uint64_t vaddr, uint64_t size) {
|
||||
}
|
||||
}
|
||||
if (wait_ctx != nullptr) {
|
||||
VulkanDeviceWaitIdle(wait_ctx);
|
||||
Transfer::WaitForGraphicsIdle(wait_ctx);
|
||||
}
|
||||
for (auto& cached: m_images) {
|
||||
if (!cached->OverlapsRange(vaddr, size, false) || !cached->gpu_modified) {
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
#include "graphics/host_gpu/graphicContext.h"
|
||||
#include "graphics/host_gpu/objects/textureCommon.h"
|
||||
#include "graphics/host_gpu/renderer/image.h"
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
#include "graphics/host_gpu/transfer.h"
|
||||
#include "graphics/host_gpu/vulkanCommon.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -26,7 +27,7 @@ static void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage*
|
||||
" host_slice=0x%016" PRIx64 " layers=%u\n",
|
||||
slice_size, host_slice_size, info.layers);
|
||||
}
|
||||
UtilScratchBuffer host_linear(host_upload_size);
|
||||
Transfer::ScratchBuffer host_linear(host_upload_size);
|
||||
std::vector<uint16_t> guest_linear(slice_size / sizeof(uint16_t));
|
||||
std::vector<BufferImageCopy> regions;
|
||||
regions.reserve(info.layers);
|
||||
@@ -48,14 +49,14 @@ static void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage*
|
||||
region.aspect = vk::ImageAspectFlagBits::eDepth;
|
||||
regions.push_back(region);
|
||||
}
|
||||
UtilFillImage(ctx, image, host_linear.Data(), host_upload_size, regions,
|
||||
vk::ImageLayout::eDepthStencilAttachmentOptimal);
|
||||
Transfer::UploadImage(ctx, image, host_linear.Data(), host_upload_size, regions,
|
||||
vk::ImageLayout::eDepthStencilAttachmentOptimal);
|
||||
}
|
||||
|
||||
void Tiler::DetileImage(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info,
|
||||
const BufferImageCopySource& source, bool refresh, bool storage) const {
|
||||
if (refresh) {
|
||||
VulkanDeviceWaitIdle(ctx);
|
||||
Transfer::WaitForGraphicsIdle(ctx);
|
||||
}
|
||||
const bool array_texture = TextureIsLayeredTexture(info.type);
|
||||
const bool volume_texture = TextureIs3DTexture(info.type);
|
||||
@@ -77,7 +78,7 @@ void Tiler::DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image,
|
||||
const DepthTargetInfo& info, const BufferImageCopySource& source,
|
||||
bool refresh, uint32_t base_layer) const {
|
||||
if (refresh) {
|
||||
VulkanDeviceWaitIdle(ctx);
|
||||
Transfer::WaitForGraphicsIdle(ctx);
|
||||
}
|
||||
if (DepthAspectTransferBytes(info.format) != info.bytes_per_element) {
|
||||
switch (info.format) {
|
||||
@@ -93,7 +94,7 @@ void Tiler::DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image,
|
||||
}
|
||||
}
|
||||
const auto slice_size = info.size / info.layers;
|
||||
UtilScratchBuffer linear(info.size);
|
||||
Transfer::ScratchBuffer linear(info.size);
|
||||
std::vector<BufferImageCopy> regions;
|
||||
regions.reserve(info.layers);
|
||||
for (uint32_t layer = 0; layer < info.layers; layer++) {
|
||||
@@ -110,8 +111,8 @@ void Tiler::DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image,
|
||||
region.aspect = vk::ImageAspectFlagBits::eDepth;
|
||||
regions.push_back(region);
|
||||
}
|
||||
UtilFillImage(ctx, image, linear.Data(), info.size, regions,
|
||||
vk::ImageLayout::eDepthStencilAttachmentOptimal);
|
||||
Transfer::UploadImage(ctx, image, linear.Data(), info.size, regions,
|
||||
vk::ImageLayout::eDepthStencilAttachmentOptimal);
|
||||
}
|
||||
|
||||
void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image,
|
||||
@@ -121,10 +122,10 @@ void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image,
|
||||
const auto stencil_pitch = TileGetTexturePitch(
|
||||
stencil_format, info.width, 1, Prospero::GpuEnumValue(Prospero::TileMode::kDepth));
|
||||
if (refresh) {
|
||||
VulkanDeviceWaitIdle(ctx);
|
||||
Transfer::WaitForGraphicsIdle(ctx);
|
||||
}
|
||||
const auto slice_size = info.stencil_size / info.layers;
|
||||
UtilScratchBuffer linear(info.stencil_size);
|
||||
Transfer::ScratchBuffer linear(info.stencil_size);
|
||||
std::vector<BufferImageCopy> regions;
|
||||
regions.reserve(info.layers);
|
||||
for (uint32_t layer = 0; layer < info.layers; layer++) {
|
||||
@@ -141,8 +142,8 @@ void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image,
|
||||
region.aspect = vk::ImageAspectFlagBits::eStencil;
|
||||
regions.push_back(region);
|
||||
}
|
||||
UtilFillImage(ctx, image, linear.Data(), info.stencil_size, regions,
|
||||
vk::ImageLayout::eDepthStencilAttachmentOptimal);
|
||||
Transfer::UploadImage(ctx, image, linear.Data(), info.stencil_size, regions,
|
||||
vk::ImageLayout::eDepthStencilAttachmentOptimal);
|
||||
}
|
||||
|
||||
void Tiler::TileImage(void* dst, const void* src, const RenderTargetInfo& info) const {
|
||||
@@ -185,10 +186,9 @@ void Tiler::TileImage(void* dst, const void* src, const ImageInfo& info) const {
|
||||
auto layout = TextureCalcUploadLayout(info.format, info.width, info.height, info.levels,
|
||||
info.depth, info.pitch, info.tile, info.size, true, false,
|
||||
false, "StorageTextureReadback");
|
||||
auto regions = TextureBuildUploadRegions(layout, Prospero::SurfaceFormat(info.format),
|
||||
info.width, info.height, info.depth, info.levels,
|
||||
false, false, TextureUploadDestination::MipLevels,
|
||||
TextureUploadSliceLayout::MipChainPerSlice);
|
||||
auto regions = TextureBuildUploadRegions(
|
||||
layout, VulkanFormat(info.format), info.width, info.height, info.depth, info.levels, false,
|
||||
false, TextureUploadDestination::MipLevels, TextureUploadSliceLayout::MipChainPerSlice);
|
||||
std::memset(dst, 0, info.size);
|
||||
for (uint32_t level = 0; level < info.levels; level++) {
|
||||
const auto& level_size = layout.level_sizes[level];
|
||||
|
||||
Reference in New Issue
Block a user