[Mesa-dev] [PATCH 2/3] st/glsl_to_tgsi: emit CANON opcode when requested

Nicolai Hähnle nhaehnle at gmail.com
Mon Sep 18 09:44:30 UTC 2017


From: Nicolai Hähnle <nicolai.haehnle at amd.com>

We canonicalize floating point values before storing them anywhere where
the application could potentially examine the underlying bit pattern.

This includes GLSL bitcases, buffer stores (but not atomics, since they're
all operating on integer types) and imageStore and imageAtomicExchange,
which both have floating point variants.
---
 src/mesa/state_tracker/st_glsl_to_tgsi.cpp | 31 ++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
index 196b547d3d9..45f14b4e839 100644
--- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
+++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
@@ -183,20 +183,21 @@ public:
    int images_used;
    int image_targets[PIPE_MAX_SHADER_IMAGES];
    unsigned image_formats[PIPE_MAX_SHADER_IMAGES];
    bool indirect_addr_consts;
    int wpos_transform_const;
 
    int glsl_version;
    bool native_integers;
    bool have_sqrt;
    bool have_fma;
+   bool has_canon;
    bool use_shared_memory;
    bool has_tex_txf_lz;
    bool precise;
 
    variable_storage *find_variable_storage(ir_variable *var);
 
    int add_constant(gl_register_file file, gl_constant_value values[8],
                     int size, int datatype, uint16_t *swizzle_out);
 
    st_src_reg get_temp(const glsl_type *type);
@@ -1721,21 +1722,23 @@ glsl_to_tgsi_visitor::visit_expression(ir_expression* ir, st_src_reg *op)
       break;
    case ir_unop_f2u:
       if (native_integers)
          emit_asm(ir, TGSI_OPCODE_F2U, result_dst, op[0]);
       else
          emit_asm(ir, TGSI_OPCODE_TRUNC, result_dst, op[0]);
       break;
    case ir_unop_bitcast_f2i:
    case ir_unop_bitcast_f2u:
       /* Make sure we don't propagate the negate modifier to integer opcodes. */
-      if (op[0].negate || op[0].abs)
+      if (has_canon)
+         emit_asm(ir, TGSI_OPCODE_CANON, result_dst, op[0]);
+      else if (op[0].negate || op[0].abs)
          emit_asm(ir, TGSI_OPCODE_MOV, result_dst, op[0]);
       else
          result_src = op[0];
       result_src.type = ir->operation == ir_unop_bitcast_f2i ? GLSL_TYPE_INT :
                                                                GLSL_TYPE_UINT;
       break;
    case ir_unop_bitcast_i2f:
    case ir_unop_bitcast_u2f:
       result_src = op[0];
       result_src.type = GLSL_TYPE_FLOAT;
@@ -3263,27 +3266,35 @@ glsl_to_tgsi_visitor::visit_ssbo_intrinsic(ir_call *ir)
 
    if (ir->callee->intrinsic_id == ir_intrinsic_ssbo_load) {
       inst = emit_asm(ir, TGSI_OPCODE_LOAD, dst, off);
       if (dst.type == GLSL_TYPE_BOOL)
          emit_asm(ir, TGSI_OPCODE_USNE, dst, st_src_reg(dst), st_src_reg_for_int(0));
    } else if (ir->callee->intrinsic_id == ir_intrinsic_ssbo_store) {
       param = param->get_next();
       ir_rvalue *val = ((ir_instruction *)param)->as_rvalue();
       val->accept(this);
 
+      st_src_reg data = this->result;
+
+      if (has_canon && data.type == GLSL_TYPE_FLOAT) {
+         st_src_reg tmp = get_temp(glsl_type::vec4_type);
+         emit_asm(ir, TGSI_OPCODE_CANON, st_dst_reg(tmp), data);
+         data = tmp;
+      }
+
       param = param->get_next();
       ir_constant *write_mask = ((ir_instruction *)param)->as_constant();
       assert(write_mask);
       dst.writemask = write_mask->value.u[0];
 
       dst.type = this->result.type;
-      inst = emit_asm(ir, TGSI_OPCODE_STORE, dst, off, this->result);
+      inst = emit_asm(ir, TGSI_OPCODE_STORE, dst, off, data);
    } else {
       param = param->get_next();
       ir_rvalue *val = ((ir_instruction *)param)->as_rvalue();
       val->accept(this);
 
       st_src_reg data = this->result, data2 = undef_src;
       unsigned opcode;
       switch (ir->callee->intrinsic_id) {
       case ir_intrinsic_ssbo_atomic_add:
          opcode = TGSI_OPCODE_ATOMUADD;
@@ -3595,20 +3606,34 @@ glsl_to_tgsi_visitor::visit_image_intrinsic(ir_call *ir)
          coord_dst.writemask = WRITEMASK_W;
          emit_asm(ir, TGSI_OPCODE_MOV, coord_dst, sample);
          coord.swizzle |= SWIZZLE_W << 9;
       }
 
       param = param->get_next();
       if (!param->is_tail_sentinel()) {
          ((ir_dereference *)param)->accept(this);
          arg1 = this->result;
          param = param->get_next();
+
+         /* imageStore and imageAtomicExchange have float variants. The stored
+          * bit representation can be observed by the application if the format
+          * of the image might be a 32-bit float format.
+          */
+         if (has_canon && arg1.type == GLSL_TYPE_FLOAT &&
+             (image_format == 0 ||
+              image_format == GL_R32F ||
+              image_format == GL_RG32F ||
+              image_format == GL_RGBA32F)) {
+            st_src_reg tmp = get_temp(glsl_type::vec4_type);
+            emit_asm(ir, TGSI_OPCODE_CANON, st_dst_reg(tmp), arg1);
+            arg1 = tmp;
+         }
       }
 
       if (!param->is_tail_sentinel()) {
          ((ir_dereference *)param)->accept(this);
          arg2 = this->result;
          param = param->get_next();
       }
 
       assert(param->is_tail_sentinel());
 
@@ -6471,20 +6496,22 @@ get_mesa_program_tgsi(struct gl_context *ctx,
    v->shader_program = shader_program;
    v->shader = shader;
    v->options = options;
    v->glsl_version = ctx->Const.GLSLVersion;
    v->native_integers = ctx->Const.NativeIntegers;
 
    v->have_sqrt = pscreen->get_shader_param(pscreen, ptarget,
                                             PIPE_SHADER_CAP_TGSI_SQRT_SUPPORTED);
    v->have_fma = pscreen->get_shader_param(pscreen, ptarget,
                                            PIPE_SHADER_CAP_TGSI_FMA_SUPPORTED);
+   v->has_canon = pscreen->get_shader_param(pscreen, ptarget,
+                                            PIPE_SHADER_CAP_TGSI_CANON);
    v->has_tex_txf_lz = pscreen->get_param(pscreen,
                                           PIPE_CAP_TGSI_TEX_TXF_LZ);
 
    v->variables = _mesa_hash_table_create(v->mem_ctx, _mesa_hash_pointer,
                                           _mesa_key_pointer_equal);
    skip_merge_registers =
       pscreen->get_shader_param(pscreen, ptarget,
                                 PIPE_SHADER_CAP_TGSI_SKIP_MERGE_REGISTERS);
 
    _mesa_generate_parameters_list_for_uniforms(ctx, shader_program, shader,
-- 
2.11.0



More information about the mesa-dev mailing list