1 /**************************************************************************
2  *
3  * Copyright (C) 2015 Advanced Micro Devices, Inc.
4  * Copyright 2007 VMware, Inc.
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sub license, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial portions
17  * of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  **************************************************************************/
28 
29 #include "main/macros.h"
30 #include "st_cb_drawpixels.h"
31 #include "tgsi/tgsi_transform.h"
32 #include "tgsi/tgsi_scan.h"
33 
34 struct tgsi_drawpix_transform {
35    struct tgsi_transform_context base;
36    struct tgsi_shader_info info;
37    bool use_texcoord;
38    bool scale_and_bias;
39    bool pixel_maps;
40    bool first_instruction_emitted;
41    unsigned scale_const;
42    unsigned bias_const;
43    unsigned color_temp;
44    unsigned drawpix_sampler;
45    unsigned pixelmap_sampler;
46    unsigned texcoord_const;
47    unsigned tex_target;
48 };
49 
50 static inline struct tgsi_drawpix_transform *
tgsi_drawpix_transform(struct tgsi_transform_context * tctx)51 tgsi_drawpix_transform(struct tgsi_transform_context *tctx)
52 {
53    return (struct tgsi_drawpix_transform *)tctx;
54 }
55 
56 static void
set_src(struct tgsi_full_instruction * inst,unsigned i,unsigned file,unsigned index,unsigned x,unsigned y,unsigned z,unsigned w)57 set_src(struct tgsi_full_instruction *inst, unsigned i, unsigned file, unsigned index,
58         unsigned x, unsigned y, unsigned z, unsigned w)
59 {
60    inst->Src[i].Register.File  = file;
61    inst->Src[i].Register.Index = index;
62    inst->Src[i].Register.SwizzleX = x;
63    inst->Src[i].Register.SwizzleY = y;
64    inst->Src[i].Register.SwizzleZ = z;
65    inst->Src[i].Register.SwizzleW = w;
66 }
67 
68 #define SET_SRC(inst, i, file, index, x, y, z, w) \
69    set_src(inst, i, file, index, TGSI_SWIZZLE_##x, TGSI_SWIZZLE_##y, \
70            TGSI_SWIZZLE_##z, TGSI_SWIZZLE_##w)
71 
72 static void
transform_instr(struct tgsi_transform_context * tctx,struct tgsi_full_instruction * current_inst)73 transform_instr(struct tgsi_transform_context *tctx,
74 		struct tgsi_full_instruction *current_inst)
75 {
76    struct tgsi_drawpix_transform *ctx = tgsi_drawpix_transform(tctx);
77    const unsigned tgsi_tex_target = ctx->tex_target == PIPE_TEXTURE_2D
78       ? TGSI_TEXTURE_2D : TGSI_TEXTURE_RECT;
79    unsigned i, sem_texcoord = ctx->use_texcoord ? TGSI_SEMANTIC_TEXCOORD :
80                                                   TGSI_SEMANTIC_GENERIC;
81    int texcoord_index = -1;
82 
83    if (ctx->first_instruction_emitted)
84       goto transform_inst;
85 
86    ctx->first_instruction_emitted = true;
87 
88    /* Add scale and bias constants. */
89    if (ctx->scale_and_bias) {
90       if (ctx->info.const_file_max[0] < (int)ctx->scale_const) {
91          tgsi_transform_const_decl(tctx, ctx->scale_const, ctx->scale_const);
92       }
93 
94       if (ctx->info.const_file_max[0] < (int)ctx->bias_const) {
95          tgsi_transform_const_decl(tctx, ctx->bias_const, ctx->bias_const);
96       }
97    }
98 
99    if (ctx->info.const_file_max[0] < (int)ctx->texcoord_const) {
100       tgsi_transform_const_decl(tctx, ctx->texcoord_const, ctx->texcoord_const);
101    }
102 
103    /* Add a new temp. */
104    ctx->color_temp = ctx->info.file_max[TGSI_FILE_TEMPORARY] + 1;
105    tgsi_transform_temp_decl(tctx, ctx->color_temp);
106 
107    /* Add TEXCOORD[texcoord_slot] if it's missing. */
108    for (i = 0; i < ctx->info.num_inputs; i++) {
109       if (ctx->info.input_semantic_name[i] == sem_texcoord &&
110           ctx->info.input_semantic_index[i] == 0) {
111          texcoord_index = i;
112          break;
113       }
114    }
115 
116    if (texcoord_index == -1) {
117       texcoord_index = ctx->info.num_inputs;
118       tgsi_transform_input_decl(tctx, texcoord_index, sem_texcoord, 0,
119                                 TGSI_INTERPOLATE_PERSPECTIVE);
120    }
121 
122    /* Declare the drawpix sampler if it's missing. */
123    if (!(ctx->info.samplers_declared & (1 << ctx->drawpix_sampler))) {
124       tgsi_transform_sampler_decl(tctx, ctx->drawpix_sampler);
125 
126       /* emit sampler view declaration */
127       tgsi_transform_sampler_view_decl(tctx, ctx->drawpix_sampler,
128                                        tgsi_tex_target, TGSI_RETURN_TYPE_FLOAT);
129    }
130 
131    /* Declare the pixel map sampler if it's missing. */
132    if (ctx->pixel_maps &&
133        !(ctx->info.samplers_declared & (1 << ctx->pixelmap_sampler))) {
134       tgsi_transform_sampler_decl(tctx, ctx->pixelmap_sampler);
135 
136       /* emit sampler view declaration */
137       tgsi_transform_sampler_view_decl(tctx, ctx->pixelmap_sampler,
138                                        TGSI_TEXTURE_2D, TGSI_RETURN_TYPE_FLOAT);
139    }
140 
141    /* Get initial pixel color from the texture.
142     * TEX temp, fragment.texcoord[0], texture[0], 2D;
143     */
144    tgsi_transform_tex_inst(tctx, TGSI_FILE_TEMPORARY, ctx->color_temp,
145                            TGSI_FILE_INPUT, texcoord_index,
146                            tgsi_tex_target, ctx->drawpix_sampler);
147 
148    /* Apply the scale and bias. */
149    if (ctx->scale_and_bias) {
150       /* MAD temp, temp, scale, bias; */
151       tgsi_transform_op3_inst(tctx, TGSI_OPCODE_MAD,
152                               TGSI_FILE_TEMPORARY, ctx->color_temp,
153                               TGSI_WRITEMASK_XYZW,
154                               TGSI_FILE_TEMPORARY, ctx->color_temp,
155                               TGSI_FILE_CONSTANT, ctx->scale_const,
156                               TGSI_FILE_CONSTANT, ctx->bias_const);
157    }
158 
159    if (ctx->pixel_maps) {
160       /* do four pixel map look-ups with two TEX instructions: */
161       struct tgsi_full_instruction inst;
162 
163       /* TEX temp.xy, temp.xyyy, texture[1], 2D; */
164       inst = tgsi_default_full_instruction();
165       inst.Instruction.Opcode = TGSI_OPCODE_TEX;
166       inst.Instruction.Texture = 1;
167       inst.Texture.Texture = TGSI_TEXTURE_2D;
168 
169       inst.Instruction.NumDstRegs = 1;
170       inst.Dst[0].Register.File  = TGSI_FILE_TEMPORARY;
171       inst.Dst[0].Register.Index = ctx->color_temp;
172       inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XY;
173 
174       inst.Instruction.NumSrcRegs = 2;
175       SET_SRC(&inst, 0, TGSI_FILE_TEMPORARY, ctx->color_temp, X, Y, Y, Y);
176       inst.Src[1].Register.File  = TGSI_FILE_SAMPLER;
177       inst.Src[1].Register.Index = ctx->pixelmap_sampler;
178 
179       tctx->emit_instruction(tctx, &inst);
180 
181       /* TEX temp.zw, temp.zwww, texture[1], 2D; */
182       inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_ZW;
183       SET_SRC(&inst, 0, TGSI_FILE_TEMPORARY, ctx->color_temp, Z, W, W, W);
184       tctx->emit_instruction(tctx, &inst);
185    }
186 
187    /* Now, "color_temp" should be used in place of IN:COLOR0,
188     * and CONST[texcoord_slot] should be used in place of IN:TEXCOORD0.
189     */
190 
191 transform_inst:
192 
193    for (i = 0; i < current_inst->Instruction.NumSrcRegs; i++) {
194       struct tgsi_full_src_register *src = &current_inst->Src[i];
195       unsigned reg = src->Register.Index;
196 
197       if (src->Register.File != TGSI_FILE_INPUT || src->Register.Indirect)
198          continue;
199 
200       if (ctx->info.input_semantic_name[reg] == TGSI_SEMANTIC_COLOR &&
201           ctx->info.input_semantic_index[reg] == 0) {
202          src->Register.File = TGSI_FILE_TEMPORARY;
203          src->Register.Index = ctx->color_temp;
204       } else if (ctx->info.input_semantic_name[reg] == sem_texcoord &&
205                  ctx->info.input_semantic_index[reg] == 0) {
206          src->Register.File = TGSI_FILE_CONSTANT;
207          src->Register.Index = ctx->texcoord_const;
208          src->Register.Dimension = 1;
209          src->Dimension.Index = 0;
210       }
211    }
212 
213    tctx->emit_instruction(tctx, current_inst);
214 }
215 
216 const struct tgsi_token *
st_get_drawpix_shader(const struct tgsi_token * tokens,bool use_texcoord,bool scale_and_bias,unsigned scale_const,unsigned bias_const,bool pixel_maps,unsigned drawpix_sampler,unsigned pixelmap_sampler,unsigned texcoord_const,unsigned tex_target)217 st_get_drawpix_shader(const struct tgsi_token *tokens, bool use_texcoord,
218                       bool scale_and_bias, unsigned scale_const,
219                       unsigned bias_const, bool pixel_maps,
220                       unsigned drawpix_sampler, unsigned pixelmap_sampler,
221                       unsigned texcoord_const, unsigned tex_target)
222 {
223    struct tgsi_drawpix_transform ctx;
224    struct tgsi_token *newtoks;
225    int newlen;
226 
227    assert(tex_target == PIPE_TEXTURE_2D ||
228           tex_target == PIPE_TEXTURE_RECT);
229 
230    memset(&ctx, 0, sizeof(ctx));
231    ctx.base.transform_instruction = transform_instr;
232    ctx.use_texcoord = use_texcoord;
233    ctx.scale_and_bias = scale_and_bias;
234    ctx.scale_const = scale_const;
235    ctx.bias_const = bias_const;
236    ctx.pixel_maps = pixel_maps;
237    ctx.drawpix_sampler = drawpix_sampler;
238    ctx.pixelmap_sampler = pixelmap_sampler;
239    ctx.texcoord_const = texcoord_const;
240    ctx.tex_target = tex_target;
241    tgsi_scan_shader(tokens, &ctx.info);
242 
243    newlen = tgsi_num_tokens(tokens) + 60;
244    newtoks = tgsi_alloc_tokens(newlen);
245    if (!newtoks)
246       return NULL;
247 
248    tgsi_transform_shader(tokens, newtoks, newlen, &ctx.base);
249    return newtoks;
250 }
251