mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-24 12:56:53 +02:00
format source files
This commit is contained in:
@@ -683,8 +683,8 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
|
||||
// host page protection is irrelevant.
|
||||
if (is_read && !is_written && size <= CACHING_PAGE_SIZE &&
|
||||
!m_memory_tracker.IsRegionGpuModified(vaddr, size) &&
|
||||
m_memory_tracker.IsRegionCpuModified(vaddr, size) &&
|
||||
!texture_region.gpu_image_bytes && !texture_region.gpu_metadata_bytes) {
|
||||
m_memory_tracker.IsRegionCpuModified(vaddr, size) && !texture_region.gpu_image_bytes &&
|
||||
!texture_region.gpu_metadata_bytes) {
|
||||
std::array<uint8_t, CACHING_PAGE_SIZE> guest_data;
|
||||
if (Libs::LibKernel::Memory::TryReadBacking(vaddr, guest_data.data(), size)) {
|
||||
VulkanBuffer* stream_buffer = nullptr;
|
||||
@@ -1143,10 +1143,10 @@ void BufferCache::CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64
|
||||
bool dst_image_transition = false;
|
||||
{
|
||||
std::lock_guard transaction(m_resource_mutex);
|
||||
const auto src_region = m_texture_cache->QueryRegion(src_vaddr, size);
|
||||
const auto dst_region = m_texture_cache->QueryRegion(dst_vaddr, size);
|
||||
const bool src_image_gpu = src_region.gpu_image_bytes;
|
||||
const bool src_meta = src_region.metadata_bytes;
|
||||
const auto src_region = m_texture_cache->QueryRegion(src_vaddr, size);
|
||||
const auto dst_region = m_texture_cache->QueryRegion(dst_vaddr, size);
|
||||
const bool src_image_gpu = src_region.gpu_image_bytes;
|
||||
const bool src_meta = src_region.metadata_bytes;
|
||||
if (src_region.non_sampled_pages) {
|
||||
EXIT("BufferCache: GPU copy aliases target pages, src=0x%016" PRIx64
|
||||
" dst=0x%016" PRIx64 " size=0x%016" PRIx64 "\n",
|
||||
@@ -1174,7 +1174,7 @@ void BufferCache::CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64
|
||||
" dst=0x%016" PRIx64 " size=0x%016" PRIx64 "\n",
|
||||
src_vaddr, dst_vaddr, size);
|
||||
}
|
||||
dst_image_transition = m_texture_cache->InvalidateMemoryFromGPU(dst_vaddr, size);
|
||||
dst_image_transition = m_texture_cache->InvalidateMemoryFromGPU(dst_vaddr, size);
|
||||
const auto transitioned_dst = m_texture_cache->QueryRegion(dst_vaddr, size);
|
||||
// A clean target destination is handled above like a protected host write. Target
|
||||
// aliases that require an actual GPU buffer copy remain unsupported.
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
#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/debug.h"
|
||||
#include "graphics/host_gpu/renderer/descriptorCache.h"
|
||||
#include "graphics/host_gpu/renderer/framebufferCache.h"
|
||||
#include "graphics/host_gpu/renderer/render.h"
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
@@ -374,11 +374,11 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
|
||||
r->color_clear_enable = false;
|
||||
r->color_clear_value = {};
|
||||
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
uint32_t pitch = 0;
|
||||
uint64_t size = 0;
|
||||
bool tile = false;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
uint32_t pitch = 0;
|
||||
uint64_t size = 0;
|
||||
bool tile = false;
|
||||
const bool standard64 =
|
||||
rt.attrib3.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kStandard64KB);
|
||||
|
||||
@@ -402,9 +402,8 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
|
||||
}
|
||||
if (standard64 &&
|
||||
(rt.attrib3.dimension != 1 || rt.attrib3.depth != 0 || levels != 1 ||
|
||||
rt.view.current_mip_level != 0 ||
|
||||
view.base_layer != 0 || view.image_layers != 1 || rt.attrib.num_samples != 0 ||
|
||||
rt.attrib.num_fragments != 0 || bytes_per_element != 4 ||
|
||||
rt.view.current_mip_level != 0 || view.base_layer != 0 || view.image_layers != 1 ||
|
||||
rt.attrib.num_samples != 0 || rt.attrib.num_fragments != 0 || bytes_per_element != 4 ||
|
||||
rt.pitch.pitch_div8_minus1 != 0 || (rt.base.addr & 0xffffu) != 0 ||
|
||||
rt.info.fmask_compression_enable || rt.info.fmask_data_compression_disable ||
|
||||
rt.info.fmask_one_frag_mode || rt.info.cmask_fast_clear_enable ||
|
||||
@@ -415,9 +414,8 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
|
||||
" dimension=%u depth=%u levels=%u layer=%u/%u samples=%u fragments=%u bpe=%u"
|
||||
" cmask=0x%016" PRIx64 " fmask=0x%016" PRIx64 " dcc=0x%016" PRIx64 "\n",
|
||||
rt.base.addr, rt.attrib3.dimension, rt.attrib3.depth, levels, view.base_layer,
|
||||
view.image_layers,
|
||||
rt.attrib.num_samples, rt.attrib.num_fragments, bytes_per_element, rt.cmask.addr,
|
||||
rt.fmask.addr, rt.dcc_addr.addr);
|
||||
view.image_layers, rt.attrib.num_samples, rt.attrib.num_fragments, bytes_per_element,
|
||||
rt.cmask.addr, rt.fmask.addr, rt.dcc_addr.addr);
|
||||
}
|
||||
if (rt.pitch.pitch_div8_minus1 != 0) {
|
||||
pitch = (rt.pitch.pitch_div8_minus1 + 1u) << 3u;
|
||||
@@ -438,7 +436,8 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
|
||||
bool valid_layout = false;
|
||||
if (standard64) {
|
||||
TileGetTextureSize(Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float), width,
|
||||
height, pitch, levels, rt.attrib3.tile_mode, &layout, nullptr, nullptr);
|
||||
height, pitch, levels, rt.attrib3.tile_mode, &layout, nullptr,
|
||||
nullptr);
|
||||
valid_layout = layout.size != 0 && layout.align == 65536;
|
||||
} else {
|
||||
valid_layout =
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
#include "common/emulatorConfig.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "graphics/guest_gpu/hardwareContext.h"
|
||||
#include "graphics/guest_gpu/gpu_defs.h"
|
||||
#include "graphics/guest_gpu/hardwareContext.h"
|
||||
#include "graphics/host_gpu/renderer/render.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
@@ -129,10 +129,9 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H
|
||||
// DB_DEPTH_SIZE_XY is independent state and may remain programmed after the attachment
|
||||
// formats and addresses are unbound. A zero encoding is the valid 1x1 value, so its
|
||||
// presence alone must not manufacture a depth attachment.
|
||||
!z.z_info.tile_surface_enable && !z.width_height_valid &&
|
||||
!z.pitch_height_valid && z.size.x_max == 0 && z.size.y_max == 0 &&
|
||||
z.pitch_div8_minus1 == 0 && z.height_div8_minus1 == 0 && z.slice_div64_minus1 == 0 &&
|
||||
z.width == 0 && z.height == 0;
|
||||
!z.z_info.tile_surface_enable && !z.width_height_valid && !z.pitch_height_valid &&
|
||||
z.size.x_max == 0 && z.size.y_max == 0 && z.pitch_div8_minus1 == 0 &&
|
||||
z.height_div8_minus1 == 0 && z.slice_div64_minus1 == 0 && z.width == 0 && z.height == 0;
|
||||
if (attachment_unbound) {
|
||||
static std::atomic_bool logged = false;
|
||||
if (!logged.exchange(true, std::memory_order_relaxed)) {
|
||||
|
||||
@@ -148,61 +148,61 @@ NativeSamplerDescriptor(const ShaderRecompiler::IR::DescriptorValue& descriptor)
|
||||
}
|
||||
|
||||
static BufferView NativeStorageBuffer(uint64_t submit_id, CommandBuffer* command_buffer,
|
||||
const ShaderBufferResource& descriptor,
|
||||
const ShaderRecompiler::IR::BufferResource& resource) {
|
||||
const ShaderBufferResource& descriptor,
|
||||
const ShaderRecompiler::IR::BufferResource& resource) {
|
||||
BufferView result;
|
||||
|
||||
//Regression
|
||||
// Bind a null buffer when these four dwords are
|
||||
// the tracked prefix of an active image sharp. Image validity is encoded by dword 3 bit 31.
|
||||
// Regression
|
||||
// Bind a null buffer when these four dwords are
|
||||
// the tracked prefix of an active image sharp. Image validity is encoded by dword 3 bit 31.
|
||||
/*if (resource.image_alias != ShaderRecompiler::IR::BufferResource::NoImageAlias &&
|
||||
(descriptor.Type() & 2u) != 0) {
|
||||
BindNullStorageBuffer(command_buffer, &result);
|
||||
return result;
|
||||
BindNullStorageBuffer(command_buffer, &result);
|
||||
return result;
|
||||
}
|
||||
// Buffer TYPE is zero. A nonzero value means a buffer instruction received the first four
|
||||
// dwords of an image sharp without a tracked image alias; support the known write-only path.
|
||||
if (descriptor.Type() != 0) {
|
||||
ShaderTextureResource texture {};
|
||||
std::copy_n(descriptor.fields, 4, texture.fields);
|
||||
const auto width = static_cast<uint32_t>(texture.Width5()) + 1u;
|
||||
const auto height = static_cast<uint32_t>(texture.Height5()) + 1u;
|
||||
const auto format = texture.Format();
|
||||
const auto tile = texture.TileMode();
|
||||
const auto type = texture.Type();
|
||||
const auto address = texture.Base40();
|
||||
const auto pitch = TileGetTexturePitch(format, width, 1, tile);
|
||||
TileSizeAlign footprint {};
|
||||
TileGetTextureTotalSize(format, width, height, 1, pitch, 1, tile, false, &footprint);
|
||||
const bool supported =
|
||||
resource.formatted && resource.written && !resource.read && !resource.atomic &&
|
||||
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8UInt) &&
|
||||
tile == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) &&
|
||||
type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) &&
|
||||
texture.DstSelXYZW() == DstSel(4, 5, 6, 7) && address != 0 && footprint.size != 0 &&
|
||||
footprint.align == 65536;
|
||||
if (!supported) {
|
||||
EXIT("unsupported texture descriptor used as storage buffer: type=%u format=%u"
|
||||
" tile=%u swizzle=0x%03x extent=%ux%u read=%d written=%d formatted=%d atomic=%d\n",
|
||||
type, format, tile, texture.DstSelXYZW(), width, height, resource.read,
|
||||
resource.written, resource.formatted, resource.atomic);
|
||||
}
|
||||
auto* ctx = g_render_ctx->GetGraphicCtx();
|
||||
g_render_ctx->GetBufferCache()->ValidateGpuAccess(address, footprint.size, false, true);
|
||||
auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer(
|
||||
command_buffer, ctx, address, footprint.size, true, false, true);
|
||||
const auto alignment = ctx->StorageMinAlignment();
|
||||
if (alignment == 0 || binding.second % alignment != 0 ||
|
||||
footprint.size > ctx->GetPhysicalDeviceProperties().limits.maxStorageBufferRange) {
|
||||
EXIT("texture-backed storage buffer binding is unsupported: addr=0x%016" PRIx64
|
||||
" size=0x%016" PRIx64 " offset=0x%016" PRIx64 " alignment=0x%016" PRIx64 "\n",
|
||||
address, footprint.size, static_cast<uint64_t>(binding.second),
|
||||
static_cast<uint64_t>(alignment));
|
||||
}
|
||||
result.buffer = binding.first;
|
||||
result.offset = binding.second;
|
||||
result.range = footprint.size;
|
||||
return result;
|
||||
ShaderTextureResource texture {};
|
||||
std::copy_n(descriptor.fields, 4, texture.fields);
|
||||
const auto width = static_cast<uint32_t>(texture.Width5()) + 1u;
|
||||
const auto height = static_cast<uint32_t>(texture.Height5()) + 1u;
|
||||
const auto format = texture.Format();
|
||||
const auto tile = texture.TileMode();
|
||||
const auto type = texture.Type();
|
||||
const auto address = texture.Base40();
|
||||
const auto pitch = TileGetTexturePitch(format, width, 1, tile);
|
||||
TileSizeAlign footprint {};
|
||||
TileGetTextureTotalSize(format, width, height, 1, pitch, 1, tile, false, &footprint);
|
||||
const bool supported =
|
||||
resource.formatted && resource.written && !resource.read && !resource.atomic &&
|
||||
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8UInt) &&
|
||||
tile == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) &&
|
||||
type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) &&
|
||||
texture.DstSelXYZW() == DstSel(4, 5, 6, 7) && address != 0 && footprint.size != 0 &&
|
||||
footprint.align == 65536;
|
||||
if (!supported) {
|
||||
EXIT("unsupported texture descriptor used as storage buffer: type=%u format=%u"
|
||||
" tile=%u swizzle=0x%03x extent=%ux%u read=%d written=%d formatted=%d atomic=%d\n",
|
||||
type, format, tile, texture.DstSelXYZW(), width, height, resource.read,
|
||||
resource.written, resource.formatted, resource.atomic);
|
||||
}
|
||||
auto* ctx = g_render_ctx->GetGraphicCtx();
|
||||
g_render_ctx->GetBufferCache()->ValidateGpuAccess(address, footprint.size, false, true);
|
||||
auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer(
|
||||
command_buffer, ctx, address, footprint.size, true, false, true);
|
||||
const auto alignment = ctx->StorageMinAlignment();
|
||||
if (alignment == 0 || binding.second % alignment != 0 ||
|
||||
footprint.size > ctx->GetPhysicalDeviceProperties().limits.maxStorageBufferRange) {
|
||||
EXIT("texture-backed storage buffer binding is unsupported: addr=0x%016" PRIx64
|
||||
" size=0x%016" PRIx64 " offset=0x%016" PRIx64 " alignment=0x%016" PRIx64 "\n",
|
||||
address, footprint.size, static_cast<uint64_t>(binding.second),
|
||||
static_cast<uint64_t>(alignment));
|
||||
}
|
||||
result.buffer = binding.first;
|
||||
result.offset = binding.second;
|
||||
result.range = footprint.size;
|
||||
return result;
|
||||
}*/
|
||||
const auto address = descriptor.Base48();
|
||||
const auto stride = descriptor.Stride();
|
||||
@@ -299,9 +299,9 @@ static bool IsSupportedSampledColorResource(const ShaderRecompiler::IR::ImageRes
|
||||
!resource.written && !resource.atomic && !resource.depth_compare;
|
||||
}
|
||||
|
||||
TargetTextureViewInfo
|
||||
ResolveTargetTextureView(const ShaderRecompiler::IR::ImageResource& resource,
|
||||
Prospero::ImageType type, uint32_t base_layer, uint32_t image_layers) {
|
||||
TargetTextureViewInfo ResolveTargetTextureView(const ShaderRecompiler::IR::ImageResource& resource,
|
||||
Prospero::ImageType type, uint32_t base_layer,
|
||||
uint32_t image_layers) {
|
||||
switch (type) {
|
||||
case Prospero::ImageType::kColor2D:
|
||||
return resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D &&
|
||||
@@ -338,16 +338,15 @@ bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor,
|
||||
const auto height = static_cast<uint32_t>(descriptor.Height5()) + 1u;
|
||||
const auto pitch = TileGetTexturePitch(descriptor.Format(), width, 1, descriptor.TileMode());
|
||||
const auto type = static_cast<Prospero::ImageType>(descriptor.Type());
|
||||
const bool supported_type = type == Prospero::ImageType::kColor2D ||
|
||||
type == Prospero::ImageType::kColor2DArray;
|
||||
const bool supported_type =
|
||||
type == Prospero::ImageType::kColor2D || type == Prospero::ImageType::kColor2DArray;
|
||||
return image.type == VulkanImageType::DepthStencil && image.layers == 1 &&
|
||||
width == image.extent.width && height == image.extent.height &&
|
||||
descriptor.Depth() == 0 && descriptor.BaseLevel() == 0 && descriptor.LastLevel() == 0 &&
|
||||
descriptor.MaxMip() == 0 && descriptor.MinLod() == 0 && descriptor.BaseArray5() == 0 &&
|
||||
descriptor.TileMode() == Prospero::GpuEnumValue(Prospero::TileMode::kDepth) &&
|
||||
supported_type &&
|
||||
descriptor.BCSwizzle() == 0 && !descriptor.MsaaDepth() && pitch >= width &&
|
||||
pitch == image.guest_pitch;
|
||||
supported_type && descriptor.BCSwizzle() == 0 && !descriptor.MsaaDepth() &&
|
||||
pitch >= width && pitch == image.guest_pitch;
|
||||
}
|
||||
|
||||
static bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor) {
|
||||
@@ -355,13 +354,13 @@ static bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descrip
|
||||
constexpr uint32_t field2_reserved_mask = 0xf0003000u;
|
||||
constexpr uint32_t field3_common = 0x01800000u;
|
||||
constexpr uint32_t field5_expected = 0x00700000u;
|
||||
const uint32_t field3_expected =
|
||||
const uint32_t field3_expected =
|
||||
(descriptor.Type() << 28u) | field3_common | descriptor.DstSelXYZW();
|
||||
return (descriptor.fields[1] & field1_reserved_mask) == 0 &&
|
||||
(descriptor.fields[2] & field2_reserved_mask) == 0 &&
|
||||
descriptor.fields[3] == field3_expected &&
|
||||
descriptor.fields[4] == 0 && descriptor.fields[5] == field5_expected &&
|
||||
descriptor.fields[6] == 0 && descriptor.fields[7] == 0;
|
||||
descriptor.fields[3] == field3_expected && descriptor.fields[4] == 0 &&
|
||||
descriptor.fields[5] == field5_expected && descriptor.fields[6] == 0 &&
|
||||
descriptor.fields[7] == 0;
|
||||
}
|
||||
|
||||
static void ValidateDepthTargetBinding(const ShaderRecompiler::IR::ImageResource& resource,
|
||||
@@ -567,8 +566,8 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
|
||||
descriptor.MsaaDepth();
|
||||
if (image == nullptr) {
|
||||
if (check_depth) {
|
||||
image = g_render_ctx->GetTextureCache()->FindDepthTargetByRange(
|
||||
command_buffer, address, size.size, true);
|
||||
image = g_render_ctx->GetTextureCache()->FindDepthTargetByRange(command_buffer, address,
|
||||
size.size, true);
|
||||
} else {
|
||||
image = g_render_ctx->GetTextureCache()->FindRenderTargetByRange(command_buffer,
|
||||
address, size.size);
|
||||
@@ -594,7 +593,8 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
|
||||
resource, type, descriptor.BaseArray5(), image->layers);
|
||||
ValidateDepthTargetBinding(resource, descriptor, image, view_format, size.size);
|
||||
if (depth_view.type == VK_IMAGE_VIEW_TYPE_MAX_ENUM) {
|
||||
EXIT("unsupported sampled depth target view: dimension=%u descriptor_type=%u "
|
||||
EXIT("unsupported sampled depth target view: dimension=%u "
|
||||
"descriptor_type=%u "
|
||||
"base_array=%u image_layers=%u\n",
|
||||
static_cast<uint32_t>(resource.dimension), descriptor.Type(),
|
||||
descriptor.BaseArray5(), image->layers);
|
||||
|
||||
@@ -19,8 +19,7 @@ struct TargetTextureViewInfo {
|
||||
|
||||
[[nodiscard]] TargetTextureViewInfo
|
||||
ResolveTargetTextureView(const ShaderRecompiler::IR::ImageResource& resource,
|
||||
Prospero::ImageType type, uint32_t base_layer,
|
||||
uint32_t image_layers);
|
||||
Prospero::ImageType type, uint32_t base_layer, uint32_t image_layers);
|
||||
|
||||
[[nodiscard]] bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor,
|
||||
const VulkanImage& image);
|
||||
|
||||
@@ -34,7 +34,7 @@ DummyTextureCache::~DummyTextureCache() {
|
||||
}
|
||||
|
||||
VulkanImage* DummyTextureCache::Get(GraphicContext* ctx, Usage usage, bool uint_format,
|
||||
bool image_3d) {
|
||||
bool image_3d) {
|
||||
Common::LockGuard lock(m_mutex);
|
||||
if (ctx == nullptr) {
|
||||
EXIT("TextureCache: dummy texture requires a graphics context\n");
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Libs::Graphics {
|
||||
|
||||
class DummyTextureCache final {
|
||||
public:
|
||||
enum class Usage: uint8_t { Sampled, Storage };
|
||||
enum class Usage : uint8_t { Sampled, Storage };
|
||||
|
||||
DummyTextureCache() = default;
|
||||
~DummyTextureCache();
|
||||
|
||||
@@ -40,10 +40,9 @@ 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)) ||
|
||||
info.format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) ||
|
||||
info.format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float));
|
||||
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;
|
||||
}
|
||||
@@ -60,7 +59,8 @@ bool RenderTargetSupportsStorage(GraphicContext* ctx, VkFormat format, VkImageCr
|
||||
|
||||
VkImageCreateFlags RenderTargetCreateFlags(VkFormat format) {
|
||||
const bool compatible_format_view =
|
||||
IsRgba8SrgbViewFormat(format) || BgraToRgbaSampledViewFormat(format) != VK_FORMAT_UNDEFINED ||
|
||||
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
|
||||
@@ -69,7 +69,7 @@ VkImageCreateFlags RenderTargetCreateFlags(VkFormat format) {
|
||||
}
|
||||
|
||||
VkImageUsageFlags RenderTargetUsage(GraphicContext* ctx, VkFormat format,
|
||||
VkImageCreateFlags flags) {
|
||||
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) |
|
||||
@@ -107,8 +107,7 @@ static constexpr uint32_t DummyTextureSwizzle() {
|
||||
}
|
||||
|
||||
TextureImageCreateParams MakeDummyTextureParams(bool uint_format, bool image_3d,
|
||||
TextureFormatUsage usage,
|
||||
const char* owner) {
|
||||
TextureFormatUsage usage, const char* owner) {
|
||||
TextureImageCreateParams params {};
|
||||
params.fmt = static_cast<uint32_t>(
|
||||
Prospero::GpuEnumValue(uint_format ? Prospero::BufferFormat::k8_8_8_8UInt
|
||||
@@ -140,7 +139,7 @@ uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element) {
|
||||
}
|
||||
|
||||
GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info, bool storage,
|
||||
VulkanMemory* memory, VkComponentMapping* components) {
|
||||
VulkanMemory* memory, VkComponentMapping* components) {
|
||||
if (components == nullptr) {
|
||||
EXIT("TextureCache: invalid texture component output\n");
|
||||
}
|
||||
@@ -151,7 +150,7 @@ GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info,
|
||||
}
|
||||
|
||||
void CreateTextureViews(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info,
|
||||
bool storage, VkComponentMapping components) {
|
||||
bool storage, VkComponentMapping components) {
|
||||
if (storage) {
|
||||
TextureCreateImageViews(ctx, image, components, info.type, 0, 0, 1, info.depth, false,
|
||||
TextureFormatUsage::Sampled | TextureFormatUsage::Storage);
|
||||
@@ -162,8 +161,8 @@ void CreateTextureViews(GraphicContext* ctx, GpuTextureVulkanImage* image, const
|
||||
}
|
||||
|
||||
void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* image,
|
||||
const RenderTargetInfo& info, uint32_t base_layer,
|
||||
uint32_t layer_count, bool refresh) {
|
||||
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) {
|
||||
@@ -218,12 +217,12 @@ void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* ima
|
||||
}
|
||||
|
||||
void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image,
|
||||
const RenderTargetInfo& info, bool refresh) {
|
||||
const RenderTargetInfo& info, bool refresh) {
|
||||
UploadRenderTargetLayers(ctx, image, info, 0, info.layers, refresh);
|
||||
}
|
||||
|
||||
RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTargetInfo& info,
|
||||
VulkanMemory* memory) {
|
||||
VulkanMemory* memory) {
|
||||
auto* image = new RenderTextureVulkanImage;
|
||||
image->extent.width = info.width;
|
||||
image->extent.height = info.height;
|
||||
@@ -257,7 +256,7 @@ RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTa
|
||||
}
|
||||
|
||||
DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info,
|
||||
VulkanMemory* memory) {
|
||||
VulkanMemory* memory) {
|
||||
VkImageCreateInfo create {};
|
||||
create.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
create.imageType = VK_IMAGE_TYPE_2D;
|
||||
@@ -333,7 +332,7 @@ void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) {
|
||||
}
|
||||
|
||||
VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info,
|
||||
VulkanMemory* memory) {
|
||||
VulkanMemory* memory) {
|
||||
auto* image = new VideoOutVulkanImage;
|
||||
image->extent.width = info.width;
|
||||
image->extent.height = info.height;
|
||||
@@ -365,7 +364,7 @@ VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& inf
|
||||
}
|
||||
|
||||
void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const VideoOutInfo& info,
|
||||
bool refresh) {
|
||||
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",
|
||||
@@ -390,17 +389,17 @@ void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const Video
|
||||
}
|
||||
|
||||
GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format, bool image_3d,
|
||||
bool storage, VulkanMemory* memory) {
|
||||
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* 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);
|
||||
|
||||
@@ -23,26 +23,26 @@ struct Image final: ImageInfo {
|
||||
EXIT("dirty sampled image cannot be reassigned\n");
|
||||
}
|
||||
static_cast<ImageInfo&>(*this) = value;
|
||||
m_track_begin = address;
|
||||
m_track_end = address + size;
|
||||
m_maybe_cpu_hash_valid = false;
|
||||
m_track_begin = address;
|
||||
m_track_end = address + size;
|
||||
m_maybe_cpu_hash_valid = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void InvalidateCpuWrite(uint64_t vaddr, uint64_t size) {
|
||||
if (ImageRangeOverlaps(address, this->size, vaddr, size)) {
|
||||
m_cpu_dirty = true;
|
||||
m_maybe_cpu_dirty = false;
|
||||
m_cpu_dirty = true;
|
||||
m_maybe_cpu_dirty = false;
|
||||
m_maybe_cpu_hash_valid = false;
|
||||
m_track_begin = m_track_end;
|
||||
m_track_begin = m_track_end;
|
||||
} else if (ImagePageRangesOverlap(address, this->size, vaddr, size)) {
|
||||
constexpr uint64_t page_mask = 4096 - 1;
|
||||
if (vaddr + size <= address) {
|
||||
const auto next_page = (address + page_mask) & ~page_mask;
|
||||
m_track_begin = std::min(m_track_end, std::max(m_track_begin, next_page));
|
||||
m_track_begin = std::min(m_track_end, std::max(m_track_begin, next_page));
|
||||
} else if (vaddr >= address + this->size) {
|
||||
const auto page = (address + this->size) & ~page_mask;
|
||||
m_track_end = std::max(m_track_begin, std::min(m_track_end, page));
|
||||
m_track_end = std::max(m_track_begin, std::min(m_track_end, page));
|
||||
}
|
||||
m_maybe_cpu_dirty = m_track_begin == m_track_end;
|
||||
}
|
||||
@@ -82,27 +82,27 @@ struct Image final: ImageInfo {
|
||||
if (!IsCpuDirty()) {
|
||||
EXIT("clean sampled image cannot complete a refresh\n");
|
||||
}
|
||||
m_cpu_dirty = false;
|
||||
m_maybe_cpu_dirty = false;
|
||||
m_cpu_dirty = false;
|
||||
m_maybe_cpu_dirty = false;
|
||||
m_maybe_cpu_hash_valid = false;
|
||||
m_track_begin = address;
|
||||
m_track_end = address + size;
|
||||
m_track_begin = address;
|
||||
m_track_end = address + size;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_cpu_dirty = false;
|
||||
bool m_maybe_cpu_dirty = false;
|
||||
bool m_maybe_cpu_hash_valid = false;
|
||||
uint64_t m_track_begin = 0;
|
||||
uint64_t m_track_end = 0;
|
||||
uint64_t m_maybe_cpu_hash = 0;
|
||||
bool m_cpu_dirty = false;
|
||||
bool m_maybe_cpu_dirty = false;
|
||||
bool m_maybe_cpu_hash_valid = false;
|
||||
uint64_t m_track_begin = 0;
|
||||
uint64_t m_track_end = 0;
|
||||
uint64_t m_maybe_cpu_hash = 0;
|
||||
};
|
||||
|
||||
namespace ImageOps {
|
||||
|
||||
[[nodiscard]] GpuTextureVulkanImage*
|
||||
CreateTexture(GraphicContext* ctx, const ImageInfo& info, bool storage, VulkanMemory* memory,
|
||||
VkComponentMapping* components);
|
||||
[[nodiscard]] GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info,
|
||||
bool storage, VulkanMemory* memory,
|
||||
VkComponentMapping* components);
|
||||
void CreateTextureViews(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info,
|
||||
bool storage, VkComponentMapping components);
|
||||
|
||||
@@ -118,15 +118,15 @@ void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image,
|
||||
[[nodiscard]] DepthStencilVulkanImage*
|
||||
CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info, VulkanMemory* memory);
|
||||
|
||||
void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info);
|
||||
[[nodiscard]] VideoOutVulkanImage*
|
||||
CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info, VulkanMemory* memory);
|
||||
void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info);
|
||||
[[nodiscard]] VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info,
|
||||
VulkanMemory* memory);
|
||||
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);
|
||||
[[nodiscard]] GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format,
|
||||
bool image_3d, bool storage,
|
||||
VulkanMemory* memory);
|
||||
|
||||
void Destroy(GraphicContext* ctx, GpuTextureVulkanImage* image, VulkanMemory* memory);
|
||||
void Destroy(GraphicContext* ctx, RenderTextureVulkanImage* image, VulkanMemory* memory);
|
||||
|
||||
@@ -225,12 +225,7 @@ FindGuestDepthFormatPolicy(uint32_t guest_format) noexcept {
|
||||
: info.format == policy->depth_attachment_format);
|
||||
}
|
||||
|
||||
enum class VideoOutCompression : uint8_t {
|
||||
Uncompressed,
|
||||
Dcc256_256_0,
|
||||
Dcc256_64_64,
|
||||
Unsupported
|
||||
};
|
||||
enum class VideoOutCompression : uint8_t { Uncompressed, Dcc256_256_0, Dcc256_64_64, Unsupported };
|
||||
|
||||
struct VideoOutInfo {
|
||||
uint64_t address = 0;
|
||||
@@ -381,15 +376,16 @@ enum class BufferImageWrite : uint8_t {
|
||||
enum class StorageBufferRebind : uint8_t { Reuse, RefreshFromBacking, Unsupported };
|
||||
enum class MetaImageOverlap : uint8_t { RetainSampled, RetireTarget, Unsupported };
|
||||
|
||||
[[nodiscard]] inline constexpr uint32_t SelectImageBackingBaseLevel(bool storage,
|
||||
uint32_t view_base_level) {
|
||||
[[nodiscard]] inline constexpr uint32_t SelectImageBackingBaseLevel(bool storage,
|
||||
uint32_t view_base_level) {
|
||||
// Storage descriptors select a per-mip view of one full allocation. Backing creation must not
|
||||
// depend on which view happens to be bound first.
|
||||
return storage ? 0u : view_base_level;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr bool IsDepthUintTextureReinterpretation(
|
||||
VkFormat image_format, uint32_t guest_format, VkFormat view_format) noexcept {
|
||||
[[nodiscard]] inline constexpr bool
|
||||
IsDepthUintTextureReinterpretation(VkFormat image_format, uint32_t guest_format,
|
||||
VkFormat view_format) noexcept {
|
||||
switch (image_format) {
|
||||
case VK_FORMAT_D32_SFLOAT:
|
||||
return guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) &&
|
||||
@@ -399,7 +395,7 @@ enum class MetaImageOverlap : uint8_t { RetainSampled, RetireTarget, Unsupported
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr bool NeedsStaticSampledArrayView(bool shader_array,
|
||||
bool dynamic_view_selected) {
|
||||
bool dynamic_view_selected) {
|
||||
return shader_array && !dynamic_view_selected;
|
||||
}
|
||||
|
||||
@@ -429,8 +425,8 @@ SelectStorageSampledViewShape(uint32_t type, uint32_t depth, uint32_t backing_la
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr bool IsSupportedDisplayRenderTargetTileMode(
|
||||
uint32_t tile_mode) noexcept {
|
||||
[[nodiscard]] inline constexpr bool
|
||||
IsSupportedDisplayRenderTargetTileMode(uint32_t tile_mode) noexcept {
|
||||
return tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget);
|
||||
}
|
||||
|
||||
@@ -637,18 +633,16 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool IsRgba16UintFloatReinterpretation(VkFormat cached,
|
||||
VkFormat requested) noexcept {
|
||||
VkFormat requested) noexcept {
|
||||
switch (cached) {
|
||||
case VK_FORMAT_R16G16B16A16_SFLOAT:
|
||||
return requested == VK_FORMAT_R16G16B16A16_UINT;
|
||||
case VK_FORMAT_R16G16B16A16_UINT:
|
||||
return requested == VK_FORMAT_R16G16B16A16_SFLOAT;
|
||||
case VK_FORMAT_R16G16B16A16_SFLOAT: return requested == VK_FORMAT_R16G16B16A16_UINT;
|
||||
case VK_FORMAT_R16G16B16A16_UINT: return requested == VK_FORMAT_R16G16B16A16_SFLOAT;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool IsRgba8UnormUintReinterpretation(VkFormat cached,
|
||||
VkFormat requested) noexcept {
|
||||
VkFormat requested) noexcept {
|
||||
switch (cached) {
|
||||
case VK_FORMAT_R8G8B8A8_UNORM: return requested == VK_FORMAT_R8G8B8A8_UINT;
|
||||
case VK_FORMAT_R8G8B8A8_UINT: return requested == VK_FORMAT_R8G8B8A8_UNORM;
|
||||
@@ -656,7 +650,7 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool IsSampledDepthExpansion(const ImageInfo& sampled,
|
||||
[[nodiscard]] inline bool IsSampledDepthExpansion(const ImageInfo& sampled,
|
||||
const DepthTargetInfo& target) noexcept {
|
||||
const bool array_expansion =
|
||||
sampled.type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) &&
|
||||
@@ -664,14 +658,13 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
|
||||
sampled.size == target.size * sampled.depth && sampled.width == target.width &&
|
||||
sampled.height == target.height && sampled.pitch == target.pitch;
|
||||
return sampled.address == target.address && sampled.size > target.size &&
|
||||
sampled.format == target.guest_format &&
|
||||
target.format == VK_FORMAT_D32_SFLOAT &&
|
||||
sampled.format == target.guest_format && target.format == VK_FORMAT_D32_SFLOAT &&
|
||||
target.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float) &&
|
||||
target.bytes_per_element == 4 && target.stencil_address == 0 &&
|
||||
target.stencil_size == 0 && target.htile_address == 0 && target.htile_size == 0 &&
|
||||
target.layers == 1 && array_expansion &&
|
||||
sampled.base_level == 0 && sampled.levels == 1 && sampled.view_levels == 1 &&
|
||||
sampled.tile == target.tile_mode && sampled.base_array == 0;
|
||||
target.layers == 1 && array_expansion && sampled.base_level == 0 &&
|
||||
sampled.levels == 1 && sampled.view_levels == 1 && sampled.tile == target.tile_mode &&
|
||||
sampled.base_array == 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline StorageSampledOverlap
|
||||
@@ -776,8 +769,8 @@ ClassifyBufferImageWrite(uint64_t buffer_address, uint64_t buffer_size, uint64_t
|
||||
|
||||
[[nodiscard]] inline StorageBufferRebind
|
||||
ClassifyStorageBufferRebind(bool buffer_overlap, bool cached_gpu_modified,
|
||||
bool cached_buffer_modified, bool tracker_gpu_modified,
|
||||
bool tracker_cpu_modified, bool coherent_guest_source) noexcept {
|
||||
bool cached_buffer_modified, bool tracker_gpu_modified,
|
||||
bool tracker_cpu_modified, bool coherent_guest_source) noexcept {
|
||||
if (cached_gpu_modified != tracker_gpu_modified ||
|
||||
(tracker_gpu_modified && tracker_cpu_modified)) {
|
||||
return StorageBufferRebind::Unsupported;
|
||||
@@ -832,13 +825,13 @@ ClassifyStorageBufferRebind(bool buffer_overlap, bool cached_gpu_modified,
|
||||
|
||||
// Mirrors storage -> depth-target binding transition. An inaccessible stencil aspect
|
||||
// does not require the otherwise necessary image content copy.
|
||||
[[nodiscard]] inline DepthOverlap ClassifyStorageDepthOverlap(const ImageInfo& storage,
|
||||
[[nodiscard]] inline DepthOverlap ClassifyStorageDepthOverlap(const ImageInfo& storage,
|
||||
const DepthTargetInfo& depth) {
|
||||
const bool overlaps_depth = ImageRangeOverlaps(storage.address, storage.size, depth.address,
|
||||
depth.size);
|
||||
const bool overlaps_stencil = depth.stencil_address != 0 &&
|
||||
ImageRangeOverlaps(storage.address, storage.size,
|
||||
depth.stencil_address, depth.stencil_size);
|
||||
const bool overlaps_depth =
|
||||
ImageRangeOverlaps(storage.address, storage.size, depth.address, depth.size);
|
||||
const bool overlaps_stencil =
|
||||
depth.stencil_address != 0 && ImageRangeOverlaps(storage.address, storage.size,
|
||||
depth.stencil_address, depth.stencil_size);
|
||||
if (!overlaps_depth && !overlaps_stencil) {
|
||||
return DepthOverlap::None;
|
||||
}
|
||||
@@ -857,7 +850,7 @@ ClassifyRenderTargetOverlap(const ImageInfo& sampled, bool sampled_gpu_modified,
|
||||
return RenderTargetOverlap::None;
|
||||
}
|
||||
return !sampled_gpu_modified && same_context ? RenderTargetOverlap::RetireSampled
|
||||
: RenderTargetOverlap::Unsupported;
|
||||
: RenderTargetOverlap::Unsupported;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline RenderTargetOverlap
|
||||
|
||||
@@ -125,11 +125,11 @@ VkImageView TextureCache::GetRenderTargetAttachmentView(GraphicContext*
|
||||
static_cast<int>(image->format), static_cast<int>(format), level);
|
||||
}
|
||||
|
||||
return GetImageView(
|
||||
ctx, image,
|
||||
{format, layer_count == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT, level, 1, base_layer, layer_count, DstSel(4, 5, 6, 7),
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT});
|
||||
return GetImageView(ctx, image,
|
||||
{format,
|
||||
layer_count == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT, level, 1, base_layer, layer_count,
|
||||
DstSel(4, 5, 6, 7), VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT});
|
||||
}
|
||||
|
||||
VkImageView TextureCache::GetDepthTargetAttachmentView(GraphicContext* ctx,
|
||||
@@ -151,9 +151,9 @@ VkImageView TextureCache::GetDepthTargetAttachmentView(GraphicContext*
|
||||
|
||||
VkImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image,
|
||||
const ImageViewInfo& info) {
|
||||
const bool supported_type = info.type == VK_IMAGE_VIEW_TYPE_2D ||
|
||||
info.type == VK_IMAGE_VIEW_TYPE_2D_ARRAY ||
|
||||
info.type == VK_IMAGE_VIEW_TYPE_3D;
|
||||
const bool supported_type = info.type == VK_IMAGE_VIEW_TYPE_2D ||
|
||||
info.type == VK_IMAGE_VIEW_TYPE_2D_ARRAY ||
|
||||
info.type == VK_IMAGE_VIEW_TYPE_3D;
|
||||
const bool supported_usage = info.usage == VK_IMAGE_USAGE_SAMPLED_BIT ||
|
||||
info.usage == VK_IMAGE_USAGE_STORAGE_BIT ||
|
||||
info.usage == VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ||
|
||||
@@ -189,14 +189,14 @@ VkImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image,
|
||||
usage.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
|
||||
usage.usage = info.usage;
|
||||
VkImageViewCreateInfo create {};
|
||||
create.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
create.pNext = &usage;
|
||||
create.image = image->image;
|
||||
create.viewType = info.type;
|
||||
create.format = info.format;
|
||||
create.components = info.usage == VK_IMAGE_USAGE_SAMPLED_BIT
|
||||
? TextureGetComponentMapping(info.swizzle)
|
||||
: VkComponentMapping {};
|
||||
create.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
create.pNext = &usage;
|
||||
create.image = image->image;
|
||||
create.viewType = info.type;
|
||||
create.format = info.format;
|
||||
create.components = info.usage == VK_IMAGE_USAGE_SAMPLED_BIT
|
||||
? TextureGetComponentMapping(info.swizzle)
|
||||
: VkComponentMapping {};
|
||||
create.subresourceRange.aspectMask = info.aspect;
|
||||
create.subresourceRange.baseMipLevel = info.base_level;
|
||||
create.subresourceRange.levelCount = info.level_count;
|
||||
@@ -239,10 +239,10 @@ VkImageView TextureCache::GetDepthTargetSampledView(GraphicContext* ctx
|
||||
}
|
||||
|
||||
VkImageView TextureCache::GetSampledColorView(GraphicContext* ctx, VulkanImage* image,
|
||||
VkFormat view_format, uint32_t swizzle,
|
||||
uint32_t base_level, uint32_t level_count,
|
||||
VkImageViewType type, uint32_t base_layer,
|
||||
uint32_t layer_count) {
|
||||
VkFormat view_format, uint32_t swizzle,
|
||||
uint32_t base_level, uint32_t level_count,
|
||||
VkImageViewType type, uint32_t base_layer,
|
||||
uint32_t layer_count) {
|
||||
if (ctx == nullptr || image == nullptr || image->image == nullptr ||
|
||||
view_format == VK_FORMAT_UNDEFINED || base_level >= 16 ||
|
||||
(type != VK_IMAGE_VIEW_TYPE_2D && type != VK_IMAGE_VIEW_TYPE_2D_ARRAY) ||
|
||||
@@ -309,8 +309,7 @@ VkImageView TextureCache::GetRenderTargetStorageView(GraphicContext* c
|
||||
}
|
||||
return GetImageView(ctx, image,
|
||||
{view_format, type, VK_IMAGE_ASPECT_COLOR_BIT, base_level, level_count,
|
||||
base_layer, layer_count, DstSel(4, 5, 6, 7),
|
||||
VK_IMAGE_USAGE_STORAGE_BIT});
|
||||
base_layer, layer_count, DstSel(4, 5, 6, 7), VK_IMAGE_USAGE_STORAGE_BIT});
|
||||
}
|
||||
|
||||
VkImageView TextureCache::GetStorageTextureSampledView(GraphicContext* ctx,
|
||||
@@ -362,8 +361,7 @@ VkImageView TextureCache::GetStorageTextureStorageView(GraphicContext*
|
||||
}
|
||||
return GetImageView(ctx, image,
|
||||
{image->format, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
base_level, 1, 0, 1, DstSel(4, 5, 6, 7),
|
||||
VK_IMAGE_USAGE_STORAGE_BIT});
|
||||
base_level, 1, 0, 1, DstSel(4, 5, 6, 7), VK_IMAGE_USAGE_STORAGE_BIT});
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
@@ -18,8 +18,7 @@ namespace Libs::Graphics {
|
||||
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k16Float) ||
|
||||
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float);
|
||||
return swizzle == DstSel(4, 5, 6, 7) ||
|
||||
(single_channel && (swizzle == DstSel(4, 0, 0, 0) ||
|
||||
swizzle == DstSel(4, 0, 0, 1) ||
|
||||
(single_channel && (swizzle == DstSel(4, 0, 0, 0) || swizzle == DstSel(4, 0, 0, 1) ||
|
||||
swizzle == DstSel(4, 4, 4, 4))) ||
|
||||
(format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32_32UInt) &&
|
||||
swizzle == DstSel(4, 5, 0, 1)) ||
|
||||
@@ -104,9 +103,8 @@ namespace Libs::Graphics {
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool IsSupportedSampledColorView(VkFormat image_format,
|
||||
VkFormat view_format,
|
||||
uint32_t swizzle) noexcept {
|
||||
[[nodiscard]] inline bool IsSupportedSampledColorView(VkFormat image_format, VkFormat view_format,
|
||||
uint32_t swizzle) noexcept {
|
||||
if (!IsValidSampledColorSwizzle(swizzle)) {
|
||||
return false;
|
||||
}
|
||||
@@ -118,8 +116,7 @@ namespace Libs::Graphics {
|
||||
swizzle == DstSel(4, 5, 6, 7)) {
|
||||
return true;
|
||||
}
|
||||
return IsBgraToRgbaSampledView(image_format, view_format) &&
|
||||
swizzle == DstSel(6, 5, 4, 7);
|
||||
return IsBgraToRgbaSampledView(image_format, view_format) && swizzle == DstSel(6, 5, 4, 7);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline uint32_t SelectSampledColorView(VkFormat image_format, VkFormat view_format,
|
||||
@@ -177,8 +174,7 @@ IsSupportedSampledDepthUintResource(const ShaderRecompiler::IR::ImageResource& r
|
||||
view_format == VK_FORMAT_R16_SFLOAT || view_format == VK_FORMAT_R32_SFLOAT;
|
||||
const bool swizzle_ok =
|
||||
swizzle == DstSel(4, 5, 6, 7) ||
|
||||
(single_channel && (swizzle == DstSel(4, 0, 0, 0) ||
|
||||
swizzle == DstSel(4, 0, 0, 1) ||
|
||||
(single_channel && (swizzle == DstSel(4, 0, 0, 0) || swizzle == DstSel(4, 0, 0, 1) ||
|
||||
swizzle == DstSel(4, 4, 4, 4))) ||
|
||||
(view_format == VK_FORMAT_R32G32_UINT && swizzle == DstSel(4, 5, 0, 1)) ||
|
||||
((view_format == VK_FORMAT_R8G8B8A8_UNORM || view_format == VK_FORMAT_R8G8B8A8_UINT) &&
|
||||
@@ -217,7 +213,7 @@ ValidateStorageImageResource(const ShaderRecompiler::IR::ImageResource& resource
|
||||
namespace ImageViewOps {
|
||||
|
||||
[[nodiscard]] VkImageAspectFlags DepthAspectMask(VkFormat format) noexcept;
|
||||
[[nodiscard]] bool FormatSupportsStorage(GraphicContext* ctx, VkFormat format);
|
||||
[[nodiscard]] bool FormatSupportsStorage(GraphicContext* ctx, VkFormat format);
|
||||
|
||||
void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* image);
|
||||
void CreateDepthViews(GraphicContext* ctx, DepthStencilVulkanImage* image);
|
||||
|
||||
@@ -15,7 +15,8 @@ namespace Libs::Graphics {
|
||||
|
||||
// Sparse two-level lookup for texture-cache page ownership.
|
||||
// Entries are selected by guest page number; queries never allocate L1 buckets.
|
||||
template <typename EntryT, size_t PageBits = 20, size_t AddressSpaceBits = 40, size_t FirstLevelBits = 10>
|
||||
template <typename EntryT, size_t PageBits = 20, size_t AddressSpaceBits = 40,
|
||||
size_t FirstLevelBits = 10>
|
||||
class MultiLevelPageTable final {
|
||||
public:
|
||||
using Entry = EntryT;
|
||||
@@ -24,14 +25,14 @@ public:
|
||||
static_assert(PageBits < AddressSpaceBits);
|
||||
static_assert(FirstLevelBits > 0 && FirstLevelBits <= AddressSpaceBits - PageBits);
|
||||
|
||||
static constexpr size_t kPageBits = PageBits;
|
||||
static constexpr size_t kAddressSpaceBits = AddressSpaceBits;
|
||||
static constexpr size_t kFirstLevelBits = FirstLevelBits;
|
||||
static constexpr size_t kSecondLevelBits = AddressSpaceBits - FirstLevelBits - PageBits;
|
||||
static constexpr size_t kFirstLevelEntries = size_t{1} << FirstLevelBits;
|
||||
static constexpr size_t kBucketEntries = size_t{1} << kSecondLevelBits;
|
||||
static constexpr size_t kPageCount = size_t{1} << (AddressSpaceBits - PageBits);
|
||||
static constexpr uint64_t kAddressSpaceSize = uint64_t{1} << AddressSpaceBits;
|
||||
static constexpr size_t kPageBits = PageBits;
|
||||
static constexpr size_t kAddressSpaceBits = AddressSpaceBits;
|
||||
static constexpr size_t kFirstLevelBits = FirstLevelBits;
|
||||
static constexpr size_t kSecondLevelBits = AddressSpaceBits - FirstLevelBits - PageBits;
|
||||
static constexpr size_t kFirstLevelEntries = size_t {1} << FirstLevelBits;
|
||||
static constexpr size_t kBucketEntries = size_t {1} << kSecondLevelBits;
|
||||
static constexpr size_t kPageCount = size_t {1} << (AddressSpaceBits - PageBits);
|
||||
static constexpr uint64_t kAddressSpaceSize = uint64_t {1} << AddressSpaceBits;
|
||||
|
||||
struct PageRange final {
|
||||
size_t first = 0;
|
||||
@@ -74,12 +75,13 @@ public:
|
||||
|
||||
// Returns the half-open page interval touched by a non-empty byte range.
|
||||
// An end exactly at 2^AddressSpaceBits is valid; wrapping or crossing it is not.
|
||||
[[nodiscard]] static constexpr bool TryGetPageRange(uint64_t address, uint64_t size, PageRange& range) {
|
||||
[[nodiscard]] static constexpr bool TryGetPageRange(uint64_t address, uint64_t size,
|
||||
PageRange& range) {
|
||||
if (size == 0 || address >= kAddressSpaceSize || size > kAddressSpaceSize - address) {
|
||||
return false;
|
||||
}
|
||||
const uint64_t end = address + size;
|
||||
range.first = static_cast<size_t>(address >> PageBits);
|
||||
const uint64_t end = address + size;
|
||||
range.first = static_cast<size_t>(address >> PageBits);
|
||||
range.last_exclusive = static_cast<size_t>(((end - 1) >> PageBits) + 1);
|
||||
return true;
|
||||
}
|
||||
@@ -89,8 +91,12 @@ public:
|
||||
private:
|
||||
using Bucket = std::array<Entry, kBucketEntries>;
|
||||
|
||||
[[nodiscard]] static constexpr size_t FirstLevelIndex(size_t page) { return page >> kSecondLevelBits; }
|
||||
[[nodiscard]] static constexpr size_t SecondLevelIndex(size_t page) { return page & (kBucketEntries - 1); }
|
||||
[[nodiscard]] static constexpr size_t FirstLevelIndex(size_t page) {
|
||||
return page >> kSecondLevelBits;
|
||||
}
|
||||
[[nodiscard]] static constexpr size_t SecondLevelIndex(size_t page) {
|
||||
return page & (kBucketEntries - 1);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Bucket>> m_first_level;
|
||||
size_t m_allocated_buckets = 0;
|
||||
@@ -151,8 +157,8 @@ public:
|
||||
if (registration == m_registrations.end()) {
|
||||
return false;
|
||||
}
|
||||
const auto coarse_pages = CollectPages<20>(registration->ranges);
|
||||
const auto tracking_pages = CollectPages<12>(registration->ranges);
|
||||
const auto coarse_pages = CollectPages<20>(registration->ranges);
|
||||
const auto tracking_pages = CollectPages<12>(registration->ranges);
|
||||
const Registration* registration_ptr = &*registration;
|
||||
if (!HasAllMemberships(m_coarse_pages, coarse_pages, registration_ptr) ||
|
||||
!HasAllMemberships(m_tracking_pages, tracking_pages, registration_ptr)) {
|
||||
@@ -179,7 +185,8 @@ public:
|
||||
}
|
||||
|
||||
template <typename Predicate>
|
||||
[[nodiscard]] std::vector<OwnerT> Query(uint64_t address, uint64_t size, Predicate&& predicate) const {
|
||||
[[nodiscard]] std::vector<OwnerT> Query(uint64_t address, uint64_t size,
|
||||
Predicate&& predicate) const {
|
||||
return QueryImpl(address, size, true, std::forward<Predicate>(predicate));
|
||||
}
|
||||
|
||||
@@ -190,7 +197,8 @@ public:
|
||||
}
|
||||
|
||||
template <typename Predicate>
|
||||
[[nodiscard]] std::vector<OwnerT> QueryCandidates(uint64_t address, uint64_t size, Predicate&& predicate) const {
|
||||
[[nodiscard]] std::vector<OwnerT> QueryCandidates(uint64_t address, uint64_t size,
|
||||
Predicate&& predicate) const {
|
||||
return QueryImpl(address, size, false, std::forward<Predicate>(predicate));
|
||||
}
|
||||
|
||||
@@ -206,9 +214,9 @@ public:
|
||||
private:
|
||||
template <typename Predicate>
|
||||
[[nodiscard]] std::vector<OwnerT> QueryImpl(uint64_t address, uint64_t size, bool strict_bytes,
|
||||
Predicate&& predicate) const {
|
||||
typename CoarseTable::PageRange coarse_range{};
|
||||
typename TrackingTable::PageRange tracking_range{};
|
||||
Predicate&& predicate) const {
|
||||
typename CoarseTable::PageRange coarse_range {};
|
||||
typename TrackingTable::PageRange tracking_range {};
|
||||
if (!CoarseTable::TryGetPageRange(address, size, coarse_range) ||
|
||||
!TrackingTable::TryGetPageRange(address, size, tracking_range)) {
|
||||
return {};
|
||||
@@ -222,7 +230,8 @@ private:
|
||||
std::vector<OwnerT> result;
|
||||
for (const Registration* registration: candidates) {
|
||||
if ((!strict_bytes || Overlaps(registration->ranges, address, size)) &&
|
||||
HasTrackingMembership(registration, tracking_range) && predicate(registration->owner)) {
|
||||
HasTrackingMembership(registration, tracking_range) &&
|
||||
predicate(registration->owner)) {
|
||||
result.push_back(registration->owner);
|
||||
}
|
||||
}
|
||||
@@ -248,20 +257,22 @@ private:
|
||||
[[nodiscard]] static std::vector<ByteRange> Normalize(const std::vector<ByteRange>& ranges) {
|
||||
std::vector<ByteRange> sorted;
|
||||
for (const auto& range: ranges) {
|
||||
typename CoarseTable::PageRange ignored{};
|
||||
typename CoarseTable::PageRange ignored {};
|
||||
if (!CoarseTable::TryGetPageRange(range.address, range.size, ignored)) {
|
||||
return {};
|
||||
}
|
||||
sorted.push_back(range);
|
||||
}
|
||||
std::sort(sorted.begin(), sorted.end(),
|
||||
[](const ByteRange& lhs, const ByteRange& rhs) { return lhs.address < rhs.address; });
|
||||
std::sort(sorted.begin(), sorted.end(), [](const ByteRange& lhs, const ByteRange& rhs) {
|
||||
return lhs.address < rhs.address;
|
||||
});
|
||||
std::vector<ByteRange> merged;
|
||||
for (const auto& range: sorted) {
|
||||
if (merged.empty() || range.address > merged.back().address + merged.back().size) {
|
||||
merged.push_back(range);
|
||||
} else {
|
||||
const uint64_t end = std::max(merged.back().address + merged.back().size, range.address + range.size);
|
||||
const uint64_t end = std::max(merged.back().address + merged.back().size,
|
||||
range.address + range.size);
|
||||
merged.back().size = end - merged.back().address;
|
||||
}
|
||||
}
|
||||
@@ -284,29 +295,33 @@ private:
|
||||
}
|
||||
|
||||
template <typename Table>
|
||||
[[nodiscard]] static bool HasAllMemberships(const Table& table, const std::vector<size_t>& pages,
|
||||
const Registration* registration) {
|
||||
[[nodiscard]] static bool HasAllMemberships(const Table& table,
|
||||
const std::vector<size_t>& pages,
|
||||
const Registration* registration) {
|
||||
for (const size_t page: pages) {
|
||||
const auto* owners = table.Find(page);
|
||||
if (owners == nullptr || std::find(owners->begin(), owners->end(), registration) == owners->end()) {
|
||||
if (owners == nullptr ||
|
||||
std::find(owners->begin(), owners->end(), registration) == owners->end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool HasTrackingMembership(const Registration* registration,
|
||||
[[nodiscard]] bool HasTrackingMembership(const Registration* registration,
|
||||
const typename TrackingTable::PageRange& range) const {
|
||||
for (size_t page = range.first; page < range.last_exclusive; ++page) {
|
||||
const auto* owners = m_tracking_pages.Find(page);
|
||||
if (owners != nullptr && std::find(owners->begin(), owners->end(), registration) != owners->end()) {
|
||||
if (owners != nullptr &&
|
||||
std::find(owners->begin(), owners->end(), registration) != owners->end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool Overlaps(const std::vector<ByteRange>& ranges, uint64_t address, uint64_t size) {
|
||||
[[nodiscard]] static bool Overlaps(const std::vector<ByteRange>& ranges, uint64_t address,
|
||||
uint64_t size) {
|
||||
const uint64_t end = address + size;
|
||||
return std::any_of(ranges.begin(), ranges.end(), [&](const ByteRange& range) {
|
||||
return range.address < end && address < range.address + range.size;
|
||||
@@ -314,26 +329,28 @@ private:
|
||||
}
|
||||
static void AppendUnique(MembershipList& destination, const MembershipList& source) {
|
||||
for (const Registration* registration: source) {
|
||||
if (std::find(destination.begin(), destination.end(), registration) == destination.end()) {
|
||||
if (std::find(destination.begin(), destination.end(), registration) ==
|
||||
destination.end()) {
|
||||
destination.push_back(registration);
|
||||
}
|
||||
}
|
||||
}
|
||||
[[nodiscard]] static std::vector<ByteRange> CoalesceTrackingPages(const std::vector<size_t>& pages) {
|
||||
[[nodiscard]] static std::vector<ByteRange>
|
||||
CoalesceTrackingPages(const std::vector<size_t>& pages) {
|
||||
std::vector<ByteRange> result;
|
||||
for (const size_t page: pages) {
|
||||
const uint64_t address = static_cast<uint64_t>(page) << 12;
|
||||
if (!result.empty() && result.back().address + result.back().size == address) {
|
||||
result.back().size += uint64_t{1} << 12;
|
||||
result.back().size += uint64_t {1} << 12;
|
||||
} else {
|
||||
result.push_back({address, uint64_t{1} << 12});
|
||||
result.push_back({address, uint64_t {1} << 12});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CoarseTable m_coarse_pages;
|
||||
TrackingTable m_tracking_pages;
|
||||
CoarseTable m_coarse_pages;
|
||||
TrackingTable m_tracking_pages;
|
||||
std::list<Registration> m_registrations;
|
||||
};
|
||||
|
||||
|
||||
@@ -268,7 +268,7 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
|
||||
}
|
||||
if (resource.written || !resource.read || resource.atomic || descriptor.Base48() == 0 ||
|
||||
descriptor_size == 0 ||
|
||||
cache->QueryRegion(descriptor.Base48(), descriptor_size).metadata_pages) {
|
||||
cache->QueryRegion(descriptor.Base48(), descriptor_size).metadata_pages) {
|
||||
EXIT("unsupported HTile clear side-buffer access\n");
|
||||
}
|
||||
g_render_ctx->GetBufferCache()->ValidateGpuAccess(descriptor.Base48(), descriptor_size,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#include "graphics/host_gpu/renderer/renderDraw.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common.h"
|
||||
#include "common/emulatorConfig.h"
|
||||
@@ -20,7 +22,6 @@
|
||||
#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/renderDraw.h"
|
||||
#include "graphics/host_gpu/renderer/renderInternal.h"
|
||||
#include "graphics/host_gpu/renderer/renderVertex.h"
|
||||
#include "graphics/host_gpu/renderer/shaderResourceBarrier.h"
|
||||
@@ -823,9 +824,9 @@ static void BindDrawIndexBuffer(CommandBuffer* buffer, VkCommandBuffer vk_buffer
|
||||
VkDeviceSize index_offset = 0;
|
||||
if (source.host_data != nullptr) {
|
||||
VkDeviceSize range = 0;
|
||||
if (!g_render_ctx->GetBufferCache()->UploadHostData(
|
||||
buffer, g_render_ctx->GetGraphicCtx(), source.host_data, source.size, 16,
|
||||
&index_buffer, &index_offset, &range)) {
|
||||
if (!g_render_ctx->GetBufferCache()->UploadHostData(buffer, g_render_ctx->GetGraphicCtx(),
|
||||
source.host_data, source.size, 16,
|
||||
&index_buffer, &index_offset, &range)) {
|
||||
EXIT("failed to upload host index buffer\n");
|
||||
}
|
||||
} else {
|
||||
@@ -1126,9 +1127,9 @@ void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx
|
||||
instance_count = 1;
|
||||
}
|
||||
|
||||
const DrawCallInfo draw {"DrawIndex", CommandBufferDebugOp::DrawIndex,
|
||||
index_count, flags,
|
||||
instance_count, first_instance};
|
||||
const DrawCallInfo draw {"DrawIndex", CommandBufferDebugOp::DrawIndex,
|
||||
index_count, flags,
|
||||
instance_count, first_instance};
|
||||
std::vector<uint16_t> expanded_indices;
|
||||
if (expand_index8_to_u16) {
|
||||
EXIT_NOT_IMPLEMENTED(index_addr == nullptr);
|
||||
@@ -1144,9 +1145,8 @@ void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx
|
||||
index_source.address = reinterpret_cast<uint64_t>(index_addr);
|
||||
index_source.host_data =
|
||||
expanded_indices.empty() ? nullptr : static_cast<const void*>(expanded_indices.data());
|
||||
index_source.size = expanded_indices.empty()
|
||||
? index_size
|
||||
: expanded_indices.size() * sizeof(uint16_t);
|
||||
index_source.size =
|
||||
expanded_indices.empty() ? index_size : expanded_indices.size() * sizeof(uint16_t);
|
||||
index_source.type = index_type;
|
||||
|
||||
DrawRenderState state {};
|
||||
|
||||
@@ -217,8 +217,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* native =
|
||||
g_render_ctx->GetTextureCache()->FindDepthTargetByRange(buffer, vaddr, size);
|
||||
auto* native = g_render_ctx->GetTextureCache()->FindDepthTargetByRange(buffer, vaddr, size);
|
||||
if (native == nullptr) {
|
||||
EXIT("depth-target barrier range has no cached image\n");
|
||||
}
|
||||
|
||||
@@ -66,15 +66,18 @@ VkSampler SamplerCache::GetSampler(const ShaderSamplerResource& r) {
|
||||
auto to_vk_address_mode = [](uint8_t clamp) {
|
||||
switch (static_cast<Prospero::SamplerClampMode>(clamp)) {
|
||||
case Prospero::SamplerClampMode::kWrap: return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
case Prospero::SamplerClampMode::kMirror: return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
||||
case Prospero::SamplerClampMode::kClampLastTexel: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
case Prospero::SamplerClampMode::kMirror:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
||||
case Prospero::SamplerClampMode::kClampLastTexel:
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
case Prospero::SamplerClampMode::kMirrorOnceLastTexel:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
|
||||
case Prospero::SamplerClampMode::kClampHalfBorder:
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||
case Prospero::SamplerClampMode::kMirrorOnceHalfBorder:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
|
||||
case Prospero::SamplerClampMode::kClampBorder: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||
case Prospero::SamplerClampMode::kClampBorder:
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||
case Prospero::SamplerClampMode::kMirrorOnceBorder:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
|
||||
default: EXIT("unknown clamp: %u\n", clamp);
|
||||
@@ -87,8 +90,12 @@ VkSampler SamplerCache::GetSampler(const ShaderSamplerResource& r) {
|
||||
case Prospero::SamplerBorderColor::kTransBlack:
|
||||
border = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK;
|
||||
break;
|
||||
case Prospero::SamplerBorderColor::kOpaqueBlack: border = VK_BORDER_COLOR_INT_OPAQUE_BLACK; break;
|
||||
case Prospero::SamplerBorderColor::kOpaqueWhite: border = VK_BORDER_COLOR_INT_OPAQUE_WHITE; break;
|
||||
case Prospero::SamplerBorderColor::kOpaqueBlack:
|
||||
border = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
||||
break;
|
||||
case Prospero::SamplerBorderColor::kOpaqueWhite:
|
||||
border = VK_BORDER_COLOR_INT_OPAQUE_WHITE;
|
||||
break;
|
||||
case Prospero::SamplerBorderColor::kFromTable:
|
||||
LOGF(
|
||||
"temporary: approximating table border color as transparent black, index = %" PRIu16
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "graphics/host_gpu/renderer/descriptorCache.h"
|
||||
#include "graphics/shader/shaderBindings.h"
|
||||
#include "graphics/shader/shader.h"
|
||||
#include "graphics/shader/shaderBindings.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
//IDK: maybe we can remove it?
|
||||
// IDK: maybe we can remove it?
|
||||
constexpr uint32_t kTemporaryPs5BufferFormat121 = 121u;
|
||||
|
||||
static bool NarrowInputFormat(VkFormat* format, uint32_t* size, uint32_t used_components) {
|
||||
|
||||
@@ -30,24 +30,22 @@ void HostStreamBuffer::EnsureBuffer(GraphicContext* ctx) {
|
||||
return;
|
||||
}
|
||||
KYTY_PROFILER_BLOCK("HostStreamBuffer::create");
|
||||
m_ctx = ctx;
|
||||
m_buffer = std::make_unique<VulkanBuffer>();
|
||||
m_buffer->usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
m_ctx = ctx;
|
||||
m_buffer = std::make_unique<VulkanBuffer>();
|
||||
m_buffer->usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
m_buffer->memory.property = static_cast<uint32_t>(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||
VulkanCreateBuffer(ctx, CAPACITY, m_buffer.get());
|
||||
VulkanMapMemory(ctx, &m_buffer->memory, &m_mapped);
|
||||
const auto count = g_stream_buffer_count.fetch_add(1, std::memory_order_relaxed) + 1;
|
||||
LOGF("HostStreamBuffer: created serial=%" PRIu64 " capacity=%" PRIu64 "\n", count,
|
||||
CAPACITY);
|
||||
LOGF("HostStreamBuffer: created serial=%" PRIu64 " capacity=%" PRIu64 "\n", count, CAPACITY);
|
||||
}
|
||||
|
||||
bool HostStreamBuffer::Copy(GraphicContext* ctx, const void* src, uint64_t size,
|
||||
uint64_t alignment, VulkanBuffer** out_buffer, uint64_t* out_offset,
|
||||
uint64_t* out_range) {
|
||||
bool HostStreamBuffer::Copy(GraphicContext* ctx, const void* src, uint64_t size, uint64_t alignment,
|
||||
VulkanBuffer** out_buffer, uint64_t* out_offset, uint64_t* out_range) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
if (ctx == nullptr || src == nullptr || out_buffer == nullptr || out_offset == nullptr ||
|
||||
out_range == nullptr) {
|
||||
@@ -69,10 +67,10 @@ bool HostStreamBuffer::Copy(GraphicContext* ctx, const void* src, uint64_t size,
|
||||
}
|
||||
EnsureBuffer(ctx);
|
||||
std::memcpy(static_cast<uint8_t*>(m_mapped) + offset, src, static_cast<size_t>(size));
|
||||
m_offset = offset + size;
|
||||
*out_buffer = m_buffer.get();
|
||||
*out_offset = offset;
|
||||
*out_range = size;
|
||||
m_offset = offset + size;
|
||||
*out_buffer = m_buffer.get();
|
||||
*out_offset = offset;
|
||||
*out_range = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,11 +22,10 @@ public:
|
||||
~HostStreamBuffer();
|
||||
KYTY_CLASS_NO_COPY(HostStreamBuffer);
|
||||
|
||||
[[nodiscard]] bool Copy(GraphicContext* ctx, const void* src, uint64_t size,
|
||||
uint64_t alignment, VulkanBuffer** out_buffer, uint64_t* out_offset,
|
||||
uint64_t* out_range);
|
||||
void Reset() noexcept;
|
||||
void Release() noexcept;
|
||||
[[nodiscard]] bool Copy(GraphicContext* ctx, const void* src, uint64_t size, uint64_t alignment,
|
||||
VulkanBuffer** out_buffer, uint64_t* out_offset, uint64_t* out_range);
|
||||
void Reset() noexcept;
|
||||
void Release() noexcept;
|
||||
|
||||
private:
|
||||
void EnsureBuffer(GraphicContext* ctx);
|
||||
@@ -36,11 +35,11 @@ private:
|
||||
// replaced by a single 64 MiB scheduler-watched ring; the BufferCache seam stays fixed.
|
||||
static constexpr uint64_t CAPACITY = 16ull * 1024ull * 1024ull;
|
||||
|
||||
mutable std::mutex m_mutex;
|
||||
GraphicContext* m_ctx = nullptr;
|
||||
mutable std::mutex m_mutex;
|
||||
GraphicContext* m_ctx = nullptr;
|
||||
std::unique_ptr<VulkanBuffer> m_buffer;
|
||||
void* m_mapped = nullptr;
|
||||
uint64_t m_offset = 0;
|
||||
void* m_mapped = nullptr;
|
||||
uint64_t m_offset = 0;
|
||||
};
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#include "graphics/host_gpu/renderer/sync.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common.h"
|
||||
#include "common/logging/log.h"
|
||||
@@ -7,7 +9,6 @@
|
||||
#include "graphics/host_gpu/renderer/bufferCache.h"
|
||||
#include "graphics/host_gpu/renderer/render.h"
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
#include "graphics/host_gpu/renderer/sync.h"
|
||||
#include "graphics/presentation/displayBuffer.h"
|
||||
#include "kernel/eventQueue.h"
|
||||
#include "kernel/pthread.h"
|
||||
@@ -82,8 +83,8 @@ void TriggerEopEvent(uint32_t context_id) {
|
||||
g_render_ctx->TriggerEopEvent(context_id);
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint32_t* dst_gpu_addr, uint32_t value) {
|
||||
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);
|
||||
@@ -93,9 +94,8 @@ void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer* buffer,
|
||||
0, 0, reinterpret_cast<uint64_t>(dst_gpu_addr));
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint32_t* dst_gpu_addr, uint32_t dw_offset,
|
||||
uint32_t dw_num) {
|
||||
void 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);
|
||||
@@ -105,8 +105,8 @@ void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer* buffer,
|
||||
dw_offset, dw_num, 0, 0, reinterpret_cast<uint64_t>(dst_gpu_addr));
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint64_t* dst_gpu_addr, uint64_t value) {
|
||||
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);
|
||||
@@ -117,8 +117,8 @@ void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer* buffer,
|
||||
reinterpret_cast<uint64_t>(dst_gpu_addr));
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint64_t* dst_gpu_addr, uint64_t value) {
|
||||
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);
|
||||
@@ -132,10 +132,8 @@ void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer,
|
||||
reinterpret_cast<uint64_t>(dst_gpu_addr), value);
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id,
|
||||
CommandBuffer* buffer,
|
||||
uint64_t* dst_gpu_addr,
|
||||
uint64_t value) {
|
||||
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);
|
||||
@@ -150,7 +148,7 @@ void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id,
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeWithWriteBack64(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint64_t* dst_gpu_addr, uint64_t value) {
|
||||
uint64_t* dst_gpu_addr, uint64_t value) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
@@ -162,7 +160,7 @@ void WriteAtEndOfPipeWithWriteBack64(uint64_t submit_id, CommandBuffer* buffer,
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint32_t* dst_gpu_addr, uint32_t value) {
|
||||
uint32_t* dst_gpu_addr, uint32_t value) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
@@ -172,10 +170,9 @@ void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer* buffer,
|
||||
value, 0, 0, reinterpret_cast<uint64_t>(dst_gpu_addr));
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id,
|
||||
CommandBuffer* buffer,
|
||||
uint64_t* dst_gpu_addr, uint64_t value,
|
||||
uint32_t context_id) {
|
||||
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);
|
||||
@@ -197,10 +194,9 @@ void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id,
|
||||
args);
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id,
|
||||
CommandBuffer* buffer,
|
||||
uint32_t* dst_gpu_addr, uint32_t value,
|
||||
uint32_t 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);
|
||||
@@ -221,8 +217,7 @@ void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id,
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint64_t* dst_gpu_addr, uint64_t value,
|
||||
uint32_t context_id) {
|
||||
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);
|
||||
@@ -245,8 +240,7 @@ void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer* buffer,
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint32_t* dst_gpu_addr, uint32_t value,
|
||||
uint32_t context_id) {
|
||||
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);
|
||||
@@ -266,8 +260,8 @@ void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer* buffer,
|
||||
args);
|
||||
}
|
||||
|
||||
uint64_t PrepareDisplayBufferFlip(CommandBuffer* buffer, int handle, int index,
|
||||
int flip_mode, int64_t flip_arg) {
|
||||
uint64_t PrepareDisplayBufferFlip(CommandBuffer* buffer, int handle, int index, int flip_mode,
|
||||
int64_t flip_arg) {
|
||||
for (;;) {
|
||||
uint64_t request_id = 0;
|
||||
const auto result = Presentation::DisplayBufferSubmitFlipFromGpu(
|
||||
@@ -285,9 +279,10 @@ uint64_t PrepareDisplayBufferFlip(CommandBuffer* buffer, int handle, int index,
|
||||
}
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeWithInterruptWriteBackFlip32(
|
||||
uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr, uint32_t value, int handle,
|
||||
int index, int flip_mode, int64_t flip_arg, uint64_t request_id) {
|
||||
void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint32_t* dst_gpu_addr, uint32_t value,
|
||||
int handle, int index, int flip_mode,
|
||||
int64_t flip_arg, uint64_t request_id) {
|
||||
EXIT_IF(g_render_ctx == nullptr);
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
EXIT_IF(buffer == nullptr);
|
||||
@@ -307,10 +302,9 @@ void WriteAtEndOfPipeWithInterruptWriteBackFlip32(
|
||||
args);
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint32_t* dst_gpu_addr, uint32_t value, int handle,
|
||||
int index, int flip_mode, int64_t flip_arg,
|
||||
uint64_t request_id) {
|
||||
void 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);
|
||||
@@ -323,9 +317,8 @@ void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer* buffer,
|
||||
SubmitLabel(buffer, CompleteDisplayBufferFlip, nullptr, args);
|
||||
}
|
||||
|
||||
void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer* buffer, int handle,
|
||||
int index, int flip_mode, int64_t flip_arg,
|
||||
uint64_t 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());
|
||||
|
||||
@@ -25,8 +25,8 @@ void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst
|
||||
uint64_t value);
|
||||
void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
|
||||
uint32_t dw_offset, uint32_t dw_num);
|
||||
void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint64_t* dst_gpu_addr, uint64_t value);
|
||||
void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr,
|
||||
uint64_t value);
|
||||
void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint64_t* dst_gpu_addr, uint64_t value);
|
||||
void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer* buffer,
|
||||
@@ -50,9 +50,9 @@ void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer*
|
||||
int flip_mode, int64_t flip_arg);
|
||||
void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer* buffer, int handle, int index,
|
||||
int flip_mode, int64_t flip_arg, uint64_t request_id);
|
||||
void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint32_t* dst_gpu_addr, uint32_t value, int handle, int index,
|
||||
int flip_mode, int64_t flip_arg, uint64_t request_id);
|
||||
void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
|
||||
uint32_t value, int handle, int index, int flip_mode,
|
||||
int64_t flip_arg, uint64_t request_id);
|
||||
void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuffer* buffer,
|
||||
uint32_t* dst_gpu_addr, uint32_t value,
|
||||
int handle, int index, int flip_mode,
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include "graphics/host_gpu/utils.h"
|
||||
#include "kernel/memory.h"
|
||||
|
||||
#include <xxhash.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
@@ -30,6 +28,7 @@
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <thread>
|
||||
#include <xxhash.h>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
@@ -39,13 +38,13 @@ thread_local const void* g_texture_cache_lock_owner = nullptr;
|
||||
thread_local const void* g_texture_fault_owner = nullptr;
|
||||
|
||||
[[nodiscard]] uint64_t HashSampledImageEdges(const Image& image) {
|
||||
constexpr uint64_t page_mask = TRACKER_PAGE_SIZE - 1;
|
||||
const uint64_t begin = image.address;
|
||||
const uint64_t end = image.address + image.size;
|
||||
const uint64_t head_end = std::min(end, (begin + page_mask) & ~page_mask);
|
||||
constexpr uint64_t page_mask = TRACKER_PAGE_SIZE - 1;
|
||||
const uint64_t begin = image.address;
|
||||
const uint64_t end = image.address + image.size;
|
||||
const uint64_t head_end = std::min(end, (begin + page_mask) & ~page_mask);
|
||||
const uint64_t tail_begin = std::max(begin, end & ~page_mask);
|
||||
const uint64_t head_size = head_end - begin;
|
||||
const uint64_t tail_size = tail_begin < head_end ? end - head_end : end - tail_begin;
|
||||
const uint64_t head_size = head_end - begin;
|
||||
const uint64_t tail_size = tail_begin < head_end ? end - head_end : end - tail_begin;
|
||||
std::array<uint8_t, TRACKER_PAGE_SIZE * 2> bytes {};
|
||||
if (head_size + tail_size > bytes.size()) {
|
||||
EXIT("TextureCache: sampled-image edge hash range overflow\n");
|
||||
@@ -243,10 +242,11 @@ void TextureCache::UnregisterImageLocked(CachedImage& image, bool release_tracki
|
||||
image.registered = false;
|
||||
}
|
||||
|
||||
VulkanImage* TextureCache::PublishImage(CommandBuffer* command,
|
||||
VulkanImage* TextureCache::PublishImage(CommandBuffer* command,
|
||||
std::shared_ptr<CachedImage> image) {
|
||||
if (command == nullptr || image == nullptr || image->image == nullptr || image->registered) {
|
||||
EXIT("TextureCache: invalid image publication, command=%p record=%p image=%p registered=%d\n",
|
||||
EXIT("TextureCache: invalid image publication, command=%p record=%p image=%p "
|
||||
"registered=%d\n",
|
||||
static_cast<const void*>(command), static_cast<const void*>(image.get()),
|
||||
image != nullptr ? static_cast<const void*>(image->image) : nullptr,
|
||||
image != nullptr && image->registered);
|
||||
@@ -389,7 +389,7 @@ struct TextureCache::ReadbackWorker {
|
||||
}
|
||||
|
||||
[[nodiscard]] ReadbackRange DownloadDepthTarget(CachedImage& cached,
|
||||
bool require_fault_range = true) {
|
||||
bool require_fault_range = true) {
|
||||
const auto& info = cached.depth;
|
||||
const bool has_stencil = info.stencil_address != 0 || info.stencil_size != 0;
|
||||
const bool has_htile = info.htile_address != 0 || info.htile_size != 0;
|
||||
@@ -423,8 +423,7 @@ struct TextureCache::ReadbackWorker {
|
||||
(!has_htile || (expected_htile.size <= UINT64_MAX / info.layers &&
|
||||
info.htile_size == expected_htile.size * info.layers));
|
||||
if ((require_fault_range && !fault_in_depth) || has_stencil || info.address == 0 ||
|
||||
info.size == 0 ||
|
||||
info.width == 0 || info.height == 0 || info.pitch < info.width ||
|
||||
info.size == 0 || info.width == 0 || info.height == 0 || info.pitch < info.width ||
|
||||
info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kDepth) ||
|
||||
!prospero_layout || info.pitch != expected_pitch || !layered_sizes ||
|
||||
expected_depth.align != 65536u || cached.image->layers != info.layers ||
|
||||
@@ -849,11 +848,11 @@ TextureCache::TextureCache(PageManager& page_manager, BufferCache& buffer_cache,
|
||||
EXIT("TextureCache: construction is restricted to the main thread\n");
|
||||
}
|
||||
m_dummy_textures = std::make_unique<DummyTextureCache>();
|
||||
m_readback = std::make_unique<ReadbackWorker>(*this);
|
||||
m_readback = std::make_unique<ReadbackWorker>(*this);
|
||||
}
|
||||
|
||||
TextureCache::CachedImage* TextureCache::FindGpuReadbackPageCandidateLocked(uint64_t vaddr,
|
||||
uint64_t size) {
|
||||
uint64_t size) {
|
||||
CachedImage* selected = nullptr;
|
||||
for (auto* cached: FindImagesInRegionLocked(vaddr, size, true)) {
|
||||
if (!cached->IsGpuReadbackPageCandidate(vaddr, size)) {
|
||||
@@ -862,8 +861,7 @@ TextureCache::CachedImage* TextureCache::FindGpuReadbackPageCandidateLocked(uint
|
||||
if (selected != nullptr) {
|
||||
EXIT("TextureCache: CPU fault has multiple GPU-modified image page candidates, "
|
||||
"addr=0x%016" PRIx64 " size=0x%016" PRIx64 " first=%p second=%p\n",
|
||||
vaddr, size, static_cast<const void*>(selected),
|
||||
static_cast<const void*>(cached));
|
||||
vaddr, size, static_cast<const void*>(selected), static_cast<const void*>(cached));
|
||||
}
|
||||
selected = cached;
|
||||
}
|
||||
@@ -929,8 +927,8 @@ void TextureCache::RetireSampledTargetAliases(GraphicContext* ctx, const ImageIn
|
||||
const bool contained =
|
||||
delta <= requested.size && cached->depth.size <= requested.size - delta;
|
||||
const bool sampled_expansion = IsSampledDepthExpansion(requested, cached->depth);
|
||||
const bool exact_range = requested.address == cached->depth.address &&
|
||||
requested.size == cached->depth.size;
|
||||
const bool exact_range =
|
||||
requested.address == cached->depth.address && requested.size == cached->depth.size;
|
||||
const bool supported = cached->ctx == ctx && !cached->buffer_modified &&
|
||||
cached->depth.stencil_address == 0 &&
|
||||
cached->depth.stencil_size == 0 && cached->depth.layers == 1 &&
|
||||
@@ -1049,8 +1047,7 @@ void TextureCache::ResolveStorageImageOverlaps(GraphicContext* ctx, const ImageI
|
||||
RetireImages(retire);
|
||||
}
|
||||
|
||||
void TextureCache::RetireStorageDepthAliasLocked(GraphicContext* ctx,
|
||||
const ImageInfo& requested) {
|
||||
void TextureCache::RetireStorageDepthAliasLocked(GraphicContext* ctx, const ImageInfo& requested) {
|
||||
CachedImage* selected = nullptr;
|
||||
for (auto* entry: FindImagesInRegionLocked(requested.address, requested.size, true)) {
|
||||
auto& cached = *entry;
|
||||
@@ -1059,7 +1056,7 @@ void TextureCache::RetireStorageDepthAliasLocked(GraphicContext* ctx,
|
||||
continue;
|
||||
}
|
||||
const auto& depth = cached.depth;
|
||||
const bool exact_d32_uint =
|
||||
const bool exact_d32_uint =
|
||||
cached.ctx == ctx && cached.gpu_modified && !cached.buffer_modified &&
|
||||
depth.address == requested.address && depth.size == requested.size &&
|
||||
depth.stencil_address == 0 && depth.stencil_size == 0 && depth.htile_address == 0 &&
|
||||
@@ -1105,10 +1102,9 @@ TextureCache::~TextureCache() {
|
||||
|
||||
VulkanImage* TextureCache::FindTexture(CommandBuffer* command, GraphicContext* ctx,
|
||||
const ImageInfo& info, bool metadata_read) {
|
||||
if (info.address == 0 || info.size == 0 ||
|
||||
info.address >= TRACKER_ADDRESS_SIZE || info.size > TRACKER_ADDRESS_SIZE - info.address ||
|
||||
info.width == 0 || info.height == 0 || info.depth == 0 || info.levels == 0 ||
|
||||
info.levels >= 16 || info.view_levels == 0 ||
|
||||
if (info.address == 0 || info.size == 0 || info.address >= TRACKER_ADDRESS_SIZE ||
|
||||
info.size > TRACKER_ADDRESS_SIZE - info.address || info.width == 0 || info.height == 0 ||
|
||||
info.depth == 0 || info.levels == 0 || info.levels >= 16 || info.view_levels == 0 ||
|
||||
info.base_level + info.view_levels > info.levels) {
|
||||
EXIT("TextureCache: invalid sampled-image request, command=%p ctx=%p addr=0x%016" PRIx64
|
||||
" size=0x%016" PRIx64 " extent=%ux%ux%u levels=%u\n",
|
||||
@@ -1265,10 +1261,10 @@ VulkanImage* TextureCache::FindTexture(CommandBuffer* command, GraphicContext* c
|
||||
}
|
||||
}
|
||||
m_images.reserve(m_images.size() + 1);
|
||||
auto cached = std::make_shared<CachedImage>();
|
||||
cached->kind = CachedImage::Kind::Texture;
|
||||
cached->info = info;
|
||||
cached->ctx = ctx;
|
||||
auto cached = std::make_shared<CachedImage>();
|
||||
cached->kind = CachedImage::Kind::Texture;
|
||||
cached->info = info;
|
||||
cached->ctx = ctx;
|
||||
VkComponentMapping components {};
|
||||
cached->image = ImageOps::CreateTexture(ctx, info, false, &cached->memory, &components);
|
||||
m_memory_tracker.ForEachUploadRange(
|
||||
@@ -1292,11 +1288,10 @@ StorageTextureVulkanImage* TextureCache::FindStorageTexture(CommandBuffer* com
|
||||
const bool supported_depth_tile =
|
||||
info.tile == Prospero::GpuEnumValue(Prospero::TileMode::kDepth) &&
|
||||
IsSupportedStorageDepthTile(info.format, info.type, info.width, info.height, info.depth);
|
||||
if (info.address == 0 || info.size == 0 ||
|
||||
info.address >= TRACKER_ADDRESS_SIZE || info.size > TRACKER_ADDRESS_SIZE - info.address ||
|
||||
info.width == 0 || info.height == 0 || info.depth == 0 || info.levels == 0 ||
|
||||
info.levels > 16 || info.base_level >= info.levels || info.view_levels != 1 ||
|
||||
info.base_array != 0 || !supported_type ||
|
||||
if (info.address == 0 || info.size == 0 || info.address >= TRACKER_ADDRESS_SIZE ||
|
||||
info.size > TRACKER_ADDRESS_SIZE - info.address || info.width == 0 || info.height == 0 ||
|
||||
info.depth == 0 || info.levels == 0 || info.levels > 16 || info.base_level >= info.levels ||
|
||||
info.view_levels != 1 || info.base_array != 0 || !supported_type ||
|
||||
(info.tile != Prospero::GpuEnumValue(Prospero::TileMode::kLinear) &&
|
||||
info.tile != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) &&
|
||||
!supported_depth_tile) ||
|
||||
@@ -1354,7 +1349,7 @@ StorageTextureVulkanImage* TextureCache::FindStorageTexture(CommandBuffer* com
|
||||
if (match != nullptr) {
|
||||
const bool cpu_modified = m_memory_tracker.IsRegionCpuModified(info.address, info.size);
|
||||
const bool gpu_modified = m_memory_tracker.IsRegionGpuModified(info.address, info.size);
|
||||
const auto rebind = ClassifyStorageBufferRebind(
|
||||
const auto rebind = ClassifyStorageBufferRebind(
|
||||
buffer_overlap, match->gpu_modified, match->buffer_modified, gpu_modified, cpu_modified,
|
||||
IsCoherentGuestImageSource(source, info.address, info.size));
|
||||
if (rebind == StorageBufferRebind::Unsupported) {
|
||||
@@ -1373,9 +1368,9 @@ StorageTextureVulkanImage* TextureCache::FindStorageTexture(CommandBuffer* com
|
||||
m_memory_tracker.ForEachUploadRange(
|
||||
info.address, info.size, true, [](uint64_t, uint64_t) noexcept {},
|
||||
[&]() noexcept {
|
||||
m_tiler.DetileImage(
|
||||
match->ctx, static_cast<GpuTextureVulkanImage*>(match->image), match->info,
|
||||
source, true, true);
|
||||
m_tiler.DetileImage(match->ctx,
|
||||
static_cast<GpuTextureVulkanImage*>(match->image),
|
||||
match->info, source, true, true);
|
||||
});
|
||||
match->buffer_modified = false;
|
||||
match->gpu_modified = true;
|
||||
@@ -1402,10 +1397,10 @@ StorageTextureVulkanImage* TextureCache::FindStorageTexture(CommandBuffer* com
|
||||
|
||||
ResolveStorageImageOverlaps(ctx, info);
|
||||
m_images.reserve(m_images.size() + 1);
|
||||
auto cached = std::make_shared<CachedImage>();
|
||||
cached->kind = CachedImage::Kind::StorageTexture;
|
||||
cached->info = info;
|
||||
cached->ctx = ctx;
|
||||
auto cached = std::make_shared<CachedImage>();
|
||||
cached->kind = CachedImage::Kind::StorageTexture;
|
||||
cached->info = info;
|
||||
cached->ctx = ctx;
|
||||
VkComponentMapping components {};
|
||||
cached->image = ImageOps::CreateTexture(ctx, info, true, &cached->memory, &components);
|
||||
m_memory_tracker.ForEachUploadRange(
|
||||
@@ -1415,8 +1410,8 @@ StorageTextureVulkanImage* TextureCache::FindStorageTexture(CommandBuffer* com
|
||||
cached->info, source, false, true);
|
||||
});
|
||||
cached->gpu_modified = true;
|
||||
ImageOps::CreateTextureViews(ctx, static_cast<GpuTextureVulkanImage*>(cached->image), info, true,
|
||||
components);
|
||||
ImageOps::CreateTextureViews(ctx, static_cast<GpuTextureVulkanImage*>(cached->image), info,
|
||||
true, components);
|
||||
return static_cast<StorageTextureVulkanImage*>(PublishImage(command, std::move(cached)));
|
||||
}
|
||||
|
||||
@@ -1424,11 +1419,11 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer*
|
||||
GraphicContext* ctx,
|
||||
const RenderTargetInfo& info) {
|
||||
const bool standard64 = IsSupportedStandard64RenderTarget(info);
|
||||
if (info.address == 0 || info.size == 0 ||
|
||||
info.address >= TRACKER_ADDRESS_SIZE || info.size > TRACKER_ADDRESS_SIZE - info.address ||
|
||||
info.format == VK_FORMAT_UNDEFINED || info.width == 0 || info.height == 0 ||
|
||||
info.pitch < info.width || info.bytes_per_element == 0 || info.levels == 0 ||
|
||||
info.levels > 16 || info.layers == 0 || info.size % info.layers != 0 ||
|
||||
if (info.address == 0 || info.size == 0 || info.address >= TRACKER_ADDRESS_SIZE ||
|
||||
info.size > TRACKER_ADDRESS_SIZE - info.address || info.format == VK_FORMAT_UNDEFINED ||
|
||||
info.width == 0 || info.height == 0 || info.pitch < info.width ||
|
||||
info.bytes_per_element == 0 || info.levels == 0 || info.levels > 16 || info.layers == 0 ||
|
||||
info.size % info.layers != 0 ||
|
||||
(info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kLinear) &&
|
||||
info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) &&
|
||||
!standard64)) {
|
||||
@@ -1579,9 +1574,10 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer*
|
||||
}
|
||||
break;
|
||||
case RenderTargetOverlap::RetireTarget:
|
||||
supported = cached.kind == CachedImage::Kind::RenderTarget ||
|
||||
(cached.kind == CachedImage::Kind::DepthTarget && target_buffer_overlap &&
|
||||
IsCoherentGuestImageSource(target_source, info.address, info.size));
|
||||
supported =
|
||||
cached.kind == CachedImage::Kind::RenderTarget ||
|
||||
(cached.kind == CachedImage::Kind::DepthTarget && target_buffer_overlap &&
|
||||
IsCoherentGuestImageSource(target_source, info.address, info.size));
|
||||
if (supported && cached.kind == CachedImage::Kind::DepthTarget) {
|
||||
buffer_owned_depth_retire.push_back(&cached);
|
||||
}
|
||||
@@ -1632,8 +1628,8 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer*
|
||||
tail_address, tail_size, true, [](uint64_t, uint64_t) noexcept {},
|
||||
[&]() noexcept {
|
||||
ImageOps::UploadRenderTargetLayers(
|
||||
ctx, static_cast<RenderTextureVulkanImage*>(cached->image), info, old.layers,
|
||||
info.layers - old.layers, false);
|
||||
ctx, static_cast<RenderTextureVulkanImage*>(cached->image), info,
|
||||
old.layers, info.layers - old.layers, false);
|
||||
});
|
||||
}
|
||||
std::vector<ImageImageCopy> regions;
|
||||
@@ -1658,11 +1654,10 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
|
||||
const DepthTargetInfo& info) {
|
||||
const bool has_stencil = info.stencil_address != 0 || info.stencil_size != 0;
|
||||
const bool has_htile = info.htile_address != 0 || info.htile_size != 0;
|
||||
if (info.address == 0 || info.size == 0 ||
|
||||
info.address >= TRACKER_ADDRESS_SIZE || info.size > TRACKER_ADDRESS_SIZE - info.address ||
|
||||
(info.address & 0xffffu) != 0 || info.width == 0 || info.height == 0 ||
|
||||
info.pitch < info.width || info.layers == 0 || info.size % info.layers != 0 ||
|
||||
info.size > UINT32_MAX || info.stencil_size > UINT32_MAX ||
|
||||
if (info.address == 0 || info.size == 0 || info.address >= TRACKER_ADDRESS_SIZE ||
|
||||
info.size > TRACKER_ADDRESS_SIZE - info.address || (info.address & 0xffffu) != 0 ||
|
||||
info.width == 0 || info.height == 0 || info.pitch < info.width || info.layers == 0 ||
|
||||
info.size % info.layers != 0 || info.size > UINT32_MAX || info.stencil_size > UINT32_MAX ||
|
||||
info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kDepth) ||
|
||||
(has_stencil &&
|
||||
(info.stencil_address == 0 || info.stencil_size == 0 ||
|
||||
@@ -1760,9 +1755,8 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
|
||||
m_memory_tracker.ForEachUploadRange(
|
||||
info.address, info.size, true, [](uint64_t, uint64_t) noexcept {},
|
||||
[&]() noexcept {
|
||||
m_tiler.DetileImage(ctx,
|
||||
static_cast<DepthStencilVulkanImage*>(match->image), info,
|
||||
depth_source, true);
|
||||
m_tiler.DetileImage(ctx, static_cast<DepthStencilVulkanImage*>(match->image),
|
||||
info, depth_source, true);
|
||||
});
|
||||
match->buffer_modified = false;
|
||||
match->gpu_modified = true;
|
||||
@@ -1832,17 +1826,15 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
|
||||
case DepthOverlap::RetireStorage:
|
||||
supported = cached.kind == CachedImage::Kind::StorageTexture &&
|
||||
cached.gpu_modified && !cached.buffer_modified &&
|
||||
!cached.info.IsCpuDirty() &&
|
||||
retired_storage_source == nullptr && native_depth_source == nullptr &&
|
||||
discarded_depth_source == nullptr;
|
||||
!cached.info.IsCpuDirty() && retired_storage_source == nullptr &&
|
||||
native_depth_source == nullptr && discarded_depth_source == nullptr;
|
||||
if (supported) {
|
||||
retired_storage_source = entry;
|
||||
}
|
||||
break;
|
||||
case DepthOverlap::ExpandTarget:
|
||||
supported =
|
||||
cached.kind == CachedImage::Kind::DepthTarget && native_depth_source == nullptr &&
|
||||
retired_storage_source == nullptr;
|
||||
supported = cached.kind == CachedImage::Kind::DepthTarget &&
|
||||
native_depth_source == nullptr && retired_storage_source == nullptr;
|
||||
if (supported) {
|
||||
native_depth_source = entry;
|
||||
}
|
||||
@@ -1872,11 +1864,10 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
|
||||
retired_storage_source->info.size);
|
||||
retired_storage_source->gpu_modified = false;
|
||||
}
|
||||
const auto* transition_source = native_depth_source != nullptr
|
||||
? native_depth_source.get()
|
||||
: (discarded_depth_source != nullptr
|
||||
? discarded_depth_source.get()
|
||||
: nullptr);
|
||||
const auto* transition_source =
|
||||
native_depth_source != nullptr
|
||||
? native_depth_source.get()
|
||||
: (discarded_depth_source != nullptr ? discarded_depth_source.get() : nullptr);
|
||||
RetireImages(retire, transition_source);
|
||||
const bool coherent_guest_stencil =
|
||||
has_stencil &&
|
||||
@@ -2050,8 +2041,8 @@ TextureCache::RegisterVideoOutSurfaces(GraphicContext* ctx,
|
||||
m_memory_tracker.ForEachUploadRange(
|
||||
info.address, info.size, false, [](uint64_t, uint64_t) noexcept {},
|
||||
[&]() noexcept {
|
||||
ImageOps::UploadVideoOut(
|
||||
ctx, static_cast<VideoOutVulkanImage*>(cached->image), info, false);
|
||||
ImageOps::UploadVideoOut(ctx, static_cast<VideoOutVulkanImage*>(cached->image),
|
||||
info, false);
|
||||
});
|
||||
} else {
|
||||
// A compressed guest surface cannot be decoded without its DCC metadata. Establish the
|
||||
@@ -2180,8 +2171,8 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer* command, uint64_t vaddr,
|
||||
static_cast<const void*>(command), vaddr, size);
|
||||
}
|
||||
m_buffer_cache.ValidateGpuAccess(vaddr, size, false, true);
|
||||
std::lock_guard transaction(m_resource_mutex);
|
||||
FaultSafeTextureLock lock(this, m_lock);
|
||||
std::lock_guard transaction(m_resource_mutex);
|
||||
FaultSafeTextureLock lock(this, m_lock);
|
||||
enum class ClearAspect : uint8_t { None, Color, Depth, Stencil };
|
||||
auto classify = [vaddr, size](const CachedImage& cached) {
|
||||
const bool color = cached.kind == CachedImage::Kind::VideoOut ||
|
||||
@@ -2238,8 +2229,7 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer* command, uint64_t vaddr,
|
||||
return false;
|
||||
}
|
||||
uint8_t stencil_clear = 0;
|
||||
if (aspect == ClearAspect::Stencil &&
|
||||
!DecodePackedStencilClear(packed_clear, &stencil_clear)) {
|
||||
if (aspect == ClearAspect::Stencil && !DecodePackedStencilClear(packed_clear, &stencil_clear)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2257,8 +2247,7 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer* command, uint64_t vaddr,
|
||||
!buffer_overlap || IsCoherentGuestImageSource(source, vaddr, size);
|
||||
const bool image_cpu_modified = m_memory_tracker.IsRegionCpuModified(vaddr, size);
|
||||
const bool invalid_common = !buffer_source_valid || buffer_cpu_modified ||
|
||||
buffer_gpu_modified || match->buffer_modified ||
|
||||
image_cpu_modified;
|
||||
buffer_gpu_modified || match->buffer_modified || image_cpu_modified;
|
||||
if (aspect == ClearAspect::Color && invalid_common) {
|
||||
EXIT("TextureCache: compute image clear requires exclusive GPU image ownership, "
|
||||
"addr=0x%016" PRIx64 " size=0x%016" PRIx64
|
||||
@@ -2276,8 +2265,8 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer* command, uint64_t vaddr,
|
||||
" gpu_modified=%d buffer_overlap=%d source_valid=%d buffer_cpu_modified=%d"
|
||||
" buffer_gpu_modified=%d buffer_modified=%d image_cpu_modified=%d\n",
|
||||
plane, source_name, vaddr, size, match->gpu_modified, buffer_overlap,
|
||||
buffer_source_valid, buffer_cpu_modified, buffer_gpu_modified,
|
||||
match->buffer_modified, image_cpu_modified);
|
||||
buffer_source_valid, buffer_cpu_modified, buffer_gpu_modified, match->buffer_modified,
|
||||
image_cpu_modified);
|
||||
}
|
||||
|
||||
auto* vk_buffer = command->GetPool()->buffers[command->GetIndex()];
|
||||
@@ -2288,9 +2277,8 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer* command, uint64_t vaddr,
|
||||
}
|
||||
GraphicsRenderColorImageBarrier(vk_buffer, match->image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
const VkImageSubresourceRange range {VK_IMAGE_ASPECT_COLOR_BIT, 0,
|
||||
VK_REMAINING_MIP_LEVELS, 0,
|
||||
match->image->layers};
|
||||
const VkImageSubresourceRange range {VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS,
|
||||
0, match->image->layers};
|
||||
vkCmdClearColorImage(vk_buffer, match->image->image, match->image->layout, &clear, 1,
|
||||
&range);
|
||||
GraphicsRenderColorImageBarrier(vk_buffer, match->image, RENDER_COLOR_IMAGE_LAYOUT);
|
||||
@@ -2312,7 +2300,7 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer* command, uint64_t vaddr,
|
||||
GraphicsRenderDepthStencilImageBarrier(vk_buffer, match->image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
const VkClearDepthStencilValue clear {depth_clear, stencil_clear};
|
||||
const auto clear_aspect = static_cast<VkImageAspectFlags>(
|
||||
const auto clear_aspect = static_cast<VkImageAspectFlags>(
|
||||
aspect == ClearAspect::Depth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT);
|
||||
const VkImageSubresourceRange range {clear_aspect, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
match->image->layers};
|
||||
@@ -2441,9 +2429,8 @@ void TextureCache::PrepareHostWrite(uint64_t vaddr, uint64_t size) {
|
||||
MarkSampledAliasesCpuDirtyLocked(vaddr, size);
|
||||
}
|
||||
|
||||
void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached,
|
||||
uint64_t write_address,
|
||||
uint64_t write_size) {
|
||||
void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached, uint64_t write_address,
|
||||
uint64_t write_size) {
|
||||
const bool render_target = cached.kind == CachedImage::Kind::RenderTarget;
|
||||
const bool video_out = cached.kind == CachedImage::Kind::VideoOut;
|
||||
const bool storage = cached.kind == CachedImage::Kind::StorageTexture;
|
||||
@@ -2485,18 +2472,17 @@ void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached,
|
||||
const bool layered_size =
|
||||
single_slice && static_cast<uint64_t>(exact.size) * target.layers == target.size;
|
||||
if (storage && target.levels > 1) {
|
||||
single_slice = TileGetRenderTargetMipLayout(
|
||||
target.width, target.height, target.pitch, target.bytes_per_element, target.levels,
|
||||
&exact, nullptr, nullptr);
|
||||
single_slice = TileGetRenderTargetMipLayout(target.width, target.height, target.pitch,
|
||||
target.bytes_per_element, target.levels, &exact,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
const bool exact_tiled =
|
||||
tiled && exact.align == 65536 &&
|
||||
(storage ? single_slice && exact.size == target.size : layered_size);
|
||||
const bool valid_kind = render_target || storage || (video_out && cached.video_out.compression ==
|
||||
VideoOutCompression::Uncompressed);
|
||||
const bool exact_tiled = tiled && exact.align == 65536 &&
|
||||
(storage ? single_slice && exact.size == target.size : layered_size);
|
||||
const bool valid_kind =
|
||||
render_target || storage ||
|
||||
(video_out && cached.video_out.compression == VideoOutCompression::Uncompressed);
|
||||
if (!valid_kind || !cached.gpu_modified || cached.buffer_modified ||
|
||||
(!storage && target.levels != 1) ||
|
||||
target.size > UINT32_MAX || (!linear && !exact_tiled) ||
|
||||
(!storage && target.levels != 1) || target.size > UINT32_MAX || (!linear && !exact_tiled) ||
|
||||
HasMetaOverlapLocked(target.address, target.size)) {
|
||||
EXIT("TextureCache: unsupported color-image buffer synchronization, "
|
||||
"addr=0x%016" PRIx64 " size=0x%016" PRIx64
|
||||
@@ -2512,8 +2498,7 @@ void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached,
|
||||
write_address - target.address > target.size ||
|
||||
write_size > target.size - (write_address - target.address)) {
|
||||
EXIT("TextureCache: image synchronization write is outside backing, "
|
||||
"write=0x%016" PRIx64 "+0x%016" PRIx64 " image=0x%016" PRIx64
|
||||
"+0x%016" PRIx64 "\n",
|
||||
"write=0x%016" PRIx64 "+0x%016" PRIx64 " image=0x%016" PRIx64 "+0x%016" PRIx64 "\n",
|
||||
write_address, write_size, target.address, target.size);
|
||||
}
|
||||
const auto slice_size = target.size / target.layers;
|
||||
@@ -2550,7 +2535,7 @@ void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached,
|
||||
}
|
||||
} else {
|
||||
regions = MakeLayeredImageBufferCopies(target.layers, slice_size, target.pitch,
|
||||
target.width, target.height);
|
||||
target.width, target.height);
|
||||
}
|
||||
UtilFillBuffer(cached.ctx, m_buffer_transition_linear.data(), target.size, regions,
|
||||
cached.image, cached.image->layout);
|
||||
@@ -2580,39 +2565,40 @@ void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached,
|
||||
cached.buffer_modified = true;
|
||||
}
|
||||
|
||||
void TextureCache::SynchronizeDepthImageToBufferLocked(CachedImage& cached,
|
||||
uint64_t write_address,
|
||||
uint64_t write_size) {
|
||||
const auto& info = cached.depth;
|
||||
const bool has_stencil = info.stencil_address != 0 || info.stencil_size != 0;
|
||||
const bool has_htile = info.htile_address != 0 || info.htile_size != 0;
|
||||
void TextureCache::SynchronizeDepthImageToBufferLocked(CachedImage& cached, uint64_t write_address,
|
||||
uint64_t write_size) {
|
||||
const auto& info = cached.depth;
|
||||
const bool has_stencil = info.stencil_address != 0 || info.stencil_size != 0;
|
||||
const bool has_htile = info.htile_address != 0 || info.htile_size != 0;
|
||||
TileSizeAlign expected_stencil {};
|
||||
TileSizeAlign expected_htile {};
|
||||
TileSizeAlign expected_depth {};
|
||||
const bool d16 = info.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm) &&
|
||||
info.format == VK_FORMAT_D16_UNORM && info.bytes_per_element == 2;
|
||||
const bool d32 = info.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float) &&
|
||||
info.format == VK_FORMAT_D32_SFLOAT && info.bytes_per_element == 4;
|
||||
const bool layout = (d16 || d32) &&
|
||||
TileGetDepthSize(info.width, info.height, 0,
|
||||
Prospero::GpuEnumValue(d16 ? Prospero::DepthFormat::kZ16
|
||||
: Prospero::DepthFormat::kZ32F),
|
||||
Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid),
|
||||
false, &expected_stencil, &expected_htile,
|
||||
&expected_depth);
|
||||
const bool d16 =
|
||||
info.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm) &&
|
||||
info.format == VK_FORMAT_D16_UNORM && info.bytes_per_element == 2;
|
||||
const bool d32 =
|
||||
info.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float) &&
|
||||
info.format == VK_FORMAT_D32_SFLOAT && info.bytes_per_element == 4;
|
||||
const bool layout =
|
||||
(d16 || d32) &&
|
||||
TileGetDepthSize(info.width, info.height, 0,
|
||||
Prospero::GpuEnumValue(d16 ? Prospero::DepthFormat::kZ16
|
||||
: Prospero::DepthFormat::kZ32F),
|
||||
Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid), false,
|
||||
&expected_stencil, &expected_htile, &expected_depth);
|
||||
if (cached.kind != CachedImage::Kind::DepthTarget || !cached.gpu_modified ||
|
||||
cached.buffer_modified || write_address != info.address || write_size != info.size ||
|
||||
has_stencil || has_htile || info.layers != 1 || !layout ||
|
||||
expected_depth.align != 65536 || expected_depth.size != info.size ||
|
||||
cached.image->format != info.format || cached.image->extent.width != info.width ||
|
||||
cached.image->extent.height != info.height || HasMetaOverlapLocked(info.address, info.size)) {
|
||||
has_stencil || has_htile || info.layers != 1 || !layout || expected_depth.align != 65536 ||
|
||||
expected_depth.size != info.size || cached.image->format != info.format ||
|
||||
cached.image->extent.width != info.width || cached.image->extent.height != info.height ||
|
||||
HasMetaOverlapLocked(info.address, info.size)) {
|
||||
EXIT("TextureCache: unsupported depth-image buffer synchronization, "
|
||||
"write=0x%016" PRIx64 "+0x%016" PRIx64 " depth=0x%016" PRIx64
|
||||
"+0x%016" PRIx64 " extent=%ux%u layers=%u format=%d guest=%u bpe=%u"
|
||||
"write=0x%016" PRIx64 "+0x%016" PRIx64 " depth=0x%016" PRIx64 "+0x%016" PRIx64
|
||||
" extent=%ux%u layers=%u format=%d guest=%u bpe=%u"
|
||||
" stencil=%d htile=%d gpu_modified=%d buffer_modified=%d\n",
|
||||
write_address, write_size, info.address, info.size, info.width, info.height, info.layers,
|
||||
static_cast<int>(info.format), info.guest_format, info.bytes_per_element, has_stencil,
|
||||
has_htile, cached.gpu_modified, cached.buffer_modified);
|
||||
write_address, write_size, info.address, info.size, info.width, info.height,
|
||||
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);
|
||||
m_buffer_transition_linear.resize(info.size);
|
||||
@@ -2623,7 +2609,8 @@ void TextureCache::SynchronizeDepthImageToBufferLocked(CachedImage& cached,
|
||||
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(), info.size);
|
||||
Libs::LibKernel::Memory::WriteBacking(info.address, m_buffer_transition_guest.data(),
|
||||
info.size);
|
||||
m_memory_tracker.ForEachDownloadRange<true>(info.address, info.size,
|
||||
[](uint64_t, uint64_t) noexcept {});
|
||||
m_buffer_cache.PublishImageBacking(write_address, write_size);
|
||||
@@ -2687,9 +2674,7 @@ bool TextureCache::InvalidateMemoryFromGPU(uint64_t vaddr, uint64_t size,
|
||||
case BufferImageWrite::InvalidateVideoOut:
|
||||
case BufferImageWrite::InvalidateStorageTexture:
|
||||
case BufferImageWrite::InvalidateDepthTarget:
|
||||
case BufferImageWrite::InvalidateRenderTarget:
|
||||
cached.buffer_modified = true;
|
||||
return true;
|
||||
case BufferImageWrite::InvalidateRenderTarget: cached.buffer_modified = true; return true;
|
||||
case BufferImageWrite::SynchronizeRenderTarget:
|
||||
case BufferImageWrite::SynchronizeStorageTexture:
|
||||
SynchronizeColorImageToBufferLocked(cached, vaddr, size);
|
||||
@@ -2709,8 +2694,8 @@ bool TextureCache::InvalidateMemoryFromGPU(uint64_t vaddr, uint64_t size,
|
||||
}
|
||||
|
||||
DepthStencilVulkanImage* TextureCache::FindDepthTargetByRange(CommandBuffer* command,
|
||||
uint64_t vaddr, uint64_t size,
|
||||
bool allow_containing_sampled) {
|
||||
uint64_t vaddr, uint64_t size,
|
||||
bool allow_containing_sampled) {
|
||||
if (command == nullptr || vaddr == 0 || size == 0 || vaddr >= TRACKER_ADDRESS_SIZE ||
|
||||
size > TRACKER_ADDRESS_SIZE - vaddr) {
|
||||
EXIT("TextureCache: invalid depth-target range query, addr=0x%016" PRIx64
|
||||
@@ -2724,9 +2709,8 @@ DepthStencilVulkanImage* TextureCache::FindDepthTargetByRange(CommandBuffer* com
|
||||
!cached->OverlapsRange(vaddr, size, false)) {
|
||||
continue;
|
||||
}
|
||||
const bool containing_sampled = allow_containing_sampled &&
|
||||
vaddr == cached->depth.address &&
|
||||
size > cached->depth.size;
|
||||
const bool containing_sampled =
|
||||
allow_containing_sampled && vaddr == cached->depth.address && size > cached->depth.size;
|
||||
if ((!IsDepthTargetRangeCompatible(cached->depth, vaddr, size) && !containing_sampled) ||
|
||||
found != nullptr) {
|
||||
EXIT("TextureCache: incompatible or ambiguous depth-target range, addr=0x%016" PRIx64
|
||||
@@ -2766,8 +2750,8 @@ RenderTextureVulkanImage* TextureCache::FindRenderTargetByRange(CommandBuffer* c
|
||||
" size=0x%016" PRIx64 "\n",
|
||||
vaddr, size);
|
||||
}
|
||||
FaultSafeTextureLock lock(this, m_lock);
|
||||
CachedImage* found = nullptr;
|
||||
FaultSafeTextureLock lock(this, m_lock);
|
||||
CachedImage* found = nullptr;
|
||||
for (auto* cached: FindImagesInRegionLocked(vaddr, size, false)) {
|
||||
if (cached->kind != CachedImage::Kind::RenderTarget ||
|
||||
!ImageRangeOverlaps(vaddr, size, cached->Address(), cached->Size())) {
|
||||
@@ -2784,8 +2768,7 @@ RenderTextureVulkanImage* TextureCache::FindRenderTargetByRange(CommandBuffer* c
|
||||
if (found != nullptr) {
|
||||
EXIT("TextureCache: incompatible or ambiguous render-target range, addr=0x%016" PRIx64
|
||||
" size=0x%016" PRIx64 " cached=0x%016" PRIx64 "+0x%016" PRIx64 " previous=%p\n",
|
||||
vaddr, size, cached->Address(), cached->Size(),
|
||||
static_cast<const void*>(found));
|
||||
vaddr, size, cached->Address(), cached->Size(), static_cast<const void*>(found));
|
||||
}
|
||||
found = cached;
|
||||
}
|
||||
@@ -2804,14 +2787,13 @@ RenderTextureVulkanImage* TextureCache::FindRenderTargetByRange(CommandBuffer* c
|
||||
TextureCache::RegionInfo TextureCache::QueryRegion(uint64_t vaddr, uint64_t size) {
|
||||
if (vaddr == 0 || size == 0 || vaddr >= TRACKER_ADDRESS_SIZE ||
|
||||
size > TRACKER_ADDRESS_SIZE - vaddr) {
|
||||
EXIT("TextureCache: invalid region query, addr=0x%016" PRIx64
|
||||
" size=0x%016" PRIx64 "\n",
|
||||
EXIT("TextureCache: invalid region query, addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n",
|
||||
vaddr, size);
|
||||
}
|
||||
FaultSafeTextureLock lock(this, m_lock);
|
||||
RegionInfo result;
|
||||
const auto candidates = FindImagesInRegionLocked(vaddr, size, true);
|
||||
result.image_pages = !candidates.empty();
|
||||
RegionInfo result;
|
||||
const auto candidates = FindImagesInRegionLocked(vaddr, size, true);
|
||||
result.image_pages = !candidates.empty();
|
||||
for (const auto* cached: candidates) {
|
||||
const bool bytes = cached->OverlapsRange(vaddr, size, false);
|
||||
result.image_bytes |= bytes;
|
||||
|
||||
@@ -34,13 +34,13 @@ class ResourceMutex;
|
||||
class TextureCache {
|
||||
public:
|
||||
struct RegionInfo {
|
||||
bool image_pages = false;
|
||||
bool image_bytes = false;
|
||||
bool gpu_image_bytes = false;
|
||||
bool non_sampled_pages = false;
|
||||
bool metadata_pages = false;
|
||||
bool metadata_bytes = false;
|
||||
bool gpu_metadata_bytes = false;
|
||||
bool image_pages = false;
|
||||
bool image_bytes = false;
|
||||
bool gpu_image_bytes = false;
|
||||
bool non_sampled_pages = false;
|
||||
bool metadata_pages = false;
|
||||
bool metadata_bytes = false;
|
||||
bool gpu_metadata_bytes = false;
|
||||
};
|
||||
|
||||
TextureCache(PageManager& page_manager, BufferCache& buffer_cache,
|
||||
@@ -103,15 +103,15 @@ public:
|
||||
FindDepthTargetByRange(CommandBuffer* command, uint64_t vaddr, uint64_t size,
|
||||
bool allow_containing_sampled = false);
|
||||
[[nodiscard]] RegionInfo QueryRegion(uint64_t vaddr, uint64_t size);
|
||||
void RegisterMeta(uint64_t vaddr, uint64_t size, uint32_t layers = 1);
|
||||
[[nodiscard]] bool IsMeta(uint64_t vaddr);
|
||||
[[nodiscard]] bool IsMetaRange(uint64_t vaddr, uint64_t size);
|
||||
[[nodiscard]] bool IsMetaCleared(uint64_t vaddr, uint32_t slice);
|
||||
[[nodiscard]] bool ClearMeta(uint64_t vaddr);
|
||||
[[nodiscard]] bool TouchMeta(uint64_t vaddr, uint32_t slice, bool is_clear);
|
||||
[[nodiscard]] bool InvalidateMemory(PageFaultAccess access, uint64_t vaddr, uint64_t size,
|
||||
PageFaultPhase phase) noexcept;
|
||||
void UnmapMemory(uint64_t vaddr, uint64_t size);
|
||||
void RegisterMeta(uint64_t vaddr, uint64_t size, uint32_t layers = 1);
|
||||
[[nodiscard]] bool IsMeta(uint64_t vaddr);
|
||||
[[nodiscard]] bool IsMetaRange(uint64_t vaddr, uint64_t size);
|
||||
[[nodiscard]] bool IsMetaCleared(uint64_t vaddr, uint32_t slice);
|
||||
[[nodiscard]] bool ClearMeta(uint64_t vaddr);
|
||||
[[nodiscard]] bool TouchMeta(uint64_t vaddr, uint32_t slice, bool is_clear);
|
||||
[[nodiscard]] bool InvalidateMemory(PageFaultAccess access, uint64_t vaddr, uint64_t size,
|
||||
PageFaultPhase phase) noexcept;
|
||||
void UnmapMemory(uint64_t vaddr, uint64_t size);
|
||||
|
||||
VulkanImage* GetDummySampledTexture(bool uint_format, bool image_3d);
|
||||
VulkanImage* GetDummyStorageTexture(bool uint_format, bool image_3d);
|
||||
@@ -137,10 +137,10 @@ private:
|
||||
void RetireStorageDepthAliasLocked(GraphicContext* ctx, const ImageInfo& requested);
|
||||
void RegisterImageLocked(CachedImage& image);
|
||||
void UnregisterImageLocked(CachedImage& image, bool release_tracking);
|
||||
[[nodiscard]] VulkanImage* PublishImage(CommandBuffer* command,
|
||||
std::shared_ptr<CachedImage> image);
|
||||
[[nodiscard]] std::vector<CachedImage*>
|
||||
FindImagesInRegionLocked(uint64_t vaddr, uint64_t size, bool page_overlap);
|
||||
[[nodiscard]] VulkanImage* PublishImage(CommandBuffer* command,
|
||||
std::shared_ptr<CachedImage> image);
|
||||
[[nodiscard]] std::vector<CachedImage*> FindImagesInRegionLocked(uint64_t vaddr, uint64_t size,
|
||||
bool page_overlap);
|
||||
void RequireRetirementIsolation(const std::vector<CachedImage*>& retire, const char* operation,
|
||||
uint64_t address, uint64_t size) const;
|
||||
void RetireImages(const std::vector<CachedImage*>& retire,
|
||||
@@ -150,7 +150,7 @@ private:
|
||||
void SynchronizeDepthImageToBufferLocked(CachedImage& cached, uint64_t write_address,
|
||||
uint64_t write_size);
|
||||
|
||||
std::unique_ptr<DummyTextureCache> m_dummy_textures;
|
||||
std::unique_ptr<DummyTextureCache> m_dummy_textures;
|
||||
TrackingSpinLock m_lock;
|
||||
std::mutex m_fault_mutex;
|
||||
MemoryTracker m_memory_tracker;
|
||||
|
||||
@@ -163,7 +163,7 @@ void Tiler::TileImage(void* dst, const void* src, const RenderTargetInfo& info)
|
||||
auto* linear_slice = static_cast<const uint8_t*>(src) + slice_size * layer;
|
||||
if (standard64) {
|
||||
TileConvertLinearToTiledStandard64KB32(guest_slice, linear_slice, info.width,
|
||||
info.height, info.pitch, slice_size);
|
||||
info.height, info.pitch, slice_size);
|
||||
} else {
|
||||
TileConvertLinearToTiledRenderTarget(guest_slice, linear_slice, info.width, info.height,
|
||||
info.pitch, info.bytes_per_element, slice_size);
|
||||
@@ -172,30 +172,30 @@ void Tiler::TileImage(void* dst, const void* src, const RenderTargetInfo& info)
|
||||
}
|
||||
|
||||
void Tiler::TileImage(void* dst, const void* src, const ImageInfo& info) const {
|
||||
const bool image_2d = info.type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) &&
|
||||
info.depth == 1;
|
||||
const bool image_2d =
|
||||
info.type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) && info.depth == 1;
|
||||
const auto bytes_per_element = Prospero::RenderTargetBytesPerElement(info.format);
|
||||
if (!image_2d || info.levels == 0 || info.levels > 16 ||
|
||||
info.tile != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) ||
|
||||
bytes_per_element == 0) {
|
||||
EXIT("Tiler: unsupported storage-texture tile, addr=0x%016" PRIx64
|
||||
"+0x%016" PRIx64 " extent=%ux%ux%u levels=%u tile=%u format=%u\n",
|
||||
EXIT("Tiler: unsupported storage-texture tile, addr=0x%016" PRIx64 "+0x%016" PRIx64
|
||||
" extent=%ux%ux%u levels=%u tile=%u format=%u\n",
|
||||
info.address, info.size, info.width, info.height, info.depth, info.levels, info.tile,
|
||||
info.format);
|
||||
}
|
||||
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, Prospero::SurfaceFormat(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];
|
||||
const auto guest_offset = level_size.src_size != 0 ? level_size.src_offset
|
||||
: level_size.offset;
|
||||
auto* guest = static_cast<uint8_t*>(dst) + guest_offset;
|
||||
const auto guest_offset =
|
||||
level_size.src_size != 0 ? level_size.src_offset : level_size.offset;
|
||||
auto* guest = static_cast<uint8_t*>(dst) + guest_offset;
|
||||
const auto* linear = static_cast<const uint8_t*>(src) + regions[level].offset;
|
||||
TileConvertLinearToTiledRenderTarget(
|
||||
guest, linear, regions[level].width, regions[level].height, regions[level].pitch,
|
||||
|
||||
Reference in New Issue
Block a user