1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2014 VMware, Inc. 3bf215546Sopenharmony_ci * All Rights Reserved. 4bf215546Sopenharmony_ci * 5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 7bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 8bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 9bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 10bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 11bf215546Sopenharmony_ci * the following conditions: 12bf215546Sopenharmony_ci * 13bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 14bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 15bf215546Sopenharmony_ci * of the Software. 16bf215546Sopenharmony_ci * 17bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20bf215546Sopenharmony_ci * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR 21bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24bf215546Sopenharmony_ci */ 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci/** 28bf215546Sopenharmony_ci * This utility transforms the geometry shader to emulate point sprite by 29bf215546Sopenharmony_ci * drawing a quad. It also adds an extra output for the original point position 30bf215546Sopenharmony_ci * if the point position is to be written to a stream output buffer. 31bf215546Sopenharmony_ci * Note: It assumes the driver will add a constant for the inverse viewport 32bf215546Sopenharmony_ci * after the user defined constants. 33bf215546Sopenharmony_ci */ 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ci#include "util/u_debug.h" 36bf215546Sopenharmony_ci#include "util/u_math.h" 37bf215546Sopenharmony_ci#include "tgsi_info.h" 38bf215546Sopenharmony_ci#include "tgsi_point_sprite.h" 39bf215546Sopenharmony_ci#include "tgsi_transform.h" 40bf215546Sopenharmony_ci#include "pipe/p_state.h" 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci#define INVALID_INDEX 9999 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_ci/* Set swizzle based on the immediates (0, 1, 0, -1) */ 45bf215546Sopenharmony_cistatic inline unsigned 46bf215546Sopenharmony_ciset_swizzle(int x, int y, int z, int w) 47bf215546Sopenharmony_ci{ 48bf215546Sopenharmony_ci static const unsigned map[3] = {TGSI_SWIZZLE_W, TGSI_SWIZZLE_X, 49bf215546Sopenharmony_ci TGSI_SWIZZLE_Y}; 50bf215546Sopenharmony_ci assert(x >= -1); 51bf215546Sopenharmony_ci assert(x <= 1); 52bf215546Sopenharmony_ci assert(y >= -1); 53bf215546Sopenharmony_ci assert(y <= 1); 54bf215546Sopenharmony_ci assert(z >= -1); 55bf215546Sopenharmony_ci assert(z <= 1); 56bf215546Sopenharmony_ci assert(w >= -1); 57bf215546Sopenharmony_ci assert(w <= 1); 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci return map[x+1] | (map[y+1] << 2) | (map[z+1] << 4) | (map[w+1] << 6); 60bf215546Sopenharmony_ci} 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_cistatic inline unsigned 63bf215546Sopenharmony_ciget_swizzle(unsigned swizzle, unsigned component) 64bf215546Sopenharmony_ci{ 65bf215546Sopenharmony_ci assert(component < 4); 66bf215546Sopenharmony_ci return (swizzle >> (component * 2)) & 0x3; 67bf215546Sopenharmony_ci} 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_cistruct psprite_transform_context 70bf215546Sopenharmony_ci{ 71bf215546Sopenharmony_ci struct tgsi_transform_context base; 72bf215546Sopenharmony_ci unsigned num_tmp; 73bf215546Sopenharmony_ci unsigned num_out; 74bf215546Sopenharmony_ci unsigned num_orig_out; 75bf215546Sopenharmony_ci unsigned num_const; 76bf215546Sopenharmony_ci unsigned num_imm; 77bf215546Sopenharmony_ci unsigned point_size_in; // point size input 78bf215546Sopenharmony_ci unsigned point_size_out; // point size output 79bf215546Sopenharmony_ci unsigned point_size_tmp; // point size temp 80bf215546Sopenharmony_ci unsigned point_pos_in; // point pos input 81bf215546Sopenharmony_ci unsigned point_pos_out; // point pos output 82bf215546Sopenharmony_ci unsigned point_pos_sout; // original point pos for streamout 83bf215546Sopenharmony_ci unsigned point_pos_tmp; // point pos temp 84bf215546Sopenharmony_ci unsigned point_scale_tmp; // point scale temp 85bf215546Sopenharmony_ci unsigned point_color_out; // point color output 86bf215546Sopenharmony_ci unsigned point_color_tmp; // point color temp 87bf215546Sopenharmony_ci unsigned point_imm; // point immediates 88bf215546Sopenharmony_ci unsigned point_ivp; // point inverseViewport constant 89bf215546Sopenharmony_ci unsigned point_dir_swz[4]; // point direction swizzle 90bf215546Sopenharmony_ci unsigned point_coord_swz[4]; // point coord swizzle 91bf215546Sopenharmony_ci unsigned point_coord_enable; // point coord enable mask 92bf215546Sopenharmony_ci unsigned point_coord_decl; // point coord output declared mask 93bf215546Sopenharmony_ci unsigned point_coord_out; // point coord output starting index 94bf215546Sopenharmony_ci unsigned point_coord_aa; // aa point coord semantic index 95bf215546Sopenharmony_ci unsigned point_coord_k; // aa point coord threshold distance 96bf215546Sopenharmony_ci unsigned stream_out_point_pos:1; // set if to stream out original point pos 97bf215546Sopenharmony_ci unsigned aa_point:1; // set if doing aa point 98bf215546Sopenharmony_ci unsigned need_texcoord_semantic:1; // set if need texcoord semantic 99bf215546Sopenharmony_ci unsigned out_tmp_index[PIPE_MAX_SHADER_OUTPUTS]; 100bf215546Sopenharmony_ci int max_generic; // max generic semantic index 101bf215546Sopenharmony_ci}; 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_cistatic inline struct psprite_transform_context * 104bf215546Sopenharmony_cipsprite_transform_context(struct tgsi_transform_context *ctx) 105bf215546Sopenharmony_ci{ 106bf215546Sopenharmony_ci return (struct psprite_transform_context *) ctx; 107bf215546Sopenharmony_ci} 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci/** 111bf215546Sopenharmony_ci * TGSI declaration transform callback. 112bf215546Sopenharmony_ci */ 113bf215546Sopenharmony_cistatic void 114bf215546Sopenharmony_cipsprite_decl(struct tgsi_transform_context *ctx, 115bf215546Sopenharmony_ci struct tgsi_full_declaration *decl) 116bf215546Sopenharmony_ci{ 117bf215546Sopenharmony_ci struct psprite_transform_context *ts = psprite_transform_context(ctx); 118bf215546Sopenharmony_ci unsigned range_end = decl->Range.Last + 1; 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci if (decl->Declaration.File == TGSI_FILE_INPUT) { 121bf215546Sopenharmony_ci if (decl->Semantic.Name == TGSI_SEMANTIC_PSIZE) { 122bf215546Sopenharmony_ci ts->point_size_in = decl->Range.First; 123bf215546Sopenharmony_ci } 124bf215546Sopenharmony_ci else if (decl->Semantic.Name == TGSI_SEMANTIC_POSITION) { 125bf215546Sopenharmony_ci ts->point_pos_in = decl->Range.First; 126bf215546Sopenharmony_ci } 127bf215546Sopenharmony_ci } 128bf215546Sopenharmony_ci else if (decl->Declaration.File == TGSI_FILE_OUTPUT) { 129bf215546Sopenharmony_ci if (decl->Semantic.Name == TGSI_SEMANTIC_PSIZE) { 130bf215546Sopenharmony_ci ts->point_size_out = decl->Range.First; 131bf215546Sopenharmony_ci } 132bf215546Sopenharmony_ci else if (decl->Semantic.Name == TGSI_SEMANTIC_POSITION) { 133bf215546Sopenharmony_ci ts->point_pos_out = decl->Range.First; 134bf215546Sopenharmony_ci } 135bf215546Sopenharmony_ci else if (!ts->need_texcoord_semantic && 136bf215546Sopenharmony_ci decl->Semantic.Name == TGSI_SEMANTIC_GENERIC && 137bf215546Sopenharmony_ci decl->Semantic.Index < 32) { 138bf215546Sopenharmony_ci ts->point_coord_decl |= 1 << decl->Semantic.Index; 139bf215546Sopenharmony_ci ts->max_generic = MAX2(ts->max_generic, (int)decl->Semantic.Index); 140bf215546Sopenharmony_ci } 141bf215546Sopenharmony_ci else if (ts->need_texcoord_semantic && 142bf215546Sopenharmony_ci decl->Semantic.Name == TGSI_SEMANTIC_TEXCOORD) { 143bf215546Sopenharmony_ci ts->point_coord_decl |= 1 << decl->Semantic.Index; 144bf215546Sopenharmony_ci } 145bf215546Sopenharmony_ci ts->num_out = MAX2(ts->num_out, range_end); 146bf215546Sopenharmony_ci } 147bf215546Sopenharmony_ci else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) { 148bf215546Sopenharmony_ci ts->num_tmp = MAX2(ts->num_tmp, range_end); 149bf215546Sopenharmony_ci } 150bf215546Sopenharmony_ci else if (decl->Declaration.File == TGSI_FILE_CONSTANT) { 151bf215546Sopenharmony_ci ts->num_const = MAX2(ts->num_const, range_end); 152bf215546Sopenharmony_ci } 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci ctx->emit_declaration(ctx, decl); 155bf215546Sopenharmony_ci} 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci/** 158bf215546Sopenharmony_ci * TGSI immediate declaration transform callback. 159bf215546Sopenharmony_ci */ 160bf215546Sopenharmony_cistatic void 161bf215546Sopenharmony_cipsprite_immediate(struct tgsi_transform_context *ctx, 162bf215546Sopenharmony_ci struct tgsi_full_immediate *imm) 163bf215546Sopenharmony_ci{ 164bf215546Sopenharmony_ci struct psprite_transform_context *ts = psprite_transform_context(ctx); 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci ctx->emit_immediate(ctx, imm); 167bf215546Sopenharmony_ci ts->num_imm++; 168bf215546Sopenharmony_ci} 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci/** 172bf215546Sopenharmony_ci * TGSI transform prolog callback. 173bf215546Sopenharmony_ci */ 174bf215546Sopenharmony_cistatic void 175bf215546Sopenharmony_cipsprite_prolog(struct tgsi_transform_context *ctx) 176bf215546Sopenharmony_ci{ 177bf215546Sopenharmony_ci struct psprite_transform_context *ts = psprite_transform_context(ctx); 178bf215546Sopenharmony_ci unsigned point_coord_enable, en; 179bf215546Sopenharmony_ci unsigned i; 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci /* Replace output registers with temporary registers */ 182bf215546Sopenharmony_ci for (i = 0; i < ts->num_out; i++) { 183bf215546Sopenharmony_ci ts->out_tmp_index[i] = ts->num_tmp++; 184bf215546Sopenharmony_ci } 185bf215546Sopenharmony_ci ts->num_orig_out = ts->num_out; 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci /* Declare a tmp register for point scale */ 188bf215546Sopenharmony_ci ts->point_scale_tmp = ts->num_tmp++; 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_ci if (ts->point_size_out != INVALID_INDEX) 191bf215546Sopenharmony_ci ts->point_size_tmp = ts->out_tmp_index[ts->point_size_out]; 192bf215546Sopenharmony_ci else 193bf215546Sopenharmony_ci ts->point_size_tmp = ts->num_tmp++; 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci assert(ts->point_pos_out != INVALID_INDEX); 196bf215546Sopenharmony_ci ts->point_pos_tmp = ts->out_tmp_index[ts->point_pos_out]; 197bf215546Sopenharmony_ci ts->out_tmp_index[ts->point_pos_out] = INVALID_INDEX; 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci /* Declare one more tmp register for point coord threshold distance 200bf215546Sopenharmony_ci * if we are generating anti-aliased point. 201bf215546Sopenharmony_ci */ 202bf215546Sopenharmony_ci if (ts->aa_point) 203bf215546Sopenharmony_ci ts->point_coord_k = ts->num_tmp++; 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci tgsi_transform_temps_decl(ctx, ts->point_size_tmp, ts->num_tmp-1); 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_ci /* Declare an extra output for the original point position for stream out */ 208bf215546Sopenharmony_ci if (ts->stream_out_point_pos) { 209bf215546Sopenharmony_ci ts->point_pos_sout = ts->num_out++; 210bf215546Sopenharmony_ci tgsi_transform_output_decl(ctx, ts->point_pos_sout, 211bf215546Sopenharmony_ci TGSI_SEMANTIC_GENERIC, 0, 0); 212bf215546Sopenharmony_ci } 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_ci /* point coord outputs to be declared */ 215bf215546Sopenharmony_ci point_coord_enable = ts->point_coord_enable & ~ts->point_coord_decl; 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci /* Declare outputs for those point coord that are enabled but are not 218bf215546Sopenharmony_ci * already declared in this shader. 219bf215546Sopenharmony_ci */ 220bf215546Sopenharmony_ci ts->point_coord_out = ts->num_out; 221bf215546Sopenharmony_ci if (point_coord_enable) { 222bf215546Sopenharmony_ci if (ts->need_texcoord_semantic) { 223bf215546Sopenharmony_ci for (i = 0, en = point_coord_enable; en; en>>=1, i++) { 224bf215546Sopenharmony_ci if (en & 0x1) { 225bf215546Sopenharmony_ci tgsi_transform_output_decl(ctx, ts->num_out++, 226bf215546Sopenharmony_ci TGSI_SEMANTIC_TEXCOORD, i, 0); 227bf215546Sopenharmony_ci } 228bf215546Sopenharmony_ci } 229bf215546Sopenharmony_ci } else { 230bf215546Sopenharmony_ci for (i = 0, en = point_coord_enable; en; en>>=1, i++) { 231bf215546Sopenharmony_ci if (en & 0x1) { 232bf215546Sopenharmony_ci tgsi_transform_output_decl(ctx, ts->num_out++, 233bf215546Sopenharmony_ci TGSI_SEMANTIC_GENERIC, i, 0); 234bf215546Sopenharmony_ci ts->max_generic = MAX2(ts->max_generic, (int)i); 235bf215546Sopenharmony_ci } 236bf215546Sopenharmony_ci } 237bf215546Sopenharmony_ci } 238bf215546Sopenharmony_ci } 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci /* add an extra generic output for aa point texcoord */ 241bf215546Sopenharmony_ci if (ts->aa_point) { 242bf215546Sopenharmony_ci if (ts->need_texcoord_semantic) { 243bf215546Sopenharmony_ci ts->point_coord_aa = 0; 244bf215546Sopenharmony_ci } else { 245bf215546Sopenharmony_ci ts->point_coord_aa = ts->max_generic + 1; 246bf215546Sopenharmony_ci assert((ts->point_coord_enable & (1 << ts->point_coord_aa)) == 0); 247bf215546Sopenharmony_ci ts->point_coord_enable |= 1 << (ts->point_coord_aa); 248bf215546Sopenharmony_ci tgsi_transform_output_decl(ctx, ts->num_out++, TGSI_SEMANTIC_GENERIC, 249bf215546Sopenharmony_ci ts->point_coord_aa, 0); 250bf215546Sopenharmony_ci } 251bf215546Sopenharmony_ci } 252bf215546Sopenharmony_ci 253bf215546Sopenharmony_ci /* Declare extra immediates */ 254bf215546Sopenharmony_ci ts->point_imm = ts->num_imm; 255bf215546Sopenharmony_ci tgsi_transform_immediate_decl(ctx, 0, 1, 0.5, -1); 256bf215546Sopenharmony_ci 257bf215546Sopenharmony_ci /* Declare point constant - 258bf215546Sopenharmony_ci * constant.xy -- inverseViewport 259bf215546Sopenharmony_ci * constant.z -- current point size 260bf215546Sopenharmony_ci * constant.w -- max point size 261bf215546Sopenharmony_ci * The driver needs to add this constant to the constant buffer 262bf215546Sopenharmony_ci */ 263bf215546Sopenharmony_ci ts->point_ivp = ts->num_const++; 264bf215546Sopenharmony_ci tgsi_transform_const_decl(ctx, ts->point_ivp, ts->point_ivp); 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci /* If this geometry shader does not specify point size, 267bf215546Sopenharmony_ci * get the current point size from the point constant. 268bf215546Sopenharmony_ci */ 269bf215546Sopenharmony_ci if (ts->point_size_out == INVALID_INDEX) { 270bf215546Sopenharmony_ci struct tgsi_full_instruction inst; 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci inst = tgsi_default_full_instruction(); 273bf215546Sopenharmony_ci inst.Instruction.Opcode = TGSI_OPCODE_MOV; 274bf215546Sopenharmony_ci inst.Instruction.NumDstRegs = 1; 275bf215546Sopenharmony_ci tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_TEMPORARY, 276bf215546Sopenharmony_ci ts->point_size_tmp, TGSI_WRITEMASK_XYZW); 277bf215546Sopenharmony_ci inst.Instruction.NumSrcRegs = 1; 278bf215546Sopenharmony_ci tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_CONSTANT, 279bf215546Sopenharmony_ci ts->point_ivp, TGSI_SWIZZLE_Z, 280bf215546Sopenharmony_ci TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z); 281bf215546Sopenharmony_ci ctx->emit_instruction(ctx, &inst); 282bf215546Sopenharmony_ci } 283bf215546Sopenharmony_ci} 284bf215546Sopenharmony_ci 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci/** 287bf215546Sopenharmony_ci * Add the point sprite emulation instructions at the emit vertex instruction 288bf215546Sopenharmony_ci */ 289bf215546Sopenharmony_cistatic void 290bf215546Sopenharmony_cipsprite_emit_vertex_inst(struct tgsi_transform_context *ctx, 291bf215546Sopenharmony_ci struct tgsi_full_instruction *vert_inst) 292bf215546Sopenharmony_ci{ 293bf215546Sopenharmony_ci struct psprite_transform_context *ts = psprite_transform_context(ctx); 294bf215546Sopenharmony_ci struct tgsi_full_instruction inst; 295bf215546Sopenharmony_ci unsigned point_coord_enable, en; 296bf215546Sopenharmony_ci unsigned i, j, s; 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_ci /* new point coord outputs */ 299bf215546Sopenharmony_ci point_coord_enable = ts->point_coord_enable & ~ts->point_coord_decl; 300bf215546Sopenharmony_ci 301bf215546Sopenharmony_ci /* OUTPUT[pos_sout] = TEMP[pos] */ 302bf215546Sopenharmony_ci if (ts->point_pos_sout != INVALID_INDEX) { 303bf215546Sopenharmony_ci tgsi_transform_op1_inst(ctx, TGSI_OPCODE_MOV, 304bf215546Sopenharmony_ci TGSI_FILE_OUTPUT, ts->point_pos_sout, 305bf215546Sopenharmony_ci TGSI_WRITEMASK_XYZW, 306bf215546Sopenharmony_ci TGSI_FILE_TEMPORARY, ts->point_pos_tmp); 307bf215546Sopenharmony_ci } 308bf215546Sopenharmony_ci 309bf215546Sopenharmony_ci /** 310bf215546Sopenharmony_ci * Set up the point scale vector 311bf215546Sopenharmony_ci * scale = pointSize * pos.w * inverseViewport 312bf215546Sopenharmony_ci */ 313bf215546Sopenharmony_ci 314bf215546Sopenharmony_ci /* MUL point_scale.x, point_size.x, point_pos.w */ 315bf215546Sopenharmony_ci tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MUL, 316bf215546Sopenharmony_ci TGSI_FILE_TEMPORARY, ts->point_scale_tmp, TGSI_WRITEMASK_X, 317bf215546Sopenharmony_ci TGSI_FILE_TEMPORARY, ts->point_size_tmp, TGSI_SWIZZLE_X, 318bf215546Sopenharmony_ci TGSI_FILE_TEMPORARY, ts->point_pos_tmp, TGSI_SWIZZLE_W, false); 319bf215546Sopenharmony_ci 320bf215546Sopenharmony_ci /* MUL point_scale.xy, point_scale.xx, inverseViewport.xy */ 321bf215546Sopenharmony_ci inst = tgsi_default_full_instruction(); 322bf215546Sopenharmony_ci inst.Instruction.Opcode = TGSI_OPCODE_MUL; 323bf215546Sopenharmony_ci inst.Instruction.NumDstRegs = 1; 324bf215546Sopenharmony_ci tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_TEMPORARY, 325bf215546Sopenharmony_ci ts->point_scale_tmp, TGSI_WRITEMASK_XY); 326bf215546Sopenharmony_ci inst.Instruction.NumSrcRegs = 2; 327bf215546Sopenharmony_ci tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_TEMPORARY, 328bf215546Sopenharmony_ci ts->point_scale_tmp, TGSI_SWIZZLE_X, 329bf215546Sopenharmony_ci TGSI_SWIZZLE_X, TGSI_SWIZZLE_X, TGSI_SWIZZLE_X); 330bf215546Sopenharmony_ci tgsi_transform_src_reg(&inst.Src[1], TGSI_FILE_CONSTANT, 331bf215546Sopenharmony_ci ts->point_ivp, TGSI_SWIZZLE_X, 332bf215546Sopenharmony_ci TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z); 333bf215546Sopenharmony_ci ctx->emit_instruction(ctx, &inst); 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_ci /** 336bf215546Sopenharmony_ci * Set up the point coord threshold distance 337bf215546Sopenharmony_ci * k = 0.5 - 1 / pointsize 338bf215546Sopenharmony_ci */ 339bf215546Sopenharmony_ci if (ts->aa_point) { 340bf215546Sopenharmony_ci tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_DIV, 341bf215546Sopenharmony_ci TGSI_FILE_TEMPORARY, ts->point_coord_k, 342bf215546Sopenharmony_ci TGSI_WRITEMASK_X, 343bf215546Sopenharmony_ci TGSI_FILE_IMMEDIATE, ts->point_imm, 344bf215546Sopenharmony_ci TGSI_SWIZZLE_Y, 345bf215546Sopenharmony_ci TGSI_FILE_TEMPORARY, ts->point_size_tmp, 346bf215546Sopenharmony_ci TGSI_SWIZZLE_X, false); 347bf215546Sopenharmony_ci 348bf215546Sopenharmony_ci tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_ADD, 349bf215546Sopenharmony_ci TGSI_FILE_TEMPORARY, ts->point_coord_k, 350bf215546Sopenharmony_ci TGSI_WRITEMASK_X, 351bf215546Sopenharmony_ci TGSI_FILE_IMMEDIATE, ts->point_imm, 352bf215546Sopenharmony_ci TGSI_SWIZZLE_Z, 353bf215546Sopenharmony_ci TGSI_FILE_TEMPORARY, ts->point_coord_k, 354bf215546Sopenharmony_ci TGSI_SWIZZLE_X, true); 355bf215546Sopenharmony_ci } 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_ci 358bf215546Sopenharmony_ci for (i = 0; i < 4; i++) { 359bf215546Sopenharmony_ci unsigned point_dir_swz = ts->point_dir_swz[i]; 360bf215546Sopenharmony_ci unsigned point_coord_swz = ts->point_coord_swz[i]; 361bf215546Sopenharmony_ci 362bf215546Sopenharmony_ci /* All outputs need to be emitted for each vertex */ 363bf215546Sopenharmony_ci for (j = 0; j < ts->num_orig_out; j++) { 364bf215546Sopenharmony_ci if (ts->out_tmp_index[j] != INVALID_INDEX) { 365bf215546Sopenharmony_ci tgsi_transform_op1_inst(ctx, TGSI_OPCODE_MOV, 366bf215546Sopenharmony_ci TGSI_FILE_OUTPUT, j, 367bf215546Sopenharmony_ci TGSI_WRITEMASK_XYZW, 368bf215546Sopenharmony_ci TGSI_FILE_TEMPORARY, ts->out_tmp_index[j]); 369bf215546Sopenharmony_ci } 370bf215546Sopenharmony_ci } 371bf215546Sopenharmony_ci 372bf215546Sopenharmony_ci /* pos = point_scale * point_dir + point_pos */ 373bf215546Sopenharmony_ci inst = tgsi_default_full_instruction(); 374bf215546Sopenharmony_ci inst.Instruction.Opcode = TGSI_OPCODE_MAD; 375bf215546Sopenharmony_ci inst.Instruction.NumDstRegs = 1; 376bf215546Sopenharmony_ci tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_OUTPUT, ts->point_pos_out, 377bf215546Sopenharmony_ci TGSI_WRITEMASK_XYZW); 378bf215546Sopenharmony_ci inst.Instruction.NumSrcRegs = 3; 379bf215546Sopenharmony_ci tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_TEMPORARY, ts->point_scale_tmp, 380bf215546Sopenharmony_ci TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y, TGSI_SWIZZLE_X, 381bf215546Sopenharmony_ci TGSI_SWIZZLE_X); 382bf215546Sopenharmony_ci tgsi_transform_src_reg(&inst.Src[1], TGSI_FILE_IMMEDIATE, ts->point_imm, 383bf215546Sopenharmony_ci get_swizzle(point_dir_swz, 0), 384bf215546Sopenharmony_ci get_swizzle(point_dir_swz, 1), 385bf215546Sopenharmony_ci get_swizzle(point_dir_swz, 2), 386bf215546Sopenharmony_ci get_swizzle(point_dir_swz, 3)); 387bf215546Sopenharmony_ci tgsi_transform_src_reg(&inst.Src[2], TGSI_FILE_TEMPORARY, ts->point_pos_tmp, 388bf215546Sopenharmony_ci TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Z, 389bf215546Sopenharmony_ci TGSI_SWIZZLE_W); 390bf215546Sopenharmony_ci ctx->emit_instruction(ctx, &inst); 391bf215546Sopenharmony_ci 392bf215546Sopenharmony_ci /* point coord */ 393bf215546Sopenharmony_ci for (j = 0, s = 0, en = point_coord_enable; en; en>>=1, s++) { 394bf215546Sopenharmony_ci unsigned dstReg; 395bf215546Sopenharmony_ci 396bf215546Sopenharmony_ci if (en & 0x1) { 397bf215546Sopenharmony_ci dstReg = ts->point_coord_out + j; 398bf215546Sopenharmony_ci 399bf215546Sopenharmony_ci inst = tgsi_default_full_instruction(); 400bf215546Sopenharmony_ci inst.Instruction.Opcode = TGSI_OPCODE_MOV; 401bf215546Sopenharmony_ci inst.Instruction.NumDstRegs = 1; 402bf215546Sopenharmony_ci tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_OUTPUT, 403bf215546Sopenharmony_ci dstReg, TGSI_WRITEMASK_XYZW); 404bf215546Sopenharmony_ci inst.Instruction.NumSrcRegs = 1; 405bf215546Sopenharmony_ci tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_IMMEDIATE, ts->point_imm, 406bf215546Sopenharmony_ci get_swizzle(point_coord_swz, 0), 407bf215546Sopenharmony_ci get_swizzle(point_coord_swz, 1), 408bf215546Sopenharmony_ci get_swizzle(point_coord_swz, 2), 409bf215546Sopenharmony_ci get_swizzle(point_coord_swz, 3)); 410bf215546Sopenharmony_ci ctx->emit_instruction(ctx, &inst); 411bf215546Sopenharmony_ci 412bf215546Sopenharmony_ci /* MOV point_coord.z point_coord_k.x */ 413bf215546Sopenharmony_ci if (s == ts->point_coord_aa) { 414bf215546Sopenharmony_ci tgsi_transform_op1_swz_inst(ctx, TGSI_OPCODE_MOV, 415bf215546Sopenharmony_ci TGSI_FILE_OUTPUT, dstReg, TGSI_WRITEMASK_Z, 416bf215546Sopenharmony_ci TGSI_FILE_TEMPORARY, ts->point_coord_k, 417bf215546Sopenharmony_ci TGSI_SWIZZLE_X); 418bf215546Sopenharmony_ci } 419bf215546Sopenharmony_ci j++; /* the next point coord output offset */ 420bf215546Sopenharmony_ci } 421bf215546Sopenharmony_ci } 422bf215546Sopenharmony_ci 423bf215546Sopenharmony_ci /* Emit the EMIT instruction for each vertex of the quad */ 424bf215546Sopenharmony_ci ctx->emit_instruction(ctx, vert_inst); 425bf215546Sopenharmony_ci } 426bf215546Sopenharmony_ci 427bf215546Sopenharmony_ci /* Emit the ENDPRIM instruction for the quad */ 428bf215546Sopenharmony_ci inst = tgsi_default_full_instruction(); 429bf215546Sopenharmony_ci inst.Instruction.Opcode = TGSI_OPCODE_ENDPRIM; 430bf215546Sopenharmony_ci inst.Instruction.NumDstRegs = 0; 431bf215546Sopenharmony_ci inst.Instruction.NumSrcRegs = 1; 432bf215546Sopenharmony_ci inst.Src[0] = vert_inst->Src[0]; 433bf215546Sopenharmony_ci ctx->emit_instruction(ctx, &inst); 434bf215546Sopenharmony_ci} 435bf215546Sopenharmony_ci 436bf215546Sopenharmony_ci 437bf215546Sopenharmony_ci/** 438bf215546Sopenharmony_ci * TGSI instruction transform callback. 439bf215546Sopenharmony_ci */ 440bf215546Sopenharmony_cistatic void 441bf215546Sopenharmony_cipsprite_inst(struct tgsi_transform_context *ctx, 442bf215546Sopenharmony_ci struct tgsi_full_instruction *inst) 443bf215546Sopenharmony_ci{ 444bf215546Sopenharmony_ci struct psprite_transform_context *ts = psprite_transform_context(ctx); 445bf215546Sopenharmony_ci 446bf215546Sopenharmony_ci if (inst->Instruction.Opcode == TGSI_OPCODE_EMIT) { 447bf215546Sopenharmony_ci psprite_emit_vertex_inst(ctx, inst); 448bf215546Sopenharmony_ci } 449bf215546Sopenharmony_ci else if (inst->Dst[0].Register.File == TGSI_FILE_OUTPUT && 450bf215546Sopenharmony_ci inst->Dst[0].Register.Index == (int)ts->point_size_out) { 451bf215546Sopenharmony_ci /** 452bf215546Sopenharmony_ci * Replace point size output reg with tmp reg. 453bf215546Sopenharmony_ci * The tmp reg will be later used as a src reg for computing 454bf215546Sopenharmony_ci * the point scale factor. 455bf215546Sopenharmony_ci */ 456bf215546Sopenharmony_ci inst->Dst[0].Register.File = TGSI_FILE_TEMPORARY; 457bf215546Sopenharmony_ci inst->Dst[0].Register.Index = ts->point_size_tmp; 458bf215546Sopenharmony_ci ctx->emit_instruction(ctx, inst); 459bf215546Sopenharmony_ci 460bf215546Sopenharmony_ci /* Clamp the point size */ 461bf215546Sopenharmony_ci /* MAX point_size_tmp.x, point_size_tmp.x, point_imm.y */ 462bf215546Sopenharmony_ci tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MAX, 463bf215546Sopenharmony_ci TGSI_FILE_TEMPORARY, ts->point_size_tmp, TGSI_WRITEMASK_X, 464bf215546Sopenharmony_ci TGSI_FILE_TEMPORARY, ts->point_size_tmp, TGSI_SWIZZLE_X, 465bf215546Sopenharmony_ci TGSI_FILE_IMMEDIATE, ts->point_imm, TGSI_SWIZZLE_Y, false); 466bf215546Sopenharmony_ci 467bf215546Sopenharmony_ci /* MIN point_size_tmp.x, point_size_tmp.x, point_ivp.w */ 468bf215546Sopenharmony_ci tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MIN, 469bf215546Sopenharmony_ci TGSI_FILE_TEMPORARY, ts->point_size_tmp, TGSI_WRITEMASK_X, 470bf215546Sopenharmony_ci TGSI_FILE_TEMPORARY, ts->point_size_tmp, TGSI_SWIZZLE_X, 471bf215546Sopenharmony_ci TGSI_FILE_CONSTANT, ts->point_ivp, TGSI_SWIZZLE_W, false); 472bf215546Sopenharmony_ci } 473bf215546Sopenharmony_ci else if (inst->Dst[0].Register.File == TGSI_FILE_OUTPUT && 474bf215546Sopenharmony_ci inst->Dst[0].Register.Index == (int)ts->point_pos_out) { 475bf215546Sopenharmony_ci /** 476bf215546Sopenharmony_ci * Replace point pos output reg with tmp reg. 477bf215546Sopenharmony_ci */ 478bf215546Sopenharmony_ci inst->Dst[0].Register.File = TGSI_FILE_TEMPORARY; 479bf215546Sopenharmony_ci inst->Dst[0].Register.Index = ts->point_pos_tmp; 480bf215546Sopenharmony_ci ctx->emit_instruction(ctx, inst); 481bf215546Sopenharmony_ci } 482bf215546Sopenharmony_ci else if (inst->Dst[0].Register.File == TGSI_FILE_OUTPUT) { 483bf215546Sopenharmony_ci /** 484bf215546Sopenharmony_ci * Replace output reg with tmp reg. 485bf215546Sopenharmony_ci */ 486bf215546Sopenharmony_ci inst->Dst[0].Register.File = TGSI_FILE_TEMPORARY; 487bf215546Sopenharmony_ci inst->Dst[0].Register.Index = ts->out_tmp_index[inst->Dst[0].Register.Index]; 488bf215546Sopenharmony_ci ctx->emit_instruction(ctx, inst); 489bf215546Sopenharmony_ci } 490bf215546Sopenharmony_ci else { 491bf215546Sopenharmony_ci ctx->emit_instruction(ctx, inst); 492bf215546Sopenharmony_ci } 493bf215546Sopenharmony_ci} 494bf215546Sopenharmony_ci 495bf215546Sopenharmony_ci 496bf215546Sopenharmony_ci/** 497bf215546Sopenharmony_ci * TGSI property instruction transform callback. 498bf215546Sopenharmony_ci * Transforms a point into a 4-vertex triangle strip. 499bf215546Sopenharmony_ci */ 500bf215546Sopenharmony_cistatic void 501bf215546Sopenharmony_cipsprite_property(struct tgsi_transform_context *ctx, 502bf215546Sopenharmony_ci struct tgsi_full_property *prop) 503bf215546Sopenharmony_ci{ 504bf215546Sopenharmony_ci switch (prop->Property.PropertyName) { 505bf215546Sopenharmony_ci case TGSI_PROPERTY_GS_OUTPUT_PRIM: 506bf215546Sopenharmony_ci prop->u[0].Data = PIPE_PRIM_TRIANGLE_STRIP; 507bf215546Sopenharmony_ci break; 508bf215546Sopenharmony_ci case TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES: 509bf215546Sopenharmony_ci prop->u[0].Data *= 4; 510bf215546Sopenharmony_ci break; 511bf215546Sopenharmony_ci default: 512bf215546Sopenharmony_ci break; 513bf215546Sopenharmony_ci } 514bf215546Sopenharmony_ci ctx->emit_property(ctx, prop); 515bf215546Sopenharmony_ci} 516bf215546Sopenharmony_ci 517bf215546Sopenharmony_ci/** 518bf215546Sopenharmony_ci * TGSI utility to transform a geometry shader to support point sprite. 519bf215546Sopenharmony_ci */ 520bf215546Sopenharmony_cistruct tgsi_token * 521bf215546Sopenharmony_citgsi_add_point_sprite(const struct tgsi_token *tokens_in, 522bf215546Sopenharmony_ci const unsigned point_coord_enable, 523bf215546Sopenharmony_ci const bool sprite_origin_lower_left, 524bf215546Sopenharmony_ci const bool stream_out_point_pos, 525bf215546Sopenharmony_ci const bool need_texcoord_semantic, 526bf215546Sopenharmony_ci int *aa_point_coord_index) 527bf215546Sopenharmony_ci{ 528bf215546Sopenharmony_ci struct psprite_transform_context transform; 529bf215546Sopenharmony_ci const uint num_new_tokens = 200; /* should be enough */ 530bf215546Sopenharmony_ci const uint new_len = tgsi_num_tokens(tokens_in) + num_new_tokens; 531bf215546Sopenharmony_ci struct tgsi_token *new_tokens; 532bf215546Sopenharmony_ci 533bf215546Sopenharmony_ci /* setup transformation context */ 534bf215546Sopenharmony_ci memset(&transform, 0, sizeof(transform)); 535bf215546Sopenharmony_ci transform.base.transform_declaration = psprite_decl; 536bf215546Sopenharmony_ci transform.base.transform_instruction = psprite_inst; 537bf215546Sopenharmony_ci transform.base.transform_property = psprite_property; 538bf215546Sopenharmony_ci transform.base.transform_immediate = psprite_immediate; 539bf215546Sopenharmony_ci transform.base.prolog = psprite_prolog; 540bf215546Sopenharmony_ci 541bf215546Sopenharmony_ci transform.point_size_in = INVALID_INDEX; 542bf215546Sopenharmony_ci transform.point_size_out = INVALID_INDEX; 543bf215546Sopenharmony_ci transform.point_size_tmp = INVALID_INDEX; 544bf215546Sopenharmony_ci transform.point_pos_in = INVALID_INDEX; 545bf215546Sopenharmony_ci transform.point_pos_out = INVALID_INDEX; 546bf215546Sopenharmony_ci transform.point_pos_sout = INVALID_INDEX; 547bf215546Sopenharmony_ci transform.point_pos_tmp = INVALID_INDEX; 548bf215546Sopenharmony_ci transform.point_scale_tmp = INVALID_INDEX; 549bf215546Sopenharmony_ci transform.point_imm = INVALID_INDEX; 550bf215546Sopenharmony_ci transform.point_coord_aa = INVALID_INDEX; 551bf215546Sopenharmony_ci transform.point_coord_k = INVALID_INDEX; 552bf215546Sopenharmony_ci 553bf215546Sopenharmony_ci transform.stream_out_point_pos = stream_out_point_pos; 554bf215546Sopenharmony_ci transform.point_coord_enable = point_coord_enable; 555bf215546Sopenharmony_ci transform.aa_point = aa_point_coord_index != NULL; 556bf215546Sopenharmony_ci transform.need_texcoord_semantic = need_texcoord_semantic; 557bf215546Sopenharmony_ci transform.max_generic = -1; 558bf215546Sopenharmony_ci 559bf215546Sopenharmony_ci /* point sprite directions based on the immediates (0, 1, 0.5, -1) */ 560bf215546Sopenharmony_ci /* (-1, -1, 0, 0) */ 561bf215546Sopenharmony_ci transform.point_dir_swz[0] = set_swizzle(-1, -1, 0, 0); 562bf215546Sopenharmony_ci /* (-1, 1, 0, 0) */ 563bf215546Sopenharmony_ci transform.point_dir_swz[1] = set_swizzle(-1, 1, 0, 0); 564bf215546Sopenharmony_ci /* (1, -1, 0, 0) */ 565bf215546Sopenharmony_ci transform.point_dir_swz[2] = set_swizzle(1, -1, 0, 0); 566bf215546Sopenharmony_ci /* (1, 1, 0, 0) */ 567bf215546Sopenharmony_ci transform.point_dir_swz[3] = set_swizzle(1, 1, 0, 0); 568bf215546Sopenharmony_ci 569bf215546Sopenharmony_ci /* point coord based on the immediates (0, 1, 0, -1) */ 570bf215546Sopenharmony_ci if (sprite_origin_lower_left) { 571bf215546Sopenharmony_ci /* (0, 0, 0, 1) */ 572bf215546Sopenharmony_ci transform.point_coord_swz[0] = set_swizzle(0, 0, 0, 1); 573bf215546Sopenharmony_ci /* (0, 1, 0, 1) */ 574bf215546Sopenharmony_ci transform.point_coord_swz[1] = set_swizzle(0, 1, 0, 1); 575bf215546Sopenharmony_ci /* (1, 0, 0, 1) */ 576bf215546Sopenharmony_ci transform.point_coord_swz[2] = set_swizzle(1, 0, 0, 1); 577bf215546Sopenharmony_ci /* (1, 1, 0, 1) */ 578bf215546Sopenharmony_ci transform.point_coord_swz[3] = set_swizzle(1, 1, 0, 1); 579bf215546Sopenharmony_ci } 580bf215546Sopenharmony_ci else { 581bf215546Sopenharmony_ci /* (0, 1, 0, 1) */ 582bf215546Sopenharmony_ci transform.point_coord_swz[0] = set_swizzle(0, 1, 0, 1); 583bf215546Sopenharmony_ci /* (0, 0, 0, 1) */ 584bf215546Sopenharmony_ci transform.point_coord_swz[1] = set_swizzle(0, 0, 0, 1); 585bf215546Sopenharmony_ci /* (1, 1, 0, 1) */ 586bf215546Sopenharmony_ci transform.point_coord_swz[2] = set_swizzle(1, 1, 0, 1); 587bf215546Sopenharmony_ci /* (1, 0, 0, 1) */ 588bf215546Sopenharmony_ci transform.point_coord_swz[3] = set_swizzle(1, 0, 0, 1); 589bf215546Sopenharmony_ci } 590bf215546Sopenharmony_ci 591bf215546Sopenharmony_ci 592bf215546Sopenharmony_ci new_tokens = tgsi_transform_shader(tokens_in, new_len, &transform.base); 593bf215546Sopenharmony_ci 594bf215546Sopenharmony_ci if (aa_point_coord_index) 595bf215546Sopenharmony_ci *aa_point_coord_index = transform.point_coord_aa; 596bf215546Sopenharmony_ci 597bf215546Sopenharmony_ci return new_tokens; 598bf215546Sopenharmony_ci} 599