mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 22:06:59 +01:00
Approximate explicit-LOD texture gathers at mip zero
Credits: YuhiAida (@YuhiAida): https://github.com/KytyPS5/KytyPS5/pull/588 https://github.com/KytyPS5/KytyPS5/pull/589 https://github.com/KytyPS5/KytyPS5/pull/655 frans (@francoisatt): https://github.com/KytyPS5/KytyPS5/pull/590 BlackCAT (@psnwd): https://github.com/KytyPS5/KytyPS5/pull/613 shadowbeat070 (@shadowbeat070): https://github.com/KytyPS5/KytyPS5/pull/654 Pouare514 (@Pouare514): https://github.com/KytyPS5/KytyPS5/pull/29 https://github.com/KytyPS5/KytyPS5/pull/32
This commit is contained in:
@@ -3,7 +3,9 @@
|
|||||||
#include "graphics/shader/recompiler/frontend/decode/ImageOps.h"
|
#include "graphics/shader/recompiler/frontend/decode/ImageOps.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <atomic>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
|
namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
|
||||||
namespace {
|
namespace {
|
||||||
@@ -646,6 +648,13 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
const auto coord =
|
const auto coord =
|
||||||
CoordF32(ctx, mem, *address, layout.coord, dimension_info.coordinate_components);
|
CoordF32(ctx, mem, *address, layout.coord, dimension_info.coordinate_components);
|
||||||
if (op == IR::ValueOpcode::ImageGatherRaw) {
|
if (op == IR::ValueOpcode::ImageGatherRaw) {
|
||||||
|
if (HasFlag(mem, Decoder::ImageSampleFlagLod)) {
|
||||||
|
static std::atomic_flag warned = ATOMIC_FLAG_INIT;
|
||||||
|
if (!warned.test_and_set(std::memory_order_relaxed)) {
|
||||||
|
std::fputs("Warning: approximating IMAGE_GATHER4_L at mip level 0; explicit LOD is ignored.\n",
|
||||||
|
stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (dimension == ImageDimension::Dim1D) {
|
if (dimension == ImageDimension::Dim1D) {
|
||||||
if (dref || !HasFlag(mem, Decoder::ImageSampleFlagLevelZero) ||
|
if (dref || !HasFlag(mem, Decoder::ImageSampleFlagLevelZero) ||
|
||||||
HasFlag(mem, Decoder::ImageSampleFlagOffset) ||
|
HasFlag(mem, Decoder::ImageSampleFlagOffset) ||
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ constexpr MimgSampleInfo MIMG_SAMPLE_OPCODE_LIST[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
constexpr MimgGatherInfo MIMG_GATHER_OPCODE_LIST[] = {
|
constexpr MimgGatherInfo MIMG_GATHER_OPCODE_LIST[] = {
|
||||||
|
{0x44u, Opcode::IMAGE_GATHER4_L, ImageSampleFlagLod},
|
||||||
{0x47u, Opcode::IMAGE_GATHER4_LZ, ImageSampleFlagLevelZero},
|
{0x47u, Opcode::IMAGE_GATHER4_LZ, ImageSampleFlagLevelZero},
|
||||||
{0x48u, Opcode::IMAGE_GATHER4_C, ImageSampleFlagCompare},
|
{0x48u, Opcode::IMAGE_GATHER4_C, ImageSampleFlagCompare},
|
||||||
{0x4fu, Opcode::IMAGE_GATHER4_C_LZ,
|
{0x4fu, Opcode::IMAGE_GATHER4_C_LZ,
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ std::string FormatMimg(const Instruction& inst) {
|
|||||||
}
|
}
|
||||||
switch (inst.opcode) {
|
switch (inst.opcode) {
|
||||||
case Opcode::IMAGE_SAMPLE:
|
case Opcode::IMAGE_SAMPLE:
|
||||||
|
case Opcode::IMAGE_GATHER4_L:
|
||||||
case Opcode::IMAGE_GATHER4_LZ:
|
case Opcode::IMAGE_GATHER4_LZ:
|
||||||
case Opcode::IMAGE_GATHER4_C:
|
case Opcode::IMAGE_GATHER4_C:
|
||||||
case Opcode::IMAGE_GATHER4_C_LZ:
|
case Opcode::IMAGE_GATHER4_C_LZ:
|
||||||
@@ -580,6 +581,7 @@ std::string InstructionToString(const Instruction& inst) {
|
|||||||
case Opcode::IMAGE_LOAD_MIP:
|
case Opcode::IMAGE_LOAD_MIP:
|
||||||
case Opcode::IMAGE_GET_RESINFO:
|
case Opcode::IMAGE_GET_RESINFO:
|
||||||
case Opcode::IMAGE_GET_LOD:
|
case Opcode::IMAGE_GET_LOD:
|
||||||
|
case Opcode::IMAGE_GATHER4_L:
|
||||||
case Opcode::IMAGE_GATHER4_LZ:
|
case Opcode::IMAGE_GATHER4_LZ:
|
||||||
case Opcode::IMAGE_GATHER4_C:
|
case Opcode::IMAGE_GATHER4_C:
|
||||||
case Opcode::IMAGE_GATHER4_C_LZ:
|
case Opcode::IMAGE_GATHER4_C_LZ:
|
||||||
|
|||||||
@@ -559,6 +559,7 @@ enum class Opcode {
|
|||||||
IMAGE_ATOMIC_OR,
|
IMAGE_ATOMIC_OR,
|
||||||
IMAGE_ATOMIC_XOR,
|
IMAGE_ATOMIC_XOR,
|
||||||
IMAGE_SAMPLE,
|
IMAGE_SAMPLE,
|
||||||
|
IMAGE_GATHER4_L,
|
||||||
IMAGE_GATHER4_LZ,
|
IMAGE_GATHER4_LZ,
|
||||||
IMAGE_GATHER4_C,
|
IMAGE_GATHER4_C,
|
||||||
IMAGE_GATHER4_C_LZ,
|
IMAGE_GATHER4_C_LZ,
|
||||||
|
|||||||
@@ -1034,6 +1034,7 @@ bool Translator::EmitMemory(const Decoder::Instruction& inst) {
|
|||||||
case Decoder::Opcode::IMAGE_STORE:
|
case Decoder::Opcode::IMAGE_STORE:
|
||||||
case Decoder::Opcode::IMAGE_STORE_MIP: return IMAGE_STORE(inst);
|
case Decoder::Opcode::IMAGE_STORE_MIP: return IMAGE_STORE(inst);
|
||||||
case Decoder::Opcode::IMAGE_SAMPLE: return IMAGE_SAMPLE(inst);
|
case Decoder::Opcode::IMAGE_SAMPLE: return IMAGE_SAMPLE(inst);
|
||||||
|
case Decoder::Opcode::IMAGE_GATHER4_L:
|
||||||
case Decoder::Opcode::IMAGE_GATHER4_LZ:
|
case Decoder::Opcode::IMAGE_GATHER4_LZ:
|
||||||
case Decoder::Opcode::IMAGE_GATHER4_C:
|
case Decoder::Opcode::IMAGE_GATHER4_C:
|
||||||
case Decoder::Opcode::IMAGE_GATHER4_C_LZ:
|
case Decoder::Opcode::IMAGE_GATHER4_C_LZ:
|
||||||
|
|||||||
@@ -12271,7 +12271,7 @@ public:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::Sampler CreateNearestSampler(const char *shader_name) {
|
vk::Sampler CreateNearestSampler(const char *shader_name, u32 mip_levels = 1) {
|
||||||
vk::SamplerCreateInfo sampler_info{};
|
vk::SamplerCreateInfo sampler_info{};
|
||||||
sampler_info.sType = vk::StructureType::eSamplerCreateInfo;
|
sampler_info.sType = vk::StructureType::eSamplerCreateInfo;
|
||||||
sampler_info.magFilter = vk::Filter::eNearest;
|
sampler_info.magFilter = vk::Filter::eNearest;
|
||||||
@@ -12281,7 +12281,7 @@ public:
|
|||||||
sampler_info.addressModeV = vk::SamplerAddressMode::eClampToEdge;
|
sampler_info.addressModeV = vk::SamplerAddressMode::eClampToEdge;
|
||||||
sampler_info.addressModeW = vk::SamplerAddressMode::eClampToEdge;
|
sampler_info.addressModeW = vk::SamplerAddressMode::eClampToEdge;
|
||||||
sampler_info.minLod = 0.0f;
|
sampler_info.minLod = 0.0f;
|
||||||
sampler_info.maxLod = 0.0f;
|
sampler_info.maxLod = static_cast<float>(mip_levels - 1u);
|
||||||
vk::Sampler sampler = nullptr;
|
vk::Sampler sampler = nullptr;
|
||||||
RequireVk(shader_name, "dispatch",
|
RequireVk(shader_name, "dispatch",
|
||||||
m_device.createSampler(&sampler_info, nullptr, &sampler),
|
m_device.createSampler(&sampler_info, nullptr, &sampler),
|
||||||
@@ -15484,7 +15484,7 @@ void RunCase(VulkanHarness *vulkan, const TestCase &test) {
|
|||||||
vk::ImageLayout::eGeneral);
|
vk::ImageLayout::eGeneral);
|
||||||
}
|
}
|
||||||
if (needs_sampler) {
|
if (needs_sampler) {
|
||||||
sampler = vulkan->CreateNearestSampler(test.name);
|
sampler = vulkan->CreateNearestSampler(test.name, sampled_image.mip_levels);
|
||||||
}
|
}
|
||||||
|
|
||||||
vulkan->Dispatch(test, compiled, buffer, needs_gds ? &gds_buffer : nullptr,
|
vulkan->Dispatch(test, compiled, buffer, needs_gds ? &gds_buffer : nullptr,
|
||||||
@@ -25001,6 +25001,34 @@ TestCase ImageSampleAndGather() {
|
|||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestCase ImageGatherLodApproximatesLevelZero() {
|
||||||
|
using O = ShaderOpcode;
|
||||||
|
std::vector<u32> code;
|
||||||
|
AppendVMovLiteral(&code, 20, 0x3f000000u);
|
||||||
|
AppendVMovLiteral(&code, 21, 0x3f000000u);
|
||||||
|
AppendVMovLiteral(&code, 22, 0x3f800000u);
|
||||||
|
code.push_back(EncodeMimg0(0x44, 0x1));
|
||||||
|
code.push_back(EncodeMimg1(0, 20));
|
||||||
|
code.push_back(EncodeMimg0(0x24, 0x1));
|
||||||
|
code.push_back(EncodeMimg1(4, 20));
|
||||||
|
for (u32 i = 0; i < 5u; i++) {
|
||||||
|
AppendStoreVgpr(&code, i, i);
|
||||||
|
}
|
||||||
|
AppendEnd(&code);
|
||||||
|
|
||||||
|
TestCase test;
|
||||||
|
test.name = "ImageGatherLodApproximatesLevelZero";
|
||||||
|
test.code = std::move(code);
|
||||||
|
test.opcodes = {O::V_MOV_B32, O::IMAGE_GATHER4_L, O::IMAGE_SAMPLE,
|
||||||
|
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||||
|
// Explicit sampling proves mip 1 is accessible; the gather must still read mip 0.
|
||||||
|
test.expected = {0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x41000000u};
|
||||||
|
test.sampled_image_rgba_mips = {std::vector<u32>(4 * 4 * 4, 0x3f800000u),
|
||||||
|
std::vector<u32>(2 * 2 * 4, 0x41000000u)};
|
||||||
|
test.required_spirv = {"OpImageGather", "OpImageSampleExplicitLod"};
|
||||||
|
return test;
|
||||||
|
}
|
||||||
|
|
||||||
TestCase ImageD16GatherPacksHalfPairs() {
|
TestCase ImageD16GatherPacksHalfPairs() {
|
||||||
using O = ShaderOpcode;
|
using O = ShaderOpcode;
|
||||||
|
|
||||||
@@ -26575,6 +26603,7 @@ std::vector<TestCase> MakeCases() {
|
|||||||
AddCase(ImageGetResinfoDmaskWidthHeight);
|
AddCase(ImageGetResinfoDmaskWidthHeight);
|
||||||
AddCase(ImageGetResinfoDmaskMipLevels);
|
AddCase(ImageGetResinfoDmaskMipLevels);
|
||||||
AddCase(ImageSampleAndGather);
|
AddCase(ImageSampleAndGather);
|
||||||
|
AddCase(ImageGatherLodApproximatesLevelZero);
|
||||||
AddCase(ImageD16GatherPacksHalfPairs);
|
AddCase(ImageD16GatherPacksHalfPairs);
|
||||||
AddCase(ImageSampleA16SamplerCoordsOnGpu);
|
AddCase(ImageSampleA16SamplerCoordsOnGpu);
|
||||||
AddCase(ImageSampleOpcodeAliasUsesNormalCoords);
|
AddCase(ImageSampleOpcodeAliasUsesNormalCoords);
|
||||||
@@ -31166,6 +31195,7 @@ int main(int argc, char **argv) {
|
|||||||
RunCase(&vulkan, BranchVccnzUsesWaveMask());
|
RunCase(&vulkan, BranchVccnzUsesWaveMask());
|
||||||
RunCase(&vulkan, BranchVccnzUsesCarryProducedWaveMask());
|
RunCase(&vulkan, BranchVccnzUsesCarryProducedWaveMask());
|
||||||
RunCase(&vulkan, ImageSampleAndGather());
|
RunCase(&vulkan, ImageSampleAndGather());
|
||||||
|
RunCase(&vulkan, ImageGatherLodApproximatesLevelZero());
|
||||||
RunCase(&vulkan, SharedReturnKeepsSelectedValues());
|
RunCase(&vulkan, SharedReturnKeepsSelectedValues());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user