summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-05-18 19:43:52 -0300
committerGravatar ameerj2021-07-22 21:51:32 -0400
commit3d3ed53511dcd338806a97bfff2afa1644ddb424 (patch)
treee92bb7bb829f41818909d20c5540b7f017f97739 /src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
parentglasm: Implement gl_FragDepth and gl_SampleMask stores (diff)
downloadyuzu-3d3ed53511dcd338806a97bfff2afa1644ddb424.tar.gz
yuzu-3d3ed53511dcd338806a97bfff2afa1644ddb424.tar.xz
yuzu-3d3ed53511dcd338806a97bfff2afa1644ddb424.zip
glasm: Implement textureGather instructions
Diffstat (limited to 'src/shader_recompiler/backend/glasm/emit_glasm_image.cpp')
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_image.cpp103
1 files changed, 92 insertions, 11 deletions
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
index 77da3400b..9da4da331 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <utility>
6
5#include "shader_recompiler/backend/glasm/emit_context.h" 7#include "shader_recompiler/backend/glasm/emit_context.h"
6#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h" 8#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
7#include "shader_recompiler/frontend/ir/modifiers.h" 9#include "shader_recompiler/frontend/ir/modifiers.h"
@@ -95,6 +97,33 @@ std::string Offset(EmitContext& ctx, const IR::Value& offset) {
95 return fmt::format(",offset({})", Register{ctx.reg_alloc.Consume(offset)}); 97 return fmt::format(",offset({})", Register{ctx.reg_alloc.Consume(offset)});
96} 98}
97 99
100std::pair<ScopedRegister, ScopedRegister> AllocOffsetsRegs(EmitContext& ctx,
101 const IR::Value& offset2) {
102 if (offset2.IsEmpty()) {
103 return {};
104 } else {
105 return {ctx.reg_alloc, ctx.reg_alloc};
106 }
107}
108
109void SwizzleOffsets(EmitContext& ctx, Register off_x, Register off_y, const IR::Value& offset1,
110 const IR::Value& offset2) {
111 const Register offsets_a{ctx.reg_alloc.Consume(offset1)};
112 const Register offsets_b{ctx.reg_alloc.Consume(offset2)};
113 // Input swizzle: [XYXY] [XYXY]
114 // Output swizzle: [XXXX] [YYYY]
115 ctx.Add("MOV {}.x,{}.x;"
116 "MOV {}.y,{}.z;"
117 "MOV {}.z,{}.x;"
118 "MOV {}.w,{}.z;"
119 "MOV {}.x,{}.y;"
120 "MOV {}.y,{}.w;"
121 "MOV {}.z,{}.y;"
122 "MOV {}.w,{}.w;",
123 off_x, offsets_a, off_x, offsets_a, off_x, offsets_b, off_x, offsets_b, off_y,
124 offsets_a, off_y, offsets_a, off_y, offsets_b, off_y, offsets_b);
125}
126
98std::pair<std::string, ScopedRegister> Coord(EmitContext& ctx, const IR::Value& coord) { 127std::pair<std::string, ScopedRegister> Coord(EmitContext& ctx, const IR::Value& coord) {
99 if (coord.IsImmediate()) { 128 if (coord.IsImmediate()) {
100 ScopedRegister scoped_reg(ctx.reg_alloc); 129 ScopedRegister scoped_reg(ctx.reg_alloc);
@@ -326,19 +355,71 @@ void EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst& inst, const IR::
326 StoreSparse(ctx, sparse_inst); 355 StoreSparse(ctx, sparse_inst);
327} 356}
328 357
329void EmitImageGather([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst, 358void EmitImageGather(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
330 [[maybe_unused]] const IR::Value& index, [[maybe_unused]] Register coord, 359 const IR::Value& coord, const IR::Value& offset, const IR::Value& offset2) {
331 [[maybe_unused]] const IR::Value& offset, 360 // Allocate offsets early so they don't overwrite any consumed register
332 [[maybe_unused]] const IR::Value& offset2) { 361 const auto [off_x, off_y]{AllocOffsetsRegs(ctx, offset2)};
333 throw NotImplementedException("GLASM instruction"); 362 const auto info{inst.Flags<IR::TextureInstInfo>()};
363 const char comp{"xyzw"[info.gather_component]};
364 const auto sparse_inst{inst.GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp)};
365 const std::string_view sparse_mod{sparse_inst ? ".SPARSE" : ""};
366 const std::string_view type{TextureType(info)};
367 const std::string texture{Texture(ctx, info, index)};
368 const Register coord_vec{ctx.reg_alloc.Consume(coord)};
369 const Register ret{ctx.reg_alloc.Define(inst)};
370 if (offset2.IsEmpty()) {
371 const std::string offset_vec{Offset(ctx, offset)};
372 ctx.Add("TXG.F{} {},{},{}.{},{}{};", sparse_mod, ret, coord_vec, texture, comp, type,
373 offset_vec);
374 } else {
375 SwizzleOffsets(ctx, off_x.reg, off_y.reg, offset, offset2);
376 ctx.Add("TXGO.F{} {},{},{},{},{}.{},{};", sparse_mod, ret, coord_vec, off_x.reg, off_y.reg,
377 texture, comp, type);
378 }
379 StoreSparse(ctx, sparse_inst);
334} 380}
335 381
336void EmitImageGatherDref([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst, 382void EmitImageGatherDref(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
337 [[maybe_unused]] const IR::Value& index, [[maybe_unused]] Register coord, 383 const IR::Value& coord, const IR::Value& offset, const IR::Value& offset2,
338 [[maybe_unused]] const IR::Value& offset, 384 const IR::Value& dref) {
339 [[maybe_unused]] const IR::Value& offset2, 385 // FIXME: This instruction is not working as expected
340 [[maybe_unused]] Register dref) { 386
341 throw NotImplementedException("GLASM instruction"); 387 // Allocate offsets early so they don't overwrite any consumed register
388 const auto [off_x, off_y]{AllocOffsetsRegs(ctx, offset2)};
389 const auto info{inst.Flags<IR::TextureInstInfo>()};
390 const auto sparse_inst{inst.GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp)};
391 const std::string_view sparse_mod{sparse_inst ? ".SPARSE" : ""};
392 const std::string_view type{ShadowTextureType(info)};
393 const std::string texture{Texture(ctx, info, index)};
394 const Register coord_vec{ctx.reg_alloc.Consume(coord)};
395 const ScalarF32 dref_value{ctx.reg_alloc.Consume(dref)};
396 const Register ret{ctx.reg_alloc.Define(inst)};
397 std::string args;
398 switch (info.type) {
399 case TextureType::Color2D:
400 ctx.Add("MOV.F {}.z,{};", coord_vec, dref_value);
401 args = fmt::to_string(coord_vec);
402 break;
403 case TextureType::ColorArray2D:
404 case TextureType::ColorCube:
405 ctx.Add("MOV.F {}.w,{};", coord_vec, dref_value);
406 args = fmt::to_string(coord_vec);
407 break;
408 case TextureType::ColorArrayCube:
409 args = fmt::format("{},{}", coord_vec, dref_value);
410 break;
411 default:
412 throw NotImplementedException("Invalid type {}", info.type.Value());
413 }
414 if (offset2.IsEmpty()) {
415 const std::string offset_vec{Offset(ctx, offset)};
416 ctx.Add("TXG.F{} {},{},{},{}{};", sparse_mod, ret, args, texture, type, offset_vec);
417 } else {
418 SwizzleOffsets(ctx, off_x.reg, off_y.reg, offset, offset2);
419 ctx.Add("TXGO.F{} {},{},{},{},{},{};", sparse_mod, ret, args, off_x.reg, off_y.reg, texture,
420 type);
421 }
422 StoreSparse(ctx, sparse_inst);
342} 423}
343 424
344void EmitImageFetch([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst, 425void EmitImageFetch([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,