video_core: Fix SNORM texture buffer emulating error (#9001)
This commit is contained in:
		| @@ -43,6 +43,10 @@ void EmitBitCastU64F64(EmitContext&, IR::Inst& inst, const IR::Value& value) { | ||||
|     Alias(inst, value); | ||||
| } | ||||
|  | ||||
| void EmitBitCastS32F32(EmitContext&, IR::Inst& inst, const IR::Value& value) { | ||||
|     Alias(inst, value); | ||||
| } | ||||
|  | ||||
| void EmitBitCastF16U16(EmitContext&, IR::Inst& inst, const IR::Value& value) { | ||||
|     Alias(inst, value); | ||||
| } | ||||
|   | ||||
| @@ -196,6 +196,7 @@ void EmitSelectF64(EmitContext& ctx, ScalarS32 cond, Register true_value, Regist | ||||
| void EmitBitCastU16F16(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | ||||
| void EmitBitCastU32F32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | ||||
| void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | ||||
| void EmitBitCastS32F32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | ||||
| void EmitBitCastF16U16(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | ||||
| void EmitBitCastF32U32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | ||||
| void EmitBitCastF64U64(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | ||||
|   | ||||
| @@ -48,6 +48,10 @@ void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, std::string_view value) | ||||
|     ctx.AddU64("{}=doubleBitsToUint64({});", inst, value); | ||||
| } | ||||
|  | ||||
| void EmitBitCastS32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value) { | ||||
|     ctx.AddF32("{}=ftoi({});", inst, value); | ||||
| } | ||||
|  | ||||
| void EmitBitCastF16U16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst) { | ||||
|     NotImplemented(); | ||||
| } | ||||
|   | ||||
| @@ -230,6 +230,7 @@ void EmitSelectF64(EmitContext& ctx, IR::Inst& inst, std::string_view cond, | ||||
| void EmitBitCastU16F16(EmitContext& ctx, IR::Inst& inst); | ||||
| void EmitBitCastU32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value); | ||||
| void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, std::string_view value); | ||||
| void EmitBitCastS32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value); | ||||
| void EmitBitCastF16U16(EmitContext& ctx, IR::Inst& inst); | ||||
| void EmitBitCastF32U32(EmitContext& ctx, IR::Inst& inst, std::string_view value); | ||||
| void EmitBitCastF64U64(EmitContext& ctx, IR::Inst& inst, std::string_view value); | ||||
|   | ||||
| @@ -18,6 +18,10 @@ void EmitBitCastU64F64(EmitContext&) { | ||||
|     throw NotImplementedException("SPIR-V Instruction"); | ||||
| } | ||||
|  | ||||
| void EmitBitCastS32F32(EmitContext&) { | ||||
|     throw NotImplementedException("SPIR-V Instruction"); | ||||
| } | ||||
|  | ||||
| void EmitBitCastF16U16(EmitContext&) { | ||||
|     throw NotImplementedException("SPIR-V Instruction"); | ||||
| } | ||||
|   | ||||
| @@ -178,7 +178,8 @@ Id EmitSelectF64(EmitContext& ctx, Id cond, Id true_value, Id false_value); | ||||
| void EmitBitCastU16F16(EmitContext& ctx); | ||||
| Id EmitBitCastU32F32(EmitContext& ctx, Id value); | ||||
| void EmitBitCastU64F64(EmitContext& ctx); | ||||
| void EmitBitCastF16U16(EmitContext& ctx); | ||||
| void EmitBitCastS32F32(EmitContext& ctx); | ||||
| void EmitBitCastF16U16(EmitContext&); | ||||
| Id EmitBitCastF32U32(EmitContext& ctx, Id value); | ||||
| void EmitBitCastF64U64(EmitContext& ctx); | ||||
| Id EmitPackUint2x32(EmitContext& ctx, Id value); | ||||
|   | ||||
| @@ -22,6 +22,8 @@ public: | ||||
|  | ||||
|     [[nodiscard]] virtual TextureType ReadTextureType(u32 raw_handle) = 0; | ||||
|  | ||||
|     [[nodiscard]] virtual TexturePixelFormat ReadTexturePixelFormat(u32 raw_handle) = 0; | ||||
|  | ||||
|     [[nodiscard]] virtual u32 ReadViewportTransformState() = 0; | ||||
|  | ||||
|     [[nodiscard]] virtual u32 TextureBoundBuffer() const = 0; | ||||
|   | ||||
| @@ -691,6 +691,11 @@ IR::U32 IREmitter::BitCast<IR::U32, IR::F32>(const IR::F32& value) { | ||||
|     return Inst<IR::U32>(Opcode::BitCastU32F32, value); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| IR::S32 IREmitter::BitCast<IR::S32, IR::F32>(const IR::F32& value) { | ||||
|     return Inst<IR::S32>(Opcode::BitCastS32F32, value); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| IR::F32 IREmitter::BitCast<IR::F32, IR::U32>(const IR::U32& value) { | ||||
|     return Inst<IR::F32>(Opcode::BitCastF32U32, value); | ||||
|   | ||||
| @@ -37,6 +37,7 @@ constexpr Type U8{Type::U8}; | ||||
| constexpr Type U16{Type::U16}; | ||||
| constexpr Type U32{Type::U32}; | ||||
| constexpr Type U64{Type::U64}; | ||||
| constexpr Type S32{Type::S32}; | ||||
| constexpr Type F16{Type::F16}; | ||||
| constexpr Type F32{Type::F32}; | ||||
| constexpr Type F64{Type::F64}; | ||||
|   | ||||
| @@ -174,6 +174,7 @@ OPCODE(SelectF64,                                           F64,            U1, | ||||
| OPCODE(BitCastU16F16,                                       U16,            F16,                                                                            ) | ||||
| OPCODE(BitCastU32F32,                                       U32,            F32,                                                                            ) | ||||
| OPCODE(BitCastU64F64,                                       U64,            F64,                                                                            ) | ||||
| OPCODE(BitCastS32F32,                                       S32,            F32,                                                                            ) | ||||
| OPCODE(BitCastF16U16,                                       F16,            U16,                                                                            ) | ||||
| OPCODE(BitCastF32U32,                                       F32,            U32,                                                                            ) | ||||
| OPCODE(BitCastF64U64,                                       F64,            U64,                                                                            ) | ||||
|   | ||||
| @@ -24,21 +24,22 @@ enum class Type { | ||||
|     U16 = 1 << 7, | ||||
|     U32 = 1 << 8, | ||||
|     U64 = 1 << 9, | ||||
|     F16 = 1 << 10, | ||||
|     F32 = 1 << 11, | ||||
|     F64 = 1 << 12, | ||||
|     U32x2 = 1 << 13, | ||||
|     U32x3 = 1 << 14, | ||||
|     U32x4 = 1 << 15, | ||||
|     F16x2 = 1 << 16, | ||||
|     F16x3 = 1 << 17, | ||||
|     F16x4 = 1 << 18, | ||||
|     F32x2 = 1 << 19, | ||||
|     F32x3 = 1 << 20, | ||||
|     F32x4 = 1 << 21, | ||||
|     F64x2 = 1 << 22, | ||||
|     F64x3 = 1 << 23, | ||||
|     F64x4 = 1 << 24, | ||||
|     S32 = 1 << 10, | ||||
|     F16 = 1 << 11, | ||||
|     F32 = 1 << 12, | ||||
|     F64 = 1 << 13, | ||||
|     U32x2 = 1 << 14, | ||||
|     U32x3 = 1 << 15, | ||||
|     U32x4 = 1 << 16, | ||||
|     F16x2 = 1 << 17, | ||||
|     F16x3 = 1 << 18, | ||||
|     F16x4 = 1 << 19, | ||||
|     F32x2 = 1 << 20, | ||||
|     F32x3 = 1 << 21, | ||||
|     F32x4 = 1 << 22, | ||||
|     F64x2 = 1 << 23, | ||||
|     F64x3 = 1 << 24, | ||||
|     F64x4 = 1 << 25, | ||||
| }; | ||||
| DECLARE_ENUM_FLAG_OPERATORS(Type) | ||||
|  | ||||
|   | ||||
| @@ -23,6 +23,8 @@ Value::Value(u16 value) noexcept : type{Type::U16}, imm_u16{value} {} | ||||
|  | ||||
| Value::Value(u32 value) noexcept : type{Type::U32}, imm_u32{value} {} | ||||
|  | ||||
| Value::Value(s32 value) noexcept : type{Type::S32}, imm_s32{value} {} | ||||
|  | ||||
| Value::Value(f32 value) noexcept : type{Type::F32}, imm_f32{value} {} | ||||
|  | ||||
| Value::Value(u64 value) noexcept : type{Type::U64}, imm_u64{value} {} | ||||
| @@ -69,6 +71,7 @@ bool Value::operator==(const Value& other) const { | ||||
|         return imm_u16 == other.imm_u16; | ||||
|     case Type::U32: | ||||
|     case Type::F32: | ||||
|     case Type::S32: | ||||
|         return imm_u32 == other.imm_u32; | ||||
|     case Type::U64: | ||||
|     case Type::F64: | ||||
|   | ||||
| @@ -44,6 +44,7 @@ public: | ||||
|     explicit Value(u8 value) noexcept; | ||||
|     explicit Value(u16 value) noexcept; | ||||
|     explicit Value(u32 value) noexcept; | ||||
|     explicit Value(s32 value) noexcept; | ||||
|     explicit Value(f32 value) noexcept; | ||||
|     explicit Value(u64 value) noexcept; | ||||
|     explicit Value(f64 value) noexcept; | ||||
| @@ -66,6 +67,7 @@ public: | ||||
|     [[nodiscard]] u8 U8() const; | ||||
|     [[nodiscard]] u16 U16() const; | ||||
|     [[nodiscard]] u32 U32() const; | ||||
|     [[nodiscard]] s32 S32() const; | ||||
|     [[nodiscard]] f32 F32() const; | ||||
|     [[nodiscard]] u64 U64() const; | ||||
|     [[nodiscard]] f64 F64() const; | ||||
| @@ -85,6 +87,7 @@ private: | ||||
|         u8 imm_u8; | ||||
|         u16 imm_u16; | ||||
|         u32 imm_u32; | ||||
|         s32 imm_s32; | ||||
|         f32 imm_f32; | ||||
|         u64 imm_u64; | ||||
|         f64 imm_f64; | ||||
| @@ -266,6 +269,7 @@ using U8 = TypedValue<Type::U8>; | ||||
| using U16 = TypedValue<Type::U16>; | ||||
| using U32 = TypedValue<Type::U32>; | ||||
| using U64 = TypedValue<Type::U64>; | ||||
| using S32 = TypedValue<Type::S32>; | ||||
| using F16 = TypedValue<Type::F16>; | ||||
| using F32 = TypedValue<Type::F32>; | ||||
| using F64 = TypedValue<Type::F64>; | ||||
| @@ -377,6 +381,14 @@ inline u32 Value::U32() const { | ||||
|     return imm_u32; | ||||
| } | ||||
|  | ||||
| inline s32 Value::S32() const { | ||||
|     if (IsIdentity()) { | ||||
|         return inst->Arg(0).S32(); | ||||
|     } | ||||
|     DEBUG_ASSERT(type == Type::S32); | ||||
|     return imm_s32; | ||||
| } | ||||
|  | ||||
| inline f32 Value::F32() const { | ||||
|     if (IsIdentity()) { | ||||
|         return inst->Arg(0).F32(); | ||||
|   | ||||
| @@ -7,6 +7,7 @@ | ||||
|  | ||||
| #include <boost/container/small_vector.hpp> | ||||
|  | ||||
| #include "common/settings.h" | ||||
| #include "shader_recompiler/environment.h" | ||||
| #include "shader_recompiler/frontend/ir/basic_block.h" | ||||
| #include "shader_recompiler/frontend/ir/breadth_first_search.h" | ||||
| @@ -363,6 +364,14 @@ TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) { | ||||
|     return env.ReadTextureType(lhs_raw | rhs_raw); | ||||
| } | ||||
|  | ||||
| TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAddr& cbuf) { | ||||
|     const u32 secondary_index{cbuf.has_secondary ? cbuf.secondary_index : cbuf.index}; | ||||
|     const u32 secondary_offset{cbuf.has_secondary ? cbuf.secondary_offset : cbuf.offset}; | ||||
|     const u32 lhs_raw{env.ReadCbufValue(cbuf.index, cbuf.offset)}; | ||||
|     const u32 rhs_raw{env.ReadCbufValue(secondary_index, secondary_offset)}; | ||||
|     return env.ReadTexturePixelFormat(lhs_raw | rhs_raw); | ||||
| } | ||||
|  | ||||
| class Descriptors { | ||||
| public: | ||||
|     explicit Descriptors(TextureBufferDescriptors& texture_buffer_descriptors_, | ||||
| @@ -451,6 +460,38 @@ void PatchImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) { | ||||
|                ir.FPMul(IR::F32(ir.CompositeExtract(coord, 1)), | ||||
|                         ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1)))))); | ||||
| } | ||||
|  | ||||
| void PathTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_format) { | ||||
|     const auto it{IR::Block::InstructionList::s_iterator_to(inst)}; | ||||
|     IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; | ||||
|     auto get_max_value = [pixel_format]() -> float { | ||||
|         switch (pixel_format) { | ||||
|         case TexturePixelFormat::A8B8G8R8_SNORM: | ||||
|         case TexturePixelFormat::R8G8_SNORM: | ||||
|         case TexturePixelFormat::R8_SNORM: | ||||
|             return 1.f / std::numeric_limits<char>::max(); | ||||
|         case TexturePixelFormat::R16G16B16A16_SNORM: | ||||
|         case TexturePixelFormat::R16G16_SNORM: | ||||
|         case TexturePixelFormat::R16_SNORM: | ||||
|             return 1.f / std::numeric_limits<short>::max(); | ||||
|         default: | ||||
|             throw InvalidArgument("Invalid texture pixel format"); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     const IR::Value new_inst{&*block.PrependNewInst(it, inst)}; | ||||
|     const IR::F32 x(ir.CompositeExtract(new_inst, 0)); | ||||
|     const IR::F32 y(ir.CompositeExtract(new_inst, 1)); | ||||
|     const IR::F32 z(ir.CompositeExtract(new_inst, 2)); | ||||
|     const IR::F32 w(ir.CompositeExtract(new_inst, 3)); | ||||
|     const IR::F16F32F64 max_value(ir.Imm32(get_max_value())); | ||||
|     const IR::Value converted = | ||||
|         ir.CompositeConstruct(ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(x)), max_value), | ||||
|                               ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(y)), max_value), | ||||
|                               ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(z)), max_value), | ||||
|                               ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(w)), max_value)); | ||||
|     inst.ReplaceUsesWith(converted); | ||||
| } | ||||
| } // Anonymous namespace | ||||
|  | ||||
| void TexturePass(Environment& env, IR::Program& program) { | ||||
| @@ -597,6 +638,14 @@ void TexturePass(Environment& env, IR::Program& program) { | ||||
|         } else { | ||||
|             inst->SetArg(0, IR::Value{}); | ||||
|         } | ||||
|  | ||||
|         if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL && | ||||
|             inst->GetOpcode() == IR::Opcode::ImageFetch && flags.type == TextureType::Buffer) { | ||||
|             const auto pixel_format = ReadTexturePixelFormat(env, cbuf); | ||||
|             if (pixel_format != TexturePixelFormat::OTHER) { | ||||
|                 PathTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -29,6 +29,16 @@ enum class TextureType : u32 { | ||||
| }; | ||||
| constexpr u32 NUM_TEXTURE_TYPES = 9; | ||||
|  | ||||
| enum class TexturePixelFormat : u32 { | ||||
|     A8B8G8R8_SNORM, | ||||
|     R8_SNORM, | ||||
|     R8G8_SNORM, | ||||
|     R16G16B16A16_SNORM, | ||||
|     R16G16_SNORM, | ||||
|     R16_SNORM, | ||||
|     OTHER | ||||
| }; | ||||
|  | ||||
| enum class ImageFormat : u32 { | ||||
|     Typeless, | ||||
|     R8_UINT, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user