Home | History | Annotate | Line # | Download | only in state_tracker
      1 /*
      2  * Copyright  2018 Collabora Ltd
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     21  * SOFTWARE.
     22  */
     23 
     24 #include "st_tgsi_lower_depth_clamp.h"
     25 #include "tgsi/tgsi_transform.h"
     26 #include "tgsi/tgsi_scan.h"
     27 
     28 struct tgsi_depth_clamp_transform {
     29    struct tgsi_transform_context base;
     30 
     31    struct tgsi_shader_info info;
     32 
     33    int depth_range_const;
     34    int next_generic;
     35    int imm;
     36    int depth_var;
     37    int pos_input;
     38    int pos_output;
     39    int pos_input_temp;
     40    int pos_output_temp;
     41    int depth_range_corrected;
     42    bool depth_clip_minus_one_to_one;
     43 };
     44 
     45 static inline struct tgsi_depth_clamp_transform *
     46 tgsi_depth_clamp_transform(struct tgsi_transform_context *tctx)
     47 {
     48    return (struct tgsi_depth_clamp_transform *)tctx;
     49 }
     50 
     51 static void
     52 transform_decl(struct tgsi_transform_context *tctx,
     53                struct tgsi_full_declaration *decl)
     54 {
     55    struct tgsi_depth_clamp_transform *ctx = tgsi_depth_clamp_transform(tctx);
     56 
     57    /* find the next generic index usable for our inserted varying */
     58    if (ctx->info.processor == PIPE_SHADER_FRAGMENT) {
     59       if (decl->Declaration.File == TGSI_FILE_INPUT &&
     60           decl->Semantic.Name == TGSI_SEMANTIC_GENERIC)
     61          ctx->next_generic = MAX2(ctx->next_generic, decl->Semantic.Index + 1);
     62    } else {
     63       if (decl->Declaration.File == TGSI_FILE_OUTPUT &&
     64           decl->Semantic.Name == TGSI_SEMANTIC_GENERIC)
     65          ctx->next_generic = MAX2(ctx->next_generic, decl->Semantic.Index + 1);
     66    }
     67 
     68    if (decl->Declaration.File == TGSI_FILE_OUTPUT &&
     69        decl->Semantic.Name == TGSI_SEMANTIC_POSITION) {
     70       assert(decl->Semantic.Index == 0);
     71       ctx->pos_output = decl->Range.First;
     72    } else if (decl->Declaration.File == TGSI_FILE_INPUT &&
     73               decl->Semantic.Name == TGSI_SEMANTIC_POSITION) {
     74       assert(decl->Semantic.Index == 0);
     75       if (ctx->info.processor == PIPE_SHADER_FRAGMENT)
     76          ctx->pos_input = decl->Range.First;
     77    }
     78 
     79    tctx->emit_declaration(tctx, decl);
     80 }
     81 
     82 static void
     83 prolog_common(struct tgsi_depth_clamp_transform *ctx)
     84 {
     85    assert(ctx->depth_range_const >= 0);
     86    if (ctx->info.const_file_max[0] < ctx->depth_range_const)
     87       tgsi_transform_const_decl(&ctx->base, ctx->depth_range_const,
     88                                 ctx->depth_range_const);
     89 
     90    /* declare a temp for the position-output */
     91    ctx->pos_output_temp = ctx->info.file_max[TGSI_FILE_TEMPORARY] + 1;
     92    tgsi_transform_temp_decl(&ctx->base, ctx->pos_output_temp);
     93 }
     94 
     95 static void
     96 prolog_last_vertex_stage(struct tgsi_transform_context *tctx)
     97 {
     98    struct tgsi_depth_clamp_transform *ctx = tgsi_depth_clamp_transform(tctx);
     99 
    100    prolog_common(ctx);
    101 
    102    ctx->imm = ctx->info.immediate_count;
    103    tgsi_transform_immediate_decl(tctx, 0.5, 0.0, 0.0, 0.0);
    104 
    105    /* declare the output */
    106    ctx->depth_var = ctx->info.num_outputs;
    107    tgsi_transform_output_decl(tctx, ctx->depth_var,
    108                               TGSI_SEMANTIC_GENERIC,
    109                               ctx->next_generic,
    110                               TGSI_INTERPOLATE_LINEAR);
    111 }
    112 
    113 static void
    114 epilog_last_vertex_stage(struct tgsi_transform_context *tctx)
    115 {
    116    struct tgsi_depth_clamp_transform *ctx = tgsi_depth_clamp_transform(tctx);
    117 
    118    int mad_dst_file = TGSI_FILE_TEMPORARY;
    119    int mad_dst_index = ctx->pos_output_temp;
    120 
    121    if (!ctx->depth_clip_minus_one_to_one) {
    122       mad_dst_file = TGSI_FILE_OUTPUT;
    123       mad_dst_index = ctx->depth_var;
    124    }
    125 
    126    /* move from temp-register to output */
    127    tgsi_transform_op1_inst(tctx, TGSI_OPCODE_MOV,
    128                            TGSI_FILE_OUTPUT, ctx->pos_output,
    129                            TGSI_WRITEMASK_XYZW,
    130                            TGSI_FILE_TEMPORARY, ctx->pos_output_temp);
    131 
    132    /* Set gl_position.z to 0.0 to avoid clipping */
    133    tgsi_transform_op1_swz_inst(tctx, TGSI_OPCODE_MOV,
    134                                TGSI_FILE_OUTPUT, ctx->pos_output,
    135                                TGSI_WRITEMASK_Z,
    136                                TGSI_FILE_IMMEDIATE, ctx->imm,
    137                                TGSI_SWIZZLE_Y);
    138 
    139    /* Evaluate and pass true depth value in depthRange terms */
    140    /* z = gl_Position.z / gl_Position.w */
    141 
    142    struct tgsi_full_instruction inst;
    143 
    144    inst = tgsi_default_full_instruction();
    145    inst.Instruction.Opcode = TGSI_OPCODE_DIV;
    146    inst.Instruction.NumDstRegs = 1;
    147    inst.Dst[0].Register.File = TGSI_FILE_TEMPORARY;
    148    inst.Dst[0].Register.Index = ctx->pos_output_temp;
    149    inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_X;
    150    inst.Instruction.NumSrcRegs = 2;
    151    tgsi_transform_src_reg_xyzw(&inst.Src[0], TGSI_FILE_TEMPORARY, ctx->pos_output_temp);
    152    tgsi_transform_src_reg_xyzw(&inst.Src[1], TGSI_FILE_TEMPORARY, ctx->pos_output_temp);
    153    inst.Src[0].Register.SwizzleX =
    154          inst.Src[0].Register.SwizzleY =
    155          inst.Src[0].Register.SwizzleZ =
    156          inst.Src[0].Register.SwizzleW = TGSI_SWIZZLE_Z;
    157 
    158    inst.Src[1].Register.SwizzleX =
    159          inst.Src[1].Register.SwizzleY =
    160          inst.Src[1].Register.SwizzleZ =
    161          inst.Src[1].Register.SwizzleW = TGSI_SWIZZLE_W;
    162 
    163    tctx->emit_instruction(tctx, &inst);
    164 
    165 
    166    /* OpenGL Core Profile 4.5 - 13.6.1
    167     * The vertex's windows z coordinate zw is given by zw = s * z + b.
    168     *
    169     * *  With clip control depth mode ZERO_TO_ONE
    170     *      s = f - n, b = n, and hence
    171     *
    172     *     zw_0_1 = z * gl_DepthRange.diff + gl_DepthRange.near
    173     */
    174    tgsi_transform_op3_swz_inst(tctx, TGSI_OPCODE_MAD,
    175                                mad_dst_file, mad_dst_index,
    176                                TGSI_WRITEMASK_X,
    177                                TGSI_FILE_TEMPORARY, ctx->pos_output_temp,
    178                                TGSI_SWIZZLE_X,
    179                                false,
    180                                TGSI_FILE_CONSTANT, ctx->depth_range_const,
    181                                TGSI_SWIZZLE_Z,
    182                                TGSI_FILE_CONSTANT, ctx->depth_range_const,
    183                                TGSI_SWIZZLE_X);
    184 
    185    /* If clip control depth mode is NEGATIVE_ONE_TO_ONE, then
    186    *     s = 0.5 * (f - n), b = 0.5 * (n + f), and hence
    187    *
    188    *     zw_m1_1 = 0.5 * (zw_01 + gl_DepthRange.far)
    189    */
    190    if (ctx->depth_clip_minus_one_to_one) {
    191        /* z += gl_DepthRange.far */
    192       tgsi_transform_op2_swz_inst(tctx, TGSI_OPCODE_ADD,
    193                                   TGSI_FILE_TEMPORARY, ctx->pos_output_temp,
    194                                   TGSI_WRITEMASK_X,
    195                                   TGSI_FILE_TEMPORARY, ctx->pos_output_temp,
    196                                   TGSI_SWIZZLE_X,
    197                                   TGSI_FILE_CONSTANT, ctx->depth_range_const,
    198                                   TGSI_SWIZZLE_Y, false);
    199       /* z *=  0.5 */
    200       tgsi_transform_op2_swz_inst(tctx, TGSI_OPCODE_MUL,
    201                                   TGSI_FILE_OUTPUT, ctx->depth_var,
    202                                   TGSI_WRITEMASK_X,
    203                                   TGSI_FILE_TEMPORARY, ctx->pos_output_temp,
    204                                   TGSI_SWIZZLE_X,
    205                                   TGSI_FILE_IMMEDIATE, ctx->imm,
    206                                   TGSI_SWIZZLE_X, false);
    207    }
    208 }
    209 
    210 
    211 static void
    212 prolog_fs(struct tgsi_transform_context *tctx)
    213 {
    214    struct tgsi_depth_clamp_transform *ctx = tgsi_depth_clamp_transform(tctx);
    215 
    216    prolog_common(ctx);
    217 
    218    ctx->depth_range_corrected = ctx->info.file_max[TGSI_FILE_TEMPORARY] + 2;
    219    tgsi_transform_temp_decl(tctx, ctx->depth_range_corrected);
    220 
    221    /* declare the input */
    222    ctx->depth_var = ctx->info.num_inputs;
    223    tgsi_transform_input_decl(tctx, ctx->depth_var,
    224                              TGSI_SEMANTIC_GENERIC,
    225                              ctx->next_generic,
    226                              TGSI_INTERPOLATE_LINEAR);
    227 
    228    /* declare the output */
    229    if (ctx->pos_output < 0) {
    230       ctx->pos_output = ctx->info.num_outputs;
    231       tgsi_transform_output_decl(tctx, ctx->pos_output,
    232                                  TGSI_SEMANTIC_POSITION,
    233                                  0,
    234                                  TGSI_INTERPOLATE_LINEAR);
    235    }
    236 
    237    if (ctx->info.reads_z) {
    238       ctx->pos_input_temp = ctx->info.file_max[TGSI_FILE_TEMPORARY] + 3;
    239       tgsi_transform_temp_decl(tctx, ctx->pos_input_temp);
    240 
    241       assert(ctx->pos_input_temp >= 0);
    242       /* copy normal position */
    243       tgsi_transform_op1_inst(tctx, TGSI_OPCODE_MOV,
    244                               TGSI_FILE_TEMPORARY, ctx->pos_input_temp,
    245                               TGSI_WRITEMASK_XYZW,
    246                               TGSI_FILE_INPUT, ctx->pos_input);
    247       /* replace z-component with varying */
    248       tgsi_transform_op1_swz_inst(tctx, TGSI_OPCODE_MOV,
    249                                   TGSI_FILE_TEMPORARY, ctx->pos_input_temp,
    250                                   TGSI_WRITEMASK_Z,
    251                                   TGSI_FILE_INPUT, ctx->depth_var,
    252                                   TGSI_SWIZZLE_X);
    253    }
    254 }
    255 
    256 static void
    257 epilog_fs(struct tgsi_transform_context *tctx)
    258 {
    259    struct tgsi_depth_clamp_transform *ctx = tgsi_depth_clamp_transform(tctx);
    260 
    261    unsigned src0_file = TGSI_FILE_INPUT;
    262    unsigned src0_index = ctx->depth_var;
    263    unsigned src0_swizzle = TGSI_SWIZZLE_X;
    264 
    265    if (ctx->info.writes_z) {
    266       src0_file = TGSI_FILE_TEMPORARY;
    267       src0_index = ctx->pos_output_temp;
    268       src0_swizzle = TGSI_SWIZZLE_Z;
    269    }
    270 
    271    /* it is possible to have gl_DepthRange.near > gl_DepthRange.far, so first
    272     * we have to sort the two */
    273    tgsi_transform_op2_swz_inst(tctx, TGSI_OPCODE_MIN,
    274                                TGSI_FILE_TEMPORARY, ctx->depth_range_corrected,
    275                                TGSI_WRITEMASK_X,
    276                                TGSI_FILE_CONSTANT, ctx->depth_range_const,
    277                                TGSI_SWIZZLE_X,
    278                                TGSI_FILE_CONSTANT, ctx->depth_range_const,
    279                                TGSI_SWIZZLE_Y,
    280                                false);
    281 
    282    tgsi_transform_op2_swz_inst(tctx, TGSI_OPCODE_MAX,
    283                                TGSI_FILE_TEMPORARY, ctx->depth_range_corrected,
    284                                TGSI_WRITEMASK_Y,
    285                                TGSI_FILE_CONSTANT, ctx->depth_range_const,
    286                                TGSI_SWIZZLE_X,
    287                                TGSI_FILE_CONSTANT, ctx->depth_range_const,
    288                                TGSI_SWIZZLE_Y,
    289                                false);
    290 
    291    /* gl_FragDepth = max(gl_FragDepth, min(gl_DepthRange.near, gl_DepthRange.far)) */
    292    tgsi_transform_op2_swz_inst(tctx, TGSI_OPCODE_MAX,
    293                                TGSI_FILE_TEMPORARY, ctx->pos_output_temp,
    294                                TGSI_WRITEMASK_X,
    295                                src0_file, src0_index, src0_swizzle,
    296                                TGSI_FILE_TEMPORARY, ctx->depth_range_corrected,
    297                                TGSI_SWIZZLE_X, false);
    298 
    299    /* gl_FragDepth = min(gl_FragDepth, max(gl_DepthRange.near, gl_DepthRange.far)) */
    300    tgsi_transform_op2_swz_inst(tctx, TGSI_OPCODE_MIN,
    301                                TGSI_FILE_OUTPUT, ctx->pos_output,
    302                                TGSI_WRITEMASK_Z,
    303                                TGSI_FILE_TEMPORARY, ctx->pos_output_temp,
    304                                TGSI_SWIZZLE_X,
    305                                TGSI_FILE_TEMPORARY, ctx->depth_range_corrected,
    306                                TGSI_SWIZZLE_Y, false);
    307 }
    308 
    309 static void
    310 transform_instr(struct tgsi_transform_context *tctx,
    311                 struct tgsi_full_instruction *inst)
    312 {
    313    struct tgsi_depth_clamp_transform *ctx = tgsi_depth_clamp_transform(tctx);
    314 
    315    if (ctx->pos_output >= 0) {
    316       /* replace writes to gl_Position / gl_FragDepth with a temp-variable
    317        */
    318       for (int i = 0; i < inst->Instruction.NumDstRegs; ++i) {
    319          if (inst->Dst[i].Register.File == TGSI_FILE_OUTPUT &&
    320              inst->Dst[i].Register.Index == ctx->pos_output) {
    321             inst->Dst[i].Register.File = TGSI_FILE_TEMPORARY;
    322             inst->Dst[i].Register.Index = ctx->pos_output_temp;
    323          }
    324       }
    325    }
    326 
    327    if (ctx->info.reads_z) {
    328       /* replace reads from gl_FragCoord with temp-variable
    329        */
    330       assert(ctx->pos_input_temp >= 0);
    331       for (int i = 0; i < inst->Instruction.NumSrcRegs; ++i) {
    332          if (inst->Src[i].Register.File == TGSI_FILE_INPUT &&
    333              inst->Src[i].Register.Index == ctx->pos_input) {
    334             inst->Src[i].Register.File = TGSI_FILE_TEMPORARY;
    335             inst->Src[i].Register.Index = ctx->pos_input_temp;
    336          }
    337       }
    338    }
    339 
    340    /* In a GS each we have to add the z-write opilog for each emit
    341     */
    342    if (ctx->info.processor == PIPE_SHADER_GEOMETRY &&
    343        inst->Instruction.Opcode == TGSI_OPCODE_EMIT)
    344       epilog_last_vertex_stage(tctx);
    345 
    346    tctx->emit_instruction(tctx, inst);
    347 }
    348 
    349 const struct tgsi_token *
    350 st_tgsi_lower_depth_clamp(const struct tgsi_token *tokens,
    351                           int depth_range_const,
    352                           bool clip_negative_one_to_one)
    353 {
    354    struct tgsi_depth_clamp_transform ctx;
    355    struct tgsi_token *newtoks;
    356    int newlen;
    357 
    358    memset(&ctx, 0, sizeof(ctx));
    359    tgsi_scan_shader(tokens, &ctx.info);
    360 
    361    /* we only want to do this for the fragment shader, and the shader-stage
    362     * right before it, but in the first pass there might be no "next" shader
    363     */
    364    if (ctx.info.processor != PIPE_SHADER_FRAGMENT &&
    365        ctx.info.processor != PIPE_SHADER_GEOMETRY &&
    366        ctx.info.processor != PIPE_SHADER_VERTEX &&
    367        ctx.info.processor != PIPE_SHADER_TESS_EVAL &&
    368        (ctx.info.properties[TGSI_PROPERTY_NEXT_SHADER] > PIPE_SHADER_VERTEX &&
    369        (ctx.info.properties[TGSI_PROPERTY_NEXT_SHADER] != PIPE_SHADER_FRAGMENT)))  {
    370       return tokens;
    371    }
    372 
    373    ctx.base.transform_declaration = transform_decl;
    374    ctx.base.transform_instruction = transform_instr;
    375 
    376    if (ctx.info.processor == PIPE_SHADER_FRAGMENT) {
    377       ctx.base.prolog = prolog_fs;
    378       ctx.base.epilog = epilog_fs;
    379    } else {
    380       ctx.base.prolog = prolog_last_vertex_stage;
    381       ctx.base.epilog = epilog_last_vertex_stage;
    382    }
    383 
    384    ctx.pos_output = ctx.pos_input = -1;
    385    ctx.depth_range_const = depth_range_const;
    386    ctx.depth_clip_minus_one_to_one = clip_negative_one_to_one;
    387 
    388    /* We add approximately 30 tokens per Z write, so add this per vertex in
    389     * a GS and some additional tokes for VS and TES
    390     */
    391    newlen = tgsi_num_tokens(tokens) +
    392             30 * ctx.info.properties[TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES] +
    393             120;
    394 
    395    newtoks = tgsi_alloc_tokens(newlen);
    396    if (!newtoks)
    397       return tokens;
    398 
    399    tgsi_transform_shader(tokens, newtoks, newlen, &ctx.base);
    400 
    401    return newtoks;
    402 }
    403 
    404 const struct tgsi_token *
    405 st_tgsi_lower_depth_clamp_fs(const struct tgsi_token *tokens,
    406                              int depth_range_const)
    407 {
    408    return st_tgsi_lower_depth_clamp(tokens, depth_range_const, false);
    409 }
    410