mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
Graphics: resolve equivalent terminal mip views without expanding backing
This commit is contained in:
@@ -514,19 +514,50 @@ static ImageViewInfo TextureViewInfo(const ShaderRecompiler::IR::ImageResource&
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool TextureViewPreservesMipLayout(const TileSurfaceDescription& description,
|
static bool ResolveTextureMipView(const TileSurfaceDescription& description, bool metadata,
|
||||||
uint32_t view_levels) {
|
uint32_t view_levels, uint32_t& levels, uint32_t& base_level) {
|
||||||
TileSurfaceLayout physical {};
|
TileSurfaceLayout physical {};
|
||||||
TileSurfaceLayout view {};
|
TileSurfaceLayout view {};
|
||||||
auto view_description = description;
|
auto view_description = description;
|
||||||
view_description.levels = view_levels;
|
view_description.levels = levels;
|
||||||
return TileGetTiledTextureLayout(description, physical) &&
|
if (!TileGetTiledTextureLayout(description, physical) ||
|
||||||
TileGetTiledTextureLayout(view_description, view) &&
|
!TileGetTiledTextureLayout(view_description, view)) {
|
||||||
physical.first_tail_level == view.first_tail_level &&
|
return false;
|
||||||
physical.block_slice_size == view.block_slice_size &&
|
}
|
||||||
physical.total_size == view.total_size &&
|
if (physical.first_tail_level == view.first_tail_level &&
|
||||||
std::equal(std::begin(physical.mips), std::begin(physical.mips) + description.levels,
|
physical.block_slice_size == view.block_slice_size &&
|
||||||
std::begin(view.mips));
|
physical.total_size == view.total_size &&
|
||||||
|
std::equal(std::begin(physical.mips), std::begin(physical.mips) + description.levels,
|
||||||
|
std::begin(view.mips))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (metadata || ((description.layers > 1 || description.depth > 1) &&
|
||||||
|
physical.block_slice_size != view.block_slice_size)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// T# addresses the last mip. A view can select the same stored subresources
|
||||||
|
// with different mip indices; inaccessible mips need no host representation.
|
||||||
|
for (uint32_t base = 0; base + view_levels <= description.levels; ++base) {
|
||||||
|
bool matches = true;
|
||||||
|
for (uint32_t i = 0; i < view_levels; ++i) {
|
||||||
|
const auto source = base_level + i;
|
||||||
|
const auto target = base + i;
|
||||||
|
if (physical.mips[target] != view.mips[source] ||
|
||||||
|
(target >= physical.first_tail_level) != (source >= view.first_tail_level) ||
|
||||||
|
std::max(description.width >> target, 1u) != std::max(description.width >> source, 1u) ||
|
||||||
|
std::max(description.height >> target, 1u) != std::max(description.height >> source, 1u) ||
|
||||||
|
std::max(description.depth >> target, 1u) != std::max(description.depth >> source, 1u)) {
|
||||||
|
matches = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matches) {
|
||||||
|
levels = description.levels;
|
||||||
|
base_level = base;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resource,
|
TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resource,
|
||||||
@@ -560,7 +591,7 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR
|
|||||||
const auto view_levels = multisampled || single_storage_mip
|
const auto view_levels = multisampled || single_storage_mip
|
||||||
? 1u
|
? 1u
|
||||||
: static_cast<uint32_t>(last_level - base_level) + 1u;
|
: static_cast<uint32_t>(last_level - base_level) + 1u;
|
||||||
const auto levels =
|
auto levels =
|
||||||
multisampled ? 1u : std::max(physical_levels, base_level + view_levels);
|
multisampled ? 1u : std::max(physical_levels, base_level + view_levels);
|
||||||
const auto tile = descriptor.TileMode();
|
const auto tile = descriptor.TileMode();
|
||||||
const bool depth_tile = tile == Prospero::TileMode::kDepth;
|
const bool depth_tile = tile == Prospero::TileMode::kDepth;
|
||||||
@@ -602,12 +633,13 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR
|
|||||||
type == Prospero::ImageType::kColor2DArray ||
|
type == Prospero::ImageType::kColor2DArray ||
|
||||||
type == Prospero::ImageType::kColor2DMsaaArray;
|
type == Prospero::ImageType::kColor2DMsaaArray;
|
||||||
const auto image_layers = layered ? depth : 1u;
|
const auto image_layers = layered ? depth : 1u;
|
||||||
|
auto view_base = static_cast<uint32_t>(base_level);
|
||||||
if (levels > physical_levels) {
|
if (levels > physical_levels) {
|
||||||
const TileSurfaceDescription physical {
|
const TileSurfaceDescription physical {
|
||||||
format, tile, volume ? TileSurfaceDimension::Dim3D : TileSurfaceDimension::Dim2D,
|
format, tile, volume ? TileSurfaceDimension::Dim3D : TileSurfaceDimension::Dim2D,
|
||||||
width, height, volume ? depth : 1u, physical_levels, image_layers};
|
width, height, volume ? depth : 1u, physical_levels, image_layers};
|
||||||
// Texture mip views take precedence over the resource count, but must keep its storage layout.
|
if (!ResolveTextureMipView(physical, !resource.r128 && descriptor.MetaCompress(),
|
||||||
if (!TextureViewPreservesMipLayout(physical, levels)) {
|
view_levels, levels, view_base)) {
|
||||||
EXIT("unsupported texture mip view changes physical layout: base=%u last=%u max=%u "
|
EXIT("unsupported texture mip view changes physical layout: base=%u last=%u max=%u "
|
||||||
"extent=%ux%ux%u tile=%u\n",
|
"extent=%ux%ux%u tile=%u\n",
|
||||||
base_level, last_level, max_mip, width, height, depth,
|
base_level, last_level, max_mip, width, height, depth,
|
||||||
@@ -679,6 +711,7 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR
|
|||||||
}
|
}
|
||||||
desc.view_info = TextureViewInfo(resource, descriptor, view_format, surface_format, storage,
|
desc.view_info = TextureViewInfo(resource, descriptor, view_format, surface_format, storage,
|
||||||
view_levels, desc.info.resources.layers);
|
view_levels, desc.info.resources.layers);
|
||||||
|
desc.view_info.base_level = view_base;
|
||||||
desc.type = storage ? TextureCache::BindingType::Storage : TextureCache::BindingType::Texture;
|
desc.type = storage ? TextureCache::BindingType::Storage : TextureCache::BindingType::Texture;
|
||||||
|
|
||||||
auto id = texture_cache.FindImage(desc, shader_conversion);
|
auto id = texture_cache.FindImage(desc, shader_conversion);
|
||||||
|
|||||||
@@ -10127,18 +10127,20 @@ public:
|
|||||||
program.shader_info_complete = true;
|
program.shader_info_complete = true;
|
||||||
ShaderRecompiler::IR::AllocateBindings(program);
|
ShaderRecompiler::IR::AllocateBindings(program);
|
||||||
};
|
};
|
||||||
|
const auto make_buffer_program =
|
||||||
|
[](ShaderType stage, ShaderRecompiler::IR::BufferResource resource) {
|
||||||
|
ShaderRecompiler::IR::CompiledShaderInfo program{};
|
||||||
|
program.stage = stage;
|
||||||
|
program.info.buffers.push_back(resource);
|
||||||
|
program.bindings.descriptors.push_back(
|
||||||
|
{ShaderRecompiler::IR::DescriptorBindingKind::Buffers, {0}});
|
||||||
|
program.bindings.memory_offset_count = 1;
|
||||||
|
program.bindings.push_data_start_dword = 0;
|
||||||
|
return program;
|
||||||
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
ShaderRecompiler::IR::Program buffer_ir{};
|
const auto buffer_program = make_buffer_program(ShaderType::Compute, {.read = true});
|
||||||
buffer_ir.stage = ShaderType::Compute;
|
|
||||||
buffer_ir.resource_tracking_complete = true;
|
|
||||||
buffer_ir.info.buffers.resize(1);
|
|
||||||
buffer_ir.info.buffers[0].read = true;
|
|
||||||
allocate_bindings(buffer_ir);
|
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo buffer_program{};
|
|
||||||
buffer_program.stage = buffer_ir.stage;
|
|
||||||
buffer_program.info = std::move(buffer_ir.info);
|
|
||||||
buffer_program.bindings = std::move(buffer_ir.bindings);
|
|
||||||
|
|
||||||
constexpr uint64_t buffer_address = base + allocation_size - 0x5000;
|
constexpr uint64_t buffer_address = base + allocation_size - 0x5000;
|
||||||
ShaderBufferResource buffer_descriptor{};
|
ShaderBufferResource buffer_descriptor{};
|
||||||
@@ -10380,6 +10382,60 @@ public:
|
|||||||
Prospero::TextureNumericClass::Uint;
|
Prospero::TextureNumericClass::Uint;
|
||||||
sampled_overwide_resource.read = true;
|
sampled_overwide_resource.read = true;
|
||||||
sampled_overwide_resource.written = false;
|
sampled_overwide_resource.written = false;
|
||||||
|
{
|
||||||
|
// MLB The Show 21 compresses a standalone final block through mip 9.
|
||||||
|
constexpr uint64_t address = base + 0x180000;
|
||||||
|
ShaderRecompiler::IR::DescriptorValue descriptor{};
|
||||||
|
descriptor.dwords = {static_cast<uint32_t>(address >> 8u),
|
||||||
|
0x03e00000u, 0, 0x9019902cu, 0, 0x00700000u, 0, 0};
|
||||||
|
descriptor.dword_count = 8;
|
||||||
|
TestCase test;
|
||||||
|
test.name = "RebasedLastMipQueryStore";
|
||||||
|
test.has_user_data = true;
|
||||||
|
std::copy_n(descriptor.dwords.begin(), 8, test.user_data.begin());
|
||||||
|
test.opcodes = {ShaderOpcode::V_MOV_B32, ShaderOpcode::IMAGE_GET_RESINFO,
|
||||||
|
ShaderOpcode::IMAGE_STORE, ShaderOpcode::S_ENDPGM};
|
||||||
|
AppendVMovU32(&test.code, 24, 0);
|
||||||
|
AppendVMovU32(&test.code, 25, 0);
|
||||||
|
test.code.push_back(EncodeMimg0(0x0e, 0x3));
|
||||||
|
test.code.push_back(EncodeMimg1(0, 24));
|
||||||
|
test.code.push_back(EncodeMimg0(0x08, 0x3));
|
||||||
|
test.code.push_back(EncodeMimg1(0, 24));
|
||||||
|
AppendEnd(&test.code);
|
||||||
|
const auto compiled = CompileCase(test, SubgroupSize());
|
||||||
|
auto sampled_descriptor = descriptor;
|
||||||
|
sampled_descriptor.dwords[1] |= 9u << 16u;
|
||||||
|
const auto query = RenderExecutorTestAccess::ResolveTexture(
|
||||||
|
executor, compiled.program.info.images.at(0), sampled_descriptor);
|
||||||
|
const auto store = RenderExecutorTestAccess::ResolveTexture(
|
||||||
|
executor, compiled.program.info.images.at(1), descriptor);
|
||||||
|
Require(name, "rebased last mip",
|
||||||
|
query.image_id == store.image_id &&
|
||||||
|
query.desc.info.data.size == 256 &&
|
||||||
|
query.desc.info.resources.levels == 1 &&
|
||||||
|
query.desc.view_info.base_level == 0 &&
|
||||||
|
query.desc.view_info.level_count == 1 &&
|
||||||
|
query.desc.view_info.min_lod == 0 &&
|
||||||
|
store.desc.view_info.base_level == 0,
|
||||||
|
"equivalent selected mip changed backing or relative LOD");
|
||||||
|
Image sampled;
|
||||||
|
sampled.view = texture_cache.FindTexture(query.image_id, query.desc);
|
||||||
|
sampled.layout = vk::ImageLayout::eGeneral;
|
||||||
|
Image storage_view;
|
||||||
|
storage_view.view = texture_cache.FindTexture(store.image_id, store.desc);
|
||||||
|
storage_view.layout = vk::ImageLayout::eGeneral;
|
||||||
|
texture_cache.GetImage(store.image_id).Transit(
|
||||||
|
vk::ImageLayout::eGeneral,
|
||||||
|
vk::AccessFlagBits2::eShaderRead | vk::AccessFlagBits2::eShaderWrite,
|
||||||
|
{}, scheduler.Current().Handle());
|
||||||
|
scheduler.Finish();
|
||||||
|
Dispatch(test, compiled, {}, nullptr, &sampled, nullptr, &storage_view);
|
||||||
|
texture_cache.MarkGpuWritten(store.image_id);
|
||||||
|
Require(name, "rebased mip query and store",
|
||||||
|
ReadCachedTexel(name, context, store.image_id) ==
|
||||||
|
std::vector<uint32_t>{1, 1},
|
||||||
|
"query/store did not access the standalone 1x1 mip");
|
||||||
|
}
|
||||||
auto plain_mipped_storage_binding =
|
auto plain_mipped_storage_binding =
|
||||||
RenderExecutorTestAccess::ResolveTexture(executor, storage_resource,
|
RenderExecutorTestAccess::ResolveTexture(executor, storage_resource,
|
||||||
mipped_storage_descriptor);
|
mipped_storage_descriptor);
|
||||||
@@ -11937,17 +11993,8 @@ public:
|
|||||||
texture_cache, scheduler.Current(), expanded_array_id,
|
texture_cache, scheduler.Current(), expanded_array_id,
|
||||||
{vk::ImageAspectFlagBits::eColor, 0, 1, 1, 1}, clear);
|
{vk::ImageAspectFlagBits::eColor, 0, 1, 1, 1}, clear);
|
||||||
|
|
||||||
ShaderRecompiler::IR::Program buffer_ir{};
|
const auto buffer_program = make_buffer_program(
|
||||||
buffer_ir.stage = ShaderType::Vertex;
|
ShaderType::Vertex, {.read = true, .formatted = true});
|
||||||
buffer_ir.resource_tracking_complete = true;
|
|
||||||
buffer_ir.info.buffers.resize(1);
|
|
||||||
buffer_ir.info.buffers[0].read = true;
|
|
||||||
buffer_ir.info.buffers[0].formatted = true;
|
|
||||||
allocate_bindings(buffer_ir);
|
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo buffer_program{};
|
|
||||||
buffer_program.stage = buffer_ir.stage;
|
|
||||||
buffer_program.info = std::move(buffer_ir.info);
|
|
||||||
buffer_program.bindings = std::move(buffer_ir.bindings);
|
|
||||||
|
|
||||||
constexpr uint64_t buffer_size = 2 * target_mip_size;
|
constexpr uint64_t buffer_size = 2 * target_mip_size;
|
||||||
static_assert(buffer_size > BufferCache::CACHING_PAGESIZE);
|
static_assert(buffer_size > BufferCache::CACHING_PAGESIZE);
|
||||||
@@ -12613,17 +12660,8 @@ public:
|
|||||||
}
|
}
|
||||||
auto plane_upload = CreateHostBuffer(name, plane_size,
|
auto plane_upload = CreateHostBuffer(name, plane_size,
|
||||||
vk::BufferUsageFlagBits::eTransferSrc, plane_words);
|
vk::BufferUsageFlagBits::eTransferSrc, plane_words);
|
||||||
ShaderRecompiler::IR::Program plane_ir{};
|
const auto plane_program = make_buffer_program(
|
||||||
plane_ir.stage = ShaderType::Compute;
|
ShaderType::Compute, {.written = true, .formatted = true});
|
||||||
plane_ir.resource_tracking_complete = true;
|
|
||||||
auto &plane_resource = plane_ir.info.buffers.emplace_back();
|
|
||||||
plane_resource.written = true;
|
|
||||||
plane_resource.formatted = true;
|
|
||||||
allocate_bindings(plane_ir);
|
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo plane_program{};
|
|
||||||
plane_program.stage = plane_ir.stage;
|
|
||||||
plane_program.info = std::move(plane_ir.info);
|
|
||||||
plane_program.bindings = std::move(plane_ir.bindings);
|
|
||||||
ShaderBufferResource plane_descriptor{};
|
ShaderBufferResource plane_descriptor{};
|
||||||
plane_descriptor.UpdateAddress48(plane_address);
|
plane_descriptor.UpdateAddress48(plane_address);
|
||||||
plane_descriptor.fields[1] |= 4u << 16u;
|
plane_descriptor.fields[1] |= 4u << 16u;
|
||||||
|
|||||||
Reference in New Issue
Block a user