support 16-bit float video-out

This commit is contained in:
nmzik
2026-07-17 19:36:06 +02:00
parent 0621d9e9d0
commit c21a4100c8
8 changed files with 163 additions and 83 deletions
+1
View File
@@ -129,6 +129,7 @@ struct ColorComponentMapping {
static_assert(sizeof(ColorComponentMapping) == sizeof(uint8_t)); static_assert(sizeof(ColorComponentMapping) == sizeof(uint8_t));
inline constexpr ColorComponentMapping ColorMappingAbgr {0x1bu}; // 3, 2, 1, 0 inline constexpr ColorComponentMapping ColorMappingAbgr {0x1bu}; // 3, 2, 1, 0
inline constexpr ColorComponentMapping ColorMappingBgra {0xc6u}; // 2, 1, 0, 3
enum class DepthFormat : uint32_t { enum class DepthFormat : uint32_t {
kInvalid = 0, kInvalid = 0,
@@ -114,6 +114,10 @@ RenderTargetFormatInfo TextureGetRenderTargetFormat(uint32_t raw_layout, uint32_
Prospero::ChannelOrder::kStandard)) { Prospero::ChannelOrder::kStandard)) {
return {VK_FORMAT_R16G16B16A16_SFLOAT, 8}; return {VK_FORMAT_R16G16B16A16_SFLOAT, 8};
} }
if (is(Prospero::ChannelLayout::k16_16_16_16, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kAlt)) {
return {VK_FORMAT_R16G16B16A16_SFLOAT, 8, Prospero::ColorMappingBgra};
}
if (is(Prospero::ChannelLayout::k16_16_16_16, Prospero::ChannelType::kFloat, if (is(Prospero::ChannelLayout::k16_16_16_16, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kReversed)) { Prospero::ChannelOrder::kReversed)) {
return {VK_FORMAT_R16G16B16A16_SFLOAT, 8, Prospero::ColorMappingAbgr}; return {VK_FORMAT_R16G16B16A16_SFLOAT, 8, Prospero::ColorMappingAbgr};
@@ -179,6 +179,10 @@ static float ColorClearF16(uint32_t value) {
color.float32[1] = ColorClearF16((c0 >> 16u) & 0xffffu); color.float32[1] = ColorClearF16((c0 >> 16u) & 0xffffu);
color.float32[2] = ColorClearF16(c1 & 0xffffu); color.float32[2] = ColorClearF16(c1 & 0xffffu);
color.float32[3] = ColorClearF16((c1 >> 16u) & 0xffffu); color.float32[3] = ColorClearF16((c1 >> 16u) & 0xffffu);
if (rt.info.channel_order ==
Prospero::GpuEnumValue(Prospero::ChannelOrder::kAlt)) {
std::swap(color.float32[0], color.float32[2]);
}
break; break;
case Prospero::ChannelLayout::k32: case Prospero::ChannelLayout::k32:
case Prospero::ChannelLayout::k11_11_10: case Prospero::ChannelLayout::k11_11_10:
@@ -535,6 +539,10 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
order == Prospero::ChannelOrder::kAlt)) || order == Prospero::ChannelOrder::kAlt)) ||
(layout == Prospero::ChannelLayout::k10_10_10_2 && (layout == Prospero::ChannelLayout::k10_10_10_2 &&
type == Prospero::ChannelType::kUNorm && type == Prospero::ChannelType::kUNorm &&
(order == Prospero::ChannelOrder::kStandard ||
order == Prospero::ChannelOrder::kAlt)) ||
(layout == Prospero::ChannelLayout::k16_16_16_16 &&
type == Prospero::ChannelType::kFloat &&
(order == Prospero::ChannelOrder::kStandard || order == Prospero::ChannelOrder::kAlt)); (order == Prospero::ChannelOrder::kStandard || order == Prospero::ChannelOrder::kAlt));
EXIT_NOT_IMPLEMENTED(!supported_display_format); EXIT_NOT_IMPLEMENTED(!supported_display_format);
@@ -555,6 +563,9 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
r->extent = video_image.image->extent; r->extent = video_image.image->extent;
r->base_mip_level = 0; r->base_mip_level = 0;
r->buffer_size = video_image.size; r->buffer_size = video_image.size;
r->export_mapping = TextureGetRenderTargetFormat(rt.info.format, rt.info.channel_type,
rt.info.channel_order)
.export_mapping;
} }
} }
+12 -4
View File
@@ -321,12 +321,20 @@ static void ValidateDepthTargetBinding(const ShaderRecompiler::IR::ImageResource
TileGetTexturePitch(descriptor.Format(), static_cast<uint32_t>(descriptor.Width5()) + 1u, 1, TileGetTexturePitch(descriptor.Format(), static_cast<uint32_t>(descriptor.Width5()) + 1u, 1,
descriptor.TileMode()); descriptor.TileMode());
EXIT("unsupported sampled depth target: resource=%d descriptor=%d encoding=%d format=%d " EXIT("unsupported sampled depth target: resource=%d descriptor=%d encoding=%d format=%d "
"image_format=%d view_format=%d descriptor_pitch=%u target_pitch=%u " "kind=%u dimension=%u mip=%u read=%d written=%d atomic=%d compare=%d "
"addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n", "image_format=%d view_format=%d image_layers=%u descriptor_type=%u base_array=%u "
"depth=%u descriptor_pitch=%u target_pitch=%u fields=%08x/%08x/%08x/%08x/%08x/"
"%08x/%08x/%08x addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n",
resource_ok, descriptor_ok, encoding_ok, format_ok, resource_ok, descriptor_ok, encoding_ok, format_ok,
static_cast<uint32_t>(resource.kind), static_cast<uint32_t>(resource.dimension),
static_cast<uint32_t>(resource.mip_mode), resource.read, resource.written, resource.atomic,
resource.depth_compare,
image == nullptr ? static_cast<int>(VK_FORMAT_UNDEFINED) : static_cast<int>(image->format), image == nullptr ? static_cast<int>(VK_FORMAT_UNDEFINED) : static_cast<int>(image->format),
static_cast<int>(view_format), descriptor_pitch, static_cast<int>(view_format), image == nullptr ? 0u : image->layers, descriptor.Type(),
image == nullptr ? 0u : image->guest_pitch, descriptor.Base40(), size); descriptor.BaseArray5(), descriptor.Depth(), descriptor_pitch,
image == nullptr ? 0u : image->guest_pitch, descriptor.fields[0], descriptor.fields[1],
descriptor.fields[2], descriptor.fields[3], descriptor.fields[4], descriptor.fields[5],
descriptor.fields[6], descriptor.fields[7], descriptor.Base40(), size);
} }
static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::ImageResource& resource, static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::ImageResource& resource,
+46 -32
View File
@@ -240,6 +240,7 @@ struct VideoOutInfo {
uint32_t tile_mode = 0; uint32_t tile_mode = 0;
uint32_t dcc_control = 0; uint32_t dcc_control = 0;
VideoOutCompression compression = VideoOutCompression::Unsupported; VideoOutCompression compression = VideoOutCompression::Unsupported;
bool bgra16 = false;
}; };
[[nodiscard]] inline VideoOutCompression [[nodiscard]] inline VideoOutCompression
@@ -265,48 +266,61 @@ CanUseVideoOutNativeWithoutUpload(VideoOutCompression compression, bool render_t
} }
struct VideoOutPixelFormatInfo { struct VideoOutPixelFormatInfo {
VkFormat format = VK_FORMAT_UNDEFINED; VkFormat format = VK_FORMAT_UNDEFINED;
uint32_t guest_format = 0; uint32_t guest_format = 0;
uint32_t bytes_per_element = 0;
bool bgra16 = false;
}; };
struct VideoOutFormatPolicy {
uint64_t pixel_format;
VideoOutPixelFormatInfo info;
};
inline constexpr std::array<VideoOutFormatPolicy, 6> VIDEO_OUT_FORMAT_POLICIES {{
{0x8000000022000000ull,
{VK_FORMAT_R8G8B8A8_SRGB, Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8Srgb), 4,
false}},
{0x8000000000000000ull,
{VK_FORMAT_B8G8R8A8_SRGB, Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8Srgb), 4,
false}},
{0x8100000022000000ull,
{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
Prospero::GpuEnumValue(Prospero::BufferFormat::k10_10_10_2UNorm), 4, false}},
{0x8100000000000000ull,
{VK_FORMAT_A2R10G10B10_UNORM_PACK32,
Prospero::GpuEnumValue(Prospero::BufferFormat::k10_10_10_2UNorm), 4, false}},
{0xc001000622000000ull,
{VK_FORMAT_R16G16B16A16_SFLOAT,
Prospero::GpuEnumValue(Prospero::BufferFormat::k16_16_16_16Float), 8, false}},
{0xc001000600000000ull,
{VK_FORMAT_R16G16B16A16_SFLOAT,
Prospero::GpuEnumValue(Prospero::BufferFormat::k16_16_16_16Float), 8, true}},
}};
[[nodiscard]] inline bool DecodeVideoOutPixelFormat(uint64_t pixel_format, [[nodiscard]] inline bool DecodeVideoOutPixelFormat(uint64_t pixel_format,
VideoOutPixelFormatInfo* info) { VideoOutPixelFormatInfo* info) {
if (info == nullptr) { if (info == nullptr) {
return false; return false;
} }
VideoOutPixelFormatInfo next {}; for (const auto& policy: VIDEO_OUT_FORMAT_POLICIES) {
switch (pixel_format) { if (policy.pixel_format == pixel_format) {
case 0x8000000022000000ull: // SCE_VIDEO_OUT_PIXEL_FORMAT2_R8_G8_B8_A8_SRGB *info = policy.info;
next.format = VK_FORMAT_R8G8B8A8_SRGB; return true;
next.guest_format = Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8Srgb); }
break;
case 0x8000000000000000ull: // SCE_VIDEO_OUT_PIXEL_FORMAT2_B8_G8_R8_A8_SRGB
next.format = VK_FORMAT_B8G8R8A8_SRGB;
next.guest_format = Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8Srgb);
break;
case 0x8100000022000000ull: // SCE_VIDEO_OUT_PIXEL_FORMAT2_R10_G10_B10_A2_SRGB
next.format = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
next.guest_format = Prospero::GpuEnumValue(Prospero::BufferFormat::k10_10_10_2UNorm);
break;
case 0x8100000000000000ull: // SCE_VIDEO_OUT_PIXEL_FORMAT2_B10_G10_R10_A2_SRGB
next.format = VK_FORMAT_A2R10G10B10_UNORM_PACK32;
next.guest_format = Prospero::GpuEnumValue(Prospero::BufferFormat::k10_10_10_2UNorm);
break;
default: return false;
} }
*info = next; return false;
return true;
} }
[[nodiscard]] inline bool IsSupportedVideoOutFormat(uint32_t guest_format, VkFormat format) { [[nodiscard]] inline bool IsSupportedVideoOutFormat(const VideoOutInfo& info) {
const bool rgba8 = for (const auto& policy: VIDEO_OUT_FORMAT_POLICIES) {
guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8Srgb) && if (info.format == policy.info.format && info.guest_format == policy.info.guest_format &&
(format == VK_FORMAT_R8G8B8A8_SRGB || format == VK_FORMAT_B8G8R8A8_SRGB); info.bytes_per_element == policy.info.bytes_per_element &&
const bool rgb10 = info.bgra16 == policy.info.bgra16) {
guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k10_10_10_2UNorm) && return true;
(format == VK_FORMAT_A2B10G10R10_UNORM_PACK32 || }
format == VK_FORMAT_A2R10G10B10_UNORM_PACK32); }
return rgba8 || rgb10; return false;
} }
enum class DepthOverlap : uint8_t { None, RetireSampled, ExpandTarget, Unsupported }; enum class DepthOverlap : uint8_t { None, RetireSampled, ExpandTarget, Unsupported };
@@ -1142,9 +1142,8 @@ void ValidateVideoOutInfo(GraphicContext* ctx, const VideoOutInfo& info) {
(info.address & 0xffffu) != 0 || info.width == 0 || info.height == 0 || (info.address & 0xffffu) != 0 || info.width == 0 || info.height == 0 ||
info.width > 16384 || info.height > 16384 || info.pitch < info.width || info.width > 16384 || info.height > 16384 || info.pitch < info.width ||
info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) || info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) ||
info.bytes_per_element != 4 || compression == VideoOutCompression::Unsupported || compression == VideoOutCompression::Unsupported || compression != info.compression ||
compression != info.compression || metadata_invalid || metadata_invalid || !IsSupportedVideoOutFormat(info)) {
!IsSupportedVideoOutFormat(info.guest_format, info.format)) {
EXIT("TextureCache: unsupported video-out surface, ctx=%p addr=0x%016" PRIx64 EXIT("TextureCache: unsupported video-out surface, ctx=%p addr=0x%016" PRIx64
" size=0x%016" PRIx64 " metadata=0x%016" PRIx64 " dcc=0x%08" PRIx32 " size=0x%016" PRIx64 " metadata=0x%016" PRIx64 " dcc=0x%08" PRIx32
" extent=%ux%u pitch=%u tile=%u guest_format=%u bpe=%u vk_format=%d\n", " extent=%ux%u pitch=%u tile=%u guest_format=%u bpe=%u vk_format=%d\n",
@@ -1211,6 +1210,12 @@ void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const Video
TileConvertTiledToLinearRenderTarget( TileConvertTiledToLinearRenderTarget(
scratch.Data(), reinterpret_cast<const void*>(info.address), info.width, info.height, scratch.Data(), reinterpret_cast<const void*>(info.address), info.width, info.height,
info.pitch, info.bytes_per_element, info.size); info.pitch, info.bytes_per_element, info.size);
if (info.bgra16) {
auto* pixels = static_cast<uint16_t*>(scratch.Data());
for (uint64_t i = 0; i < info.size / sizeof(uint16_t); i += 4) {
std::swap(pixels[i], pixels[i + 2]);
}
}
UtilFillImage(ctx, image, scratch.Data(), info.size, info.pitch, UtilFillImage(ctx, image, scratch.Data(), info.size, info.pitch,
static_cast<uint64_t>(VK_IMAGE_LAYOUT_GENERAL)); static_cast<uint64_t>(VK_IMAGE_LAYOUT_GENERAL));
} }
+4 -2
View File
@@ -303,7 +303,8 @@ static Graphics::VideoOutInfo MakeVideoOutInfo(const VideoOutBufferAttribute2& a
if (!Graphics::DecodeVideoOutPixelFormat(attribute.pixel_format, &pixel_format)) { if (!Graphics::DecodeVideoOutPixelFormat(attribute.pixel_format, &pixel_format)) {
EXIT("unsupported video-out pixel format: 0x%016" PRIx64 "\n", attribute.pixel_format); EXIT("unsupported video-out pixel format: 0x%016" PRIx64 "\n", attribute.pixel_format);
} }
const auto tile_mode = Graphics::Prospero::GpuEnumValue(Graphics::Prospero::TileMode::kRenderTarget); const auto tile_mode =
Graphics::Prospero::GpuEnumValue(Graphics::Prospero::TileMode::kRenderTarget);
const auto pitch = const auto pitch =
Graphics::TileGetTexturePitch(pixel_format.guest_format, attribute.width, 1, tile_mode); Graphics::TileGetTexturePitch(pixel_format.guest_format, attribute.width, 1, tile_mode);
Graphics::TileSizeAlign total {}; Graphics::TileSizeAlign total {};
@@ -321,10 +322,11 @@ static Graphics::VideoOutInfo MakeVideoOutInfo(const VideoOutBufferAttribute2& a
info.width = attribute.width; info.width = attribute.width;
info.height = attribute.height; info.height = attribute.height;
info.pitch = pitch; info.pitch = pitch;
info.bytes_per_element = 4; info.bytes_per_element = pixel_format.bytes_per_element;
info.tile_mode = tile_mode; info.tile_mode = tile_mode;
info.dcc_control = attribute.dcc_control; info.dcc_control = attribute.dcc_control;
info.compression = compression; info.compression = compression;
info.bgra16 = pixel_format.bgra16;
return info; return info;
} }
+77 -42
View File
@@ -10706,62 +10706,97 @@ void CheckBufferImageWrites() {
void CheckImageOverlapResolution() { void CheckImageOverlapResolution() {
CheckBufferImageWrites(); CheckBufferImageWrites();
VideoOutPixelFormatInfo video_format {}; VideoOutPixelFormatInfo video_format{};
Require("ImageOverlapResolution", "existing video-out formats", Require(
DecodeVideoOutPixelFormat(0x8000000022000000ull, &video_format) && "ImageOverlapResolution", "existing video-out formats",
video_format.format == VK_FORMAT_R8G8B8A8_SRGB && DecodeVideoOutPixelFormat(0x8000000022000000ull, &video_format) &&
video_format.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8Srgb) && video_format.format == VK_FORMAT_R8G8B8A8_SRGB &&
DecodeVideoOutPixelFormat(0x8000000000000000ull, &video_format) && video_format.guest_format ==
video_format.format == VK_FORMAT_B8G8R8A8_SRGB && Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8Srgb) &&
video_format.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8Srgb) && DecodeVideoOutPixelFormat(0x8000000000000000ull, &video_format) &&
DecodeVideoOutPixelFormat(0x8100000022000000ull, &video_format) && video_format.format == VK_FORMAT_B8G8R8A8_SRGB &&
video_format.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32 && video_format.guest_format ==
video_format.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k10_10_10_2UNorm), Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8Srgb) &&
"pre-existing PS5 video-out format mappings changed during decoder centralization"); DecodeVideoOutPixelFormat(0x8100000022000000ull, &video_format) &&
Require("ImageOverlapResolution", "B10G10R10A2 video-out format", video_format.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32 &&
DecodeVideoOutPixelFormat(0x8100000000000000ull, &video_format) && video_format.guest_format ==
video_format.format == VK_FORMAT_A2R10G10B10_UNORM_PACK32 && Prospero::GpuEnumValue(Prospero::BufferFormat::k10_10_10_2UNorm),
video_format.guest_format == "pre-existing PS5 video-out format mappings changed during decoder "
Prospero::GpuEnumValue(Prospero::BufferFormat::k10_10_10_2UNorm) && "centralization");
IsSupportedVideoOutFormat(video_format.guest_format, video_format.format), Require(
"PS5 B10G10R10A2 sRGB video-out format did not preserve alternate channel order"); "ImageOverlapResolution", "B10G10R10A2 video-out format",
Require("ImageOverlapResolution", "video-out format guards", DecodeVideoOutPixelFormat(0x8100000000000000ull, &video_format) &&
!DecodeVideoOutPixelFormat(0x8100070400000000ull, &video_format) && video_format.format == VK_FORMAT_A2R10G10B10_UNORM_PACK32 &&
!DecodeVideoOutPixelFormat(0x8100000000000000ull, nullptr) && video_format.guest_format ==
!IsSupportedVideoOutFormat(Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8Srgb), Prospero::GpuEnumValue(Prospero::BufferFormat::k10_10_10_2UNorm),
VK_FORMAT_A2R10G10B10_UNORM_PACK32) && "PS5 B10G10R10A2 sRGB video-out format did not preserve alternate "
!IsSupportedVideoOutFormat(Prospero::GpuEnumValue(Prospero::BufferFormat::k10_10_10_2UNorm), "channel order");
VK_FORMAT_R8G8B8A8_SRGB), Require(
"unsupported PS5 video-out formats or mismatched guest/host pairs were admitted"); "ImageOverlapResolution", "RGBA16 float video-out formats",
DecodeVideoOutPixelFormat(0xc001000622000000ull, &video_format) &&
video_format.format == VK_FORMAT_R16G16B16A16_SFLOAT &&
video_format.guest_format ==
Prospero::GpuEnumValue(
Prospero::BufferFormat::k16_16_16_16Float) &&
video_format.bytes_per_element == 8 &&
DecodeVideoOutPixelFormat(0xc001000600000000ull, &video_format) &&
video_format.bgra16,
"PS5 RGBA16-float video-out formats lost their 64-bpp storage contract");
VideoOutInfo supported_video_out{};
supported_video_out.format = video_format.format;
supported_video_out.guest_format = video_format.guest_format;
supported_video_out.bytes_per_element = video_format.bytes_per_element;
supported_video_out.bgra16 = video_format.bgra16;
Require(
"ImageOverlapResolution", "video-out format policy",
IsSupportedVideoOutFormat(supported_video_out),
"decoded PS5 video-out format was rejected by the centralized policy");
Require(
"ImageOverlapResolution", "video-out byte-size guards", ([&] {
auto mismatched = supported_video_out;
mismatched.bytes_per_element = 4;
return !IsSupportedVideoOutFormat(mismatched);
})(),
"video-out format validation admitted a mismatched storage element size");
Require(
"ImageOverlapResolution", "video-out format guards",
!DecodeVideoOutPixelFormat(0x8100070400000000ull, &video_format) &&
!DecodeVideoOutPixelFormat(0xc001070700000000ull, &video_format) &&
!DecodeVideoOutPixelFormat(0x8100000000000000ull, nullptr) && !([&] {
auto mismatched = supported_video_out;
mismatched.guest_format =
Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8Srgb);
return IsSupportedVideoOutFormat(mismatched);
})(),
"unsupported PS5 video-out formats or mismatched guest/host pairs were "
"admitted");
TileSizeAlign render_target_layout{}; TileSizeAlign render_target_layout{};
Require("ImageOverlapResolution", "R8 render-target pitch", Require("ImageOverlapResolution", "R8 render-target pitch",
TileGetRenderTargetPitch(1920, 1) == 2048, TileGetRenderTargetPitch(1920, 1) == 2048,
"R8 target did not use native 256-pixel block width"); "R8 target did not use native 256-pixel block width");
Require("ImageOverlapResolution", "R8 render-target size", Require("ImageOverlapResolution", "R8 render-target size",
TileGetRenderTargetSize(1920, 1080, 2048, 1, TileGetRenderTargetSize(1920, 1080, 2048, 1, &render_target_layout) &&
&render_target_layout) &&
render_target_layout.size == 0x280000 && render_target_layout.size == 0x280000 &&
render_target_layout.align == 0x10000, render_target_layout.align == 0x10000,
"R8 target did not use native 64-KiB block geometry"); "R8 target did not use native 64-KiB block geometry");
Require("ImageOverlapResolution", "RGBA8 render-target size", Require(
TileGetRenderTargetPitch(1920, 4) == 1920 && "ImageOverlapResolution", "RGBA8 render-target size",
TileGetRenderTargetSize(1920, 1080, 1920, 4, TileGetRenderTargetPitch(1920, 4) == 1920 &&
&render_target_layout) && TileGetRenderTargetSize(1920, 1080, 1920, 4, &render_target_layout) &&
render_target_layout.size == 0x870000, render_target_layout.size == 0x870000,
"RGBA8 target layout regressed"); "RGBA8 target layout regressed");
Require("ImageOverlapResolution", "PPSA19268 render-target edge", Require("ImageOverlapResolution", "PPSA19268 render-target edge",
TileGetRenderTargetPitch(120, 8) == 128 && TileGetRenderTargetPitch(120, 8) == 128 &&
TileGetRenderTargetSize(120, 67, 128, 8, TileGetRenderTargetSize(120, 67, 128, 8, &render_target_layout) &&
&render_target_layout) &&
render_target_layout.size == 0x20000 && render_target_layout.size == 0x20000 &&
ImageRangeOverlaps(0x11029fff8ull, 1, 0x110280000ull, ImageRangeOverlaps(0x11029fff8ull, 1, 0x110280000ull,
render_target_layout.size), render_target_layout.size),
"title write did not land in the final native render-target block"); "title write did not land in the final native render-target block");
Require("ImageOverlapResolution", "render-target layout rejection", Require(
TileGetRenderTargetPitch(1920, 3) == 0 && "ImageOverlapResolution", "render-target layout rejection",
!TileGetRenderTargetSize(1920, 1080, 1920, 1, TileGetRenderTargetPitch(1920, 3) == 0 &&
&render_target_layout), !TileGetRenderTargetSize(1920, 1080, 1920, 1, &render_target_layout),
"unsupported element size or mismatched pitch was admitted"); "unsupported element size or mismatched pitch was admitted");
TileSizeOffset mip_levels[16]{}; TileSizeOffset mip_levels[16]{};
TilePaddedSize mip_padded[16]{}; TilePaddedSize mip_padded[16]{};