spirv: Implement image derivatives
This commit is contained in:
parent
4eda0452b5
commit
03c8b3515d
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
#pragma clang optimize off
|
|
||||||
#include <boost/container/static_vector.hpp>
|
#include <boost/container/static_vector.hpp>
|
||||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||||
|
@ -16,6 +16,12 @@ struct ImageOperands {
|
||||||
static_cast<u32>(new_mask));
|
static_cast<u32>(new_mask));
|
||||||
operands.push_back(value);
|
operands.push_back(value);
|
||||||
}
|
}
|
||||||
|
void Add(spv::ImageOperandsMask new_mask, Id value1, Id value2) {
|
||||||
|
mask = static_cast<spv::ImageOperandsMask>(static_cast<u32>(mask) |
|
||||||
|
static_cast<u32>(new_mask));
|
||||||
|
operands.push_back(value1);
|
||||||
|
operands.push_back(value2);
|
||||||
|
}
|
||||||
|
|
||||||
void AddOffset(EmitContext& ctx, const IR::Value& offset,
|
void AddOffset(EmitContext& ctx, const IR::Value& offset,
|
||||||
bool can_use_runtime_offsets = false) {
|
bool can_use_runtime_offsets = false) {
|
||||||
|
@ -53,6 +59,15 @@ struct ImageOperands {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddDerivatives(EmitContext& ctx, Id derivatives) {
|
||||||
|
if (!Sirit::ValidId(derivatives)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const Id dx{ctx.OpVectorShuffle(ctx.F32[2], derivatives, derivatives, 0, 1)};
|
||||||
|
const Id dy{ctx.OpVectorShuffle(ctx.F32[2], derivatives, derivatives, 2, 3)};
|
||||||
|
Add(spv::ImageOperandsMask::Grad, dx, dy);
|
||||||
|
}
|
||||||
|
|
||||||
spv::ImageOperandsMask mask{};
|
spv::ImageOperandsMask mask{};
|
||||||
boost::container::static_vector<Id, 4> operands;
|
boost::container::static_vector<Id, 4> operands;
|
||||||
};
|
};
|
||||||
|
@ -181,9 +196,17 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords) {
|
||||||
return ctx.OpImageQueryLod(ctx.F32[2], sampled_image, coords);
|
return ctx.OpImageQueryLod(ctx.F32[2], sampled_image, coords);
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords,
|
||||||
Id derivatives, const IR::Value& offset, Id lod_clamp) {
|
Id derivatives, const IR::Value& offset, Id lod_clamp) {
|
||||||
UNREACHABLE_MSG("SPIR-V Instruction");
|
const auto& texture = ctx.images[handle & 0xFFFF];
|
||||||
|
const Id image = ctx.OpLoad(texture.image_type, texture.id);
|
||||||
|
const Id sampler = ctx.OpLoad(ctx.sampler_type, ctx.samplers[handle >> 16]);
|
||||||
|
const Id sampled_image = ctx.OpSampledImage(texture.sampled_type, image, sampler);
|
||||||
|
ImageOperands operands;
|
||||||
|
operands.AddDerivatives(ctx, derivatives);
|
||||||
|
operands.AddOffset(ctx, offset);
|
||||||
|
return ctx.OpImageSampleExplicitLod(ctx.F32[4], sampled_image, coords, operands.mask,
|
||||||
|
operands.operands);
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) {
|
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) {
|
||||||
|
|
|
@ -387,7 +387,7 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, const
|
||||||
Id lod, Id ms);
|
Id lod, Id ms);
|
||||||
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, u32 handle, Id lod, bool skip_mips);
|
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, u32 handle, Id lod, bool skip_mips);
|
||||||
Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords);
|
Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords);
|
||||||
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords,
|
||||||
Id derivatives, const IR::Value& offset, Id lod_clamp);
|
Id derivatives, const IR::Value& offset, Id lod_clamp);
|
||||||
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
|
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
|
||||||
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id color);
|
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id color);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
#pragma clang optimize off
|
|
||||||
#include "shader_recompiler/frontend/translate/translate.h"
|
#include "shader_recompiler/frontend/translate/translate.h"
|
||||||
|
|
||||||
namespace Shader::Gcn {
|
namespace Shader::Gcn {
|
||||||
|
|
|
@ -17,6 +17,7 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
|
||||||
case Opcode::IMAGE_SAMPLE_C_O:
|
case Opcode::IMAGE_SAMPLE_C_O:
|
||||||
case Opcode::IMAGE_SAMPLE_B:
|
case Opcode::IMAGE_SAMPLE_B:
|
||||||
case Opcode::IMAGE_SAMPLE_C_LZ_O:
|
case Opcode::IMAGE_SAMPLE_C_LZ_O:
|
||||||
|
case Opcode::IMAGE_SAMPLE_D:
|
||||||
return IMAGE_SAMPLE(inst);
|
return IMAGE_SAMPLE(inst);
|
||||||
case Opcode::IMAGE_GATHER4_C:
|
case Opcode::IMAGE_GATHER4_C:
|
||||||
case Opcode::IMAGE_GATHER4_LZ:
|
case Opcode::IMAGE_GATHER4_LZ:
|
||||||
|
@ -162,12 +163,16 @@ void Translator::IMAGE_SAMPLE(const GcnInst& inst) {
|
||||||
flags.test(MimgModifier::LodBias) ? ir.GetVectorReg<IR::F32>(addr_reg++) : IR::F32{};
|
flags.test(MimgModifier::LodBias) ? ir.GetVectorReg<IR::F32>(addr_reg++) : IR::F32{};
|
||||||
const IR::F32 dref =
|
const IR::F32 dref =
|
||||||
flags.test(MimgModifier::Pcf) ? ir.GetVectorReg<IR::F32>(addr_reg++) : IR::F32{};
|
flags.test(MimgModifier::Pcf) ? ir.GetVectorReg<IR::F32>(addr_reg++) : IR::F32{};
|
||||||
|
const IR::Value derivatives = [&] -> IR::Value {
|
||||||
// Derivatives are tricky because their number depends on the texture type which is located in
|
if (!flags.test(MimgModifier::Derivative)) {
|
||||||
// T#. We don't have access to T# though until resource tracking pass. For now assume no
|
return {};
|
||||||
// derivatives are present, otherwise we don't know where coordinates are placed in the address
|
}
|
||||||
// stream.
|
addr_reg = addr_reg + 4;
|
||||||
ASSERT_MSG(!flags.test(MimgModifier::Derivative), "Derivative image instruction");
|
return ir.CompositeConstruct(ir.GetVectorReg<IR::F32>(addr_reg - 4),
|
||||||
|
ir.GetVectorReg<IR::F32>(addr_reg - 3),
|
||||||
|
ir.GetVectorReg<IR::F32>(addr_reg - 2),
|
||||||
|
ir.GetVectorReg<IR::F32>(addr_reg - 1));
|
||||||
|
}();
|
||||||
|
|
||||||
// Now we can load body components as noted in Table 8.9 Image Opcodes with Sampler
|
// Now we can load body components as noted in Table 8.9 Image Opcodes with Sampler
|
||||||
// Since these are at most 4 dwords, we load them into a single uvec4 and place them
|
// Since these are at most 4 dwords, we load them into a single uvec4 and place them
|
||||||
|
@ -177,6 +182,10 @@ void Translator::IMAGE_SAMPLE(const GcnInst& inst) {
|
||||||
ir.GetVectorReg<IR::F32>(addr_reg), ir.GetVectorReg<IR::F32>(addr_reg + 1),
|
ir.GetVectorReg<IR::F32>(addr_reg), ir.GetVectorReg<IR::F32>(addr_reg + 1),
|
||||||
ir.GetVectorReg<IR::F32>(addr_reg + 2), ir.GetVectorReg<IR::F32>(addr_reg + 3));
|
ir.GetVectorReg<IR::F32>(addr_reg + 2), ir.GetVectorReg<IR::F32>(addr_reg + 3));
|
||||||
|
|
||||||
|
// Derivatives are tricky because their number depends on the texture type which is located in
|
||||||
|
// T#. We don't have access to T# though until resource tracking pass. For now assume if
|
||||||
|
// derivatives are present, that a 2D image is bound.
|
||||||
|
const bool has_derivatives = flags.test(MimgModifier::Derivative);
|
||||||
const bool explicit_lod = flags.any(MimgModifier::Level0, MimgModifier::Lod);
|
const bool explicit_lod = flags.any(MimgModifier::Level0, MimgModifier::Lod);
|
||||||
|
|
||||||
IR::TextureInstInfo info{};
|
IR::TextureInstInfo info{};
|
||||||
|
@ -186,9 +195,13 @@ void Translator::IMAGE_SAMPLE(const GcnInst& inst) {
|
||||||
info.force_level0.Assign(flags.test(MimgModifier::Level0));
|
info.force_level0.Assign(flags.test(MimgModifier::Level0));
|
||||||
info.has_offset.Assign(flags.test(MimgModifier::Offset));
|
info.has_offset.Assign(flags.test(MimgModifier::Offset));
|
||||||
info.explicit_lod.Assign(explicit_lod);
|
info.explicit_lod.Assign(explicit_lod);
|
||||||
|
info.has_derivatives.Assign(has_derivatives);
|
||||||
|
|
||||||
// Issue IR instruction, leaving unknown fields blank to patch later.
|
// Issue IR instruction, leaving unknown fields blank to patch later.
|
||||||
const IR::Value texel = [&]() -> IR::Value {
|
const IR::Value texel = [&]() -> IR::Value {
|
||||||
|
if (has_derivatives) {
|
||||||
|
return ir.ImageGradient(handle, body, derivatives, offset, {}, info);
|
||||||
|
}
|
||||||
if (!flags.test(MimgModifier::Pcf)) {
|
if (!flags.test(MimgModifier::Pcf)) {
|
||||||
if (explicit_lod) {
|
if (explicit_lod) {
|
||||||
return ir.ImageSampleExplicitLod(handle, body, offset, info);
|
return ir.ImageSampleExplicitLod(handle, body, offset, info);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
#pragma clang optimize off
|
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
#pragma clang optimize off
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <boost/container/small_vector.hpp>
|
#include <boost/container/small_vector.hpp>
|
||||||
#include "shader_recompiler/ir/basic_block.h"
|
#include "shader_recompiler/ir/basic_block.h"
|
||||||
|
@ -631,7 +631,10 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (inst_info.has_derivatives) {
|
||||||
|
ASSERT_MSG(image.GetType() == AmdGpu::ImageType::Color2D,
|
||||||
|
"User derivatives only supported for 2D images");
|
||||||
|
}
|
||||||
if (inst_info.has_lod_clamp) {
|
if (inst_info.has_lod_clamp) {
|
||||||
const u32 arg_pos = [&]() -> u32 {
|
const u32 arg_pos = [&]() -> u32 {
|
||||||
switch (inst.GetOpcode()) {
|
switch (inst.GetOpcode()) {
|
||||||
|
|
|
@ -58,6 +58,7 @@ union TextureInstInfo {
|
||||||
BitField<4, 1, u32> explicit_lod;
|
BitField<4, 1, u32> explicit_lod;
|
||||||
BitField<5, 1, u32> has_offset;
|
BitField<5, 1, u32> has_offset;
|
||||||
BitField<6, 2, u32> gather_comp;
|
BitField<6, 2, u32> gather_comp;
|
||||||
|
BitField<8, 1, u32> has_derivatives;
|
||||||
};
|
};
|
||||||
|
|
||||||
union BufferInstInfo {
|
union BufferInstInfo {
|
||||||
|
|
|
@ -64,7 +64,7 @@ IR::Program TranslateProgram(Common::ObjectPool<IR::Inst>& inst_pool,
|
||||||
Shader::Optimization::IdentityRemovalPass(program.blocks);
|
Shader::Optimization::IdentityRemovalPass(program.blocks);
|
||||||
Shader::Optimization::DeadCodeEliminationPass(program);
|
Shader::Optimization::DeadCodeEliminationPass(program);
|
||||||
Shader::Optimization::CollectShaderInfoPass(program);
|
Shader::Optimization::CollectShaderInfoPass(program);
|
||||||
LOG_INFO(Render_Vulkan, "{}", Shader::IR::DumpProgram(program));
|
LOG_DEBUG(Render_Vulkan, "{}", Shader::IR::DumpProgram(program));
|
||||||
|
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
#pragma clang optimize off
|
|
||||||
#include <xxhash.h>
|
#include <xxhash.h>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "video_core/buffer_cache/buffer_cache.h"
|
#include "video_core/buffer_cache/buffer_cache.h"
|
||||||
|
|
Loading…
Reference in New Issue