mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 02:47:02 +02:00
Support Standard64KB color render targets
This commit is contained in:
@@ -1476,6 +1476,67 @@ void TileConvertTiledToLinearStandard64KB32(void* dst, const void* src, uint32_t
|
||||
}
|
||||
}
|
||||
|
||||
void TileConvertLinearToTiledStandard64KB32(void* dst, const void* src, uint32_t width,
|
||||
uint32_t height, uint32_t pitch, uint64_t size) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
const auto rows = static_cast<uint64_t>(height == 0 ? 0 : height - 1u);
|
||||
const auto expected_pitch = (static_cast<uint64_t>(width) + 127u) & ~uint64_t {127u};
|
||||
if (pitch != expected_pitch || size < (rows * pitch + width) * sizeof(uint32_t)) {
|
||||
EXIT("invalid linear-to-Standard64KB32 conversion, dst=%p src=%p extent=%ux%u "
|
||||
"pitch=%u size=0x%016" PRIx64 "\n",
|
||||
dst, src, width, height, pitch, size);
|
||||
}
|
||||
|
||||
auto* dst32 = static_cast<uint32_t*>(dst);
|
||||
const auto* src32 = static_cast<const uint32_t*>(src);
|
||||
const auto& tables = GetStandard64KB32Tables();
|
||||
const auto blocks_per_row = (static_cast<uint64_t>(pitch) + 127u) >> 7u;
|
||||
const auto block_rows = (static_cast<uint64_t>(height) + 127u) >> 7u;
|
||||
if (blocks_per_row > UINT64_MAX / block_rows / 65536u ||
|
||||
size != blocks_per_row * block_rows * 65536u) {
|
||||
EXIT("invalid Standard64KB32 allocation, extent=%ux%u pitch=%u size=0x%016" PRIx64
|
||||
" blocks=%" PRIu64 "x%" PRIu64 "\n",
|
||||
width, height, pitch, size, blocks_per_row, block_rows);
|
||||
}
|
||||
const auto* x_words = tables.x_words.data();
|
||||
const auto* y_words = tables.y_words.data();
|
||||
|
||||
std::memset(dst32, 0, static_cast<size_t>(size));
|
||||
for (uint32_t block_y = 0; block_y < height; block_y += 128u) {
|
||||
const uint32_t block_height = std::min(128u, height - block_y);
|
||||
for (uint32_t block_x = 0; block_x < width; block_x += 128u) {
|
||||
const uint32_t block_width = std::min(128u, width - block_x);
|
||||
const uint64_t block_base =
|
||||
(((static_cast<uint64_t>(block_y) >> 7u) * blocks_per_row) + (block_x >> 7u))
|
||||
<< 14u;
|
||||
if (block_width == 128u && block_height == 128u) {
|
||||
for (uint32_t local_y = 0; local_y < 128u; local_y++) {
|
||||
const uint64_t src_row =
|
||||
(static_cast<uint64_t>(block_y + local_y) * pitch) + block_x;
|
||||
const uint64_t dst_row = block_base + y_words[local_y];
|
||||
for (uint32_t local_x = 0; local_x < 128u; local_x += 4u) {
|
||||
dst32[dst_row + x_words[local_x + 0u]] = src32[src_row + local_x + 0u];
|
||||
dst32[dst_row + x_words[local_x + 1u]] = src32[src_row + local_x + 1u];
|
||||
dst32[dst_row + x_words[local_x + 2u]] = src32[src_row + local_x + 2u];
|
||||
dst32[dst_row + x_words[local_x + 3u]] = src32[src_row + local_x + 3u];
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t local_y = 0; local_y < block_height; local_y++) {
|
||||
const uint64_t src_row =
|
||||
(static_cast<uint64_t>(block_y + local_y) * pitch) + block_x;
|
||||
const uint64_t dst_row = block_base + y_words[local_y];
|
||||
for (uint32_t local_x = 0; local_x < block_width; local_x++) {
|
||||
dst32[dst_row + x_words[local_x]] = src32[src_row + local_x];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TileConvertTiledToLinearStandard64KB16(void* dst, const void* src, uint32_t width,
|
||||
uint32_t height, uint32_t pitch, uint64_t size,
|
||||
uint64_t src_size, uint32_t src_x, uint32_t src_y) {
|
||||
|
||||
@@ -53,6 +53,8 @@ void TileConvertTiledToLinearStandard64KB32(void* dst, const void* src, uint32_t
|
||||
uint32_t height, uint32_t pitch, uint64_t size,
|
||||
uint64_t src_size = 0, uint32_t src_x = 0,
|
||||
uint32_t src_y = 0);
|
||||
void TileConvertLinearToTiledStandard64KB32(void* dst, const void* src, uint32_t width,
|
||||
uint32_t height, uint32_t pitch, uint64_t size);
|
||||
void TileConvertTiledToLinearStandard64KB16(void* dst, const void* src, uint32_t width,
|
||||
uint32_t height, uint32_t pitch, uint64_t size,
|
||||
uint64_t src_size = 0, uint32_t src_x = 0,
|
||||
|
||||
@@ -373,9 +373,12 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
|
||||
uint32_t pitch = 0;
|
||||
uint64_t size = 0;
|
||||
bool tile = false;
|
||||
const bool standard64 =
|
||||
rt.attrib3.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kStandard64KB);
|
||||
|
||||
switch (rt.attrib3.tile_mode) {
|
||||
case Prospero::GpuEnumValue(Prospero::TileMode::kLinear):
|
||||
case Prospero::GpuEnumValue(Prospero::TileMode::kStandard64KB):
|
||||
case Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget):
|
||||
tile = !RenderIsColorTileModeLinear(rt.attrib3.tile_mode);
|
||||
break;
|
||||
@@ -391,10 +394,32 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
|
||||
if (bytes_per_element == 0) {
|
||||
EXIT("render-target format has no valid element size\n");
|
||||
}
|
||||
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.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 ||
|
||||
rt.info.dcc_compression_enable || rt.info.cmask_is_linear != 0 ||
|
||||
rt.info.cmask_addr_type != 0 || rt.info.alt_tile_mode || rt.cmask.addr != 0 ||
|
||||
rt.fmask.addr != 0 || rt.dcc_addr.addr != 0 || rt.dcc.data_write_on_dcc_clear_to_reg)) {
|
||||
EXIT("unsupported Standard64KB render target: addr=0x%016" PRIx64
|
||||
" 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);
|
||||
}
|
||||
if (rt.pitch.pitch_div8_minus1 != 0) {
|
||||
pitch = (rt.pitch.pitch_div8_minus1 + 1u) << 3u;
|
||||
} else if (tile) {
|
||||
pitch = TileGetRenderTargetPitch(width, bytes_per_element);
|
||||
pitch = standard64
|
||||
? TileGetTexturePitch(Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float),
|
||||
width, levels, rt.attrib3.tile_mode)
|
||||
: TileGetRenderTargetPitch(width, bytes_per_element);
|
||||
if (pitch == 0) {
|
||||
EXIT("unsupported render-target pitch: width=%u bytes=%u\n", width, bytes_per_element);
|
||||
}
|
||||
@@ -404,10 +429,18 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
|
||||
|
||||
if (tile) {
|
||||
TileSizeAlign layout {};
|
||||
const bool valid_layout =
|
||||
levels == 1 ? TileGetRenderTargetSize(width, height, pitch, bytes_per_element, &layout)
|
||||
: TileGetRenderTargetMipLayout(width, height, pitch, bytes_per_element,
|
||||
levels, &layout, nullptr, nullptr);
|
||||
bool valid_layout = false;
|
||||
if (standard64) {
|
||||
TileGetTextureSize(Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float), width,
|
||||
height, pitch, levels, rt.attrib3.tile_mode, &layout, nullptr, nullptr);
|
||||
valid_layout = layout.size != 0 && layout.align == 65536;
|
||||
} else {
|
||||
valid_layout =
|
||||
levels == 1
|
||||
? TileGetRenderTargetSize(width, height, pitch, bytes_per_element, &layout)
|
||||
: TileGetRenderTargetMipLayout(width, height, pitch, bytes_per_element, levels,
|
||||
&layout, nullptr, nullptr);
|
||||
}
|
||||
if (!valid_layout) {
|
||||
EXIT("unsupported render-target layout: %ux%u pitch=%u bytes=%u levels=%u\n", width,
|
||||
height, pitch, bytes_per_element, levels);
|
||||
@@ -430,7 +463,14 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
|
||||
EXIT("render-target backing range is invalid\n");
|
||||
}
|
||||
|
||||
auto video_image = Presentation::DisplayBufferFind(rt.base.addr, true);
|
||||
auto video_image = Presentation::DisplayBufferFind(rt.base.addr, true);
|
||||
if (video_image.image != nullptr &&
|
||||
!IsSupportedDisplayRenderTargetTileMode(rt.attrib3.tile_mode)) {
|
||||
EXIT("unsupported display render-target tile mode: tile=%u expected=%u addr=0x%010" PRIx64
|
||||
" backing_size=0x%016" PRIx64 " video_size=0x%016" PRIx64 "\n",
|
||||
rt.attrib3.tile_mode, Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget),
|
||||
rt.base.addr, backing_size, video_image.size);
|
||||
}
|
||||
bool render_to_texture = view.base_layer != 0 || video_image.image == nullptr;
|
||||
if (!render_to_texture && (levels != 1 || rt.view.current_mip_level != 0)) {
|
||||
EXIT("mipmapped display render targets are unsupported\n");
|
||||
|
||||
@@ -369,15 +369,6 @@ static void RtCheck(const HW::RenderTarget& rt) {
|
||||
if (!RenderIsColorTileMode(rt.attrib3.tile_mode)) {
|
||||
EXIT("unknown PS5 render-target tile mode: 0x%08" PRIx32 "\n", rt.attrib3.tile_mode);
|
||||
}
|
||||
if (rt.attrib3.tile_mode != 0x0000001b) {
|
||||
static bool logged = false;
|
||||
if (!logged) {
|
||||
LOGF("RenderTarget: temporary: using generic PS5 color tile fallback for "
|
||||
"tile_mode=0x%08" PRIx32 "\n",
|
||||
rt.attrib3.tile_mode);
|
||||
logged = true;
|
||||
}
|
||||
}
|
||||
if (!RenderIsColorDimension(rt.attrib3.dimension)) {
|
||||
EXIT("unknown PS5 render-target dimension: 0x%08" PRIx32 "\n", rt.attrib3.dimension);
|
||||
}
|
||||
|
||||
@@ -360,6 +360,30 @@ SelectStorageSampledViewShape(uint32_t type, uint32_t depth, uint32_t backing_la
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr bool IsSupportedDisplayRenderTargetTileMode(
|
||||
uint32_t tile_mode) noexcept {
|
||||
return tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr bool
|
||||
IsSupportedStandard64RenderTarget(const RenderTargetInfo& info) noexcept {
|
||||
if (info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kStandard64KB) ||
|
||||
info.address == 0 || (info.address & 0xffffu) != 0 || info.width == 0 || info.height == 0 ||
|
||||
info.bytes_per_element != 4 || info.levels != 1 || info.layers != 1) {
|
||||
return false;
|
||||
}
|
||||
const auto expected_pitch = (static_cast<uint64_t>(info.width) + 127u) & ~uint64_t {127u};
|
||||
const auto padded_height = (static_cast<uint64_t>(info.height) + 127u) & ~uint64_t {127u};
|
||||
return expected_pitch <= UINT32_MAX && info.pitch == expected_pitch &&
|
||||
expected_pitch <= UINT64_MAX / padded_height / info.bytes_per_element &&
|
||||
info.size == expected_pitch * padded_height * info.bytes_per_element;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr bool IsTiledRenderTarget(const RenderTargetInfo& info) noexcept {
|
||||
return info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) ||
|
||||
IsSupportedStandard64RenderTarget(info);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline constexpr DepthTransitionSource
|
||||
SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available,
|
||||
bool sampled_cpu_dirty, bool sampled_buffer_modified,
|
||||
|
||||
@@ -415,9 +415,8 @@ struct TextureCache::ReadbackWorker {
|
||||
cached.info, Prospero::SurfaceFormat(cached.info.format),
|
||||
Prospero::NumBytesPerElement(cached.info.format))
|
||||
: MakeColorImageTransferInfo(cached.target);
|
||||
const bool linear = info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kLinear);
|
||||
const bool tiled =
|
||||
target && info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget);
|
||||
const bool linear = info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kLinear);
|
||||
const bool tiled = target && IsTiledRenderTarget(cached.target);
|
||||
bool single_layer_storage = false;
|
||||
if (storage) {
|
||||
switch (static_cast<Prospero::ImageType>(cached.info.type)) {
|
||||
@@ -975,14 +974,16 @@ void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* ima
|
||||
}
|
||||
const auto slice_size = info.size / info.layers;
|
||||
const auto upload_size = slice_size * layer_count;
|
||||
if (info.levels > 1 || info.layers > 1) {
|
||||
const bool standard64 = IsSupportedStandard64RenderTarget(info);
|
||||
if (standard64 || info.levels > 1 || info.layers > 1) {
|
||||
const auto format = RenderTargetTransferFormat(info.bytes_per_element);
|
||||
auto layout = TextureCalcUploadLayout(format, info.width, info.height, info.levels,
|
||||
layer_count, info.pitch, info.tile_mode, upload_size,
|
||||
false, false, false, "TextureCache render target");
|
||||
const bool tiled =
|
||||
const bool render_target_tiled =
|
||||
info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget);
|
||||
if ((tiled && !layout.fmt_tiled_render_target) || layout.pitch != info.pitch) {
|
||||
if ((render_target_tiled && !layout.fmt_tiled_render_target) ||
|
||||
(standard64 && !layout.fmt_tiled_standard64kb) || layout.pitch != info.pitch) {
|
||||
EXIT("TextureCache: unsupported render-target mip upload layout, pitch=%u/%u tile=%u\n",
|
||||
info.pitch, layout.pitch, info.tile_mode);
|
||||
}
|
||||
@@ -2074,13 +2075,15 @@ StorageTextureVulkanImage* TextureCache::FindStorageTexture(CommandBuffer* com
|
||||
RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer* command,
|
||||
GraphicContext* ctx,
|
||||
const RenderTargetInfo& info) {
|
||||
const bool standard64 = IsSupportedStandard64RenderTarget(info);
|
||||
if (command == nullptr || ctx == nullptr || 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))) {
|
||||
info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) &&
|
||||
!standard64)) {
|
||||
EXIT("TextureCache: invalid render-target request, ctx=%p addr=0x%016" PRIx64
|
||||
" size=0x%016" PRIx64 " extent=%ux%u pitch=%u bpe=%u tile=%u format=%d\n",
|
||||
static_cast<const void*>(ctx), info.address, info.size, info.width, info.height,
|
||||
@@ -2100,6 +2103,19 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer*
|
||||
info.bytes_per_element, info.levels, info.tile_mode);
|
||||
}
|
||||
}
|
||||
if (standard64) {
|
||||
const auto format = RenderTargetTransferFormat(info.bytes_per_element);
|
||||
const auto expected_pitch =
|
||||
TileGetTexturePitch(format, info.width, info.levels, info.tile_mode);
|
||||
TileSizeAlign layout {};
|
||||
TileGetTextureSize(format, info.width, info.height, expected_pitch, info.levels,
|
||||
info.tile_mode, &layout, nullptr, nullptr);
|
||||
if (expected_pitch != info.pitch || layout.align != 65536 || layout.size != info.size) {
|
||||
EXIT("TextureCache: invalid Standard64KB render-target layout,"
|
||||
" size=0x%016" PRIx64 " expected=0x%08x align=0x%08x pitch=%u/%u\n",
|
||||
info.size, layout.size, layout.align, info.pitch, expected_pitch);
|
||||
}
|
||||
}
|
||||
const auto rows = static_cast<uint64_t>(info.height - 1);
|
||||
if (rows > (UINT64_MAX - info.width) / info.pitch) {
|
||||
EXIT("TextureCache: render-target element count overflow, extent=%ux%u pitch=%u\n",
|
||||
@@ -3085,12 +3101,21 @@ void TextureCache::PrepareHostWrite(uint64_t vaddr, uint64_t size) {
|
||||
void TextureCache::SynchronizeRenderTargetToBufferLocked(CachedImage& cached) {
|
||||
const auto& target = cached.target;
|
||||
const bool linear = target.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kLinear);
|
||||
const bool tiled =
|
||||
target.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget);
|
||||
const bool tiled = IsTiledRenderTarget(target);
|
||||
const auto rows = static_cast<uint64_t>(target.height - 1);
|
||||
TileSizeAlign exact {};
|
||||
const bool single_slice = TileGetRenderTargetSize(target.width, target.height, target.pitch,
|
||||
target.bytes_per_element, &exact);
|
||||
bool single_slice = false;
|
||||
if (IsSupportedStandard64RenderTarget(target)) {
|
||||
const auto format = RenderTargetTransferFormat(target.bytes_per_element);
|
||||
const auto expected_pitch =
|
||||
TileGetTexturePitch(format, target.width, target.levels, target.tile_mode);
|
||||
TileGetTextureSize(format, target.width, target.height, expected_pitch, target.levels,
|
||||
target.tile_mode, &exact, nullptr, nullptr);
|
||||
single_slice = target.pitch == expected_pitch && exact.align == 65536 && exact.size != 0;
|
||||
} else {
|
||||
single_slice = TileGetRenderTargetSize(target.width, target.height, target.pitch,
|
||||
target.bytes_per_element, &exact);
|
||||
}
|
||||
const bool layered_size = target.layers != 0 && single_slice &&
|
||||
exact.size <= UINT64_MAX / target.layers &&
|
||||
exact.size * target.layers == target.size;
|
||||
|
||||
@@ -214,7 +214,7 @@ void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image,
|
||||
void Tiler::TileImage(void* dst, const void* src, const RenderTargetInfo& info) const {
|
||||
if (dst == nullptr || src == nullptr || info.address == 0 || info.size == 0 ||
|
||||
info.width == 0 || info.height == 0 || info.pitch < info.width ||
|
||||
info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) ||
|
||||
!IsTiledRenderTarget(info) ||
|
||||
info.levels != 1 || info.layers == 0 || info.size % info.layers != 0 ||
|
||||
!IsSupportedRenderTargetElementSize(info.bytes_per_element)) {
|
||||
EXIT("Tiler: unsupported render-target tile, dst=%p src=%p "
|
||||
@@ -227,8 +227,13 @@ void Tiler::TileImage(void* dst, const void* src, const RenderTargetInfo& info)
|
||||
for (uint32_t layer = 0; layer < info.layers; layer++) {
|
||||
auto* guest_slice = static_cast<uint8_t*>(dst) + slice_size * layer;
|
||||
auto* linear_slice = static_cast<const uint8_t*>(src) + slice_size * layer;
|
||||
TileConvertLinearToTiledRenderTarget(guest_slice, linear_slice, info.width, info.height,
|
||||
info.pitch, info.bytes_per_element, slice_size);
|
||||
if (IsSupportedStandard64RenderTarget(info)) {
|
||||
TileConvertLinearToTiledStandard64KB32(guest_slice, linear_slice, info.width,
|
||||
info.height, info.pitch, slice_size);
|
||||
} else {
|
||||
TileConvertLinearToTiledRenderTarget(guest_slice, linear_slice, info.width, info.height,
|
||||
info.pitch, info.bytes_per_element, slice_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user