Support Standard64KB color render targets
This commit is contained in:
parent
1416131a0a
commit
a290a06ea5
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9649,6 +9649,180 @@ void CheckColorResolveLayers() {
|
|||
std::printf("[host] %-32s ok\n", "ColorResolveLayers");
|
||||
}
|
||||
|
||||
[[noreturn]] void RunStandard64RenderTargetDeathCase() {
|
||||
RenderTargetInfo info{};
|
||||
info.address = 0x10000;
|
||||
info.size = 0x10000;
|
||||
info.format = VK_FORMAT_R16G16B16A16_SFLOAT;
|
||||
info.width = 128;
|
||||
info.height = 64;
|
||||
info.pitch = 128;
|
||||
info.bytes_per_element = 8;
|
||||
info.tile_mode =
|
||||
Prospero::GpuEnumValue(Prospero::TileMode::kStandard64KB);
|
||||
std::vector<uint8_t> linear(info.size, 0);
|
||||
std::vector<uint8_t> tiled(info.size, 0);
|
||||
Tiler tiler;
|
||||
tiler.TileImage(tiled.data(), linear.data(), info);
|
||||
std::_Exit(0x7f);
|
||||
}
|
||||
|
||||
void CheckStandard64RenderTargetTileRoundTrip() {
|
||||
constexpr uint32_t format =
|
||||
Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float);
|
||||
constexpr uint32_t tile =
|
||||
Prospero::GpuEnumValue(Prospero::TileMode::kStandard64KB);
|
||||
|
||||
constexpr uint32_t observed_width = 3840;
|
||||
constexpr uint32_t observed_height = 2160;
|
||||
const auto observed_pitch =
|
||||
TileGetTexturePitch(format, observed_width, 1, tile);
|
||||
TileSizeAlign observed{};
|
||||
TileGetTextureSize(format, observed_width, observed_height, observed_pitch,
|
||||
1, tile, &observed, nullptr, nullptr);
|
||||
Require("Standard64RenderTarget", "observed layout",
|
||||
observed_pitch == 3840 && observed.size == 0x1fe0000 &&
|
||||
observed.align == 0x10000,
|
||||
"PPSA02721 Standard64KB render-target footprint changed");
|
||||
|
||||
constexpr uint32_t width = 257;
|
||||
constexpr uint32_t height = 131;
|
||||
const auto pitch = TileGetTexturePitch(format, width, 1, tile);
|
||||
TileSizeAlign storage{};
|
||||
TileGetTextureSize(format, width, height, pitch, 1, tile, &storage,
|
||||
nullptr, nullptr);
|
||||
Require("Standard64RenderTarget", "partial layout",
|
||||
pitch == 384 && storage.size == 0x60000 &&
|
||||
storage.align == 0x10000,
|
||||
"partial Standard64KB footprint was not padded in 128x128 blocks");
|
||||
|
||||
RenderTargetInfo info{};
|
||||
info.address = 0x10000;
|
||||
info.size = storage.size;
|
||||
info.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
info.width = width;
|
||||
info.height = height;
|
||||
info.pitch = pitch;
|
||||
info.bytes_per_element = 4;
|
||||
info.tile_mode = tile;
|
||||
Require("Standard64RenderTarget", "support boundary",
|
||||
IsSupportedStandard64RenderTarget(info) &&
|
||||
IsTiledRenderTarget(info),
|
||||
"exact Standard64KB render target was not classified as tiled");
|
||||
Require(
|
||||
"Standard64RenderTarget", "display tile boundary",
|
||||
IsSupportedDisplayRenderTargetTileMode(
|
||||
Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget)) &&
|
||||
!IsSupportedDisplayRenderTargetTileMode(tile),
|
||||
"Standard64KB render target could alias a mode-27 display image");
|
||||
auto unsupported = info;
|
||||
unsupported.address += 4;
|
||||
Require("Standard64RenderTarget", "address guard",
|
||||
!IsSupportedStandard64RenderTarget(unsupported),
|
||||
"unaligned Standard64KB backing was accepted");
|
||||
unsupported = info;
|
||||
unsupported.bytes_per_element = 8;
|
||||
Require("Standard64RenderTarget", "element guard",
|
||||
!IsSupportedStandard64RenderTarget(unsupported),
|
||||
"unimplemented Standard64KB element size was accepted");
|
||||
unsupported = info;
|
||||
unsupported.pitch += 128;
|
||||
Require("Standard64RenderTarget", "pitch guard",
|
||||
!IsSupportedStandard64RenderTarget(unsupported),
|
||||
"non-minimal Standard64KB pitch was accepted");
|
||||
unsupported = info;
|
||||
unsupported.size += 0x10000;
|
||||
Require("Standard64RenderTarget", "size guard",
|
||||
!IsSupportedStandard64RenderTarget(unsupported),
|
||||
"non-exact Standard64KB allocation was accepted");
|
||||
unsupported = info;
|
||||
unsupported.levels = 2;
|
||||
Require("Standard64RenderTarget", "mip guard",
|
||||
!IsSupportedStandard64RenderTarget(unsupported),
|
||||
"unimplemented Standard64KB mip chain was accepted");
|
||||
unsupported = info;
|
||||
unsupported.layers = 2;
|
||||
Require("Standard64RenderTarget", "layer guard",
|
||||
!IsSupportedStandard64RenderTarget(unsupported),
|
||||
"unimplemented Standard64KB array was accepted");
|
||||
|
||||
std::vector<uint32_t> linear(storage.size / sizeof(uint32_t), 0);
|
||||
for (uint32_t y = 0; y < height; y++) {
|
||||
for (uint32_t x = 0; x < width; x++) {
|
||||
linear[static_cast<uint64_t>(y) * pitch + x] =
|
||||
(y * 0x1f123bb5u) ^ (x * 0x9e3779b9u) ^ 0xa55a3cc3u;
|
||||
}
|
||||
}
|
||||
std::vector<uint32_t> tiled(linear.size(), 0xcdcdcdcdu);
|
||||
std::vector<uint32_t> restored(linear.size(), 0xa5a5a5a5u);
|
||||
Tiler tiler;
|
||||
tiler.TileImage(tiled.data(), linear.data(), info);
|
||||
TileConvertTiledToLinearStandard64KB32(
|
||||
restored.data(), tiled.data(), width, height, pitch, storage.size);
|
||||
for (uint32_t y = 0; y < height; y++) {
|
||||
const auto row = static_cast<uint64_t>(y) * pitch;
|
||||
Require("Standard64RenderTarget", "round trip",
|
||||
std::memcmp(linear.data() + row, restored.data() + row,
|
||||
width * sizeof(uint32_t)) == 0,
|
||||
"Standard64KB render-target conversion did not round-trip");
|
||||
}
|
||||
Require("Standard64RenderTarget", "padding",
|
||||
tiled.back() == 0,
|
||||
"Standard64KB render-target conversion retained stale padding");
|
||||
|
||||
constexpr uint32_t block_width = 128;
|
||||
constexpr uint32_t block_height = 128;
|
||||
constexpr uint64_t block_size = 0x10000;
|
||||
std::vector<uint32_t> known(block_size / sizeof(uint32_t));
|
||||
for (uint32_t i = 0; i < known.size(); i++) {
|
||||
known[i] = i;
|
||||
}
|
||||
std::vector<uint32_t> standard(known.size(), 0);
|
||||
std::vector<uint32_t> render_target(known.size(), 0);
|
||||
TileConvertLinearToTiledStandard64KB32(
|
||||
standard.data(), known.data(), block_width, block_height, block_width,
|
||||
block_size);
|
||||
Require("Standard64RenderTarget", "SDK byte mapping",
|
||||
standard[0] == 0 && standard[1] == 1 && standard[2] == 2 &&
|
||||
standard[4] == 128 && standard[8] == 256 &&
|
||||
standard[16] == 512 && standard[32] == 4 &&
|
||||
standard[16383] == 16383,
|
||||
"Standard64KB reciprocal mapping disagreed with the PS5 SDK");
|
||||
TileConvertLinearToTiledRenderTarget(
|
||||
render_target.data(), known.data(), block_width, block_height,
|
||||
block_width, sizeof(uint32_t), block_size);
|
||||
Require("Standard64RenderTarget", "mode identity",
|
||||
standard != render_target,
|
||||
"Standard64KB was accidentally treated as RenderTarget/XOR tiling");
|
||||
|
||||
char path[MAX_PATH]{};
|
||||
Require("Standard64RenderTarget", "host",
|
||||
GetModuleFileNameA(nullptr, path, MAX_PATH) != 0,
|
||||
"GetModuleFileName failed");
|
||||
std::string command =
|
||||
std::string("\"") + path + "\" --standard64-rt-death";
|
||||
std::vector<char> mutable_command(command.begin(), command.end());
|
||||
mutable_command.push_back('\0');
|
||||
STARTUPINFOA startup{sizeof(startup)};
|
||||
PROCESS_INFORMATION process{};
|
||||
Require("Standard64RenderTarget", "host",
|
||||
CreateProcessA(nullptr, mutable_command.data(), nullptr, nullptr,
|
||||
FALSE, CREATE_NO_WINDOW, nullptr, nullptr, &startup,
|
||||
&process) != 0,
|
||||
"CreateProcess failed");
|
||||
Require("Standard64RenderTarget", "host",
|
||||
WaitForSingleObject(process.hProcess, 10000) == WAIT_OBJECT_0,
|
||||
"unsupported Standard64KB render-target case timed out");
|
||||
DWORD exit_code = 0;
|
||||
const bool exited = GetExitCodeProcess(process.hProcess, &exit_code) != 0;
|
||||
CloseHandle(process.hThread);
|
||||
CloseHandle(process.hProcess);
|
||||
Require("Standard64RenderTarget", "hard failure",
|
||||
exited && exit_code == 321,
|
||||
"unsupported Standard64KB render-target shape lost its fatal guard");
|
||||
std::printf("[host] %-32s ok\n", "Standard64RenderTarget");
|
||||
}
|
||||
|
||||
void CheckRenderTargetTileRoundTrip() {
|
||||
struct Case {
|
||||
uint32_t width;
|
||||
|
|
@ -11790,10 +11964,17 @@ int main(int argc, char **argv) {
|
|||
if (argc == 2 && std::strcmp(argv[1], "--reverse-rt-death") == 0) {
|
||||
RunReverseRenderTargetDeathCase();
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--standard64-rt-death") == 0) {
|
||||
RunStandard64RenderTargetDeathCase();
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--reverse-rt-only") == 0) {
|
||||
CheckReverseRenderTargetFormatContract();
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--standard64-rt-only") == 0) {
|
||||
CheckStandard64RenderTargetTileRoundTrip();
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--image-overlap-only") == 0) {
|
||||
CheckImageOverlapResolution();
|
||||
return 0;
|
||||
|
|
@ -11878,6 +12059,7 @@ int main(int argc, char **argv) {
|
|||
CheckStorageTextureLinearReadbackLayout();
|
||||
CheckStorageImageSwizzleSpecializationId();
|
||||
CheckColorResolveLayers();
|
||||
CheckStandard64RenderTargetTileRoundTrip();
|
||||
CheckRenderTargetTileRoundTrip();
|
||||
CheckDepthTargetTileRoundTrip();
|
||||
CheckStencilTargetTileRoundTrip();
|
||||
|
|
|
|||
Loading…
Reference in New Issue