diff options
Diffstat (limited to 'src/shader_recompiler/backend')
5 files changed, 67 insertions, 14 deletions
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp index 85ee27333..d0e308124 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp @@ -558,12 +558,15 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, const IR::Value& coord, const IR::Value& derivatives, const IR::Value& offset, const IR::Value& lod_clamp) { const auto info{inst.Flags<IR::TextureInstInfo>()}; - ScopedRegister dpdx, dpdy; + ScopedRegister dpdx, dpdy, coords; const bool multi_component{info.num_derivates > 1 || info.has_lod_clamp}; if (multi_component) { // Allocate this early to avoid aliasing other registers dpdx = ScopedRegister{ctx.reg_alloc}; dpdy = ScopedRegister{ctx.reg_alloc}; + if (info.num_derivates >= 3) { + coords = ScopedRegister{ctx.reg_alloc}; + } } const auto sparse_inst{PrepareSparse(inst)}; const std::string_view sparse_mod{sparse_inst ? ".SPARSE" : ""}; @@ -580,15 +583,27 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, "MOV.F {}.y,{}.w;", dpdx.reg, derivatives_vec, dpdx.reg, derivatives_vec, dpdy.reg, derivatives_vec, dpdy.reg, derivatives_vec); + Register final_coord; + if (info.num_derivates >= 3) { + ctx.Add("MOV.F {}.z,{}.x;" + "MOV.F {}.z,{}.y;", + dpdx.reg, coord_vec, dpdy.reg, coord_vec); + ctx.Add("MOV.F {}.x,0;" + "MOV.F {}.y,0;", + "MOV.F {}.z,0;", coords.reg, coords.reg, coords.reg); + final_coord = coords.reg; + } else { + final_coord = coord_vec; + } if (info.has_lod_clamp) { const ScalarF32 lod_clamp_value{ctx.reg_alloc.Consume(lod_clamp)}; ctx.Add("MOV.F {}.w,{};" "TXD.F.LODCLAMP{} {},{},{},{},{},{}{};", - dpdy.reg, lod_clamp_value, sparse_mod, ret, coord_vec, dpdx.reg, dpdy.reg, + dpdy.reg, lod_clamp_value, sparse_mod, ret, final_coord, dpdx.reg, dpdy.reg, texture, type, offset_vec); } else { - ctx.Add("TXD.F{} {},{},{},{},{},{}{};", sparse_mod, ret, coord_vec, dpdx.reg, dpdy.reg, - texture, type, offset_vec); + ctx.Add("TXD.F{} {},{},{},{},{},{}{};", sparse_mod, ret, final_coord, dpdx.reg, + dpdy.reg, texture, type, offset_vec); } } else { ctx.Add("TXD.F{} {},{},{}.x,{}.y,{},{}{};", sparse_mod, ret, coord_vec, derivatives_vec, diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp index 418505475..d9872ecc2 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp @@ -548,7 +548,7 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, if (sparse_inst) { throw NotImplementedException("EmitImageGradient Sparse"); } - if (!offset.IsEmpty()) { + if (!offset.IsEmpty() && info.num_derivates <= 2) { throw NotImplementedException("EmitImageGradient offset"); } const auto texture{Texture(ctx, info, index)}; @@ -556,6 +556,12 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, const bool multi_component{info.num_derivates > 1 || info.has_lod_clamp}; const auto derivatives_vec{ctx.var_alloc.Consume(derivatives)}; if (multi_component) { + if (info.num_derivates >= 3) { + const auto offset_vec{ctx.var_alloc.Consume(offset)}; + ctx.Add("{}=textureGrad({},{},vec3({}.xz, {}.x),vec3({}.yw, {}.y));", texel, texture, + coords, derivatives_vec, offset_vec, derivatives_vec, offset_vec); + return; + } ctx.Add("{}=textureGrad({},{},vec2({}.xz),vec2({}.yz));", texel, texture, coords, derivatives_vec, derivatives_vec); } else { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp index 7d901c04b..8decdf399 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp @@ -91,6 +91,34 @@ public: } } + explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivates_1, Id derivates_2, + Id offset, Id lod_clamp) { + if (!Sirit::ValidId(derivates_1) || !Sirit::ValidId(derivates_2)) { + throw LogicError("Derivates must be present"); + } + boost::container::static_vector<Id, 3> deriv_1_accum{ + ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 0), + ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 2), + ctx.OpCompositeExtract(ctx.F32[1], derivates_2, 0), + }; + boost::container::static_vector<Id, 3> deriv_2_accum{ + ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 1), + ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 3), + ctx.OpCompositeExtract(ctx.F32[1], derivates_2, 1), + }; + const Id derivates_id1{ctx.OpCompositeConstruct( + ctx.F32[3], std::span{deriv_1_accum.data(), deriv_1_accum.size()})}; + const Id derivates_id2{ctx.OpCompositeConstruct( + ctx.F32[3], std::span{deriv_2_accum.data(), deriv_2_accum.size()})}; + Add(spv::ImageOperandsMask::Grad, derivates_id1, derivates_id2); + if (Sirit::ValidId(offset)) { + Add(spv::ImageOperandsMask::Offset, offset); + } + if (has_lod_clamp) { + Add(spv::ImageOperandsMask::MinLod, lod_clamp); + } + } + std::span<const Id> Span() const noexcept { return std::span{operands.data(), operands.size()}; } @@ -176,9 +204,7 @@ Id TextureImage(EmitContext& ctx, IR::TextureInstInfo info, const IR::Value& ind if (def.count > 1) { throw NotImplementedException("Indirect texture sample"); } - const Id sampler_id{def.id}; - const Id id{ctx.OpLoad(ctx.sampled_texture_buffer_type, sampler_id)}; - return ctx.OpImage(ctx.image_buffer_type, id); + return ctx.OpLoad(ctx.image_buffer_type, def.id); } else { const TextureDefinition& def{ctx.textures.at(info.descriptor_index)}; if (def.count > 1) { @@ -524,8 +550,11 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id derivates, Id offset, Id lod_clamp) { const auto info{inst->Flags<IR::TextureInstInfo>()}; - const ImageOperands operands(ctx, info.has_lod_clamp != 0, derivates, info.num_derivates, - offset, lod_clamp); + const auto operands = + info.num_derivates == 3 + ? ImageOperands(ctx, info.has_lod_clamp != 0, derivates, offset, {}, lod_clamp) + : ImageOperands(ctx, info.has_lod_clamp != 0, derivates, info.num_derivates, offset, + lod_clamp); return Emit(&EmitContext::OpImageSparseSampleExplicitLod, &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], Texture(ctx, info, index), coords, operands.Mask(), operands.Span()); diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index bec5db173..72f69b7aa 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -74,6 +74,11 @@ spv::ImageFormat GetImageFormat(ImageFormat format) { throw InvalidArgument("Invalid image format {}", format); } +spv::ImageFormat GetImageFormatForBuffer(ImageFormat format) { + const auto spv_format = GetImageFormat(format); + return spv_format == spv::ImageFormat::Unknown ? spv::ImageFormat::R32ui : spv_format; +} + Id ImageType(EmitContext& ctx, const ImageDescriptor& desc) { const spv::ImageFormat format{GetImageFormat(desc.format)}; const Id type{ctx.U32[1]}; @@ -1242,9 +1247,8 @@ void EmitContext::DefineTextureBuffers(const Info& info, u32& binding) { } const spv::ImageFormat format{spv::ImageFormat::Unknown}; image_buffer_type = TypeImage(F32[1], spv::Dim::Buffer, 0U, false, false, 1, format); - sampled_texture_buffer_type = TypeSampledImage(image_buffer_type); - const Id type{TypePointer(spv::StorageClass::UniformConstant, sampled_texture_buffer_type)}; + const Id type{TypePointer(spv::StorageClass::UniformConstant, image_buffer_type)}; texture_buffers.reserve(info.texture_buffer_descriptors.size()); for (const TextureBufferDescriptor& desc : info.texture_buffer_descriptors) { if (desc.count != 1) { @@ -1271,7 +1275,7 @@ void EmitContext::DefineImageBuffers(const Info& info, u32& binding) { if (desc.count != 1) { throw NotImplementedException("Array of image buffers"); } - const spv::ImageFormat format{GetImageFormat(desc.format)}; + const spv::ImageFormat format{GetImageFormatForBuffer(desc.format)}; const Id image_type{TypeImage(U32[1], spv::Dim::Buffer, false, false, false, 2, format)}; const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index e63330f11..7c49fd504 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h @@ -206,7 +206,6 @@ public: Id output_u32{}; Id image_buffer_type{}; - Id sampled_texture_buffer_type{}; Id image_u32{}; std::array<UniformDefinitions, Info::MAX_CBUFS> cbufs{}; |