mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 19:36:55 +02:00
graphics: represent rebased contiguous mip-tail texture views
Co-authored-by: fxpw <fxpw@outlook.com>
This commit is contained in:
@@ -21,6 +21,54 @@ bool IsDepthPlane(const ImageInfo& info) {
|
|||||||
info.tile_mode == Prospero::TileMode::kLinear);
|
info.tile_mode == Prospero::TileMode::kLinear);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GuestRange ContiguousMipRange(const ImageInfo& info, uint32_t level) {
|
||||||
|
const auto& block = info.tiling.block;
|
||||||
|
if (info.tile_mode != Prospero::TileMode::kStandard4KB ||
|
||||||
|
block.family != TileBlockFamily::Standard4KB || info.IsVolume() || info.samples != 1 ||
|
||||||
|
info.HasMetadata() || level >= info.resources.levels || level >= info.mip_layout.size() ||
|
||||||
|
info.tiling.texel_width == 0 || info.tiling.texel_height == 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const auto extent = info.MipExtent(level);
|
||||||
|
const auto width = (extent.width + info.tiling.texel_width - 1u) / info.tiling.texel_width;
|
||||||
|
const auto height = (extent.height + info.tiling.texel_height - 1u) / info.tiling.texel_height;
|
||||||
|
const auto& mip = info.mip_layout[level];
|
||||||
|
uint32_t last = 0, origin = 0;
|
||||||
|
if (!std::has_single_bit(width) || !std::has_single_bit(height) ||
|
||||||
|
width > block.block_width || height > block.block_height ||
|
||||||
|
mip.tail_x > block.block_width - width || mip.tail_y > block.block_height - height ||
|
||||||
|
mip.tail_x % width != 0 || mip.tail_y % height != 0 ||
|
||||||
|
!TileGetBlockOffset(block, width - 1u, height - 1u, 0, last) ||
|
||||||
|
!TileGetBlockOffset(block, mip.tail_x, mip.tail_y, 0, origin)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
// Standard4KB interleaves monotonically ordered X/Y bits. A dense rectangle
|
||||||
|
// fills exactly this power-of-two interval, including when rebased into a tail.
|
||||||
|
const uint64_t size = uint64_t {last} + block.bytes_per_element;
|
||||||
|
if (!std::has_single_bit(size) || size != uint64_t {width} * height * block.bytes_per_element ||
|
||||||
|
(origin & (size - 1u)) != 0 || size > block.block_size - origin ||
|
||||||
|
mip.offset > UINT64_MAX - origin) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return {mip.offset + origin, size};
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t CompactMipSize(const ImageInfo& info) {
|
||||||
|
if (info.resources.levels != 1 || info.resources.layers != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const auto range = ContiguousMipRange(info, 0);
|
||||||
|
if (range.size == 0 || range.address != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const auto alignment = std::max<uint64_t>(256, range.size);
|
||||||
|
const auto in_block = info.data.address & (info.tiling.block.block_size - 1u);
|
||||||
|
return (info.data.address & (alignment - 1u)) == 0 &&
|
||||||
|
range.size <= info.tiling.block.block_size - in_block
|
||||||
|
? static_cast<uint32_t>(range.size)
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
vk::Extent3D ImageInfo::MipExtent(uint32_t level) const {
|
vk::Extent3D ImageInfo::MipExtent(uint32_t level) const {
|
||||||
@@ -34,6 +82,7 @@ void ImageInfo::UpdateSize() {
|
|||||||
extent.height == 0 || extent.depth == 0 || resources.levels == 0 ||
|
extent.height == 0 || extent.depth == 0 || resources.levels == 0 ||
|
||||||
resources.levels > mip_layout.size() || resources.layers == 0 || samples == 0 ||
|
resources.levels > mip_layout.size() || resources.layers == 0 || samples == 0 ||
|
||||||
!std::has_single_bit(samples));
|
!std::has_single_bit(samples));
|
||||||
|
const bool auto_size = data.size == 0;
|
||||||
TileTextureElementLayout element {};
|
TileTextureElementLayout element {};
|
||||||
EXIT_NOT_IMPLEMENTED(!TileGetTextureElementLayout(guest_format, element));
|
EXIT_NOT_IMPLEMENTED(!TileGetTextureElementLayout(guest_format, element));
|
||||||
if (bytes_per_block == 0) {
|
if (bytes_per_block == 0) {
|
||||||
@@ -164,9 +213,86 @@ void ImageInfo::UpdateSize() {
|
|||||||
linear_offset = Add(mip.linear_offset, Multiply(mip.linear_size, active.depth));
|
linear_offset = Add(mip.linear_offset, Multiply(mip.linear_size, active.depth));
|
||||||
mip_pitch = std::max(mip_pitch >> 1u, 1u);
|
mip_pitch = std::max(mip_pitch >> 1u, 1u);
|
||||||
}
|
}
|
||||||
|
const auto compact_size = CompactMipSize(*this);
|
||||||
|
if (compact_size != 0 && (auto_size || data.size == compact_size)) {
|
||||||
|
data.size = mip_layout[0].size = compact_size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t ImageInfo::DataAlignment() const {
|
||||||
|
if (!IsTiled()) {
|
||||||
|
return 256;
|
||||||
|
}
|
||||||
|
const auto compact_size = CompactMipSize(*this);
|
||||||
|
if (compact_size != 0 && data.size == compact_size && mip_layout[0].size == compact_size) {
|
||||||
|
return std::max(256u, compact_size);
|
||||||
|
}
|
||||||
|
return tiling.block.block_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t ImageInfo::SliceOf(const ImageInfo& container, int32_t mip) const noexcept {
|
||||||
|
if (!IsCompatible(container) || tile_mode != container.tile_mode || type != container.type ||
|
||||||
|
IsVolume() || resources.levels != 1 || resources.layers == 0 ||
|
||||||
|
container.resources.layers == 0 || mip < 0 ||
|
||||||
|
static_cast<uint32_t>(mip) >= container.resources.levels ||
|
||||||
|
container.resources.levels > container.mip_layout.size() ||
|
||||||
|
!data.Valid() || !container.data.Valid() || data.address < container.data.address ||
|
||||||
|
data.End() > container.data.End()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (HasStencil() != container.HasStencil() ||
|
||||||
|
(HasStencil() && (stencil.address < container.stencil.address ||
|
||||||
|
stencil.End() > container.stencil.End()))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto level = static_cast<uint32_t>(mip);
|
||||||
|
const auto& layout = container.mip_layout[level];
|
||||||
|
if (extent.width != std::max(container.extent.width >> level, 1u) ||
|
||||||
|
extent.height != std::max(container.extent.height >> level, 1u) ||
|
||||||
|
extent.depth != container.extent.depth || mip_layout[0].pitch != layout.pitch ||
|
||||||
|
mip_layout[0].height != layout.height || layout.size == 0 ||
|
||||||
|
layout.size % container.resources.layers != 0 ||
|
||||||
|
container.data.size % container.resources.layers != 0 ||
|
||||||
|
data.size % resources.layers != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PS5 block slices contain the entire reversed mip chain. A rebased tail
|
||||||
|
// descriptor covers only its active bytes within the shared tail block.
|
||||||
|
const auto slice_stride = container.data.size / container.resources.layers;
|
||||||
|
const auto child_stride = data.size / resources.layers;
|
||||||
|
auto mip_offset = layout.offset;
|
||||||
|
auto mip_size = layout.size / container.resources.layers;
|
||||||
|
const auto compact_size = CompactMipSize(*this);
|
||||||
|
if (compact_size != 0 && child_stride == compact_size && mip_layout[0].size == compact_size) {
|
||||||
|
const auto range = ContiguousMipRange(container, level);
|
||||||
|
if (range.size != compact_size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
mip_offset = range.address;
|
||||||
|
mip_size = range.size;
|
||||||
|
} else if (mip_layout[0].tail_x != layout.tail_x || mip_layout[0].tail_y != layout.tail_y) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (child_stride != mip_size || mip_offset >= slice_stride ||
|
||||||
|
child_stride > slice_stride - mip_offset ||
|
||||||
|
(resources.layers > 1 && child_stride != slice_stride)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
const auto address_delta = data.address - container.data.address;
|
||||||
|
if (address_delta < mip_offset || (address_delta - mip_offset) % slice_stride != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
const auto layer = (address_delta - mip_offset) / slice_stride;
|
||||||
|
if (layer > INT32_MAX || layer >= container.resources.layers ||
|
||||||
|
resources.layers > container.resources.layers - layer) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return static_cast<int32_t>(layer);
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t ImageInfo::LinearSize(uint32_t levels) const {
|
uint64_t ImageInfo::LinearSize(uint32_t levels) const {
|
||||||
levels = levels == 0 ? resources.levels : levels;
|
levels = levels == 0 ? resources.levels : levels;
|
||||||
EXIT_IF(levels == 0 || levels > resources.levels || levels > mip_layout.size());
|
EXIT_IF(levels == 0 || levels > resources.levels || levels > mip_layout.size());
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ struct ImageInfo {
|
|||||||
uint32_t first_tail_level = 16;
|
uint32_t first_tail_level = 16;
|
||||||
|
|
||||||
void UpdateSize();
|
void UpdateSize();
|
||||||
|
[[nodiscard]] uint32_t DataAlignment() const;
|
||||||
[[nodiscard]] uint64_t LinearSize(uint32_t levels = 0) const;
|
[[nodiscard]] uint64_t LinearSize(uint32_t levels = 0) const;
|
||||||
[[nodiscard]] vk::Extent3D MipExtent(uint32_t level) const;
|
[[nodiscard]] vk::Extent3D MipExtent(uint32_t level) const;
|
||||||
[[nodiscard]] std::vector<vk::BufferImageCopy> BufferCopies(uint64_t buffer_offset = 0,
|
[[nodiscard]] std::vector<vk::BufferImageCopy> BufferCopies(uint64_t buffer_offset = 0,
|
||||||
@@ -136,53 +137,7 @@ struct ImageInfo {
|
|||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
[[nodiscard]] int32_t SliceOf(const ImageInfo& container, int32_t mip) const noexcept {
|
[[nodiscard]] int32_t SliceOf(const ImageInfo& container, int32_t mip) const noexcept;
|
||||||
if (!IsCompatible(container) || tile_mode != container.tile_mode || type != container.type ||
|
|
||||||
IsVolume() || resources.levels != 1 || resources.layers == 0 ||
|
|
||||||
container.resources.layers == 0 || mip < 0 ||
|
|
||||||
static_cast<uint32_t>(mip) >= container.resources.levels ||
|
|
||||||
container.resources.levels > container.mip_layout.size() ||
|
|
||||||
!data.Valid() || !container.data.Valid() || data.address < container.data.address ||
|
|
||||||
data.End() > container.data.End()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (HasStencil() != container.HasStencil() ||
|
|
||||||
(HasStencil() && (stencil.address < container.stencil.address ||
|
|
||||||
stencil.End() > container.stencil.End()))) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto level = static_cast<uint32_t>(mip);
|
|
||||||
const auto& layout = container.mip_layout[level];
|
|
||||||
if (extent.width != std::max(container.extent.width >> level, 1u) ||
|
|
||||||
extent.height != std::max(container.extent.height >> level, 1u) ||
|
|
||||||
extent.depth != container.extent.depth || mip_layout[0].pitch != layout.pitch ||
|
|
||||||
mip_layout[0].height != layout.height || layout.size == 0 ||
|
|
||||||
layout.size % container.resources.layers != 0 ||
|
|
||||||
container.data.size % container.resources.layers != 0 ||
|
|
||||||
data.size % resources.layers != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PS5 block slices contain the entire reversed mip chain.
|
|
||||||
const auto slice_stride = container.data.size / container.resources.layers;
|
|
||||||
const auto child_stride = data.size / resources.layers;
|
|
||||||
if (child_stride != layout.size / container.resources.layers ||
|
|
||||||
layout.offset >= slice_stride || child_stride > slice_stride - layout.offset ||
|
|
||||||
(resources.layers > 1 && child_stride != slice_stride)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
const auto address_delta = data.address - container.data.address;
|
|
||||||
if (address_delta < layout.offset || (address_delta - layout.offset) % slice_stride != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
const auto layer = (address_delta - layout.offset) / slice_stride;
|
|
||||||
if (layer > INT32_MAX || layer >= container.resources.layers ||
|
|
||||||
resources.layers > container.resources.layers - layer) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return static_cast<int32_t>(layer);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ImageViewInfo {
|
struct ImageViewInfo {
|
||||||
|
|||||||
@@ -608,6 +608,9 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR
|
|||||||
block_bytes != 0 ? block_bytes : Prospero::NumBytesPerElement(format);
|
block_bytes != 0 ? block_bytes : Prospero::NumBytesPerElement(format);
|
||||||
desc.info.samples = samples;
|
desc.info.samples = samples;
|
||||||
desc.info.tile_mode = tile;
|
desc.info.tile_mode = tile;
|
||||||
|
if (!resource.r128 && descriptor.MetaCompress() && tile != Prospero::TileMode::kDepth) {
|
||||||
|
desc.info.metadata.kind = ImageMetadataKind::Dcc;
|
||||||
|
}
|
||||||
if (levels > physical_levels) {
|
if (levels > physical_levels) {
|
||||||
if (!ResolveTextureMipView(desc.info, physical_levels,
|
if (!ResolveTextureMipView(desc.info, physical_levels,
|
||||||
!resource.r128 && descriptor.MetaCompress(), view_levels,
|
!resource.r128 && descriptor.MetaCompress(), view_levels,
|
||||||
@@ -620,8 +623,7 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR
|
|||||||
} else {
|
} else {
|
||||||
desc.info.UpdateSize();
|
desc.info.UpdateSize();
|
||||||
}
|
}
|
||||||
const auto alignment =
|
const auto alignment = desc.info.DataAlignment();
|
||||||
tile == Prospero::TileMode::kLinear ? 256u : desc.info.tiling.block.block_size;
|
|
||||||
EXIT_NOT_IMPLEMENTED(desc.info.data.size == 0 || alignment == 0 ||
|
EXIT_NOT_IMPLEMENTED(desc.info.data.size == 0 || alignment == 0 ||
|
||||||
(address & (static_cast<uint64_t>(alignment) - 1u)) != 0);
|
(address & (static_cast<uint64_t>(alignment) - 1u)) != 0);
|
||||||
if (storage) {
|
if (storage) {
|
||||||
@@ -632,7 +634,6 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR
|
|||||||
(void)TileGetDccSize(width, height, volume ? depth : image_layers,
|
(void)TileGetDccSize(width, height, volume ? depth : image_layers,
|
||||||
desc.info.bytes_per_block, physical_levels, tile, metadata_size,
|
desc.info.bytes_per_block, physical_levels, tile, metadata_size,
|
||||||
std::countr_zero(samples));
|
std::countr_zero(samples));
|
||||||
desc.info.metadata.kind = ImageMetadataKind::Dcc;
|
|
||||||
desc.info.metadata.range = {descriptor.MetaAddr() << 8u, metadata_size.size};
|
desc.info.metadata.range = {descriptor.MetaAddr() << 8u, metadata_size.size};
|
||||||
desc.info.metadata.dcc_alpha_msb = descriptor.DccAlphaPos();
|
desc.info.metadata.dcc_alpha_msb = descriptor.DccAlphaPos();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18673,6 +18673,36 @@ public:
|
|||||||
check_round_trip("odd multi-mip", total.size, layout);
|
check_round_trip("odd multi-mip", total.size, layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
constexpr auto format = Prospero::BufferFormat::k16_16_16_16Float;
|
||||||
|
constexpr auto tile = Prospero::TileMode::kStandard4KB;
|
||||||
|
auto view = MakeTilingImage(format, 16, 16, 1, 1, tile, 0, false);
|
||||||
|
view.data.address = 0x5032b23800;
|
||||||
|
view.UpdateSize();
|
||||||
|
Require(name, "rebased mip footprint",
|
||||||
|
view.data.size == 0x800 && view.DataAlignment() == 0x800 &&
|
||||||
|
view.mip_layout[0].pitch == 32 &&
|
||||||
|
view.mip_layout[0].height == 16 &&
|
||||||
|
view.tiled_slice_stride == 0x1000,
|
||||||
|
"a compact view changed its allocation geometry");
|
||||||
|
check_round_trip("rebased mip exact range", view.data.size, view);
|
||||||
|
check_round_trip("rebased mip adjacent canary", 0x1000, view);
|
||||||
|
|
||||||
|
std::vector<uint8_t> linear(view.LinearSize());
|
||||||
|
fill(&linear, ++case_index);
|
||||||
|
std::vector<uint8_t> expected(0x1000, 0xab), observed;
|
||||||
|
convert_reference(true, &expected, linear, view);
|
||||||
|
gpu_tile(linear, &observed, 0x1000, linear.size(), view, nullptr, 0,
|
||||||
|
0x100, 0x800);
|
||||||
|
compare("rebased mip prefix and neighboring mip", expected, observed);
|
||||||
|
std::vector<uint8_t> round_trip;
|
||||||
|
gpu_detile(observed, &round_trip, observed.size(), linear.size(), view,
|
||||||
|
nullptr, 0x800);
|
||||||
|
std::vector<uint8_t> expected_linear(linear.size(), 0);
|
||||||
|
convert_reference(false, &expected_linear, expected, view);
|
||||||
|
compare("rebased mip nonzero source", expected_linear, round_trip);
|
||||||
|
}
|
||||||
|
|
||||||
struct TailMode {
|
struct TailMode {
|
||||||
Prospero::TileMode tile;
|
Prospero::TileMode tile;
|
||||||
TileBlockFamily family;
|
TileBlockFamily family;
|
||||||
|
|||||||
@@ -1296,6 +1296,100 @@ void TestNormalizedImageContracts() {
|
|||||||
"Vulkan image-view compatibility classes diverged from production");
|
"Vulkan image-view compatibility classes diverged from production");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestRebasedTextureMipViews() {
|
||||||
|
constexpr auto format = Prospero::BufferFormat::k16_16_16_16Float;
|
||||||
|
constexpr auto tile = Prospero::TileMode::kStandard4KB;
|
||||||
|
TileSizeAlign allocation{};
|
||||||
|
TileGetTextureSize(format, 16, 16, 1, tile, &allocation, nullptr, nullptr);
|
||||||
|
Check(allocation.size == 0x1000 && allocation.align == 0x1000,
|
||||||
|
"rebased texture views changed guest allocation size/alignment");
|
||||||
|
|
||||||
|
ImageInfo chain{};
|
||||||
|
chain.data.address = 0x5032b23000;
|
||||||
|
chain.pixel_format = vk::Format::eR16G16B16A16Sfloat;
|
||||||
|
chain.guest_format = format;
|
||||||
|
chain.extent = {256, 256, 1};
|
||||||
|
chain.resources = {9, 2};
|
||||||
|
chain.tile_mode = tile;
|
||||||
|
chain.UpdateSize();
|
||||||
|
Check(chain.tiled_slice_stride == 0xab000 && chain.data.size == 0x156000 &&
|
||||||
|
chain.first_tail_level == 4 && chain.DataAlignment() == 0x1000,
|
||||||
|
"full texture chain lost its guest allocation layout");
|
||||||
|
const std::array<uint64_t, 9> offsets{
|
||||||
|
0x2b000, 0xb000, 0x3000, 0x1000, 0x800, 0x600, 0x500, 0x400, 0x300};
|
||||||
|
const auto make_view = [&](uint32_t level, uint32_t layer) {
|
||||||
|
auto view = chain;
|
||||||
|
view.data = {chain.data.address + layer * chain.tiled_slice_stride +
|
||||||
|
offsets[level], 0};
|
||||||
|
view.extent = {256u >> level, 256u >> level, 1};
|
||||||
|
view.resources = {1, 1};
|
||||||
|
view.pitch = 0;
|
||||||
|
view.UpdateSize();
|
||||||
|
return view;
|
||||||
|
};
|
||||||
|
for (uint32_t layer = 0; layer < 2; ++layer) {
|
||||||
|
for (uint32_t level = 0; level < offsets.size(); ++level) {
|
||||||
|
auto view = make_view(level, layer);
|
||||||
|
const uint64_t bytes = uint64_t{view.extent.width} * view.extent.height * 8;
|
||||||
|
Check(view.data.size == bytes && view.mip_layout[0].size == bytes &&
|
||||||
|
view.tiled_slice_stride == std::max<uint64_t>(0x1000, bytes) &&
|
||||||
|
view.DataAlignment() == std::min<uint64_t>(0x1000,
|
||||||
|
std::max<uint64_t>(0x100, bytes)) &&
|
||||||
|
view.MipOf(chain) == static_cast<int32_t>(level) &&
|
||||||
|
view.SliceOf(chain, static_cast<int32_t>(level)) ==
|
||||||
|
static_cast<int32_t>(layer),
|
||||||
|
"rebased mip footprint/origin or parent layer stride was incorrect");
|
||||||
|
view.UpdateSize();
|
||||||
|
Check(view.data.size == bytes && view.mip_layout[0].size == bytes &&
|
||||||
|
view.MipOf(chain) == static_cast<int32_t>(level),
|
||||||
|
"resizing a normalized view lost its compact footprint");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto view = make_view(4, 0);
|
||||||
|
Check(view.data.address == 0x5032b23800 && view.mip_layout[0].pitch == 32 &&
|
||||||
|
view.mip_layout[0].height == 16 &&
|
||||||
|
view.mip_layout[0].linear_pitch == 32 && view.LinearSize() == 0x1000,
|
||||||
|
"captured 16x16 view changed its padded tiling or linear transfer size");
|
||||||
|
view.data.address += 0x800;
|
||||||
|
Check(view.MipOf(chain) == -1, "tail view accepted the following mip's address");
|
||||||
|
view = make_view(4, 0);
|
||||||
|
view.mip_layout[0].pitch /= 2;
|
||||||
|
Check(view.MipOf(chain) == -1, "tail view accepted a different padded pitch");
|
||||||
|
view = make_view(4, 0);
|
||||||
|
view.resources.layers = 2;
|
||||||
|
view.data.size *= 2;
|
||||||
|
view.mip_layout[0].size *= 2;
|
||||||
|
Check(view.MipOf(chain) == -1, "tail array view ignored the parent chain stride");
|
||||||
|
view = make_view(4, 0);
|
||||||
|
view.data = {chain.data.address, 0x1000};
|
||||||
|
view.UpdateSize();
|
||||||
|
Check(view.MipOf(chain) == -1,
|
||||||
|
"full-block child ignored the parent mip's nonzero tail origin");
|
||||||
|
|
||||||
|
for (uint32_t variant = 0; variant < 7; ++variant) {
|
||||||
|
view = make_view(4, 0);
|
||||||
|
view.data = {chain.data.address, 0};
|
||||||
|
view.pitch = 0;
|
||||||
|
switch (variant) {
|
||||||
|
case 0: view.extent = {8, 16, 1}; break; // Holes in the Standard4KB span.
|
||||||
|
case 1: view.resources.levels = 2; break;
|
||||||
|
case 2: view.resources.layers = 2; break;
|
||||||
|
case 3: view.type = Prospero::ImageType::kColor3D; break;
|
||||||
|
case 4: view.tile_mode = Prospero::TileMode::kStandard64KB; break;
|
||||||
|
case 5: view.metadata.kind = ImageMetadataKind::Dcc; break;
|
||||||
|
case 6: view.data = {0x5032b23800, 0x1000}; break;
|
||||||
|
}
|
||||||
|
view.UpdateSize();
|
||||||
|
Check(view.data.size >= 0x1000 && view.DataAlignment() >= 0x1000,
|
||||||
|
"unsupported or explicitly sized texture became a compact tail view");
|
||||||
|
}
|
||||||
|
view = make_view(4, 0);
|
||||||
|
view.data = {0x5032b23900, 0};
|
||||||
|
view.UpdateSize();
|
||||||
|
Check(view.data.size == 0x1000 && view.DataAlignment() == 0x1000,
|
||||||
|
"misaligned descriptor received compact tail alignment");
|
||||||
|
}
|
||||||
|
|
||||||
void TestShaderFeatureCollection() {
|
void TestShaderFeatureCollection() {
|
||||||
using namespace ShaderRecompiler::IR;
|
using namespace ShaderRecompiler::IR;
|
||||||
|
|
||||||
@@ -15725,6 +15819,7 @@ int main() {
|
|||||||
TestShaderBufferResourceSize();
|
TestShaderBufferResourceSize();
|
||||||
TestNativeShaderResourceDependencies();
|
TestNativeShaderResourceDependencies();
|
||||||
TestNormalizedImageContracts();
|
TestNormalizedImageContracts();
|
||||||
|
TestRebasedTextureMipViews();
|
||||||
TestShaderFeatureCollection();
|
TestShaderFeatureCollection();
|
||||||
TestTypedSpirvSerialization();
|
TestTypedSpirvSerialization();
|
||||||
TestDeferredSpirvPhiPatching();
|
TestDeferredSpirvPhiPatching();
|
||||||
|
|||||||
Reference in New Issue
Block a user