mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-27 16:02:37 +00:00
471 lines
21 KiB
C++
471 lines
21 KiB
C++
#include "graphics/host_gpu/renderer/image.h"
|
|
|
|
#include "common/assert.h"
|
|
#include "common/profiler.h"
|
|
#include "graphics/guest_gpu/gpu_defs.h"
|
|
#include "graphics/guest_gpu/tile.h"
|
|
#include "graphics/host_gpu/graphicContext.h"
|
|
#include "graphics/host_gpu/objects/textureCommon.h"
|
|
#include "graphics/host_gpu/regionDefinitions.h"
|
|
#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/shader/shader.h"
|
|
|
|
#include <algorithm>
|
|
|
|
namespace Libs::Graphics {
|
|
|
|
namespace {
|
|
|
|
TextureImageCreateParams MakeImageParams(const ImageInfo& info, bool storage) {
|
|
TextureImageCreateParams params {};
|
|
params.fmt = info.format;
|
|
params.width = info.width;
|
|
params.height = info.height;
|
|
params.base_level = SelectImageBackingBaseLevel(storage, info.base_level);
|
|
params.levels = info.levels;
|
|
params.depth = info.depth;
|
|
params.type = info.type;
|
|
// Storage image views use identity component mapping. The guest storage write mapping is
|
|
// validated before this point and intentionally does not become a Vulkan view swizzle.
|
|
params.swizzle = storage ? DstSel(4, 5, 6, 7) : info.swizzle;
|
|
params.format_usage = TextureFormatUsage::Sampled | TextureFormatUsage::Storage;
|
|
params.required_format_usage = storage
|
|
? TextureFormatUsage::Sampled | TextureFormatUsage::Storage
|
|
: TextureFormatUsage::Sampled;
|
|
params.view_usage = storage ? TextureFormatUsage::Sampled | TextureFormatUsage::Storage
|
|
: TextureFormatUsage::Sampled;
|
|
params.image_layout = TextureUploadDestination::MipLevels;
|
|
params.allow_cube_view = !storage;
|
|
params.compatible_format_views =
|
|
storage &&
|
|
(IsRgba8SrgbViewFormat(TextureGetFormat(info.format, params.format_usage)) ||
|
|
info.format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) ||
|
|
info.format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float));
|
|
params.owner = storage ? "StorageTextureCache" : "TextureCache";
|
|
return params;
|
|
}
|
|
|
|
bool RenderTargetSupportsStorage(GraphicContext* ctx, VkFormat format, VkImageCreateFlags flags) {
|
|
const auto compatible = SrgbStorageViewFormat(format);
|
|
const auto required_flags =
|
|
VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
|
|
const bool compatible_views = (flags & required_flags) == required_flags;
|
|
return ImageViewOps::FormatSupportsStorage(ctx, format) ||
|
|
(compatible_views && compatible != VK_FORMAT_UNDEFINED &&
|
|
ImageViewOps::FormatSupportsStorage(ctx, compatible));
|
|
}
|
|
|
|
VkImageCreateFlags RenderTargetCreateFlags(VkFormat format) {
|
|
const bool compatible_format_view =
|
|
IsRgba8SrgbViewFormat(format) || BgraToRgbaSampledViewFormat(format) != VK_FORMAT_UNDEFINED ||
|
|
format == VK_FORMAT_R8G8B8A8_UINT || format == VK_FORMAT_R16G16B16A16_SFLOAT ||
|
|
format == VK_FORMAT_R16G16B16A16_UINT;
|
|
return compatible_format_view
|
|
? VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT
|
|
: VkImageCreateFlags {0};
|
|
}
|
|
|
|
VkImageUsageFlags RenderTargetUsage(GraphicContext* ctx, VkFormat format,
|
|
VkImageCreateFlags flags) {
|
|
auto usage = static_cast<VkImageUsageFlags>(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) |
|
|
static_cast<VkImageUsageFlags>(VK_IMAGE_USAGE_TRANSFER_SRC_BIT) |
|
|
static_cast<VkImageUsageFlags>(VK_IMAGE_USAGE_TRANSFER_DST_BIT) |
|
|
static_cast<VkImageUsageFlags>(VK_IMAGE_USAGE_SAMPLED_BIT);
|
|
if (RenderTargetSupportsStorage(ctx, format, flags)) {
|
|
usage |= VK_IMAGE_USAGE_STORAGE_BIT;
|
|
}
|
|
VkImageFormatProperties properties {};
|
|
if (ctx->GetImageFormatProperties(format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, usage,
|
|
flags, &properties) != VK_SUCCESS) {
|
|
EXIT("TextureCache: render-target format does not support required usage, format=%d "
|
|
"usage=0x%x\n",
|
|
static_cast<int>(format), usage);
|
|
}
|
|
return usage;
|
|
}
|
|
|
|
[[nodiscard]] uint32_t RenderTargetTransferFormatImpl(uint32_t bytes_per_element) {
|
|
switch (bytes_per_element) {
|
|
case 1: return Prospero::GpuEnumValue(Prospero::BufferFormat::k8UNorm);
|
|
case 2: return Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm);
|
|
case 4: return Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float);
|
|
case 8: return Prospero::GpuEnumValue(Prospero::BufferFormat::k16_16_16_16Float);
|
|
case 16: return Prospero::GpuEnumValue(Prospero::BufferFormat::k32_32_32_32Float);
|
|
default:
|
|
EXIT("TextureCache: unsupported render-target element size: %u\n", bytes_per_element);
|
|
}
|
|
}
|
|
|
|
static constexpr uint32_t DummyTextureSwizzle() {
|
|
return Prospero::GpuEnumValue(Prospero::CompSwizzle::kRed) |
|
|
(Prospero::GpuEnumValue(Prospero::CompSwizzle::kGreen) << 3u) |
|
|
(Prospero::GpuEnumValue(Prospero::CompSwizzle::kBlue) << 6u) |
|
|
(Prospero::GpuEnumValue(Prospero::CompSwizzle::kAlpha) << 9u);
|
|
}
|
|
|
|
TextureImageCreateParams MakeDummyTextureParams(bool uint_format, bool image_3d,
|
|
TextureFormatUsage usage,
|
|
const char* owner) {
|
|
TextureImageCreateParams params {};
|
|
params.fmt = static_cast<uint32_t>(
|
|
Prospero::GpuEnumValue(uint_format ? Prospero::BufferFormat::k8_8_8_8UInt
|
|
: Prospero::BufferFormat::k8_8_8_8UNorm));
|
|
params.width = 1;
|
|
params.height = 1;
|
|
params.base_level = 0;
|
|
params.levels = 1;
|
|
params.depth = 1;
|
|
params.type = Prospero::GpuEnumValue(image_3d ? Prospero::ImageType::kColor3D
|
|
: Prospero::ImageType::kColor2D);
|
|
params.swizzle = DummyTextureSwizzle();
|
|
params.format_usage = usage;
|
|
params.required_format_usage = usage;
|
|
params.view_usage = usage;
|
|
params.image_layout = TextureUploadDestination::MipLevels;
|
|
params.allow_cube_view = true;
|
|
params.storage_swizzle_fallback = TextureHasFormatUsage(usage, TextureFormatUsage::Storage);
|
|
params.owner = owner;
|
|
return params;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
namespace ImageOps {
|
|
|
|
uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element) {
|
|
return RenderTargetTransferFormatImpl(bytes_per_element);
|
|
}
|
|
|
|
GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info, bool storage,
|
|
VulkanMemory* memory, VkComponentMapping* 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));
|
|
return image;
|
|
}
|
|
|
|
void CreateTextureViews(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info,
|
|
bool storage, VkComponentMapping components) {
|
|
if (storage) {
|
|
TextureCreateImageViews(ctx, image, components, info.type, 0, 0, 1, info.depth, false,
|
|
TextureFormatUsage::Sampled | TextureFormatUsage::Storage);
|
|
} else {
|
|
TextureCreateImageViews(ctx, image, components, info.type, info.base_array, info.base_level,
|
|
info.view_levels, info.depth, true, TextureFormatUsage::Sampled);
|
|
}
|
|
}
|
|
|
|
void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* image,
|
|
const RenderTargetInfo& info, uint32_t base_layer,
|
|
uint32_t layer_count, bool refresh) {
|
|
if (info.layers == 0 || info.size % info.layers != 0 || layer_count == 0 ||
|
|
base_layer >= info.layers || layer_count > info.layers - base_layer || image == nullptr ||
|
|
base_layer >= image->layers || layer_count > image->layers - base_layer) {
|
|
EXIT("TextureCache: invalid render-target layer upload, base=%u count=%u "
|
|
"info_layers=%u image_layers=%u size=0x%016" PRIx64 "\n",
|
|
base_layer, layer_count, info.layers, image != nullptr ? image->layers : 0, info.size);
|
|
}
|
|
if (refresh) {
|
|
VulkanDeviceWaitIdle(ctx);
|
|
}
|
|
const auto slice_size = info.size / info.layers;
|
|
const auto upload_size = slice_size * layer_count;
|
|
const bool standard64 = IsSupportedStandard64RenderTarget(info);
|
|
if (standard64 || info.levels > 1 || info.layers > 1) {
|
|
const auto format = RenderTargetTransferFormat(info.bytes_per_element);
|
|
auto layout = TextureCalcUploadLayout(format, info.width, info.height, info.levels,
|
|
layer_count, info.pitch, info.tile_mode, upload_size,
|
|
false, false, false, "TextureCache render target");
|
|
const bool render_target_tiled =
|
|
info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget);
|
|
if (!standard64 && ((render_target_tiled && !layout.fmt_tiled_render_target) ||
|
|
layout.pitch != info.pitch)) {
|
|
EXIT("TextureCache: unsupported render-target mip upload layout, pitch=%u/%u tile=%u\n",
|
|
info.pitch, layout.pitch, info.tile_mode);
|
|
}
|
|
auto regions = TextureBuildUploadRegions(
|
|
layout, info.format, info.width, info.height, layer_count, info.levels, true, false,
|
|
TextureUploadDestination::MipLevels, TextureUploadSliceLayout::MipChainPerSlice);
|
|
for (auto& region: regions) {
|
|
region.dst_layer += base_layer;
|
|
}
|
|
const auto source_address = info.address + slice_size * base_layer;
|
|
TextureUploadGuestImage(
|
|
ctx, image, reinterpret_cast<const void*>(source_address), upload_size, regions, layout,
|
|
format, info.width, info.height, layer_count, info.levels,
|
|
TextureUploadSliceLayout::MipChainPerSlice, "TextureCache render target",
|
|
static_cast<uint64_t>(VK_IMAGE_LAYOUT_GENERAL));
|
|
return;
|
|
}
|
|
if (info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) &&
|
|
UtilBufferIsTiled(info.address, slice_size)) {
|
|
UtilScratchBuffer 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,
|
|
static_cast<uint64_t>(VK_IMAGE_LAYOUT_GENERAL));
|
|
} else {
|
|
UtilFillImage(ctx, image, reinterpret_cast<const void*>(info.address), slice_size,
|
|
info.pitch, static_cast<uint64_t>(VK_IMAGE_LAYOUT_GENERAL));
|
|
}
|
|
}
|
|
|
|
void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image,
|
|
const RenderTargetInfo& info, bool refresh) {
|
|
UploadRenderTargetLayers(ctx, image, info, 0, info.layers, refresh);
|
|
}
|
|
|
|
RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTargetInfo& info,
|
|
VulkanMemory* memory) {
|
|
auto* image = new RenderTextureVulkanImage;
|
|
image->extent.width = info.width;
|
|
image->extent.height = info.height;
|
|
image->format = info.format;
|
|
image->mip_levels = info.levels;
|
|
image->layers = info.layers;
|
|
image->layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
UtilResetImageViews(image);
|
|
VkImageCreateInfo create {};
|
|
create.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
create.flags = RenderTargetCreateFlags(info.format);
|
|
create.imageType = VK_IMAGE_TYPE_2D;
|
|
create.extent = {info.width, info.height, 1};
|
|
create.mipLevels = info.levels;
|
|
create.arrayLayers = info.layers;
|
|
create.format = info.format;
|
|
create.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
create.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
create.usage = RenderTargetUsage(ctx, info.format, create.flags);
|
|
create.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
create.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
memory->property = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
|
if (!VulkanCreateImage(ctx, &create, image, memory)) {
|
|
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) {
|
|
VkImageCreateInfo create {};
|
|
create.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
create.imageType = VK_IMAGE_TYPE_2D;
|
|
create.extent = {info.width, info.height, 1};
|
|
create.mipLevels = 1;
|
|
create.arrayLayers = info.layers;
|
|
create.format = info.format;
|
|
create.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
create.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
create.usage = DepthTargetImageUsage();
|
|
create.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
create.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
VkImageFormatProperties properties {};
|
|
if (ctx->GetImageFormatProperties(info.format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
|
|
create.usage, 0, &properties) != VK_SUCCESS) {
|
|
EXIT("TextureCache: depth format does not support required usage, format=%d usage=0x%x\n",
|
|
static_cast<int>(info.format), 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_IMAGE_LAYOUT_UNDEFINED;
|
|
image->compressed = false;
|
|
UtilResetImageViews(image);
|
|
memory->property = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
|
if (!VulkanCreateImage(ctx, &create, image, memory)) {
|
|
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;
|
|
}
|
|
|
|
void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) {
|
|
const auto compression =
|
|
ClassifyVideoOutCompression(info.compression != VideoOutCompression::Uncompressed,
|
|
info.metadata_address, info.dcc_control, 0);
|
|
const bool metadata_invalid = compression == VideoOutCompression::Dcc256_64_64 &&
|
|
(info.metadata_address >= TRACKER_ADDRESS_SIZE ||
|
|
(info.metadata_address >= info.address &&
|
|
info.metadata_address < info.address + info.size));
|
|
if (ctx == nullptr || info.address == 0 || info.size == 0 ||
|
|
info.address >= TRACKER_ADDRESS_SIZE || info.size > TRACKER_ADDRESS_SIZE - info.address ||
|
|
(info.address & 0xffffu) != 0 || info.width == 0 || info.height == 0 ||
|
|
info.width > 16384 || info.height > 16384 || info.pitch < info.width ||
|
|
info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) ||
|
|
compression == VideoOutCompression::Unsupported || compression != info.compression ||
|
|
metadata_invalid || !IsSupportedVideoOutFormat(info)) {
|
|
EXIT("TextureCache: unsupported video-out surface, ctx=%p addr=0x%016" PRIx64
|
|
" size=0x%016" PRIx64 " metadata=0x%016" PRIx64 " dcc=0x%08" PRIx32
|
|
" extent=%ux%u pitch=%u tile=%u guest_format=%u bpe=%u vk_format=%d\n",
|
|
static_cast<const void*>(ctx), info.address, info.size, info.metadata_address,
|
|
info.dcc_control, info.width, info.height, info.pitch, info.tile_mode,
|
|
info.guest_format, info.bytes_per_element, static_cast<int>(info.format));
|
|
}
|
|
TileSizeAlign exact {};
|
|
TileGetTextureTotalSize(info.guest_format, info.width, info.height, 1, info.pitch, 1,
|
|
info.tile_mode, false, &exact);
|
|
if (exact.align != 65536 || exact.size != info.size ||
|
|
TileGetTexturePitch(info.guest_format, info.width, 1, info.tile_mode) != info.pitch) {
|
|
EXIT("TextureCache: video-out tile layout mismatch, addr=0x%016" PRIx64
|
|
" size=0x%016" PRIx64 " expected_size=0x%016" PRIx64 " align=0x%016" PRIx64
|
|
" pitch=%u\n",
|
|
info.address, info.size, exact.size, exact.align, info.pitch);
|
|
}
|
|
(void)RenderTargetUsage(ctx, info.format, 0);
|
|
}
|
|
|
|
VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info,
|
|
VulkanMemory* memory) {
|
|
auto* image = new VideoOutVulkanImage;
|
|
image->extent.width = info.width;
|
|
image->extent.height = info.height;
|
|
image->format = info.format;
|
|
image->layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
UtilResetImageViews(image);
|
|
VkImageCreateInfo create {};
|
|
create.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
create.imageType = VK_IMAGE_TYPE_2D;
|
|
create.extent = {info.width, info.height, 1};
|
|
create.mipLevels = 1;
|
|
create.arrayLayers = 1;
|
|
create.format = info.format;
|
|
create.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
create.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
create.flags = RenderTargetCreateFlags(info.format);
|
|
create.usage = RenderTargetUsage(ctx, info.format, create.flags);
|
|
create.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
create.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
memory->property = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
|
if (!VulkanCreateImage(ctx, &create, image, memory)) {
|
|
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;
|
|
}
|
|
|
|
void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const VideoOutInfo& info,
|
|
bool refresh) {
|
|
if (info.compression != VideoOutCompression::Uncompressed) {
|
|
EXIT("TextureCache: compressed video-out guest upload is unsupported, "
|
|
"addr=0x%016" PRIx64 " metadata=0x%016" PRIx64 " dcc=0x%08" PRIx32 "\n",
|
|
info.address, info.metadata_address, info.dcc_control);
|
|
}
|
|
if (refresh) {
|
|
VulkanDeviceWaitIdle(ctx);
|
|
}
|
|
image->layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
UtilScratchBuffer scratch(info.size);
|
|
TileConvertTiledToLinearRenderTarget(
|
|
scratch.Data(), reinterpret_cast<const void*>(info.address), info.width, info.height,
|
|
info.pitch, info.bytes_per_element, info.size);
|
|
if (info.bgra16) {
|
|
auto* pixels = static_cast<uint16_t*>(scratch.Data());
|
|
for (uint64_t i = 0; i < info.size / sizeof(uint16_t); i += 4) {
|
|
std::swap(pixels[i], pixels[i + 2]);
|
|
}
|
|
}
|
|
UtilFillImage(ctx, image, scratch.Data(), info.size, info.pitch,
|
|
static_cast<uint64_t>(VK_IMAGE_LAYOUT_GENERAL));
|
|
}
|
|
|
|
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);
|
|
}
|
|
auto* image = storage ? static_cast<GpuTextureVulkanImage*>(new StorageTextureVulkanImage)
|
|
: new TextureVulkanImage;
|
|
auto usage = storage ? TextureFormatUsage::Storage : TextureFormatUsage::Sampled;
|
|
auto layout = storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
auto owner = storage ? "DummyStorageTexture" : "DummySampledTexture";
|
|
|
|
auto params = MakeDummyTextureParams(uint_format, image_3d, usage, owner);
|
|
auto components = TextureCreateImage(ctx, image, memory, params);
|
|
|
|
static constexpr uint32_t zero = 0;
|
|
UtilFillImage(ctx, image, &zero, sizeof(zero), 1, static_cast<uint64_t>(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");
|
|
|
|
EXIT_IF(ctx == nullptr);
|
|
EXIT_IF(image == nullptr);
|
|
|
|
ImageViewOps::DestroyViews(ctx, image);
|
|
VulkanDeleteImage(ctx, image, memory);
|
|
|
|
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));
|
|
}
|
|
}
|
|
|
|
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
|