2 * Copyright © 2016 Red Hat
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:
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
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
26 #include "st_tgsi_lower_yuv.h"
27 #include "tgsi/tgsi_transform.h"
28 #include "tgsi/tgsi_scan.h"
29 #include "tgsi/tgsi_dump.h"
30 #include "util/u_debug.h"
32 #include "util/bitscan.h"
34 struct tgsi_yuv_transform
{
35 struct tgsi_transform_context base
;
36 struct tgsi_shader_info info
;
37 struct tgsi_full_src_register imm
[4];
39 struct tgsi_full_src_register src
;
40 struct tgsi_full_dst_register dst
;
45 /* Maps a primary sampler (used for Y) to the U or UV sampler. In
46 * case of 3-plane YUV format, the V plane is next sampler after U.
48 unsigned char sampler_map
[PIPE_MAX_SAMPLERS
][2];
50 bool first_instruction_emitted
;
56 static inline struct tgsi_yuv_transform
*
57 tgsi_yuv_transform(struct tgsi_transform_context
*tctx
)
59 return (struct tgsi_yuv_transform
*)tctx
;
63 reg_dst(struct tgsi_full_dst_register
*dst
,
64 const struct tgsi_full_dst_register
*orig_dst
, unsigned wrmask
)
67 dst
->Register
.WriteMask
&= wrmask
;
68 assert(dst
->Register
.WriteMask
);
72 get_swiz(unsigned *swiz
, const struct tgsi_src_register
*src
)
74 swiz
[0] = src
->SwizzleX
;
75 swiz
[1] = src
->SwizzleY
;
76 swiz
[2] = src
->SwizzleZ
;
77 swiz
[3] = src
->SwizzleW
;
81 reg_src(struct tgsi_full_src_register
*src
,
82 const struct tgsi_full_src_register
*orig_src
,
83 unsigned sx
, unsigned sy
, unsigned sz
, unsigned sw
)
86 get_swiz(swiz
, &orig_src
->Register
);
88 src
->Register
.SwizzleX
= swiz
[sx
];
89 src
->Register
.SwizzleY
= swiz
[sy
];
90 src
->Register
.SwizzleZ
= swiz
[sz
];
91 src
->Register
.SwizzleW
= swiz
[sw
];
94 #define TGSI_SWIZZLE__ TGSI_SWIZZLE_X /* don't-care value! */
95 #define SWIZ(x,y,z,w) TGSI_SWIZZLE_ ## x, TGSI_SWIZZLE_ ## y, \
96 TGSI_SWIZZLE_ ## z, TGSI_SWIZZLE_ ## w
98 static inline struct tgsi_full_instruction
99 tex_instruction(unsigned samp
)
101 struct tgsi_full_instruction inst
;
103 inst
= tgsi_default_full_instruction();
104 inst
.Instruction
.Opcode
= TGSI_OPCODE_TEX
;
105 inst
.Instruction
.Texture
= 1;
106 inst
.Texture
.Texture
= TGSI_TEXTURE_2D
;
107 inst
.Instruction
.NumDstRegs
= 1;
108 inst
.Instruction
.NumSrcRegs
= 2;
109 inst
.Src
[1].Register
.File
= TGSI_FILE_SAMPLER
;
110 inst
.Src
[1].Register
.Index
= samp
;
115 static inline struct tgsi_full_instruction
116 mov_instruction(void)
118 struct tgsi_full_instruction inst
;
120 inst
= tgsi_default_full_instruction();
121 inst
.Instruction
.Opcode
= TGSI_OPCODE_MOV
;
122 inst
.Instruction
.Saturate
= 0;
123 inst
.Instruction
.NumDstRegs
= 1;
124 inst
.Instruction
.NumSrcRegs
= 1;
129 static inline struct tgsi_full_instruction
130 dp3_instruction(void)
132 struct tgsi_full_instruction inst
;
134 inst
= tgsi_default_full_instruction();
135 inst
.Instruction
.Opcode
= TGSI_OPCODE_DP3
;
136 inst
.Instruction
.NumDstRegs
= 1;
137 inst
.Instruction
.NumSrcRegs
= 2;
145 emit_immed(struct tgsi_transform_context
*tctx
, int idx
,
146 float x
, float y
, float z
, float w
)
148 struct tgsi_yuv_transform
*ctx
= tgsi_yuv_transform(tctx
);
149 struct tgsi_shader_info
*info
= &ctx
->info
;
150 struct tgsi_full_immediate immed
;
152 immed
= tgsi_default_full_immediate();
153 immed
.Immediate
.NrTokens
= 1 + 4; /* one for the token itself */
154 immed
.u
[0].Float
= x
;
155 immed
.u
[1].Float
= y
;
156 immed
.u
[2].Float
= z
;
157 immed
.u
[3].Float
= w
;
158 tctx
->emit_immediate(tctx
, &immed
);
160 ctx
->imm
[idx
].Register
.File
= TGSI_FILE_IMMEDIATE
;
161 ctx
->imm
[idx
].Register
.Index
= info
->immediate_count
+ idx
;
162 ctx
->imm
[idx
].Register
.SwizzleX
= TGSI_SWIZZLE_X
;
163 ctx
->imm
[idx
].Register
.SwizzleY
= TGSI_SWIZZLE_Y
;
164 ctx
->imm
[idx
].Register
.SwizzleZ
= TGSI_SWIZZLE_Z
;
165 ctx
->imm
[idx
].Register
.SwizzleW
= TGSI_SWIZZLE_W
;
169 emit_samp(struct tgsi_transform_context
*tctx
, unsigned samp
)
171 tgsi_transform_sampler_decl(tctx
, samp
);
172 tgsi_transform_sampler_view_decl(tctx
, samp
, PIPE_TEXTURE_2D
,
173 TGSI_RETURN_TYPE_FLOAT
);
176 /* Emit extra declarations we need:
177 * + 2 TEMP to hold intermediate results
178 * + 1 (for 2-plane YUV) or 2 (for 3-plane YUV) extra samplers per
179 * lowered YUV sampler
180 * + extra immediates for doing CSC
183 emit_decls(struct tgsi_transform_context
*tctx
)
185 struct tgsi_yuv_transform
*ctx
= tgsi_yuv_transform(tctx
);
186 struct tgsi_shader_info
*info
= &ctx
->info
;
187 unsigned mask
, tempbase
, i
;
188 struct tgsi_full_declaration decl
;
191 * Declare immediates for CSC conversion:
194 /* ITU-R BT.601 conversion */
195 emit_immed(tctx
, 0, 1.164, 0.000, 1.596, 0.0);
196 emit_immed(tctx
, 1, 1.164, -0.392, -0.813, 0.0);
197 emit_immed(tctx
, 2, 1.164, 2.017, 0.000, 0.0);
198 emit_immed(tctx
, 3, 0.0625, 0.500, 0.500, 1.0);
201 * Declare extra samplers / sampler-views:
204 mask
= ctx
->lower_nv12
| ctx
->lower_iyuv
;
206 unsigned extra
, y_samp
= u_bit_scan(&mask
);
208 extra
= u_bit_scan(&ctx
->free_slots
);
209 ctx
->sampler_map
[y_samp
][0] = extra
;
210 emit_samp(tctx
, extra
);
212 if (ctx
->lower_iyuv
& (1 << y_samp
)) {
213 extra
= u_bit_scan(&ctx
->free_slots
);
214 ctx
->sampler_map
[y_samp
][1] = extra
;
215 emit_samp(tctx
, extra
);
220 * Declare extra temp:
223 tempbase
= info
->file_max
[TGSI_FILE_TEMPORARY
] + 1;
225 for (i
= 0; i
< 2; i
++) {
226 decl
= tgsi_default_full_declaration();
227 decl
.Declaration
.File
= TGSI_FILE_TEMPORARY
;
228 decl
.Range
.First
= decl
.Range
.Last
= tempbase
+ i
;
229 tctx
->emit_declaration(tctx
, &decl
);
231 ctx
->tmp
[i
].src
.Register
.File
= TGSI_FILE_TEMPORARY
;
232 ctx
->tmp
[i
].src
.Register
.Index
= tempbase
+ i
;
233 ctx
->tmp
[i
].src
.Register
.SwizzleX
= TGSI_SWIZZLE_X
;
234 ctx
->tmp
[i
].src
.Register
.SwizzleY
= TGSI_SWIZZLE_Y
;
235 ctx
->tmp
[i
].src
.Register
.SwizzleZ
= TGSI_SWIZZLE_Z
;
236 ctx
->tmp
[i
].src
.Register
.SwizzleW
= TGSI_SWIZZLE_W
;
238 ctx
->tmp
[i
].dst
.Register
.File
= TGSI_FILE_TEMPORARY
;
239 ctx
->tmp
[i
].dst
.Register
.Index
= tempbase
+ i
;
240 ctx
->tmp
[i
].dst
.Register
.WriteMask
= TGSI_WRITEMASK_XYZW
;
244 /* call with YUV in tmpA.xyz */
246 yuv_to_rgb(struct tgsi_transform_context
*tctx
,
247 struct tgsi_full_dst_register
*dst
)
249 struct tgsi_yuv_transform
*ctx
= tgsi_yuv_transform(tctx
);
250 struct tgsi_full_instruction inst
;
253 * IMM[0] FLT32 { 1.164, 0.000, 1.596, 0.0 }
254 * IMM[1] FLT32 { 1.164, -0.392, -0.813, 0.0 }
255 * IMM[2] FLT32 { 1.164, 2.017, 0.000, 0.0 }
256 * IMM[3] FLT32 { 0.0625, 0.500, 0.500, 1.0 }
259 /* SUB tmpA.xyz, tmpA, imm[3] */
260 inst
= tgsi_default_full_instruction();
261 inst
.Instruction
.Opcode
= TGSI_OPCODE_ADD
;
262 inst
.Instruction
.Saturate
= 0;
263 inst
.Instruction
.NumDstRegs
= 1;
264 inst
.Instruction
.NumSrcRegs
= 2;
265 reg_dst(&inst
.Dst
[0], &ctx
->tmp
[A
].dst
, TGSI_WRITEMASK_XYZ
);
266 reg_src(&inst
.Src
[0], &ctx
->tmp
[A
].src
, SWIZ(X
, Y
, Z
, _
));
267 reg_src(&inst
.Src
[1], &ctx
->imm
[3], SWIZ(X
, Y
, Z
, _
));
268 inst
.Src
[1].Register
.Negate
= 1;
269 tctx
->emit_instruction(tctx
, &inst
);
271 /* DP3 dst.x, tmpA, imm[0] */
272 inst
= dp3_instruction();
273 reg_dst(&inst
.Dst
[0], dst
, TGSI_WRITEMASK_X
);
274 reg_src(&inst
.Src
[0], &ctx
->tmp
[A
].src
, SWIZ(X
, Y
, Z
, W
));
275 reg_src(&inst
.Src
[1], &ctx
->imm
[0], SWIZ(X
, Y
, Z
, W
));
276 tctx
->emit_instruction(tctx
, &inst
);
278 /* DP3 dst.y, tmpA, imm[1] */
279 inst
= dp3_instruction();
280 reg_dst(&inst
.Dst
[0], dst
, TGSI_WRITEMASK_Y
);
281 reg_src(&inst
.Src
[0], &ctx
->tmp
[A
].src
, SWIZ(X
, Y
, Z
, W
));
282 reg_src(&inst
.Src
[1], &ctx
->imm
[1], SWIZ(X
, Y
, Z
, W
));
283 tctx
->emit_instruction(tctx
, &inst
);
285 /* DP3 dst.z, tmpA, imm[2] */
286 inst
= dp3_instruction();
287 reg_dst(&inst
.Dst
[0], dst
, TGSI_WRITEMASK_Z
);
288 reg_src(&inst
.Src
[0], &ctx
->tmp
[A
].src
, SWIZ(X
, Y
, Z
, W
));
289 reg_src(&inst
.Src
[1], &ctx
->imm
[2], SWIZ(X
, Y
, Z
, W
));
290 tctx
->emit_instruction(tctx
, &inst
);
292 /* MOV dst.w, imm[0].x */
293 inst
= mov_instruction();
294 reg_dst(&inst
.Dst
[0], dst
, TGSI_WRITEMASK_W
);
295 reg_src(&inst
.Src
[0], &ctx
->imm
[3], SWIZ(_
, _
, _
, W
));
296 tctx
->emit_instruction(tctx
, &inst
);
300 lower_nv12(struct tgsi_transform_context
*tctx
,
301 struct tgsi_full_instruction
*originst
)
303 struct tgsi_yuv_transform
*ctx
= tgsi_yuv_transform(tctx
);
304 struct tgsi_full_instruction inst
;
305 struct tgsi_full_src_register
*coord
= &originst
->Src
[0];
306 unsigned samp
= originst
->Src
[1].Register
.Index
;
309 * TEX tempA.x, coord, texture[samp], 2D;
311 inst
= tex_instruction(samp
);
312 reg_dst(&inst
.Dst
[0], &ctx
->tmp
[A
].dst
, TGSI_WRITEMASK_X
);
313 reg_src(&inst
.Src
[0], coord
, SWIZ(X
, Y
, Z
, W
));
314 tctx
->emit_instruction(tctx
, &inst
);
317 * TEX tempB.xy, coord, texture[sampler_map[samp][0]], 2D;
318 * MOV tempA.yz, tempB._xy_
320 inst
= tex_instruction(ctx
->sampler_map
[samp
][0]);
321 reg_dst(&inst
.Dst
[0], &ctx
->tmp
[B
].dst
, TGSI_WRITEMASK_XY
);
322 reg_src(&inst
.Src
[0], coord
, SWIZ(X
, Y
, Z
, W
));
323 tctx
->emit_instruction(tctx
, &inst
);
325 inst
= mov_instruction();
326 reg_dst(&inst
.Dst
[0], &ctx
->tmp
[A
].dst
, TGSI_WRITEMASK_YZ
);
327 reg_src(&inst
.Src
[0], &ctx
->tmp
[B
].src
, SWIZ(_
, X
, Y
, _
));
328 tctx
->emit_instruction(tctx
, &inst
);
330 /* At this point, we have YUV in tempA.xyz, rest is common: */
331 yuv_to_rgb(tctx
, &originst
->Dst
[0]);
335 lower_iyuv(struct tgsi_transform_context
*tctx
,
336 struct tgsi_full_instruction
*originst
)
338 struct tgsi_yuv_transform
*ctx
= tgsi_yuv_transform(tctx
);
339 struct tgsi_full_instruction inst
;
340 struct tgsi_full_src_register
*coord
= &originst
->Src
[0];
341 unsigned samp
= originst
->Src
[1].Register
.Index
;
344 * TEX tempA.x, coord, texture[samp], 2D;
346 inst
= tex_instruction(samp
);
347 reg_dst(&inst
.Dst
[0], &ctx
->tmp
[A
].dst
, TGSI_WRITEMASK_X
);
348 reg_src(&inst
.Src
[0], coord
, SWIZ(X
, Y
, Z
, W
));
349 tctx
->emit_instruction(tctx
, &inst
);
352 * TEX tempB.x, coord, texture[sampler_map[samp][0]], 2D;
353 * MOV tempA.y, tempB._x__
355 inst
= tex_instruction(ctx
->sampler_map
[samp
][0]);
356 reg_dst(&inst
.Dst
[0], &ctx
->tmp
[B
].dst
, TGSI_WRITEMASK_X
);
357 reg_src(&inst
.Src
[0], coord
, SWIZ(X
, Y
, Z
, W
));
358 tctx
->emit_instruction(tctx
, &inst
);
360 inst
= mov_instruction();
361 reg_dst(&inst
.Dst
[0], &ctx
->tmp
[A
].dst
, TGSI_WRITEMASK_Y
);
362 reg_src(&inst
.Src
[0], &ctx
->tmp
[B
].src
, SWIZ(_
, X
, _
, _
));
363 tctx
->emit_instruction(tctx
, &inst
);
366 * TEX tempB.x, coord, texture[sampler_map[samp][1]], 2D;
367 * MOV tempA.z, tempB.__x_
369 inst
= tex_instruction(ctx
->sampler_map
[samp
][1]);
370 reg_dst(&inst
.Dst
[0], &ctx
->tmp
[B
].dst
, TGSI_WRITEMASK_X
);
371 reg_src(&inst
.Src
[0], coord
, SWIZ(X
, Y
, Z
, W
));
372 tctx
->emit_instruction(tctx
, &inst
);
374 inst
= mov_instruction();
375 reg_dst(&inst
.Dst
[0], &ctx
->tmp
[A
].dst
, TGSI_WRITEMASK_Z
);
376 reg_src(&inst
.Src
[0], &ctx
->tmp
[B
].src
, SWIZ(_
, _
, X
, _
));
377 tctx
->emit_instruction(tctx
, &inst
);
379 /* At this point, we have YUV in tempA.xyz, rest is common: */
380 yuv_to_rgb(tctx
, &originst
->Dst
[0]);
384 transform_instr(struct tgsi_transform_context
*tctx
,
385 struct tgsi_full_instruction
*inst
)
387 struct tgsi_yuv_transform
*ctx
= tgsi_yuv_transform(tctx
);
389 if (!ctx
->first_instruction_emitted
) {
391 ctx
->first_instruction_emitted
= true;
394 switch (inst
->Instruction
.Opcode
) {
395 /* TODO what other tex opcode's can be used w/ external eglimgs? */
396 case TGSI_OPCODE_TEX
: {
397 unsigned samp
= inst
->Src
[1].Register
.Index
;
398 if (ctx
->lower_nv12
& (1 << samp
)) {
399 lower_nv12(tctx
, inst
);
400 } else if (ctx
->lower_iyuv
& (1 << samp
)) {
401 lower_iyuv(tctx
, inst
);
409 tctx
->emit_instruction(tctx
, inst
);
414 extern const struct tgsi_token
*
415 st_tgsi_lower_yuv(const struct tgsi_token
*tokens
, unsigned free_slots
,
416 unsigned lower_nv12
, unsigned lower_iyuv
)
418 struct tgsi_yuv_transform ctx
;
419 struct tgsi_token
*newtoks
;
422 assert(!(lower_nv12
& lower_iyuv
)); /* bitmasks should be mutually exclusive */
424 // tgsi_dump(tokens, 0);
425 // debug_printf("\n");
427 memset(&ctx
, 0, sizeof(ctx
));
428 ctx
.base
.transform_instruction
= transform_instr
;
429 ctx
.free_slots
= free_slots
;
430 ctx
.lower_nv12
= lower_nv12
;
431 ctx
.lower_iyuv
= lower_iyuv
;
432 tgsi_scan_shader(tokens
, &ctx
.info
);
434 /* TODO better job of figuring out how many extra tokens we need..
435 * this is a pain about tgsi_transform :-/
437 newlen
= tgsi_num_tokens(tokens
) + 120;
438 newtoks
= tgsi_alloc_tokens(newlen
);
442 tgsi_transform_shader(tokens
, newtoks
, newlen
, &ctx
.base
);
444 // tgsi_dump(newtoks, 0);
445 // debug_printf("\n");