mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 00:12:40 +00:00
refactor renderer
This commit is contained in:
1 parent
a720b28b7f
commit
a20cf5d298
112 files changed
+18269
-18368
No files matched your search
@@ -1,17 +1,12 @@
|
||||
#include "graphics/host_gpu/objects/textureCommon.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "graphics/guest_gpu/gpu_defs.h"
|
||||
#include "graphics/guest_gpu/gpu_format.h"
|
||||
#include "graphics/host_gpu/graphicContext.h"
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
#include "graphics/host_gpu/transfer.h"
|
||||
#include "graphics/host_gpu/vma.h"
|
||||
#include "graphics/host_gpu/renderer/tiler.h"
|
||||
#include "graphics/host_gpu/vulkanCommon.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <bit>
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
@@ -159,6 +154,8 @@ RenderTargetFormatInfo TextureGetRenderTargetFormat(uint32_t raw_layout, uint32_
|
||||
raw_type, raw_order);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
static uint64_t GetLevelSrcOffset(const TileSizeOffset& level_size) {
|
||||
return (level_size.src_size != 0 ? level_size.src_offset : level_size.offset);
|
||||
}
|
||||
@@ -193,28 +190,6 @@ uint64_t TextureUploadSliceSourceOffset(const TextureUploadLayout& layout, uint3
|
||||
return level_offset + static_cast<uint64_t>(slice) * slice_stride;
|
||||
}
|
||||
|
||||
uint64_t TextureCalcUploadSize(const TextureUploadLayout& layout,
|
||||
const std::vector<BufferImageCopy>& regions, uint64_t levels,
|
||||
uint32_t depth) {
|
||||
uint64_t size = 0;
|
||||
|
||||
for (const auto& r: regions) {
|
||||
size = std::max<uint64_t>(size, static_cast<uint64_t>(r.offset) +
|
||||
layout.level_sizes[r.dst_level].size);
|
||||
}
|
||||
|
||||
for (uint32_t level = 0; level < levels; level++) {
|
||||
const auto src_size = GetLevelSrcSize(layout.level_sizes[level]);
|
||||
const auto mip_depth = GetTextureLevelDepth(depth, level, layout.volume_texture);
|
||||
for (uint32_t z = 0; z < mip_depth; z++) {
|
||||
size = std::max<uint64_t>(size,
|
||||
TextureUploadSliceSourceOffset(layout, level, z) + src_size);
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
vk::ComponentSwizzle TextureGetComponentSwizzle(uint8_t s) {
|
||||
switch (static_cast<Prospero::CompSwizzle>(s)) {
|
||||
case Prospero::CompSwizzle::kZero: return vk::ComponentSwizzle::eZero;
|
||||
@@ -232,6 +207,8 @@ static uint32_t TextureGetDstSel(uint32_t swizzle, uint32_t channel) {
|
||||
return (swizzle >> (channel * 3u)) & 0x7u;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
vk::ComponentMapping TextureGetComponentMapping(uint32_t swizzle) {
|
||||
vk::ComponentMapping components {};
|
||||
components.r = TextureGetComponentSwizzle(static_cast<uint8_t>(TextureGetDstSel(swizzle, 0)));
|
||||
@@ -241,94 +218,6 @@ vk::ComponentMapping TextureGetComponentMapping(uint32_t swizzle) {
|
||||
return components;
|
||||
}
|
||||
|
||||
bool TextureCheckFormat(vk::ImageCreateInfo& image_info) {
|
||||
auto& graphics = GetRenderContext().GetGraphics();
|
||||
vk::ImageFormatProperties props {};
|
||||
if (graphics.GetImageFormatProperties(image_info.format, image_info.imageType,
|
||||
image_info.tiling, image_info.usage, image_info.flags,
|
||||
&props) == vk::Result::eErrorFormatNotSupported) {
|
||||
auto apply_fallback = [&](vk::Format replacement, const char* message) {
|
||||
image_info.format = replacement;
|
||||
const bool result = TextureCheckFormat(image_info);
|
||||
LOGF("%s [%s]\n", message, (!result ? "FAIL" : "SUCCESS"));
|
||||
return result;
|
||||
};
|
||||
|
||||
if (image_info.format == vk::Format::eR8G8B8A8Srgb) {
|
||||
// TODO() convert SRGB -> LINEAR in shader
|
||||
return apply_fallback(
|
||||
vk::Format::eR8G8B8A8Unorm,
|
||||
"replace vk::Format::eR8G8B8A8Srgb => vk::Format::eR8G8B8A8Unorm");
|
||||
}
|
||||
if (image_info.format == vk::Format::eB8G8R8A8Srgb) {
|
||||
// TODO() convert SRGB -> LINEAR in shader
|
||||
return apply_fallback(
|
||||
vk::Format::eB8G8R8A8Unorm,
|
||||
"replace vk::Format::eB8G8R8A8Srgb => vk::Format::eB8G8R8A8Unorm");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TextureCheckFormatExact(const vk::ImageCreateInfo& image_info) {
|
||||
auto& graphics = GetRenderContext().GetGraphics();
|
||||
vk::ImageFormatProperties props {};
|
||||
return graphics.GetImageFormatProperties(image_info.format, image_info.imageType,
|
||||
image_info.tiling, image_info.usage, image_info.flags,
|
||||
&props) != vk::Result::eErrorFormatNotSupported;
|
||||
}
|
||||
|
||||
bool TextureCheckStorageSwizzle(vk::ImageCreateInfo& image_info, vk::ComponentMapping& components) {
|
||||
if (image_info.usage & vk::ImageUsageFlagBits::eStorage) {
|
||||
if (components.r == vk::ComponentSwizzle::eR && components.g == vk::ComponentSwizzle::eG &&
|
||||
components.b == vk::ComponentSwizzle::eB && components.a == vk::ComponentSwizzle::eA) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (components.r == vk::ComponentSwizzle::eB && components.g == vk::ComponentSwizzle::eG &&
|
||||
components.b == vk::ComponentSwizzle::eR && components.a == vk::ComponentSwizzle::eA &&
|
||||
image_info.format == vk::Format::eR8G8B8A8Srgb) {
|
||||
LOGF("replace vk::Format::eR8G8B8A8Srgb => vk::Format::eB8G8R8A8Srgb\n");
|
||||
|
||||
components.r = vk::ComponentSwizzle::eR;
|
||||
components.g = vk::ComponentSwizzle::eG;
|
||||
components.b = vk::ComponentSwizzle::eB;
|
||||
components.a = vk::ComponentSwizzle::eA;
|
||||
image_info.format = vk::Format::eB8G8R8A8Srgb;
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO() swizzle channels in shader
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
vk::ImageUsageFlags TextureGetUsage(TextureFormatUsage usage) {
|
||||
vk::ImageUsageFlags vk_usage =
|
||||
vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eTransferSrc;
|
||||
if (TextureHasFormatUsage(usage, TextureFormatUsage::Sampled)) {
|
||||
vk_usage |= vk::ImageUsageFlagBits::eSampled;
|
||||
}
|
||||
if (TextureHasFormatUsage(usage, TextureFormatUsage::Storage)) {
|
||||
vk_usage |= vk::ImageUsageFlagBits::eStorage;
|
||||
}
|
||||
return vk_usage;
|
||||
}
|
||||
|
||||
vk::ImageUsageFlags TextureGetViewUsage(TextureFormatUsage usage) {
|
||||
vk::ImageUsageFlags vk_usage = {};
|
||||
if (TextureHasFormatUsage(usage, TextureFormatUsage::Sampled)) {
|
||||
vk_usage |= vk::ImageUsageFlagBits::eSampled;
|
||||
}
|
||||
if (TextureHasFormatUsage(usage, TextureFormatUsage::Storage)) {
|
||||
vk_usage |= vk::ImageUsageFlagBits::eStorage;
|
||||
}
|
||||
return vk_usage;
|
||||
}
|
||||
|
||||
vk::Format TextureGetFormat(uint32_t fmt) {
|
||||
const auto vk_format = VulkanFormat(fmt);
|
||||
if (vk_format != vk::Format::eUndefined) {
|
||||
@@ -338,261 +227,10 @@ vk::Format TextureGetFormat(uint32_t fmt) {
|
||||
return vk::Format::eUndefined;
|
||||
}
|
||||
|
||||
static uint32_t AlignUpU32(uint32_t value, uint32_t alignment) {
|
||||
return (value + alignment - 1u) & ~(alignment - 1u);
|
||||
}
|
||||
namespace {
|
||||
|
||||
uint32_t TextureGetAtlasSliceYStride(vk::Format format, uint32_t mip_height, uint32_t depth,
|
||||
uint64_t levels) {
|
||||
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 || !Transfer::IsBlockCompressedFormat(format)) {
|
||||
return image_height;
|
||||
}
|
||||
|
||||
uint32_t mip_height = height;
|
||||
for (uint32_t level = 0; level < levels; level++) {
|
||||
const auto mip_image_height =
|
||||
TextureGetAtlasSliceYStride(format, mip_height, depth, levels) * depth;
|
||||
image_height = std::max<uint32_t>(image_height, mip_image_height << level);
|
||||
if (mip_height > 1) {
|
||||
mip_height /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
return image_height;
|
||||
}
|
||||
|
||||
uint32_t TextureCalcMipmapAtlasImageHeight(vk::Format format, uint32_t width, uint32_t height,
|
||||
uint32_t depth, uint64_t levels) {
|
||||
auto image_height = height * depth;
|
||||
if (levels <= 1) {
|
||||
return image_height;
|
||||
}
|
||||
|
||||
uint32_t mip_height = height;
|
||||
for (uint32_t level = 0; level < levels; level++) {
|
||||
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;
|
||||
image_height = std::max<uint32_t>(image_height, mip_bottom);
|
||||
if (mip_height > 1) {
|
||||
mip_height /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
return image_height;
|
||||
}
|
||||
|
||||
bool TextureIs3DTexture(uint64_t type) {
|
||||
return static_cast<Prospero::ImageType>(type) == Prospero::ImageType::kColor3D;
|
||||
}
|
||||
|
||||
bool TextureIsCubeTexture(uint64_t type) {
|
||||
return static_cast<Prospero::ImageType>(type) == Prospero::ImageType::kCube;
|
||||
}
|
||||
|
||||
bool TextureIsLayeredTexture(uint64_t type) {
|
||||
const auto image_type = static_cast<Prospero::ImageType>(type);
|
||||
return image_type == Prospero::ImageType::kCube ||
|
||||
image_type == Prospero::ImageType::kColor1DArray ||
|
||||
image_type == Prospero::ImageType::kColor2DArray ||
|
||||
image_type == Prospero::ImageType::kColor2DMsaaArray;
|
||||
}
|
||||
|
||||
bool TextureCanCreateCubeView(uint64_t type, uint32_t base_array, uint32_t layer_count) {
|
||||
return TextureIsCubeTexture(type) && base_array % 6u == 0 && layer_count >= 6 &&
|
||||
layer_count % 6u == 0;
|
||||
}
|
||||
|
||||
vk::ComponentMapping TextureCreateImage(VulkanImage& vk_obj,
|
||||
const TextureImageCreateParams& params) {
|
||||
auto& graphics = GetRenderContext().GetGraphics();
|
||||
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);
|
||||
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;
|
||||
uint32_t image_mips = 0;
|
||||
if (params.image_layout == TextureUploadDestination::MipAtlas) {
|
||||
EXIT_NOT_IMPLEMENTED(params.base_level != 0);
|
||||
const auto atlas_depth = (array_texture || volume_texture ? 1u : params.depth);
|
||||
image_height = TextureCalcMipmapAtlasImageHeight(
|
||||
pixel_format, static_cast<uint32_t>(params.width), static_cast<uint32_t>(params.height),
|
||||
atlas_depth, params.levels);
|
||||
image_mips = 1;
|
||||
} else {
|
||||
image_height =
|
||||
(array_texture || volume_texture
|
||||
? static_cast<uint32_t>(params.height)
|
||||
: TextureCalcStackedImageHeight(pixel_format, static_cast<uint32_t>(params.height),
|
||||
params.depth, params.levels));
|
||||
image_mips = static_cast<uint32_t>(params.levels);
|
||||
}
|
||||
|
||||
vk::ComponentMapping components =
|
||||
TextureGetComponentMapping(static_cast<uint32_t>(params.swizzle));
|
||||
|
||||
vk::ImageCreateInfo image_info {};
|
||||
image_info.sType = vk::StructureType::eImageCreateInfo;
|
||||
image_info.pNext = nullptr;
|
||||
image_info.flags =
|
||||
(params.allow_cube_view && TextureCanCreateCubeView(params.type, 0, params.depth)
|
||||
? vk::ImageCreateFlagBits::eCubeCompatible
|
||||
: vk::ImageCreateFlags {}) |
|
||||
(volume_texture ? vk::ImageCreateFlagBits::e2DArrayCompatible : vk::ImageCreateFlags {}) |
|
||||
(params.compatible_format_views ? vk::ImageCreateFlagBits::eMutableFormat
|
||||
: vk::ImageCreateFlags {});
|
||||
image_info.imageType = (volume_texture ? vk::ImageType::e3D : vk::ImageType::e2D);
|
||||
image_info.extent.width = static_cast<uint32_t>(params.width);
|
||||
image_info.extent.height = image_height;
|
||||
image_info.extent.depth = (volume_texture ? params.depth : 1);
|
||||
image_info.mipLevels = image_mips;
|
||||
image_info.arrayLayers = (array_texture ? params.depth : 1);
|
||||
image_info.format = pixel_format;
|
||||
image_info.tiling = vk::ImageTiling::eOptimal;
|
||||
image_info.initialLayout = vk::ImageLayout::eUndefined;
|
||||
image_info.usage = TextureGetUsage(params.format_usage);
|
||||
image_info.sharingMode = vk::SharingMode::eExclusive;
|
||||
image_info.samples = vk::SampleCountFlagBits::e1;
|
||||
|
||||
const bool storage_view = TextureHasFormatUsage(params.view_usage, TextureFormatUsage::Storage);
|
||||
if (storage_view && !TextureCheckStorageSwizzle(image_info, components)) {
|
||||
if (!params.storage_swizzle_fallback) {
|
||||
EXIT("swizzle is not supported");
|
||||
}
|
||||
|
||||
static std::atomic_uint log_count {0};
|
||||
if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) {
|
||||
LOGF("\t %s swizzle 0x%08" PRIx64 " is not supported, using identity mapping\n",
|
||||
params.owner, params.swizzle);
|
||||
}
|
||||
components.r = vk::ComponentSwizzle::eR;
|
||||
components.g = vk::ComponentSwizzle::eG;
|
||||
components.b = vk::ComponentSwizzle::eB;
|
||||
components.a = vk::ComponentSwizzle::eA;
|
||||
}
|
||||
|
||||
const auto view_checked_format = image_info.format;
|
||||
const auto requested_usage = params.format_usage;
|
||||
const auto required_usage = params.required_format_usage;
|
||||
const bool has_optional_usage = static_cast<uint32_t>(requested_usage & ~required_usage) != 0;
|
||||
if (!TextureCheckFormatExact(image_info) && has_optional_usage) {
|
||||
auto required_info = image_info;
|
||||
required_info.usage = TextureGetUsage(required_usage);
|
||||
required_info.format = view_checked_format;
|
||||
if (TextureCheckFormatExact(required_info)) {
|
||||
static std::atomic_uint log_count {0};
|
||||
if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) {
|
||||
LOGF("\t %s usage 0x%08x is not supported for format %d, using required "
|
||||
"usage 0x%08x\n",
|
||||
params.owner, static_cast<uint32_t>(TextureGetUsage(requested_usage)),
|
||||
static_cast<int>(image_info.format),
|
||||
static_cast<uint32_t>(TextureGetUsage(required_usage)));
|
||||
}
|
||||
image_info = required_info;
|
||||
}
|
||||
}
|
||||
|
||||
if (!TextureCheckFormat(image_info)) {
|
||||
if (has_optional_usage) {
|
||||
image_info.format = view_checked_format;
|
||||
image_info.usage = TextureGetUsage(required_usage);
|
||||
}
|
||||
if (!has_optional_usage || !TextureCheckFormat(image_info)) {
|
||||
EXIT("format is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
vk_obj.extent.width = image_info.extent.width;
|
||||
vk_obj.extent.height = image_info.extent.height;
|
||||
vk_obj.layers = image_info.arrayLayers;
|
||||
vk_obj.mip_levels = image_info.mipLevels;
|
||||
vk_obj.format = image_info.format;
|
||||
vk_obj.image = nullptr;
|
||||
vk_obj.layout = image_info.initialLayout;
|
||||
|
||||
vk_obj.memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
|
||||
|
||||
bool created = graphics.CreateImage(image_info, vk_obj);
|
||||
EXIT_NOT_IMPLEMENTED(!created);
|
||||
|
||||
return components;
|
||||
}
|
||||
|
||||
void TextureCreateImageViews(VulkanImage& vk_obj,
|
||||
vk::ComponentMapping components, uint64_t type, uint32_t base_array,
|
||||
uint32_t base_level, uint32_t level_count, uint32_t depth,
|
||||
bool allow_cube_view, TextureFormatUsage view_usage) {
|
||||
auto& graphics = GetRenderContext().GetGraphics();
|
||||
EXIT_IF(level_count == 0 || base_level + level_count > vk_obj.mip_levels);
|
||||
|
||||
const bool layered_texture = TextureIsLayeredTexture(type);
|
||||
const bool volume_texture = TextureIs3DTexture(type);
|
||||
const auto layer_count = (layered_texture && base_array < depth ? depth - base_array : 1u);
|
||||
const auto volume_slices = std::max(depth >> base_level, 1u);
|
||||
|
||||
vk::ImageViewUsageCreateInfo usage_info {};
|
||||
usage_info.sType = vk::StructureType::eImageViewUsageCreateInfo;
|
||||
usage_info.pNext = nullptr;
|
||||
usage_info.usage = TextureGetViewUsage(view_usage);
|
||||
|
||||
vk::ImageViewCreateInfo create_info {};
|
||||
create_info.sType = vk::StructureType::eImageViewCreateInfo;
|
||||
create_info.pNext = (usage_info.usage ? &usage_info : 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 = components;
|
||||
create_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
|
||||
create_info.subresourceRange.baseArrayLayer = (layered_texture ? base_array : 0);
|
||||
create_info.subresourceRange.baseMipLevel = base_level;
|
||||
create_info.subresourceRange.layerCount = layer_count;
|
||||
create_info.subresourceRange.levelCount = level_count;
|
||||
if (volume_texture) {
|
||||
create_info.viewType = vk::ImageViewType::e3D;
|
||||
create_info.subresourceRange.baseArrayLayer = 0;
|
||||
create_info.subresourceRange.layerCount = 1;
|
||||
} else if (allow_cube_view && TextureCanCreateCubeView(type, base_array, layer_count)) {
|
||||
create_info.viewType =
|
||||
(layer_count > 6 ? vk::ImageViewType::eCubeArray : vk::ImageViewType::eCube);
|
||||
} else if (layered_texture) {
|
||||
create_info.viewType = vk::ImageViewType::e2DArray;
|
||||
}
|
||||
|
||||
auto create_view = [&](int index) {
|
||||
const auto result =
|
||||
graphics.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);
|
||||
|
||||
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,
|
||||
uint64_t total_size, uint32_t depth) {
|
||||
uint64_t CalcTextureSliceStride(const TileSizeOffset* level_sizes, uint64_t levels,
|
||||
uint64_t total_size, uint32_t depth) {
|
||||
uint64_t stride = 0;
|
||||
for (uint32_t i = 0; i < levels; i++) {
|
||||
stride =
|
||||
@@ -609,7 +247,7 @@ static uint64_t CalcTextureSliceStride(const TileSizeOffset* level_sizes, uint64
|
||||
return stride;
|
||||
}
|
||||
|
||||
static uint64_t CalcLinearUploadLevelSize(uint32_t fmt, uint32_t pitch, uint32_t height) {
|
||||
uint64_t CalcLinearUploadLevelSize(uint32_t fmt, uint32_t pitch, uint32_t height) {
|
||||
if (const uint32_t bytes_per_element = Prospero::NumBytesPerElement(fmt);
|
||||
bytes_per_element != 0) {
|
||||
return static_cast<uint64_t>(pitch) * height * bytes_per_element;
|
||||
@@ -625,8 +263,8 @@ static uint64_t CalcLinearUploadLevelSize(uint32_t fmt, uint32_t pitch, uint32_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t SetLinearUploadLevels(TileSizeOffset* level_sizes, uint32_t fmt, uint64_t height,
|
||||
uint64_t levels, uint32_t base_pitch) {
|
||||
uint64_t SetLinearUploadLevels(TileSizeOffset* level_sizes, uint32_t fmt, uint64_t height,
|
||||
uint64_t levels, uint32_t base_pitch) {
|
||||
uint64_t offset = 0;
|
||||
auto pitch = base_pitch;
|
||||
auto h = static_cast<uint32_t>(height);
|
||||
@@ -655,6 +293,8 @@ static uint64_t SetLinearUploadLevels(TileSizeOffset* level_sizes, uint32_t fmt,
|
||||
return offset;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TextureUploadLayout TextureCalcUploadLayout(uint32_t fmt, uint64_t width, uint64_t height,
|
||||
uint64_t levels, uint32_t depth, uint64_t pitch,
|
||||
uint64_t tile, uint64_t upload_size,
|
||||
@@ -663,6 +303,7 @@ TextureUploadLayout TextureCalcUploadLayout(uint32_t fmt, uint64_t width, uint64
|
||||
TextureUploadLayout layout {};
|
||||
layout.tile = static_cast<uint32_t>(tile);
|
||||
layout.pitch = static_cast<uint32_t>(pitch);
|
||||
layout.texel_block = Prospero::BlockCompressedBytesPerBlock(fmt) != 0 ? 4u : 1u;
|
||||
layout.volume_texture = volume_texture;
|
||||
|
||||
if (fmt != 0) {
|
||||
@@ -752,12 +393,10 @@ TextureUploadLayout TextureCalcUploadLayout(uint32_t fmt, uint64_t width, uint64
|
||||
return layout;
|
||||
}
|
||||
|
||||
std::vector<BufferImageCopy> TextureBuildUploadRegions(const TextureUploadLayout& layout,
|
||||
vk::Format image_format, uint32_t width,
|
||||
uint32_t height, uint32_t depth,
|
||||
uint64_t levels, bool array_texture,
|
||||
bool volume_texture,
|
||||
TextureUploadDestination destination) {
|
||||
std::vector<vk::BufferImageCopy>
|
||||
TextureBuildImageCopies(const TextureUploadLayout& layout, uint32_t width, uint32_t height,
|
||||
uint32_t depth, uint64_t levels, bool array_texture,
|
||||
bool volume_texture) {
|
||||
uint32_t mip_width = width;
|
||||
uint32_t mip_height = height;
|
||||
uint32_t mip_pitch = volume_texture && static_cast<Prospero::TileMode>(layout.tile) !=
|
||||
@@ -765,53 +404,34 @@ std::vector<BufferImageCopy> TextureBuildUploadRegions(const TextureUploadLayout
|
||||
? width
|
||||
: layout.pitch;
|
||||
|
||||
std::vector<BufferImageCopy> regions;
|
||||
std::vector<vk::BufferImageCopy> regions;
|
||||
regions.reserve(GetTextureRegionCount(depth, levels, volume_texture));
|
||||
for (uint32_t i = 0; i < levels; i++) {
|
||||
EXIT_NOT_IMPLEMENTED(layout.level_sizes[i].size == 0);
|
||||
|
||||
const auto mipmap_offset = Transfer::MipmapAtlasOffset(i, width, height);
|
||||
const auto mip_depth = GetTextureLevelDepth(depth, i, volume_texture);
|
||||
const auto mip_depth = GetTextureLevelDepth(depth, i, volume_texture);
|
||||
|
||||
for (uint32_t z = 0; z < mip_depth; z++) {
|
||||
const auto slice_offset = z * layout.slice_stride;
|
||||
BufferImageCopy region {};
|
||||
|
||||
region.offset = static_cast<uint32_t>(layout.level_sizes[i].offset + slice_offset);
|
||||
region.width = mip_width;
|
||||
region.height = mip_height;
|
||||
region.copy_height =
|
||||
(!array_texture && !volume_texture && depth > 1 && levels > 1 &&
|
||||
Transfer::IsBlockCompressedFormat(image_format)
|
||||
? TextureGetAtlasSliceYStride(image_format, mip_height, depth, levels)
|
||||
: 0);
|
||||
region.dst_layer = (array_texture ? z : 0);
|
||||
region.dst_z = (volume_texture ? static_cast<int>(z) : 0);
|
||||
if (!layout.volume_texture &&
|
||||
static_cast<Prospero::TileMode>(layout.tile) == Prospero::TileMode::kLinear &&
|
||||
layout.padded_sizes[i].width != 0) {
|
||||
region.pitch = layout.padded_sizes[i].width;
|
||||
const auto slice_offset = z * layout.slice_stride;
|
||||
vk::BufferImageCopy region {};
|
||||
region.bufferOffset =
|
||||
layout.level_sizes[i].offset + slice_offset;
|
||||
region.imageSubresource = {vk::ImageAspectFlagBits::eColor, i,
|
||||
array_texture ? z : 0, 1};
|
||||
region.imageOffset.z = volume_texture ? static_cast<int>(z) : 0;
|
||||
region.imageExtent = {mip_width, mip_height, 1};
|
||||
const bool linear =
|
||||
static_cast<Prospero::TileMode>(layout.tile) == Prospero::TileMode::kLinear;
|
||||
if (linear) {
|
||||
region.bufferRowLength = layout.padded_sizes[i].width;
|
||||
region.bufferImageHeight = layout.padded_sizes[i].height;
|
||||
} else {
|
||||
region.pitch = mip_pitch;
|
||||
}
|
||||
|
||||
if (destination == TextureUploadDestination::MipLevels) {
|
||||
region.dst_level = i;
|
||||
region.dst_x = 0;
|
||||
region.dst_y =
|
||||
(array_texture || volume_texture
|
||||
? 0
|
||||
: static_cast<int>(z * TextureGetAtlasSliceYStride(
|
||||
image_format, mip_height, depth, levels)));
|
||||
} else {
|
||||
region.dst_level = 0;
|
||||
region.dst_x = mipmap_offset.first;
|
||||
region.dst_y =
|
||||
(array_texture || volume_texture
|
||||
? mipmap_offset.second
|
||||
: mipmap_offset.second +
|
||||
static_cast<int>(z * TextureGetAtlasSliceYStride(
|
||||
image_format, mip_height, depth, levels)));
|
||||
const auto align = [](uint32_t value, uint32_t block) {
|
||||
return ((value + block - 1u) / block) * block;
|
||||
};
|
||||
const auto pitch = align(mip_pitch, layout.texel_block);
|
||||
region.bufferRowLength =
|
||||
pitch > align(mip_width, layout.texel_block) ? pitch : 0;
|
||||
}
|
||||
regions.push_back(region);
|
||||
}
|
||||
@@ -830,55 +450,6 @@ std::vector<BufferImageCopy> TextureBuildUploadRegions(const TextureUploadLayout
|
||||
return regions;
|
||||
}
|
||||
|
||||
std::vector<ImageBufferCopy>
|
||||
TextureBuildDownloadRegions(const std::vector<BufferImageCopy>& upload_regions) {
|
||||
std::vector<ImageBufferCopy> regions;
|
||||
regions.reserve(upload_regions.size());
|
||||
for (const auto& region: upload_regions) {
|
||||
regions.push_back({region.offset, region.pitch, region.dst_level, region.width,
|
||||
region.height, region.copy_height, region.dst_layer, region.dst_x,
|
||||
region.dst_y, region.dst_z, region.aspect});
|
||||
}
|
||||
return regions;
|
||||
}
|
||||
|
||||
static uint64_t FmaskRegionCopySize(const BufferImageCopy& region) {
|
||||
const uint64_t row_length = (region.pitch != 0 ? region.pitch : region.width);
|
||||
if (region.height == 0 || region.width == 0) {
|
||||
return 0;
|
||||
}
|
||||
return ((static_cast<uint64_t>(region.height - 1u) * row_length) + region.width) *
|
||||
sizeof(uint32_t);
|
||||
}
|
||||
|
||||
static void UploadFmaskIdentity(VulkanImage& vk_obj,
|
||||
const std::vector<BufferImageCopy>& regions,
|
||||
vk::ImageLayout dst_layout, const char* owner) {
|
||||
constexpr uint32_t kIdentityFmaskPattern = 0x76543210u;
|
||||
|
||||
std::vector<BufferImageCopy> upload_regions = regions;
|
||||
uint64_t upload_size = 0;
|
||||
for (auto& region: upload_regions) {
|
||||
upload_size = (upload_size + 255u) & ~uint64_t {255};
|
||||
EXIT_NOT_IMPLEMENTED(upload_size > UINT32_MAX);
|
||||
region.offset = static_cast<uint32_t>(upload_size);
|
||||
upload_size += FmaskRegionCopySize(region);
|
||||
}
|
||||
|
||||
LOGF("%s: temporary: decoding PS5 FMASK8_S4_F4 as identity pattern 0x%08" PRIx32
|
||||
", upload_size=%" PRIu64 " regions=%zu\n",
|
||||
owner, kIdentityFmaskPattern, upload_size, upload_regions.size());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Transfer::UploadImage(vk_obj, temp_buf.Data(), upload_size, upload_regions,
|
||||
dst_layout);
|
||||
}
|
||||
|
||||
struct GpuTileElementLayout {
|
||||
uint32_t bytes = 0;
|
||||
uint32_t wide = 1;
|
||||
@@ -905,7 +476,8 @@ static bool SetGpuTileSize(uint64_t offset, uint64_t length, uint64_t capacity,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>& regions,
|
||||
bool TextureBuildGpuTileInfos(uint64_t size,
|
||||
const std::vector<vk::BufferImageCopy>& regions,
|
||||
const TextureUploadLayout& layout, uint32_t fmt, uint32_t depth,
|
||||
uint64_t levels, std::vector<GpuTileInfo>& out_infos) {
|
||||
if (size == 0 || levels == 0 || levels > 16 || depth == 0 ||
|
||||
@@ -929,7 +501,8 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
|
||||
infos.reserve(regions.size());
|
||||
if (layout.volume_texture) {
|
||||
TileVolumeLayout volume {};
|
||||
if (!TileGetTextureVolumeLayout(fmt, regions[0].width, regions[0].height, depth,
|
||||
if (!TileGetTextureVolumeLayout(fmt, regions[0].imageExtent.width,
|
||||
regions[0].imageExtent.height, depth,
|
||||
static_cast<uint32_t>(levels), layout.tile, volume)) {
|
||||
return false;
|
||||
}
|
||||
@@ -945,10 +518,16 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
|
||||
for (uint32_t z = 0; z < mip_depth; z += block.block_depth) {
|
||||
const uint32_t copy_depth = std::min(block.block_depth, mip_depth - z);
|
||||
const auto& region = regions[region_base + z];
|
||||
const auto pitch = region.bufferRowLength != 0
|
||||
? region.bufferRowLength
|
||||
: region.imageExtent.width;
|
||||
const auto logical_height = region.bufferImageHeight != 0
|
||||
? region.bufferImageHeight
|
||||
: region.imageExtent.height;
|
||||
GpuTileInfo info {};
|
||||
info.family = block.family;
|
||||
info.bytes_per_element = block.bytes_per_element;
|
||||
info.linear_offset = region.offset;
|
||||
info.linear_offset = region.bufferOffset;
|
||||
info.tiled_offset =
|
||||
static_cast<uint64_t>(z / block.block_depth) * volume.block_slice_size +
|
||||
volume.level_offsets[level];
|
||||
@@ -961,11 +540,16 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
|
||||
return false;
|
||||
}
|
||||
info.linear_slice_stride = linear_stride;
|
||||
info.width = std::max((region.width + element.wide - 1u) / element.wide, 1u);
|
||||
info.height = std::max((region.height + element.tall - 1u) / element.tall, 1u);
|
||||
info.width = std::max(
|
||||
(region.imageExtent.width + element.wide - 1u) / element.wide, 1u);
|
||||
info.height = std::max(
|
||||
(logical_height + element.tall - 1u) / element.tall, 1u);
|
||||
info.depth = copy_depth;
|
||||
info.surface_z = block.block_depth == 1 ? static_cast<uint32_t>(region.dst_z) : 0;
|
||||
info.pitch = std::max((region.pitch + element.wide - 1u) / element.wide, 1u);
|
||||
info.surface_z = block.block_depth == 1
|
||||
? static_cast<uint32_t>(region.imageOffset.z)
|
||||
: 0;
|
||||
info.pitch =
|
||||
std::max((pitch + element.wide - 1u) / element.wide, 1u);
|
||||
info.tail_x = tail ? volume.tail_x[level] : 0;
|
||||
info.tail_y = tail ? volume.tail_y[level] : 0;
|
||||
info.tail = tail;
|
||||
@@ -993,23 +577,32 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
|
||||
const auto level_depth = GetTextureLevelDepth(depth, level, layout.volume_texture);
|
||||
for (uint32_t z = 0; z < level_depth; z++) {
|
||||
const auto& region = regions[region_index++];
|
||||
const auto pitch = region.bufferRowLength != 0
|
||||
? region.bufferRowLength
|
||||
: region.imageExtent.width;
|
||||
const auto logical_height = region.bufferImageHeight != 0
|
||||
? region.bufferImageHeight
|
||||
: region.imageExtent.height;
|
||||
GpuTileInfo info {};
|
||||
info.family = block.family;
|
||||
info.bytes_per_element = block.bytes_per_element;
|
||||
info.linear_offset = region.offset;
|
||||
info.linear_offset = region.bufferOffset;
|
||||
info.tiled_offset = TextureUploadSliceSourceOffset(layout, level, z);
|
||||
if (!SetGpuTileSize(info.linear_offset, level_size.size, size, info.linear_size) ||
|
||||
!SetGpuTileSize(info.tiled_offset, GetLevelSrcSize(level_size), size,
|
||||
info.tiled_size)) {
|
||||
return false;
|
||||
}
|
||||
info.width = std::max((region.width + element.wide - 1u) / element.wide, 1u);
|
||||
info.height = std::max((region.height + element.tall - 1u) / element.tall, 1u);
|
||||
info.width = std::max(
|
||||
(region.imageExtent.width + element.wide - 1u) / element.wide, 1u);
|
||||
info.height = std::max(
|
||||
(logical_height + element.tall - 1u) / element.tall, 1u);
|
||||
info.surface_z = base_family == TileBlockFamily::RenderTarget64KB ||
|
||||
base_family == TileBlockFamily::Depth64KB
|
||||
? region.dst_layer
|
||||
? region.imageSubresource.baseArrayLayer
|
||||
: 0;
|
||||
info.pitch = std::max((region.pitch + element.wide - 1u) / element.wide, 1u);
|
||||
info.pitch =
|
||||
std::max((pitch + element.wide - 1u) / element.wide, 1u);
|
||||
info.tail = tail;
|
||||
info.tail_x = tail ? level_size.x : 0;
|
||||
info.tail_y = tail ? level_size.y : 0;
|
||||
@@ -1037,32 +630,4 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextureUploadGuestImage(VulkanImage& vk_obj, const void* src_data,
|
||||
uint64_t size, const std::vector<BufferImageCopy>& regions,
|
||||
const TextureUploadLayout& layout, uint32_t fmt, uint64_t width,
|
||||
uint64_t height, uint32_t depth, uint64_t levels, const char* owner,
|
||||
vk::ImageLayout dst_layout) {
|
||||
if (fmt == 0) {
|
||||
EXIT("%s: texture upload format unsupported: fmt=0 tile=%u size=%" PRIu64 " extent=%" PRIu64
|
||||
"x%" PRIu64 " depth=%u pitch=%u levels=%" PRIu64 "\n",
|
||||
owner, layout.tile, size, width, height, depth, layout.pitch, levels);
|
||||
}
|
||||
if (static_cast<Prospero::TileMode>(layout.tile) == Prospero::TileMode::kLinear) {
|
||||
Transfer::UploadImage(vk_obj, src_data, size, regions, dst_layout);
|
||||
return;
|
||||
}
|
||||
if (layout.tile_family == TileBlockFamily::Depth64KB && Prospero::IsFmaskTextureFormat(fmt)) {
|
||||
UploadFmaskIdentity(vk_obj, regions, dst_layout, owner);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<GpuTileInfo> infos;
|
||||
if (!TextureBuildGpuTileInfos(size, regions, layout, fmt, depth, levels, infos)) {
|
||||
EXIT("%s: GPU tiled upload unsupported: fmt=%u tile=%u size=%" PRIu64 " extent=%" PRIu64
|
||||
"x%" PRIu64 " depth=%u pitch=%u levels=%" PRIu64 "\n",
|
||||
owner, fmt, layout.tile, size, width, height, depth, layout.pitch, levels);
|
||||
}
|
||||
Transfer::UploadTiledImage(vk_obj, src_data, size, size, infos, regions, dst_layout);
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
Reference in new issue
Block a user