Refactor graphics #1

This commit is contained in:
nmzik
2026-07-19 00:54:31 +02:00
parent 7905f2d12f
commit cbc11d2eaf
71 changed files with 2051 additions and 3399 deletions
+4 -2
View File
@@ -7,6 +7,7 @@
#include "graphics/host_gpu/vulkanCommon.h" // IWYU pragma: export
#include "graphics/host_gpu/vulkanInstance.h"
#include <array>
#include <memory>
#include <mutex>
#include <vector>
@@ -42,8 +43,9 @@ struct VulkanCommandPool {
};
struct GraphicContext: public VulkanInstance {
uint32_t screen_width = 0;
uint32_t screen_height = 0;
uint32_t screen_width = 0;
uint32_t screen_height = 0;
std::array<Common::Mutex, QUEUES_NUM> queue_mutexes;
};
struct VulkanMemory {
+13 -4
View File
@@ -4,6 +4,7 @@
#include "common/threads.h"
#include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include <algorithm>
#include <memory>
@@ -270,7 +271,7 @@ void LabelManager::Set(CommandBuffer* buffer, Label* label) {
submission.completion = std::make_shared<LabelEvent>();
submission.completion->device = label->device;
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()];
auto vk_buffer = buffer->Handle();
EXIT_NOT_IMPLEMENTED(vk_buffer == nullptr);
@@ -279,14 +280,22 @@ void LabelManager::Set(CommandBuffer* buffer, Label* label) {
create_info.pNext = nullptr;
create_info.flags = {};
label->device.createEvent(&create_info, nullptr, &submission.completion->event);
EXIT_NOT_IMPLEMENTED(submission.completion->event == nullptr);
const auto create_result =
label->device.createEvent(&create_info, nullptr, &submission.completion->event);
if (create_result != vk::Result::eSuccess || submission.completion->event == nullptr) {
EXIT("failed to create label event: %s (%d)\n", VulkanToString(create_result).c_str(),
static_cast<int>(create_result));
}
buffer->RetainResourceUntilFence(submission.completion);
// Labels can be reused before an earlier end-of-pipe event has been
// observed by the polling thread. Capture a separate Vulkan event and
// callback snapshot for each set so older writes are not lost.
label->device.resetEvent(submission.completion->event);
const auto reset_result = label->device.resetEvent(submission.completion->event);
if (reset_result != vk::Result::eSuccess) {
EXIT("failed to reset label event: %s (%d)\n", VulkanToString(reset_result).c_str(),
static_cast<int>(reset_result));
}
vk_buffer.setEvent(submission.completion->event, vk::PipelineStageFlagBits::eBottomOfPipe);
label->submissions.push_back(submission);
+178 -172
View File
@@ -5,8 +5,9 @@
#include "graphics/guest_gpu/gpu_defs.h"
#include "graphics/guest_gpu/gpu_format.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 "graphics/host_gpu/vulkanCommon.h"
#include <algorithm>
#include <atomic>
@@ -14,6 +15,127 @@
#include <cstring>
namespace Libs::Graphics {
namespace {
struct RenderTargetFormatMapping {
Prospero::ChannelLayout layout;
Prospero::ChannelType type;
Prospero::ChannelOrder order;
RenderTargetFormatInfo info;
};
constexpr RenderTargetFormatMapping kRenderTargetFormats[] = {
{Prospero::ChannelLayout::k8_8,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR8G8Unorm, 2}},
{Prospero::ChannelLayout::k8_8_8_8,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR8G8B8A8Unorm, 4}},
{Prospero::ChannelLayout::k8_8_8_8,
Prospero::ChannelType::kSNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR8G8B8A8Snorm, 4}},
{Prospero::ChannelLayout::k8_8_8_8,
Prospero::ChannelType::kSrgb,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR8G8B8A8Srgb, 4}},
{Prospero::ChannelLayout::k8_8_8_8,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kAlt,
{vk::Format::eB8G8R8A8Unorm, 4}},
{Prospero::ChannelLayout::k8_8_8_8,
Prospero::ChannelType::kSNorm,
Prospero::ChannelOrder::kAlt,
{vk::Format::eB8G8R8A8Snorm, 4}},
{Prospero::ChannelLayout::k8_8_8_8,
Prospero::ChannelType::kSrgb,
Prospero::ChannelOrder::kAlt,
{vk::Format::eB8G8R8A8Srgb, 4}},
{Prospero::ChannelLayout::k5_5_5_1,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR5G5B5A1UnormPack16, 2}},
{Prospero::ChannelLayout::k4_4_4_4,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kReversed,
{vk::Format::eB4G4R4A4UnormPack16, 2}},
{Prospero::ChannelLayout::k10_10_10_2,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eA2B10G10R10UnormPack32, 4}},
{Prospero::ChannelLayout::k10_10_10_2,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kAlt,
{vk::Format::eA2R10G10B10UnormPack32, 4}},
{Prospero::ChannelLayout::k11_11_10,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard,
{vk::Format::eB10G11R11UfloatPack32, 4}},
{Prospero::ChannelLayout::k16,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16Unorm, 2}},
{Prospero::ChannelLayout::k16,
Prospero::ChannelType::kUInt,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16Uint, 2}},
{Prospero::ChannelLayout::k16,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16Sfloat, 2}},
{Prospero::ChannelLayout::k16_16,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16G16Unorm, 4}},
{Prospero::ChannelLayout::k16_16,
Prospero::ChannelType::kSNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16G16Snorm, 4}},
{Prospero::ChannelLayout::k16_16,
Prospero::ChannelType::kUInt,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16G16Uint, 4}},
{Prospero::ChannelLayout::k16_16,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16G16Sfloat, 4}},
{Prospero::ChannelLayout::k16_16_16_16,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16G16B16A16Unorm, 8}},
{Prospero::ChannelLayout::k16_16_16_16,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16G16B16A16Sfloat, 8}},
{Prospero::ChannelLayout::k16_16_16_16,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kAlt,
{vk::Format::eR16G16B16A16Sfloat, 8, Prospero::ColorMappingBgra}},
{Prospero::ChannelLayout::k16_16_16_16,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kReversed,
{vk::Format::eR16G16B16A16Sfloat, 8, Prospero::ColorMappingAbgr}},
{Prospero::ChannelLayout::k32,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR32Sfloat, 4}},
{Prospero::ChannelLayout::k32_32,
Prospero::ChannelType::kUInt,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR32G32Uint, 8}},
{Prospero::ChannelLayout::k32_32,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR32G32Sfloat, 8}},
{Prospero::ChannelLayout::k32_32_32_32,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR32G32B32A32Sfloat, 16}},
};
} // namespace
// TODO: cleanup!
RenderTargetFormatInfo TextureGetRenderTargetFormat(uint32_t raw_layout, uint32_t raw_type,
@@ -21,132 +143,25 @@ RenderTargetFormatInfo TextureGetRenderTargetFormat(uint32_t raw_layout, uint32_
const auto layout = static_cast<Prospero::ChannelLayout>(raw_layout);
const auto type = static_cast<Prospero::ChannelType>(raw_type);
const auto order = static_cast<Prospero::ChannelOrder>(raw_order);
const auto is = [=](Prospero::ChannelLayout l, Prospero::ChannelType t,
Prospero::ChannelOrder o) {
return layout == l && type == t && order == o;
};
if (layout == Prospero::ChannelLayout::k8 && type == Prospero::ChannelType::kUNorm &&
raw_order <= Prospero::GpuEnumValue(Prospero::ChannelOrder::kAltReversed)) {
return {vk::Format::eR8Unorm, 1};
}
if (is(Prospero::ChannelLayout::k8_8, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR8G8Unorm, 2};
}
if (is(Prospero::ChannelLayout::k8_8_8_8, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR8G8B8A8Unorm, 4};
}
if (is(Prospero::ChannelLayout::k8_8_8_8, Prospero::ChannelType::kSNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR8G8B8A8Snorm, 4};
}
if (is(Prospero::ChannelLayout::k8_8_8_8, Prospero::ChannelType::kSrgb,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR8G8B8A8Srgb, 4};
}
if (is(Prospero::ChannelLayout::k8_8_8_8, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kAlt)) {
return {vk::Format::eB8G8R8A8Unorm, 4};
}
if (is(Prospero::ChannelLayout::k8_8_8_8, Prospero::ChannelType::kSNorm,
Prospero::ChannelOrder::kAlt)) {
return {vk::Format::eB8G8R8A8Snorm, 4};
}
if (is(Prospero::ChannelLayout::k8_8_8_8, Prospero::ChannelType::kSrgb,
Prospero::ChannelOrder::kAlt)) {
return {vk::Format::eB8G8R8A8Srgb, 4};
}
if (is(Prospero::ChannelLayout::k5_5_5_1, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR5G5B5A1UnormPack16, 2};
}
if (is(Prospero::ChannelLayout::k4_4_4_4, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kReversed)) {
return {vk::Format::eB4G4R4A4UnormPack16, 2};
}
if (is(Prospero::ChannelLayout::k10_10_10_2, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eA2B10G10R10UnormPack32, 4};
}
if (is(Prospero::ChannelLayout::k10_10_10_2, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kAlt)) {
return {vk::Format::eA2R10G10B10UnormPack32, 4};
}
if (is(Prospero::ChannelLayout::k11_11_10, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eB10G11R11UfloatPack32, 4};
}
if (is(Prospero::ChannelLayout::k16, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16Unorm, 2};
}
if (is(Prospero::ChannelLayout::k16, Prospero::ChannelType::kUInt,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16Uint, 2};
}
if (is(Prospero::ChannelLayout::k16, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16Sfloat, 2};
}
if (is(Prospero::ChannelLayout::k16_16, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16G16Unorm, 4};
}
if (is(Prospero::ChannelLayout::k16_16, Prospero::ChannelType::kSNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16G16Snorm, 4};
}
if (is(Prospero::ChannelLayout::k16_16, Prospero::ChannelType::kUInt,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16G16Uint, 4};
}
if (is(Prospero::ChannelLayout::k16_16, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16G16Sfloat, 4};
}
if (is(Prospero::ChannelLayout::k16_16_16_16, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16G16B16A16Unorm, 8};
}
if (is(Prospero::ChannelLayout::k16_16_16_16, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16G16B16A16Sfloat, 8};
}
if (is(Prospero::ChannelLayout::k16_16_16_16, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kAlt)) {
return {vk::Format::eR16G16B16A16Sfloat, 8, Prospero::ColorMappingBgra};
}
if (is(Prospero::ChannelLayout::k16_16_16_16, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kReversed)) {
return {vk::Format::eR16G16B16A16Sfloat, 8, Prospero::ColorMappingAbgr};
}
if (is(Prospero::ChannelLayout::k32, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR32Sfloat, 4};
}
if (is(Prospero::ChannelLayout::k32_32, Prospero::ChannelType::kUInt,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR32G32Uint, 8};
}
if (is(Prospero::ChannelLayout::k32_32, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR32G32Sfloat, 8};
}
if (is(Prospero::ChannelLayout::k32_32_32_32, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR32G32B32A32Sfloat, 16};
for (const auto& mapping: kRenderTargetFormats) {
if (mapping.layout == layout && mapping.type == type && mapping.order == order) {
return mapping.info;
}
}
EXIT("unsupported render-target format combination: layout=%u type=%u order=%u\n", raw_layout,
raw_type, raw_order);
}
static uint64_t TextureUploadLevelSrcOffset(const TileSizeOffset& level_size) {
static uint64_t GetLevelSrcOffset(const TileSizeOffset& level_size) {
return (level_size.src_size != 0 ? level_size.src_offset : level_size.offset);
}
static uint64_t TextureUploadLevelSrcSize(const TileSizeOffset& level_size) {
static uint64_t GetLevelSrcSize(const TileSizeOffset& level_size) {
return (level_size.src_size != 0 ? level_size.src_size : level_size.size);
}
@@ -156,11 +171,11 @@ uint64_t TextureUploadSliceSourceOffset(const TextureUploadLayout& layout, uint3
if (level >= 16 || layout.level_sizes[level].size == 0) {
EXIT("invalid texture upload slice source, level=%u slice=%u\n", level, slice);
}
const auto level_offset = TextureUploadLevelSrcOffset(layout.level_sizes[level]);
const auto level_offset = GetLevelSrcOffset(layout.level_sizes[level]);
const auto slice_stride =
source_slice_layout == TextureUploadSliceLayout::MipChainPerSlice
? (layout.source_slice_stride != 0 ? layout.source_slice_stride : layout.slice_stride)
: TextureUploadLevelSrcSize(layout.level_sizes[level]);
: GetLevelSrcSize(layout.level_sizes[level]);
if (slice_stride != 0 && slice > (UINT64_MAX - level_offset) / slice_stride) {
EXIT("texture upload slice source offset overflow, level=%u slice=%u\n", level, slice);
}
@@ -178,7 +193,7 @@ uint64_t TextureCalcUploadSize(const TextureUploadLayout& layout,
}
for (uint32_t level = 0; level < levels; level++) {
const auto src_size = TextureUploadLevelSrcSize(layout.level_sizes[level]);
const auto src_size = GetLevelSrcSize(layout.level_sizes[level]);
for (uint32_t z = 0; z < depth; z++) {
size = std::max<uint64_t>(
size,
@@ -191,7 +206,7 @@ uint64_t TextureCalcUploadSize(const TextureUploadLayout& layout,
void TextureCopyBufferBytes(GraphicContext* ctx, VulkanBuffer* src_buffer,
uint64_t src_buffer_offset, uint64_t copy_size,
UtilScratchBuffer* dst) {
Transfer::ScratchBuffer* dst) {
EXIT_IF(ctx == nullptr);
EXIT_IF(src_buffer == nullptr);
EXIT_IF(dst == nullptr);
@@ -223,7 +238,7 @@ void TextureCopyBufferBytes(GraphicContext* ctx, VulkanBuffer* src_buffer,
vk::MemoryPropertyFlagBits::eHostCoherent |
vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, (src_buffer_offset + available + 3u) & ~uint64_t {3}, &readback);
UtilCopyBuffer(src_buffer, &readback, src_buffer_offset + available);
Transfer::CopyBuffer(src_buffer, &readback, src_buffer_offset + available);
void* data = nullptr;
VulkanMapMemory(ctx, &readback.memory, &data);
@@ -349,8 +364,8 @@ vk::ImageUsageFlags TextureGetViewUsage(TextureFormatUsage usage) {
return vk_usage;
}
vk::Format TextureGetFormat(uint32_t fmt, [[maybe_unused]] TextureFormatUsage usage) {
const auto vk_format = Prospero::SurfaceFormat(fmt);
vk::Format TextureGetFormat(uint32_t fmt) {
const auto vk_format = VulkanFormat(fmt);
if (vk_format != vk::Format::eUndefined) {
return vk_format;
}
@@ -435,14 +450,15 @@ static bool CalcStandard4kbVolumeMipLayout(uint32_t format, uint32_t pitch, uint
uint32_t TextureGetAtlasSliceYStride(vk::Format format, uint32_t mip_height, uint32_t depth,
uint64_t levels) {
return (depth > 1 && levels > 1 && UtilIsBcFormat(format) ? AlignUpU32(mip_height, 4u)
: mip_height);
return (depth > 1 && levels > 1 && Transfer::IsBlockCompressedFormat(format)
? AlignUpU32(mip_height, 4u)
: mip_height);
}
uint32_t TextureCalcStackedImageHeight(vk::Format format, uint32_t height, uint32_t depth,
uint64_t levels) {
auto image_height = height * depth;
if (depth <= 1 || levels <= 1 || !UtilIsBcFormat(format)) {
if (depth <= 1 || levels <= 1 || !Transfer::IsBlockCompressedFormat(format)) {
return image_height;
}
@@ -468,7 +484,7 @@ uint32_t TextureCalcMipmapAtlasImageHeight(vk::Format format, uint32_t width, ui
uint32_t mip_height = height;
for (uint32_t level = 0; level < levels; level++) {
const auto mipmap_offset = UtilCalcMipmapOffset(level, width, height);
const auto mipmap_offset = Transfer::MipmapAtlasOffset(level, width, height);
const auto mip_bottom =
static_cast<uint32_t>(mipmap_offset.second) +
TextureGetAtlasSliceYStride(format, mip_height, depth, levels) * depth;
@@ -502,20 +518,20 @@ bool TextureCanCreateCubeView(uint64_t type, uint32_t base_array, uint32_t layer
layer_count % 6u == 0;
}
vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj, VulkanMemory* mem,
vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj,
const TextureImageCreateParams& params) {
EXIT_IF(ctx == nullptr);
EXIT_IF(vk_obj == nullptr);
EXIT_IF(mem == nullptr);
EXIT_IF(params.owner == nullptr);
const bool array_texture = TextureIsLayeredTexture(params.type);
const bool volume_texture = TextureIs3DTexture(params.type);
auto pixel_format = TextureGetFormat(params.fmt, params.format_usage);
auto pixel_format = TextureGetFormat(params.fmt);
EXIT_NOT_IMPLEMENTED(pixel_format == vk::Format::eUndefined);
EXIT_NOT_IMPLEMENTED(params.width == 0);
EXIT_NOT_IMPLEMENTED(params.height == 0);
EXIT_NOT_IMPLEMENTED(params.depth == 0);
EXIT_NOT_IMPLEMENTED(params.levels == 0 || params.levels > 16);
uint32_t image_height = 0;
@@ -618,15 +634,11 @@ vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj
vk_obj->image = nullptr;
vk_obj->layout = image_info.initialLayout;
UtilResetImageViews(vk_obj);
vk_obj->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
mem->property = vk::MemoryPropertyFlagBits::eDeviceLocal;
bool created = VulkanCreateImage(ctx, &image_info, vk_obj, mem);
bool created = VulkanCreateImage(ctx, image_info, vk_obj);
EXIT_NOT_IMPLEMENTED(!created);
vk_obj->memory = *mem;
return components;
}
@@ -672,17 +684,19 @@ void TextureCreateImageViews(GraphicContext* ctx, VulkanImage* vk_obj,
create_info.viewType = vk::ImageViewType::e2DArray;
}
ctx->device.createImageView(&create_info, nullptr,
&vk_obj->image_view[VulkanImage::VIEW_DEFAULT]);
EXIT_NOT_IMPLEMENTED(vk_obj->image_view[VulkanImage::VIEW_DEFAULT] == nullptr);
auto create_view = [&](int index) {
const auto result =
ctx->device.createImageView(&create_info, nullptr, &vk_obj->image_view[index]);
if (result != vk::Result::eSuccess || vk_obj->image_view[index] == nullptr) {
EXIT("failed to create texture image view: result=%d format=%d index=%d\n",
static_cast<int>(result), static_cast<int>(create_info.format), index);
}
};
create_view(VulkanImage::VIEW_DEFAULT);
if (!volume_texture || depth >= 1) {
create_info.viewType = vk::ImageViewType::e2DArray;
create_info.subresourceRange.layerCount = (volume_texture ? volume_slices : layer_count);
ctx->device.createImageView(&create_info, nullptr,
&vk_obj->image_view[VulkanImage::VIEW_DEFAULT_ARRAY]);
EXIT_NOT_IMPLEMENTED(vk_obj->image_view[VulkanImage::VIEW_DEFAULT_ARRAY] == nullptr);
}
create_info.viewType = vk::ImageViewType::e2DArray;
create_info.subresourceRange.layerCount = volume_texture ? volume_slices : layer_count;
create_view(VulkanImage::VIEW_DEFAULT_ARRAY);
}
static uint64_t CalcTextureSliceStride(const TileSizeOffset* level_sizes, uint64_t levels,
@@ -847,7 +861,7 @@ std::vector<BufferImageCopy> TextureBuildUploadRegions(
for (uint32_t i = 0; i < levels; i++) {
EXIT_NOT_IMPLEMENTED(layout.level_sizes[i].size == 0);
const auto mipmap_offset = UtilCalcMipmapOffset(i, width, height);
const auto mipmap_offset = Transfer::MipmapAtlasOffset(i, width, height);
for (uint32_t z = 0; z < depth; z++) {
const auto region_index = i * depth + z;
@@ -861,7 +875,7 @@ std::vector<BufferImageCopy> TextureBuildUploadRegions(
regions[region_index].height = mip_height;
regions[region_index].copy_height =
(!array_texture && !volume_texture && depth > 1 && levels > 1 &&
UtilIsBcFormat(image_format)
Transfer::IsBlockCompressedFormat(image_format)
? TextureGetAtlasSliceYStride(image_format, mip_height, depth, levels)
: 0);
regions[region_index].dst_layer = (array_texture ? z : 0);
@@ -911,14 +925,6 @@ std::vector<BufferImageCopy> TextureBuildUploadRegions(
return regions;
}
static uint64_t GetLevelSrcOffset(const TileSizeOffset& level_size) {
return (level_size.src_size != 0 ? level_size.src_offset : level_size.offset);
}
static uint64_t GetLevelSrcSize(const TileSizeOffset& level_size) {
return (level_size.src_size != 0 ? level_size.src_size : level_size.size);
}
static uint64_t GetSliceSrcStride(const TextureUploadLayout& layout, uint32_t level,
TextureUploadSliceLayout source_slice_layout) {
return (
@@ -954,13 +960,13 @@ static void UploadFmaskIdentity(GraphicContext* ctx, VulkanImage* vk_obj,
", upload_size=%" PRIu64 " regions=%zu\n",
owner, kIdentityFmaskPattern, upload_size, upload_regions.size());
UtilScratchBuffer temp_buf(upload_size);
auto* words = static_cast<uint32_t*>(temp_buf.Data());
Transfer::ScratchBuffer temp_buf(upload_size);
auto* words = static_cast<uint32_t*>(temp_buf.Data());
for (uint64_t i = 0; i < upload_size / sizeof(uint32_t); i++) {
words[i] = kIdentityFmaskPattern;
}
UtilFillImage(ctx, vk_obj, temp_buf.Data(), upload_size, upload_regions, dst_layout);
Transfer::UploadImage(ctx, vk_obj, temp_buf.Data(), upload_size, upload_regions, dst_layout);
}
void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const void* src_data,
@@ -974,13 +980,13 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
" extent=%" PRIu64 "x%" PRIu64 " depth=%u pitch=%u levels=%" PRIu64 "\n",
owner, layout.tile, size, width, height, depth, layout.pitch, levels);
} else if (static_cast<Prospero::TileMode>(layout.tile) == Prospero::TileMode::kLinear) {
UtilFillImage(ctx, vk_obj, src_data, size, regions, dst_layout);
Transfer::UploadImage(ctx, vk_obj, src_data, size, regions, dst_layout);
} else if (layout.fmt_tiled_render_target) {
LOGF("%s: detiling typed render-target texture: fmt=%u tile=%u size=%" PRIu64
" extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u levels=%" PRIu64 "\n",
owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height,
static_cast<uint64_t>(depth), layout.pitch, levels);
UtilScratchBuffer temp_buf(size);
Transfer::ScratchBuffer temp_buf(size);
for (uint32_t i = 0; i < levels; i++) {
for (uint32_t z = 0; z < depth; z++) {
const auto region_index = i * depth + z;
@@ -995,7 +1001,7 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
layout.level_sizes[i].x, layout.level_sizes[i].y);
}
}
UtilFillImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
Transfer::UploadImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
} else if (layout.fmt_tiled_depth) {
if (Prospero::IsFmaskTextureFormat(static_cast<uint32_t>(fmt))) {
UploadFmaskIdentity(ctx, vk_obj, regions, dst_layout, owner);
@@ -1004,13 +1010,13 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
const uint32_t bytes_per_element =
Prospero::RenderTargetBytesPerElement(static_cast<uint32_t>(fmt));
if (bytes_per_element == 1) {
UtilFillImage(ctx, vk_obj, src_data, size, regions, dst_layout);
Transfer::UploadImage(ctx, vk_obj, src_data, size, regions, dst_layout);
} else {
LOGF("%s: detiling typed depth texture: fmt=%u tile=%u size=%" PRIu64 " extent=%" PRIu64
"x%" PRIu64 " depth=%" PRIu64 " pitch=%u levels=%" PRIu64 "\n",
owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height,
static_cast<uint64_t>(depth), layout.pitch, levels);
UtilScratchBuffer temp_buf(size);
Transfer::ScratchBuffer temp_buf(size);
for (uint32_t i = 0; i < levels; i++) {
for (uint32_t z = 0; z < depth; z++) {
const auto region_index = i * depth + z;
@@ -1025,10 +1031,10 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
layout.level_sizes[i].size);
}
}
UtilFillImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
Transfer::UploadImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
}
} else if (layout.fmt_tiled_standard256b) {
UtilScratchBuffer temp_buf(size);
Transfer::ScratchBuffer temp_buf(size);
for (uint32_t i = 0; i < levels; i++) {
for (uint32_t z = 0; z < depth; z++) {
const auto region_index = i * depth + z;
@@ -1042,13 +1048,13 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
layout.level_sizes[i].size, layout.level_sizes[i].size);
}
}
UtilFillImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
Transfer::UploadImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
} else if (layout.fmt_tiled_standard4kb && layout.volume_texture) {
LOGF("%s: detiling typed Standard4KB 3D texture: fmt=%u tile=%u size=%" PRIu64
" extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u levels=%" PRIu64 "\n",
owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height,
static_cast<uint64_t>(depth), layout.pitch, levels);
UtilScratchBuffer temp_buf(size);
Transfer::ScratchBuffer temp_buf(size);
if (levels == 1) {
TileConvertTiledToLinearStandard4KB3D(
temp_buf.Data(), src_data, static_cast<uint32_t>(fmt), static_cast<uint32_t>(width),
@@ -1099,13 +1105,13 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
}
}
}
UtilFillImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
Transfer::UploadImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
} else if (layout.fmt_tiled_standard4kb) {
LOGF("%s: detiling typed Standard4KB texture: fmt=%u tile=%u size=%" PRIu64
" extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u\n",
owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height,
static_cast<uint64_t>(depth), layout.pitch);
UtilScratchBuffer temp_buf(size);
Transfer::ScratchBuffer temp_buf(size);
for (uint32_t i = 0; i < levels; i++) {
for (uint32_t z = 0; z < depth; z++) {
const auto region_index = i * depth + z;
@@ -1120,13 +1126,13 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
layout.level_sizes[i].x, layout.level_sizes[i].y);
}
}
UtilFillImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
Transfer::UploadImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
} else if (layout.fmt_tiled_standard64kb) {
LOGF("%s: detiling typed Standard64KB texture: fmt=%u tile=%u size=%" PRIu64
" extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u\n",
owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height,
static_cast<uint64_t>(depth), layout.pitch);
UtilScratchBuffer temp_buf(size);
Transfer::ScratchBuffer temp_buf(size);
for (uint32_t i = 0; i < levels; i++) {
for (uint32_t z = 0; z < depth; z++) {
const auto region_index = i * depth + z;
@@ -1141,14 +1147,14 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
layout.level_sizes[i].x, layout.level_sizes[i].y);
}
}
UtilFillImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
Transfer::UploadImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
} else if (layout.tile != 0) {
EXIT("%s: typed tiled upload still unsupported after sizing, using linear fallback: fmt=%u "
"tile=%u size=%" PRIu64 " extent=%" PRIu64 "x%" PRIu64 " pitch=%u levels=%" PRIu64
"\n",
owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height, layout.pitch,
levels);
UtilFillImage(ctx, vk_obj, src_data, size, regions, dst_layout);
Transfer::UploadImage(ctx, vk_obj, src_data, size, regions, dst_layout);
}
}
@@ -5,7 +5,7 @@
#include "common/common.h"
#include "graphics/guest_gpu/gpu_defs.h"
#include "graphics/guest_gpu/tile.h"
#include "graphics/host_gpu/utils.h"
#include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include <vector>
@@ -14,7 +14,6 @@ namespace Libs::Graphics {
struct GraphicContext;
struct VulkanImage;
struct VulkanMemory;
enum class TextureFormatUsage : uint32_t {
None = 0,
@@ -93,7 +92,7 @@ bool TextureCheckFormat(GraphicContext* ctx, vk::ImageCreateInfo
bool TextureCheckStorageSwizzle(vk::ImageCreateInfo* image_info, vk::ComponentMapping* components);
vk::ImageUsageFlags TextureGetUsage(TextureFormatUsage usage);
vk::ImageUsageFlags TextureGetViewUsage(TextureFormatUsage usage);
vk::Format TextureGetFormat(uint32_t fmt, TextureFormatUsage usage);
vk::Format TextureGetFormat(uint32_t fmt);
RenderTargetFormatInfo TextureGetRenderTargetFormat(uint32_t layout, uint32_t type, uint32_t order);
uint32_t TextureGetAtlasSliceYStride(vk::Format format, uint32_t mip_height, uint32_t depth,
uint64_t levels);
@@ -105,7 +104,7 @@ bool TextureIs3DTexture(uint64_t type);
bool TextureIsCubeTexture(uint64_t type);
bool TextureIsLayeredTexture(uint64_t type);
bool TextureCanCreateCubeView(uint64_t type, uint32_t base_array, uint32_t layer_count);
vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj, VulkanMemory* mem,
vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* image,
const TextureImageCreateParams& params);
void TextureCreateImageViews(GraphicContext* ctx, VulkanImage* vk_obj,
vk::ComponentMapping components, uint64_t type, uint32_t base_array,
@@ -128,7 +127,8 @@ std::vector<BufferImageCopy> TextureBuildUploadRegions(
uint32_t depth, uint64_t levels, bool array_texture, bool volume_texture,
TextureUploadDestination destination, TextureUploadSliceLayout slice_layout);
void TextureCopyBufferBytes(GraphicContext* ctx, VulkanBuffer* src_buffer,
uint64_t src_buffer_offset, uint64_t copy_size, UtilScratchBuffer* dst);
uint64_t src_buffer_offset, uint64_t copy_size,
Transfer::ScratchBuffer* dst);
void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const void* src_data,
uint64_t size, const std::vector<BufferImageCopy>& regions,
const TextureUploadLayout& layout, uint32_t fmt, uint64_t width,
+24 -45
View File
@@ -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();
}
+4 -6
View File
@@ -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;
}
}
+103 -186
View File
@@ -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
+24 -56
View File
@@ -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 -1
View File
@@ -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 {
+1 -1
View File
@@ -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);
+85 -114
View File
@@ -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
+10 -16
View File
@@ -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
+59 -16
View File
@@ -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"
+1 -1
View File
@@ -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);
-11
View File
@@ -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;
+11 -6
View File
@@ -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);
+34 -82
View File
@@ -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>
+170 -174
View File
@@ -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
+50 -64
View File
@@ -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) {
+17 -17
View File
@@ -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];
@@ -1,10 +1,11 @@
#include "graphics/host_gpu/utils.h"
#include "graphics/host_gpu/transfer.h"
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/profiler.h"
#include "common/threads.h"
#include "graphics/host_gpu/graphicContext.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/vma.h"
@@ -16,7 +17,7 @@
#include <span>
#include <vector>
namespace Libs::Graphics {
namespace Libs::Graphics::Transfer {
static Common::Mutex g_scratch_buffer_mutex;
static std::unique_ptr<uint8_t[]> g_scratch_buffer;
@@ -43,7 +44,7 @@ std::vector<ImageBufferCopy> MakeLayeredImageBufferCopies(uint32_t layers, uint6
return regions;
}
UtilScratchBuffer::UtilScratchBuffer(uint64_t size) {
ScratchBuffer::ScratchBuffer(uint64_t size) {
EXIT_IF(size == 0);
g_scratch_buffer_mutex.Lock();
@@ -56,11 +57,11 @@ UtilScratchBuffer::UtilScratchBuffer(uint64_t size) {
m_data = g_scratch_buffer.get();
}
UtilScratchBuffer::~UtilScratchBuffer() {
ScratchBuffer::~ScratchBuffer() {
g_scratch_buffer_mutex.Unlock();
}
bool UtilBufferIsTiled(uint64_t vaddr, uint64_t size) {
bool GuestBufferIsTiled(uint64_t vaddr, uint64_t size) {
if ((size & 0x7u) == 0) {
if (size == 0) {
return false;
@@ -80,7 +81,7 @@ bool UtilBufferIsTiled(uint64_t vaddr, uint64_t size) {
return true;
}
void VulkanDeviceWaitIdle(GraphicContext* ctx) {
void WaitForGraphicsIdle(GraphicContext* ctx) {
Common::Mutex* locked[GraphicContext::QUEUES_NUM] {};
int locked_num = 0;
@@ -117,64 +118,17 @@ void VulkanDeviceWaitIdle(GraphicContext* ctx) {
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
}
void UtilResetImageViews(VulkanImage* image) {
for (auto& view: image->image_view) {
view = nullptr;
}
}
void UtilCreateImageView(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::ImageUsageFlags view_usage) {
if (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,
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.pNext = nullptr;
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.flags = {};
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);
}
}
static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uint32_t base_level,
uint32_t levels, vk::ImageAspectFlags aspect_mask,
vk::ImageLayout old_image_layout, vk::ImageLayout new_image_layout);
template <typename Recorder>
static void ExecuteImmediateUtilCommands(const Recorder& recorder) {
static void ExecuteImmediateCommands(const Recorder& recorder) {
// Keep synchronous utility submission behind one boundary so adopting a central scheduler does
// not touch every caller.
CommandBuffer command(GraphicContext::QUEUE_UTIL);
command.Begin();
recorder(&command, command.GetPool()->buffers[command.GetIndex()]);
recorder(&command, command.Handle());
command.End();
command.Execute();
command.WaitForFence();
@@ -220,18 +174,6 @@ static void SetBufferMemoryBarrier(vk::CommandBuffer command, vk::Buffer buffer,
0, nullptr);
}
[[nodiscard]] static vk::ImageAspectFlags GetDepthStencilAspects(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));
}
}
[[nodiscard]] static vk::ImageAspectFlags GetTransferAspects(const VulkanImage& image,
vk::ImageAspectFlags copy_aspect) {
if (copy_aspect == vk::ImageAspectFlagBits::eColor) {
@@ -239,7 +181,7 @@ static void SetBufferMemoryBarrier(vk::CommandBuffer command, vk::Buffer buffer,
}
if (copy_aspect == vk::ImageAspectFlagBits::eDepth ||
copy_aspect == vk::ImageAspectFlagBits::eStencil) {
const auto aspects = GetDepthStencilAspects(image.format);
const auto aspects = ImageViewOps::DepthAspectMask(image.format);
if (!(copy_aspect & aspects)) {
EXIT("image transfer aspect is unavailable: format=%d copy=0x%x available=0x%x\n",
static_cast<int>(image.format),
@@ -257,7 +199,7 @@ static void RecordBufferToImageCopy(CommandBuffer& command, VulkanBuffer& src_bu
std::span<const vk::BufferImageCopy> regions,
vk::ImageAspectFlags transition_aspects,
vk::ImageLayout initial_layout, vk::ImageLayout final_layout) {
auto vk_command = command.GetPool()->buffers[command.GetIndex()];
auto vk_command = command.Handle();
SetBufferMemoryBarrier(vk_command, src_buffer.buffer, 0, VK_WHOLE_SIZE,
vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead,
vk::PipelineStageFlagBits::eAllCommands,
@@ -301,7 +243,7 @@ ConvertImageBufferCopies(std::span<const ImageBufferCopy> regions) {
static void RecordImageToBuffer(CommandBuffer& command, VulkanImage& src_image,
VulkanBuffer& dst_buffer, std::span<const ImageBufferCopy> regions,
vk::ImageLayout final_layout) {
auto vk_command = command.GetPool()->buffers[command.GetIndex()];
auto vk_command = command.Handle();
vk::ImageAspectFlags aspects = {};
for (const auto& region: regions) {
aspects |= GetTransferAspects(src_image, region.aspect);
@@ -399,7 +341,7 @@ public:
EnsureBuffer(ctx, size, vk::BufferUsageFlagBits::eTransferDst);
ExecuteImmediateUtilCommands([&](CommandBuffer* command, vk::CommandBuffer) {
ExecuteImmediateCommands([&](CommandBuffer* command, vk::CommandBuffer) {
RecordImageToBuffer(*command, *src_image, m_buffer, dst_pitch, src_layout, aspect);
});
@@ -411,7 +353,7 @@ public:
vk::ImageLayout src_layout) {
Common::LockGuard lock(m_mutex);
EnsureBuffer(ctx, size, vk::BufferUsageFlagBits::eTransferDst);
ExecuteImmediateUtilCommands([&](CommandBuffer* command, vk::CommandBuffer) {
ExecuteImmediateCommands([&](CommandBuffer* command, vk::CommandBuffer) {
RecordImageToBuffer(*command, *src_image, m_buffer, regions, src_layout);
});
std::memcpy(dst_data, m_mapped_data, size);
@@ -435,9 +377,9 @@ private:
Common::LockGuard lock(m_mutex);
CopyFromHost(ctx, src_data, size, vk::BufferUsageFlagBits::eTransferSrc);
if constexpr (WaitIdle) {
VulkanDeviceWaitIdle(ctx);
WaitForGraphicsIdle(ctx);
}
ExecuteImmediateUtilCommands(recorder);
ExecuteImmediateCommands(recorder);
}
void CopyFromHost(GraphicContext* ctx, const void* src_data, uint64_t size,
@@ -476,10 +418,7 @@ static ReusableStagingBuffer g_texture_staging_buffer;
static ReusableStagingBuffer g_vertex_staging_buffer;
static ReusableStagingBuffer g_readback_staging_buffer;
static Common::Mutex g_compressed_image_copy_mutex;
static VulkanBuffer g_compressed_image_copy_buffer;
bool UtilIsBcFormat(vk::Format format) {
bool IsBlockCompressedFormat(vk::Format format) {
return format == vk::Format::eBc1RgbUnormBlock || format == vk::Format::eBc1RgbSrgbBlock ||
format == vk::Format::eBc1RgbaUnormBlock || format == vk::Format::eBc1RgbaSrgbBlock ||
format == vk::Format::eBc2UnormBlock || format == vk::Format::eBc2SrgbBlock ||
@@ -490,7 +429,7 @@ bool UtilIsBcFormat(vk::Format format) {
format == vk::Format::eBc7UnormBlock || format == vk::Format::eBc7SrgbBlock;
}
uint32_t UtilGetBcBlockSize(vk::Format format) {
uint32_t BlockCompressedBytesPerBlock(vk::Format format) {
switch (format) {
case vk::Format::eBc1RgbUnormBlock:
case vk::Format::eBc1RgbSrgbBlock:
@@ -522,24 +461,6 @@ static uint32_t GetFormatTexelSize(vk::Format format) {
}
}
static VulkanBuffer* GetCompressedImageCopyBuffer(GraphicContext* ctx, uint64_t size) {
EXIT_IF(size == 0);
constexpr uint64_t buffer_size = 64ull * 1024ull * 1024ull;
EXIT_NOT_IMPLEMENTED(size > buffer_size);
Common::LockGuard lock(g_compressed_image_copy_mutex);
if (g_compressed_image_copy_buffer.buffer == nullptr) {
g_compressed_image_copy_buffer.usage =
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst;
g_compressed_image_copy_buffer.memory.property = {};
VulkanCreateBuffer(ctx, buffer_size, &g_compressed_image_copy_buffer);
}
return &g_compressed_image_copy_buffer;
}
static ReusableStagingBuffer* GetStagingBuffer(StagingBufferType type) {
switch (type) {
case StagingBufferType::Texture: return &g_texture_staging_buffer;
@@ -551,6 +472,13 @@ static ReusableStagingBuffer* GetStagingBuffer(StagingBufferType type) {
return nullptr;
}
void ReleaseCachedResources(GraphicContext* ctx) {
EXIT_IF(ctx == nullptr);
g_texture_staging_buffer.Release(ctx);
g_vertex_staging_buffer.Release(ctx);
g_readback_staging_buffer.Release(ctx);
}
static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uint32_t base_level,
uint32_t levels, vk::ImageAspectFlags aspect_mask,
vk::ImageLayout old_image_layout, vk::ImageLayout new_image_layout) {
@@ -662,28 +590,35 @@ static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uin
dst_image->layout = new_image_layout;
}
static bool CopyBlockImageToCompressedImage(vk::CommandBuffer vk_buffer, const ImageImageCopy& r,
VulkanImage* dst_image) {
static uint64_t CompressedImageCopyBufferSize(const ImageImageCopy& r,
const VulkanImage& dst_image) {
if (r.src_aspect != vk::ImageAspectFlagBits::eColor ||
r.dst_aspect != vk::ImageAspectFlagBits::eColor || !UtilIsBcFormat(dst_image->format)) {
return false;
r.dst_aspect != vk::ImageAspectFlagBits::eColor ||
!IsBlockCompressedFormat(dst_image.format)) {
return 0;
}
auto src_texel_size = GetFormatTexelSize(r.src_image->format);
auto dst_block_size = UtilGetBcBlockSize(dst_image->format);
auto dst_block_size = BlockCompressedBytesPerBlock(dst_image.format);
if (src_texel_size == 0 || src_texel_size != dst_block_size) {
return false;
return 0;
}
auto block_width = (r.width + 3u) / 4u;
auto block_height = (r.height + 3u) / 4u;
if (block_width > r.src_image->extent.width || block_height > r.src_image->extent.height) {
return false;
return 0;
}
return static_cast<uint64_t>(block_width) * block_height * dst_block_size;
}
auto* ctx = WindowGetGraphicContext();
auto* copy_buffer = GetCompressedImageCopyBuffer(ctx, static_cast<uint64_t>(block_width) *
block_height * dst_block_size);
static void CopyBlockImageToCompressedImage(vk::CommandBuffer vk_buffer, const ImageImageCopy& r,
VulkanImage* dst_image, VulkanBuffer* copy_buffer) {
const auto copy_size = CompressedImageCopyBufferSize(r, *dst_image);
EXIT_IF(copy_size == 0 || copy_buffer == nullptr || copy_buffer->buffer_size < copy_size);
const auto block_width = (r.width + 3u) / 4u;
const auto block_height = (r.height + 3u) / 4u;
const auto src_region =
MakeBufferImageCopy(0, 0, vk::ImageAspectFlagBits::eColor, r.src_level, r.src_layer,
@@ -713,13 +648,11 @@ static bool CopyBlockImageToCompressedImage(vk::CommandBuffer vk_buffer, const I
SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, vk::ImageAspectFlagBits::eColor,
vk::ImageLayout::eTransferSrcOptimal, src_layout);
return true;
}
void UtilImageToImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout) {
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()];
void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout) {
auto vk_buffer = buffer->Handle();
bool same_image_copy = false;
vk::ImageAspectFlags dst_transition_aspects = {};
@@ -777,15 +710,28 @@ void UtilImageToImage(CommandBuffer* buffer, std::span<const ImageImageCopy> reg
SetImageLayout(vk_buffer, dst_image, 0, VK_REMAINING_MIP_LEVELS, dst_transition_aspects,
dst_image->layout, vk::ImageLayout::eTransferDstOptimal);
uint64_t compressed_copy_size = 0;
for (const auto& r: regions) {
compressed_copy_size =
std::max(compressed_copy_size, CompressedImageCopyBufferSize(r, *dst_image));
}
VulkanBuffer* compressed_copy_buffer = nullptr;
if (compressed_copy_size != 0) {
compressed_copy_buffer = new VulkanBuffer;
compressed_copy_buffer->usage =
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst;
compressed_copy_buffer->memory.property = {};
VulkanCreateBuffer(WindowGetGraphicContext(), compressed_copy_size, compressed_copy_buffer);
buffer->DeleteAfterFence(compressed_copy_buffer);
}
for (const auto& r: regions) {
vk::ImageCopy region;
auto src_layout = r.src_image->layout;
if (r.src_aspect == vk::ImageAspectFlagBits::eColor &&
r.dst_aspect == vk::ImageAspectFlagBits::eColor &&
CopyBlockImageToCompressedImage(vk_buffer, r, dst_image)) {
if (CompressedImageCopyBufferSize(r, *dst_image) != 0) {
CopyBlockImageToCompressedImage(vk_buffer, r, dst_image, compressed_copy_buffer);
continue;
}
@@ -817,10 +763,10 @@ void UtilImageToImage(CommandBuffer* buffer, std::span<const ImageImageCopy> reg
vk::ImageLayout::eTransferDstOptimal, dst_layout);
}
void UtilCopyImageWithBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage* src_image,
vk::ImageAspectFlags src_aspect, VulkanImage* dst_image,
vk::ImageAspectFlags dst_aspect, uint32_t bytes_per_element,
vk::ImageLayout dst_layout) {
void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage* src_image,
vk::ImageAspectFlags src_aspect, VulkanImage* dst_image,
vk::ImageAspectFlags dst_aspect, uint32_t bytes_per_element,
vk::ImageLayout dst_layout) {
if (!IsSingleImageAspect(src_aspect) || !IsSingleImageAspect(dst_aspect) ||
(bytes_per_element != 2 && bytes_per_element != 4) || src_image->layers != 1 ||
dst_image->layers != 1 || src_image->mip_levels != 1 || dst_image->mip_levels != 1 ||
@@ -849,7 +795,7 @@ void UtilCopyImageWithBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanI
// recording the recreate copy; commands already recorded on this buffer remain ordered by the
// barriers below. The preservation policy stays isolated here so a future scheduler can replace
// this synchronization without changing texture-cache ownership logic.
VulkanDeviceWaitIdle(ctx);
WaitForGraphicsIdle(ctx);
auto* copy_buffer = new VulkanBuffer;
copy_buffer->usage =
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst;
@@ -857,7 +803,7 @@ void UtilCopyImageWithBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanI
VulkanCreateBuffer(ctx, copy_buffer_size, copy_buffer);
buffer->DeleteAfterFence(copy_buffer);
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()];
auto vk_buffer = buffer->Handle();
const auto src_layout = src_image->layout;
const auto final_layout = dst_layout;
SetImageLayout(vk_buffer, src_image, 0, 1, src_aspect, src_layout,
@@ -894,9 +840,9 @@ void UtilCopyImageWithBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanI
final_layout);
}
void UtilBlitPreparedImage(CommandBuffer* buffer, VulkanImage* src_image,
VulkanSwapchain* dst_swapchain) {
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()];
void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image,
VulkanSwapchain* dst_swapchain) {
auto vk_buffer = buffer->Handle();
if (src_image->layout != vk::ImageLayout::eTransferSrcOptimal) {
EXIT("invalid prepared presentation image, image=%p vk_image=%p layout=%d\n",
static_cast<const void*>(src_image),
@@ -939,9 +885,8 @@ void UtilBlitPreparedImage(CommandBuffer* buffer, VulkanImage* src_image,
vk::Filter::eLinear);
}
void UtilClearColorImage(CommandBuffer* buffer, VulkanImage* image,
const vk::ClearColorValue& color) {
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()];
void ClearColorImage(CommandBuffer* buffer, VulkanImage* image, const vk::ClearColorValue& color) {
auto vk_buffer = buffer->Handle();
SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor, image->layout,
vk::ImageLayout::eTransferDstOptimal);
const vk::ImageSubresourceRange range {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
@@ -951,105 +896,8 @@ void UtilClearColorImage(CommandBuffer* buffer, VulkanImage* image,
vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eTransferSrcOptimal);
}
void VulkanCreateBuffer(GraphicContext* gctx, uint64_t size, VulkanBuffer* buffer) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(buffer->buffer != nullptr);
vk::BufferCreateInfo buffer_info {};
buffer_info.sType = vk::StructureType::eBufferCreateInfo;
buffer_info.size = size;
buffer_info.usage = buffer->usage;
buffer_info.sharingMode = vk::SharingMode::eExclusive;
VmaAllocationCreateInfo alloc_info {};
alloc_info.requiredFlags =
static_cast<vk::MemoryPropertyFlags::MaskType>(buffer->memory.property);
vk::Buffer::CType native_buffer = VK_NULL_HANDLE;
const auto result = static_cast<vk::Result>(vmaCreateBuffer(
gctx->allocator, static_cast<const vk::BufferCreateInfo::NativeType*>(buffer_info),
&alloc_info, &native_buffer, &buffer->memory.allocation, &buffer->memory.allocation_info));
buffer->buffer = native_buffer;
if (result != vk::Result::eSuccess) {
VulkanLogMemoryBudget(gctx);
}
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
gctx->device.getBufferMemoryRequirements(buffer->buffer, &buffer->memory.requirements);
buffer->memory.type = buffer->memory.allocation_info.memoryType;
buffer->memory.memory = buffer->memory.allocation_info.deviceMemory;
buffer->memory.offset = buffer->memory.allocation_info.offset;
buffer->memory.unique_id = VulkanNextMemoryUniqueId();
buffer->buffer_size = size;
VulkanTrackAllocation(&buffer->memory);
}
void VulkanDeleteBuffer(GraphicContext* gctx, VulkanBuffer* buffer) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(buffer->memory.allocation == nullptr);
VulkanUntrackAllocation(&buffer->memory);
vmaDestroyBuffer(gctx->allocator, buffer->buffer, buffer->memory.allocation);
buffer->buffer = nullptr;
buffer->memory.memory = nullptr;
buffer->memory.allocation = nullptr;
buffer->memory.allocation_info = {};
buffer->memory.offset = 0;
}
bool VulkanCreateImage(GraphicContext* gctx, const vk::ImageCreateInfo* image_info,
VulkanImage* image, VulkanMemory* memory) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(image->image != nullptr);
EXIT_IF(memory->allocation != nullptr);
VmaAllocationCreateInfo alloc_info {};
alloc_info.requiredFlags = static_cast<vk::MemoryPropertyFlags::MaskType>(memory->property);
vk::Image::CType native_image = VK_NULL_HANDLE;
const auto result = static_cast<vk::Result>(vmaCreateImage(
gctx->allocator, static_cast<const vk::ImageCreateInfo::NativeType*>(*image_info),
&alloc_info, &native_image, &memory->allocation, &memory->allocation_info));
image->image = native_image;
if (result != vk::Result::eSuccess) {
VulkanLogMemoryBudget(gctx);
return false;
}
gctx->device.getImageMemoryRequirements(image->image, &memory->requirements);
memory->type = memory->allocation_info.memoryType;
memory->memory = memory->allocation_info.deviceMemory;
memory->offset = memory->allocation_info.offset;
memory->unique_id = VulkanNextMemoryUniqueId();
VulkanTrackAllocation(memory);
return true;
}
void VulkanDeleteImage(GraphicContext* gctx, VulkanImage* image, VulkanMemory* memory) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(memory->allocation == nullptr);
VulkanUntrackAllocation(memory);
vmaDestroyImage(gctx->allocator, image->image, memory->allocation);
image->image = nullptr;
memory->memory = nullptr;
memory->allocation = nullptr;
memory->allocation_info = {};
memory->offset = 0;
}
void UtilFillImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size,
uint32_t src_pitch, vk::ImageLayout dst_layout) {
void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size,
uint32_t src_pitch, vk::ImageLayout dst_layout) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(size == 0);
@@ -1059,9 +907,9 @@ void UtilFillImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_
vk::ImageLayout::eUndefined, dst_layout);
}
void UtilFillBuffer(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch,
VulkanImage* src_image, vk::ImageLayout src_layout,
vk::ImageAspectFlags aspect) {
void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch,
VulkanImage* src_image, vk::ImageLayout src_layout,
vk::ImageAspectFlags aspect) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(size == 0);
@@ -1070,67 +918,49 @@ void UtilFillBuffer(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t
->DownloadFromImage(ctx, dst_data, size, dst_pitch, src_image, src_layout, aspect);
}
void UtilFillBuffer(GraphicContext* ctx, void* dst_data, uint64_t size,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image,
vk::ImageLayout src_layout) {
void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image,
vk::ImageLayout src_layout) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(size == 0 || regions.empty());
GetStagingBuffer(StagingBufferType::ReadBack)
->DownloadFromImage(ctx, dst_data, size, regions, src_image, src_layout);
}
void UtilSetImageLayoutOptimal(VulkanImage* image) {
ExecuteImmediateUtilCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) {
SetImageLayout(vk_command, image, 0, VK_REMAINING_MIP_LEVELS,
vk::ImageAspectFlagBits::eColor, image->layout, vk::ImageLayout::eGeneral);
});
}
void UtilFillImage(GraphicContext* ctx, VulkanImage* image, const void* src_data, uint64_t size,
std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout) {
void UploadImage(GraphicContext* ctx, VulkanImage* image, const void* src_data, uint64_t size,
std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout) {
EXIT_IF(size == 0 || regions.empty());
GetStagingBuffer(StagingBufferType::Texture)
->UploadToImage(ctx, image, src_data, size, regions, dst_layout);
}
void UtilFillImage(GraphicContext* ctx, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout) {
ExecuteImmediateUtilCommands([&](CommandBuffer* command, vk::CommandBuffer) {
UtilImageToImage(command, regions, dst_image, dst_layout);
void CopyImageImmediate(GraphicContext* ctx, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout) {
ExecuteImmediateCommands([&](CommandBuffer* command, vk::CommandBuffer) {
CopyImage(command, regions, dst_image, dst_layout);
});
}
void UtilFillImage(GraphicContext* ctx, DepthStencilVulkanImage* image, const void* src_data,
uint64_t size, uint32_t src_pitch, vk::ImageAspectFlags aspect) {
void UploadImage(GraphicContext* ctx, DepthStencilVulkanImage* image, const void* src_data,
uint64_t size, uint32_t src_pitch, vk::ImageAspectFlags aspect) {
EXIT_IF(size == 0);
GetStagingBuffer(StagingBufferType::Texture)
->UploadToImage(ctx, image, src_data, size, src_pitch, aspect, image->layout,
vk::ImageLayout::eDepthStencilAttachmentOptimal);
}
void UtilUploadBuffer(GraphicContext* ctx, StagingBufferType type, VulkanBuffer* dst_buffer,
uint64_t dst_offset, const void* src_data, uint64_t size) {
void UploadBuffer(GraphicContext* ctx, StagingBufferType type, VulkanBuffer* dst_buffer,
uint64_t dst_offset, const void* src_data, uint64_t size) {
EXIT_IF(size == 0);
EXIT_IF(dst_offset > dst_buffer->buffer_size || size > dst_buffer->buffer_size - dst_offset);
GetStagingBuffer(type)->UploadToBuffer(ctx, dst_buffer, src_data, size, dst_offset);
}
void UtilReleaseCachedResources(GraphicContext* ctx) {
EXIT_IF(ctx == nullptr);
g_texture_staging_buffer.Release(ctx);
g_vertex_staging_buffer.Release(ctx);
g_readback_staging_buffer.Release(ctx);
Common::LockGuard lock(g_compressed_image_copy_mutex);
if (g_compressed_image_copy_buffer.buffer != nullptr) {
VulkanDeleteBuffer(ctx, &g_compressed_image_copy_buffer);
}
}
void UtilCopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t size) {
void CopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t size) {
EXIT_IF(size == 0 || size > src_buffer->buffer_size || size > dst_buffer->buffer_size);
ExecuteImmediateUtilCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) {
ExecuteImmediateCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) {
SetBufferMemoryBarrier(vk_command, src_buffer->buffer, 0, size,
vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead,
vk::PipelineStageFlagBits::eAllCommands,
@@ -1149,8 +979,8 @@ void UtilCopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t
});
}
void UtilDownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_offset,
void* dst_data, uint64_t size) {
void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_offset,
void* dst_data, uint64_t size) {
EXIT_IF(size == 0);
EXIT_IF(src_offset > src_buffer->buffer_size || size > src_buffer->buffer_size - src_offset);
const auto family = ctx->queues[GraphicContext::QUEUE_UTIL].family;
@@ -1176,7 +1006,7 @@ void UtilDownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t
vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, size, &readback);
ExecuteImmediateUtilCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) {
ExecuteImmediateCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) {
SetBufferMemoryBarrier(vk_command, src_buffer->buffer, src_offset, size,
vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead,
vk::PipelineStageFlagBits::eAllCommands,
@@ -1196,4 +1026,4 @@ void UtilDownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t
VulkanDeleteBuffer(ctx, &readback);
}
} // namespace Libs::Graphics
} // namespace Libs::Graphics::Transfer
+148
View File
@@ -0,0 +1,148 @@
#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_TRANSFER_H_
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_TRANSFER_H_
#include "common/abi.h"
#include "common/common.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include <span>
#include <utility>
#include <vector>
namespace Libs::Graphics {
class CommandBuffer;
struct GraphicContext;
struct VulkanBuffer;
struct VulkanImage;
struct DepthStencilVulkanImage;
struct VulkanSwapchain;
struct BufferImageCopy {
uint32_t offset;
uint32_t pitch;
uint32_t dst_level;
uint32_t width;
uint32_t height;
uint32_t copy_height = 0;
uint32_t dst_layer = 0;
int dst_x;
int dst_y;
int dst_z = 0;
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor;
};
struct ImageBufferCopy {
uint32_t offset;
uint32_t pitch;
uint32_t src_level;
uint32_t width;
uint32_t height;
uint32_t copy_height = 0;
uint32_t src_layer = 0;
int src_x;
int src_y;
int src_z = 0;
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor;
};
struct ImageImageCopy {
VulkanImage* src_image;
uint32_t src_level;
uint32_t dst_level;
uint32_t width;
uint32_t height;
uint32_t src_layer = 0;
uint32_t dst_layer = 0;
vk::ImageAspectFlags src_aspect = vk::ImageAspectFlagBits::eColor;
vk::ImageAspectFlags dst_aspect = vk::ImageAspectFlagBits::eColor;
int src_x;
int src_y;
int src_z = 0;
int dst_x;
int dst_y;
int dst_z = 0;
};
namespace Transfer {
[[nodiscard]] std::vector<ImageBufferCopy>
MakeLayeredImageBufferCopies(uint32_t layers, uint64_t slice_size, uint32_t pitch, uint32_t width,
uint32_t height,
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor);
enum class StagingBufferType { Texture, Vertex, ReadBack };
class ScratchBuffer {
public:
explicit ScratchBuffer(uint64_t size);
~ScratchBuffer();
KYTY_CLASS_NO_COPY(ScratchBuffer);
[[nodiscard]] void* Data() const { return m_data; }
private:
void* m_data = nullptr;
};
void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout);
void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage* src_image,
vk::ImageAspectFlags src_aspect, VulkanImage* dst_image,
vk::ImageAspectFlags dst_aspect, uint32_t bytes_per_element,
vk::ImageLayout dst_layout);
void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image, VulkanSwapchain* dst_swapchain);
void ClearColorImage(CommandBuffer* buffer, VulkanImage* image, const vk::ClearColorValue& color);
void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size,
uint32_t src_pitch, vk::ImageLayout dst_layout);
void UploadImage(GraphicContext* ctx, DepthStencilVulkanImage* dst_image, const void* src_data,
uint64_t size, uint32_t src_pitch, vk::ImageAspectFlags aspect);
void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size,
std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout);
void CopyImageImmediate(GraphicContext* ctx, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout);
void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch,
VulkanImage* src_image, vk::ImageLayout src_layout,
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor);
void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image,
vk::ImageLayout src_layout);
void UploadBuffer(GraphicContext* ctx, StagingBufferType type, VulkanBuffer* dst_buffer,
uint64_t dst_offset, const void* src_data, uint64_t size);
void CopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t size);
void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_offset,
void* dst_data, uint64_t size);
void ReleaseCachedResources(GraphicContext* ctx);
bool GuestBufferIsTiled(uint64_t vaddr, uint64_t size);
bool IsBlockCompressedFormat(vk::Format format);
uint32_t BlockCompressedBytesPerBlock(vk::Format format);
void WaitForGraphicsIdle(GraphicContext* ctx);
inline std::pair<int, int> MipmapAtlasOffset(uint32_t lod, uint32_t width, uint32_t height) {
uint32_t mip_width = width;
uint32_t mip_height = height;
int mip_x = 0;
int mip_y = 0;
for (uint32_t i = 0; i < 16; i++) {
if (i == lod) {
return {mip_x, mip_y};
}
bool odd = ((i & 1u) != 0);
mip_x += static_cast<int>(odd ? mip_width : 0);
mip_y += static_cast<int>(odd ? 0 : mip_height);
mip_width >>= (mip_width > 1 ? 1u : 0u);
mip_height >>= (mip_height > 1 ? 1u : 0u);
}
return {mip_x, mip_y};
}
} // namespace Transfer
} // namespace Libs::Graphics
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_TRANSFER_H_
-160
View File
@@ -1,160 +0,0 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_UTILS_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_UTILS_H_
#include "common/abi.h"
#include "common/common.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include <span>
#include <utility>
#include <vector>
namespace Libs::Graphics {
class CommandBuffer;
struct GraphicContext;
struct VulkanBuffer;
struct VulkanImage;
struct VulkanMemory;
struct DepthStencilVulkanImage;
struct VulkanSwapchain;
struct BufferImageCopy {
uint32_t offset;
uint32_t pitch;
uint32_t dst_level;
uint32_t width;
uint32_t height;
uint32_t copy_height = 0;
uint32_t dst_layer = 0;
int dst_x;
int dst_y;
int dst_z = 0;
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor;
};
struct ImageBufferCopy {
uint32_t offset;
uint32_t pitch;
uint32_t src_level;
uint32_t width;
uint32_t height;
uint32_t copy_height = 0;
uint32_t src_layer = 0;
int src_x;
int src_y;
int src_z = 0;
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor;
};
struct ImageImageCopy {
VulkanImage* src_image;
uint32_t src_level;
uint32_t dst_level;
uint32_t width;
uint32_t height;
uint32_t src_layer = 0;
uint32_t dst_layer = 0;
vk::ImageAspectFlags src_aspect = vk::ImageAspectFlagBits::eColor;
vk::ImageAspectFlags dst_aspect = vk::ImageAspectFlagBits::eColor;
int src_x;
int src_y;
int src_z = 0;
int dst_x;
int dst_y;
int dst_z = 0;
};
[[nodiscard]] std::vector<ImageBufferCopy>
MakeLayeredImageBufferCopies(uint32_t layers, uint64_t slice_size, uint32_t pitch, uint32_t width,
uint32_t height,
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor);
enum class StagingBufferType { Texture, Vertex, ReadBack };
class UtilScratchBuffer {
public:
explicit UtilScratchBuffer(uint64_t size);
~UtilScratchBuffer();
KYTY_CLASS_NO_COPY(UtilScratchBuffer);
[[nodiscard]] void* Data() const { return m_data; }
private:
void* m_data = nullptr;
};
void UtilImageToImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout);
void UtilCopyImageWithBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage* src_image,
vk::ImageAspectFlags src_aspect, VulkanImage* dst_image,
vk::ImageAspectFlags dst_aspect, uint32_t bytes_per_element,
vk::ImageLayout dst_layout);
void UtilBlitPreparedImage(CommandBuffer* buffer, VulkanImage* src_image,
VulkanSwapchain* dst_swapchain);
void UtilClearColorImage(CommandBuffer* buffer, VulkanImage* image,
const vk::ClearColorValue& color);
void UtilFillImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size,
uint32_t src_pitch, vk::ImageLayout dst_layout);
void UtilFillImage(GraphicContext* ctx, DepthStencilVulkanImage* dst_image, const void* src_data,
uint64_t size, uint32_t src_pitch, vk::ImageAspectFlags aspect);
void UtilFillImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size,
std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout);
void UtilFillImage(GraphicContext* ctx, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout);
void UtilFillBuffer(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch,
VulkanImage* src_image, vk::ImageLayout src_layout,
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor);
void UtilFillBuffer(GraphicContext* ctx, void* dst_data, uint64_t size,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image,
vk::ImageLayout src_layout);
void UtilUploadBuffer(GraphicContext* ctx, StagingBufferType type, VulkanBuffer* dst_buffer,
uint64_t dst_offset, const void* src_data, uint64_t size);
void UtilReleaseCachedResources(GraphicContext* ctx);
void UtilCopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t size);
void UtilDownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_offset,
void* dst_data, uint64_t size);
bool UtilBufferIsTiled(uint64_t vaddr, uint64_t size);
void UtilSetImageLayoutOptimal(VulkanImage* image);
void UtilResetImageViews(VulkanImage* image);
void UtilCreateImageView(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 = {});
bool UtilIsBcFormat(vk::Format format);
uint32_t UtilGetBcBlockSize(vk::Format format);
void VulkanCreateBuffer(GraphicContext* gctx, uint64_t size, VulkanBuffer* buffer);
void VulkanDeleteBuffer(GraphicContext* gctx, VulkanBuffer* buffer);
bool VulkanCreateImage(GraphicContext* gctx, const vk::ImageCreateInfo* image_info,
VulkanImage* image, VulkanMemory* memory);
void VulkanDeleteImage(GraphicContext* gctx, VulkanImage* image, VulkanMemory* memory);
void VulkanDeviceWaitIdle(GraphicContext* ctx);
inline std::pair<int, int> UtilCalcMipmapOffset(uint32_t lod, uint32_t width, uint32_t height) {
uint32_t mip_width = width;
uint32_t mip_height = height;
int mip_x = 0;
int mip_y = 0;
for (uint32_t i = 0; i < 16; i++) {
if (i == lod) {
return {mip_x, mip_y};
}
bool odd = ((i & 1u) != 0);
mip_x += static_cast<int>(odd ? mip_width : 0);
mip_y += static_cast<int>(odd ? 0 : mip_height);
mip_width >>= (mip_width > 1 ? 1u : 0u);
mip_height >>= (mip_height > 1 ? 1u : 0u);
}
return {mip_x, mip_y};
}
} // namespace Libs::Graphics
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_UTILS_H_ */
+82 -65
View File
@@ -17,15 +17,11 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/profiler.h"
#include "common/stringUtils.h"
#include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/vma.h"
#include <atomic>
#include <cinttypes>
#include <fmt/format.h>
#include <string>
#include <vector>
namespace Libs::Graphics {
@@ -117,57 +113,96 @@ void VulkanLogMemoryBudget(GraphicContext* ctx) {
}
}
bool VulkanAllocate(GraphicContext* ctx, VulkanMemory* memory) {
void VulkanCreateBuffer(GraphicContext* ctx, uint64_t size, VulkanBuffer* buffer) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || memory == nullptr || memory->memory != nullptr ||
memory->allocation != nullptr || ctx->allocator == nullptr ||
memory->requirements.size == 0);
EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || buffer == nullptr ||
buffer->buffer != nullptr || buffer->memory.allocation != nullptr || size == 0);
const auto& properties = ctx->GetPhysicalDeviceMemoryProperties();
uint32_t index = 0;
for (; index < properties.memoryTypeCount; index++) {
if ((memory->requirements.memoryTypeBits & (uint32_t {1} << index)) != 0 &&
(properties.memoryTypes[index].propertyFlags & memory->property) == memory->property) {
break;
}
}
vk::BufferCreateInfo buffer_info {};
buffer_info.sType = vk::StructureType::eBufferCreateInfo;
buffer_info.size = size;
buffer_info.usage = buffer->usage;
buffer_info.sharingMode = vk::SharingMode::eExclusive;
VmaAllocationCreateInfo info {};
info.requiredFlags = static_cast<vk::MemoryPropertyFlags::MaskType>(memory->property);
memory->unique_id = VulkanNextMemoryUniqueId();
const auto result = static_cast<vk::Result>(vmaAllocateMemory(
ctx->allocator,
static_cast<const vk::MemoryRequirements::NativeType*>(memory->requirements), &info,
&memory->allocation, &memory->allocation_info));
if (result == vk::Result::eSuccess) {
memory->type = memory->allocation_info.memoryType;
memory->memory = memory->allocation_info.deviceMemory;
memory->offset = memory->allocation_info.offset;
VulkanTrackAllocation(memory);
return true;
}
VmaAllocationCreateInfo alloc_info {};
alloc_info.requiredFlags =
static_cast<vk::MemoryPropertyFlags::MaskType>(buffer->memory.property);
VulkanLogMemoryBudget(ctx);
std::vector<std::string> stats;
for (uint32_t i = 0; i < properties.memoryTypeCount; i++) {
stats.push_back(fmt::format("{}, {}, {}", i, g_memory_stats.count[i].load(),
g_memory_stats.allocated[i].load()));
vk::Buffer::CType native_buffer = VK_NULL_HANDLE;
const auto result = static_cast<vk::Result>(vmaCreateBuffer(
ctx->allocator, static_cast<const vk::BufferCreateInfo::NativeType*>(buffer_info),
&alloc_info, &native_buffer, &buffer->memory.allocation, &buffer->memory.allocation_info));
buffer->buffer = native_buffer;
if (result != vk::Result::eSuccess) {
VulkanLogMemoryBudget(ctx);
}
EXIT("size = %" PRIu64 ", index = %u, error: %s:%s\n", memory->requirements.size, index,
VulkanToString(result).c_str(), Common::Concat(stats, '\n').c_str());
return false;
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
ctx->device.getBufferMemoryRequirements(buffer->buffer, &buffer->memory.requirements);
buffer->memory.type = buffer->memory.allocation_info.memoryType;
buffer->memory.memory = buffer->memory.allocation_info.deviceMemory;
buffer->memory.offset = buffer->memory.allocation_info.offset;
buffer->memory.unique_id = VulkanNextMemoryUniqueId();
buffer->buffer_size = size;
VulkanTrackAllocation(&buffer->memory);
}
void VulkanFree(GraphicContext* ctx, VulkanMemory* memory) {
void VulkanDeleteBuffer(GraphicContext* ctx, VulkanBuffer* buffer) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || memory == nullptr || ctx->allocator == nullptr ||
memory->allocation == nullptr);
vmaFreeMemory(ctx->allocator, memory->allocation);
VulkanUntrackAllocation(memory);
memory->memory = nullptr;
memory->allocation = nullptr;
memory->allocation_info = {};
memory->offset = 0;
EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || buffer == nullptr ||
buffer->buffer == nullptr || buffer->memory.allocation == nullptr);
VulkanUntrackAllocation(&buffer->memory);
vmaDestroyBuffer(ctx->allocator, buffer->buffer, buffer->memory.allocation);
buffer->buffer = nullptr;
buffer->memory.memory = nullptr;
buffer->memory.allocation = nullptr;
buffer->memory.allocation_info = {};
buffer->memory.offset = 0;
}
bool VulkanCreateImage(GraphicContext* ctx, const vk::ImageCreateInfo& image_info,
VulkanImage* image) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || image == nullptr ||
image->image != nullptr || image->memory.allocation != nullptr);
auto& memory = image->memory;
VmaAllocationCreateInfo alloc_info {};
alloc_info.requiredFlags = static_cast<vk::MemoryPropertyFlags::MaskType>(memory.property);
vk::Image::CType native_image = VK_NULL_HANDLE;
const auto result = static_cast<vk::Result>(vmaCreateImage(
ctx->allocator, static_cast<const vk::ImageCreateInfo::NativeType*>(image_info),
&alloc_info, &native_image, &memory.allocation, &memory.allocation_info));
image->image = native_image;
if (result != vk::Result::eSuccess) {
VulkanLogMemoryBudget(ctx);
return false;
}
ctx->device.getImageMemoryRequirements(image->image, &memory.requirements);
memory.type = memory.allocation_info.memoryType;
memory.memory = memory.allocation_info.deviceMemory;
memory.offset = memory.allocation_info.offset;
memory.unique_id = VulkanNextMemoryUniqueId();
VulkanTrackAllocation(&memory);
return true;
}
void VulkanDeleteImage(GraphicContext* ctx, VulkanImage* image) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || image == nullptr ||
image->image == nullptr || image->memory.allocation == nullptr);
auto& memory = image->memory;
VulkanUntrackAllocation(&memory);
vmaDestroyImage(ctx->allocator, image->image, memory.allocation);
image->image = nullptr;
memory.memory = nullptr;
memory.allocation = nullptr;
memory.allocation_info = {};
memory.offset = 0;
}
void VulkanMapMemory(GraphicContext* ctx, VulkanMemory* memory, void** data) {
@@ -185,22 +220,4 @@ void VulkanUnmapMemory(GraphicContext* ctx, VulkanMemory* memory) {
vmaUnmapMemory(ctx->allocator, memory->allocation);
}
void VulkanBindImageMemory(GraphicContext* ctx, VulkanImage* image, VulkanMemory* memory) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || image == nullptr || memory == nullptr || ctx->allocator == nullptr ||
memory->allocation == nullptr);
EXIT_NOT_IMPLEMENTED(
static_cast<vk::Result>(vmaBindImageMemory(ctx->allocator, memory->allocation,
image->image)) != vk::Result::eSuccess);
}
void VulkanBindBufferMemory(GraphicContext* ctx, VulkanBuffer* buffer, VulkanMemory* memory) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || buffer == nullptr || memory == nullptr || ctx->allocator == nullptr ||
memory->allocation == nullptr);
EXIT_NOT_IMPLEMENTED(
static_cast<vk::Result>(vmaBindBufferMemory(ctx->allocator, memory->allocation,
buffer->buffer)) != vk::Result::eSuccess);
}
} // namespace Libs::Graphics
+6 -4
View File
@@ -2,6 +2,7 @@
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_VMA_H_
#include "common/common.h"
#include "graphics/host_gpu/vulkanCommon.h"
namespace Libs::Graphics {
@@ -16,12 +17,13 @@ uint64_t VulkanNextMemoryUniqueId();
void VulkanTrackAllocation(const VulkanMemory* memory);
void VulkanUntrackAllocation(const VulkanMemory* memory);
void VulkanLogMemoryBudget(GraphicContext* ctx);
bool VulkanAllocate(GraphicContext* ctx, VulkanMemory* memory);
void VulkanFree(GraphicContext* ctx, VulkanMemory* memory);
void VulkanCreateBuffer(GraphicContext* ctx, uint64_t size, VulkanBuffer* buffer);
void VulkanDeleteBuffer(GraphicContext* ctx, VulkanBuffer* buffer);
bool VulkanCreateImage(GraphicContext* ctx, const vk::ImageCreateInfo& image_info,
VulkanImage* image);
void VulkanDeleteImage(GraphicContext* ctx, VulkanImage* image);
void VulkanMapMemory(GraphicContext* ctx, VulkanMemory* memory, void** data);
void VulkanUnmapMemory(GraphicContext* ctx, VulkanMemory* memory);
void VulkanBindImageMemory(GraphicContext* ctx, VulkanImage* image, VulkanMemory* memory);
void VulkanBindBufferMemory(GraphicContext* ctx, VulkanBuffer* buffer, VulkanMemory* memory);
} // namespace Libs::Graphics
+99
View File
@@ -1,8 +1,95 @@
#include "graphics/host_gpu/vulkanCommon.h"
#include "common/assert.h"
#include "graphics/guest_gpu/gpu_defs.h"
#include <array>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
namespace Libs::Graphics {
namespace {
struct FormatMapping {
Prospero::BufferFormat guest;
vk::Format host;
};
constexpr FormatMapping kFormatMappings[] = {
{Prospero::BufferFormat::k8UNorm, vk::Format::eR8Unorm},
{Prospero::BufferFormat::k8UInt, vk::Format::eR8Uint},
{Prospero::BufferFormat::k16UNorm, vk::Format::eR16Unorm},
{Prospero::BufferFormat::k16SNorm, vk::Format::eR16Snorm},
{Prospero::BufferFormat::k16UInt, vk::Format::eR16Uint},
{Prospero::BufferFormat::k16SInt, vk::Format::eR16Sint},
{Prospero::BufferFormat::k16Float, vk::Format::eR16Sfloat},
{Prospero::BufferFormat::k8_8UNorm, vk::Format::eR8G8Unorm},
{Prospero::BufferFormat::k8_8SNorm, vk::Format::eR8G8Snorm},
{Prospero::BufferFormat::k8_8UInt, vk::Format::eR8G8Uint},
{Prospero::BufferFormat::k8_8SInt, vk::Format::eR8G8Sint},
{Prospero::BufferFormat::k32UInt, vk::Format::eR32Uint},
{Prospero::BufferFormat::k32SInt, vk::Format::eR32Sint},
{Prospero::BufferFormat::k32Float, vk::Format::eR32Sfloat},
{Prospero::BufferFormat::k16_16UNorm, vk::Format::eR16G16Unorm},
{Prospero::BufferFormat::k16_16SNorm, vk::Format::eR16G16Snorm},
{Prospero::BufferFormat::k16_16UInt, vk::Format::eR16G16Uint},
{Prospero::BufferFormat::k16_16SInt, vk::Format::eR16G16Sint},
{Prospero::BufferFormat::k16_16Float, vk::Format::eR16G16Sfloat},
{Prospero::BufferFormat::k11_11_10Float, vk::Format::eB10G11R11UfloatPack32},
{Prospero::BufferFormat::k10_10_10_2UNorm, vk::Format::eA2B10G10R10UnormPack32},
{Prospero::BufferFormat::k8_8_8_8UNorm, vk::Format::eR8G8B8A8Unorm},
{Prospero::BufferFormat::k8_8_8_8SNorm, vk::Format::eR8G8B8A8Snorm},
{Prospero::BufferFormat::k8_8_8_8UInt, vk::Format::eR8G8B8A8Uint},
{Prospero::BufferFormat::k8_8_8_8SInt, vk::Format::eR8G8B8A8Sint},
{Prospero::BufferFormat::k32_32UInt, vk::Format::eR32G32Uint},
{Prospero::BufferFormat::k32_32SInt, vk::Format::eR32G32Sint},
{Prospero::BufferFormat::k32_32Float, vk::Format::eR32G32Sfloat},
{Prospero::BufferFormat::k16_16_16_16UNorm, vk::Format::eR16G16B16A16Unorm},
{Prospero::BufferFormat::k16_16_16_16SNorm, vk::Format::eR16G16B16A16Snorm},
{Prospero::BufferFormat::k16_16_16_16UInt, vk::Format::eR16G16B16A16Uint},
{Prospero::BufferFormat::k16_16_16_16SInt, vk::Format::eR16G16B16A16Sint},
{Prospero::BufferFormat::k16_16_16_16Float, vk::Format::eR16G16B16A16Sfloat},
{Prospero::BufferFormat::k32_32_32UInt, vk::Format::eR32G32B32Uint},
{Prospero::BufferFormat::k32_32_32SInt, vk::Format::eR32G32B32Sint},
{Prospero::BufferFormat::k32_32_32Float, vk::Format::eR32G32B32Sfloat},
{Prospero::BufferFormat::k32_32_32_32UInt, vk::Format::eR32G32B32A32Uint},
{Prospero::BufferFormat::k32_32_32_32SInt, vk::Format::eR32G32B32A32Sint},
{Prospero::BufferFormat::k32_32_32_32Float, vk::Format::eR32G32B32A32Sfloat},
{Prospero::BufferFormat::k8_8_8_8Srgb, vk::Format::eR8G8B8A8Srgb},
{Prospero::BufferFormat::k9_9_9_5Float, vk::Format::eE5B9G9R9UfloatPack32},
{Prospero::BufferFormat::k5_6_5UNorm, vk::Format::eB5G6R5UnormPack16},
{Prospero::BufferFormat::k5_5_5_1UNorm, vk::Format::eR5G5B5A1UnormPack16},
{Prospero::BufferFormat::k4_4_4_4UNorm, vk::Format::eR4G4B4A4UnormPack16},
{Prospero::BufferFormat::kFmask8_S4_F4, vk::Format::eR32Sfloat},
{Prospero::BufferFormat::kBc1UNorm, vk::Format::eBc1RgbaUnormBlock},
{Prospero::BufferFormat::kBc1Srgb, vk::Format::eBc1RgbaSrgbBlock},
{Prospero::BufferFormat::kBc2UNorm, vk::Format::eBc2UnormBlock},
{Prospero::BufferFormat::kBc2Srgb, vk::Format::eBc2SrgbBlock},
{Prospero::BufferFormat::kBc3UNorm, vk::Format::eBc3UnormBlock},
{Prospero::BufferFormat::kBc3Srgb, vk::Format::eBc3SrgbBlock},
{Prospero::BufferFormat::kBc4UNorm, vk::Format::eBc4UnormBlock},
{Prospero::BufferFormat::kBc4SNorm, vk::Format::eBc4SnormBlock},
{Prospero::BufferFormat::kBc5UNorm, vk::Format::eBc5UnormBlock},
{Prospero::BufferFormat::kBc5SNorm, vk::Format::eBc5SnormBlock},
{Prospero::BufferFormat::kBc6UFloat, vk::Format::eBc6HUfloatBlock},
{Prospero::BufferFormat::kBc6SFloat, vk::Format::eBc6HSfloatBlock},
{Prospero::BufferFormat::kBc7UNorm, vk::Format::eBc7UnormBlock},
{Prospero::BufferFormat::kBc7Srgb, vk::Format::eBc7SrgbBlock},
};
constexpr auto MakeFormatLookup() {
constexpr auto kMaxFormat = Prospero::GpuEnumValue(Prospero::BufferFormat::kBc7Srgb);
std::array<vk::Format, kMaxFormat + 1> lookup {};
lookup.fill(vk::Format::eUndefined);
for (const auto& mapping: kFormatMappings) {
lookup[Prospero::GpuEnumValue(mapping.guest)] = mapping.host;
}
return lookup;
}
constexpr auto kFormatLookup = MakeFormatLookup();
} // namespace
std::string VulkanToString(vk::Result value) {
return vk::to_string(value);
@@ -20,4 +107,16 @@ std::string VulkanToString(vk::QueueFlags value) {
return vk::to_string(value);
}
vk::Format VulkanFormat(uint32_t guest_format) {
return guest_format < kFormatLookup.size() ? kFormatLookup[guest_format]
: vk::Format::eUndefined;
}
void RequireVulkanSuccess(vk::Result result, const char* operation) {
if (result != vk::Result::eSuccess) {
EXIT("%s failed: %s (%d)\n", operation, VulkanToString(result).c_str(),
static_cast<int>(result));
}
}
} // namespace Libs::Graphics
+25
View File
@@ -10,7 +10,9 @@
#define VMA_STATIC_VULKAN_FUNCTIONS 0
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
#include <cstdint>
#include <string>
#include <vector>
#include <vulkan/vulkan.hpp>
#include <vulkan/vulkan_hash.hpp>
@@ -27,6 +29,29 @@ std::string VulkanToString(vk::Result value);
std::string VulkanToString(vk::Format value);
std::string VulkanToString(vk::ImageLayout value);
std::string VulkanToString(vk::QueueFlags value);
vk::Format VulkanFormat(uint32_t guest_format);
void RequireVulkanSuccess(vk::Result result, const char* operation);
template <typename T, typename Enumerator>
[[nodiscard]] std::vector<T> EnumerateVulkan(const char* operation, Enumerator&& enumerate) {
for (;;) {
uint32_t count = 0;
RequireVulkanSuccess(enumerate(&count, nullptr), operation);
if (count == 0) {
return {};
}
std::vector<T> values(count);
const auto result = enumerate(&count, values.data());
if (result == vk::Result::eSuccess) {
values.resize(count);
return values;
}
if (result != vk::Result::eIncomplete) {
RequireVulkanSuccess(result, operation);
}
}
}
} // namespace Libs::Graphics