• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 Advanced Micro Devices, Inc.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  */
25 
26 #include "tgsi/tgsi_transform.h"
27 #include "tgsi/tgsi_scan.h"
28 #include "tgsi/tgsi_dump.h"
29 #include "util/u_debug.h"
30 
31 #include "tgsi_emulate.h"
32 
33 struct tgsi_emulation_context {
34    struct tgsi_transform_context base;
35    struct tgsi_shader_info info;
36    unsigned flags;
37    bool first_instruction_emitted;
38 };
39 
40 static inline struct tgsi_emulation_context *
tgsi_emulation_context(struct tgsi_transform_context * tctx)41 tgsi_emulation_context(struct tgsi_transform_context *tctx)
42 {
43    return (struct tgsi_emulation_context *)tctx;
44 }
45 
46 static void
transform_decl(struct tgsi_transform_context * tctx,struct tgsi_full_declaration * decl)47 transform_decl(struct tgsi_transform_context *tctx,
48                struct tgsi_full_declaration *decl)
49 {
50    struct tgsi_emulation_context *ctx = tgsi_emulation_context(tctx);
51 
52    if (ctx->flags & TGSI_EMU_FORCE_PERSAMPLE_INTERP &&
53        decl->Declaration.File == TGSI_FILE_INPUT) {
54       assert(decl->Declaration.Interpolate);
55       decl->Interp.Location = TGSI_INTERPOLATE_LOC_SAMPLE;
56    }
57 
58    tctx->emit_declaration(tctx, decl);
59 }
60 
61 static void
passthrough_edgeflag(struct tgsi_transform_context * tctx)62 passthrough_edgeflag(struct tgsi_transform_context *tctx)
63 {
64    struct tgsi_emulation_context *ctx = tgsi_emulation_context(tctx);
65    struct tgsi_full_declaration decl;
66    struct tgsi_full_instruction new_inst;
67 
68    /* Input */
69    decl = tgsi_default_full_declaration();
70    decl.Declaration.File = TGSI_FILE_INPUT;
71    decl.Range.First = decl.Range.Last = ctx->info.num_inputs;
72    tctx->emit_declaration(tctx, &decl);
73 
74    /* Output */
75    decl = tgsi_default_full_declaration();
76    decl.Declaration.File = TGSI_FILE_OUTPUT;
77    decl.Declaration.Semantic = true;
78    decl.Range.First = decl.Range.Last = ctx->info.num_outputs;
79    decl.Semantic.Name = TGSI_SEMANTIC_EDGEFLAG;
80    decl.Semantic.Index = 0;
81    tctx->emit_declaration(tctx, &decl);
82 
83    /* MOV */
84    new_inst = tgsi_default_full_instruction();
85    new_inst.Instruction.Opcode = TGSI_OPCODE_MOV;
86 
87    new_inst.Instruction.NumDstRegs = 1;
88    new_inst.Dst[0].Register.File  = TGSI_FILE_OUTPUT;
89    new_inst.Dst[0].Register.Index = ctx->info.num_outputs;
90    new_inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZW;
91 
92    new_inst.Instruction.NumSrcRegs = 1;
93    new_inst.Src[0].Register.File  = TGSI_FILE_INPUT;
94    new_inst.Src[0].Register.Index = ctx->info.num_inputs;
95    new_inst.Src[0].Register.SwizzleX = TGSI_SWIZZLE_X;
96    new_inst.Src[0].Register.SwizzleY = TGSI_SWIZZLE_X;
97    new_inst.Src[0].Register.SwizzleZ = TGSI_SWIZZLE_X;
98    new_inst.Src[0].Register.SwizzleW = TGSI_SWIZZLE_X;
99 
100    tctx->emit_instruction(tctx, &new_inst);
101 }
102 
103 static void
transform_instr(struct tgsi_transform_context * tctx,struct tgsi_full_instruction * inst)104 transform_instr(struct tgsi_transform_context *tctx,
105                 struct tgsi_full_instruction *inst)
106 {
107    struct tgsi_emulation_context *ctx = tgsi_emulation_context(tctx);
108 
109    /* Pass through edgeflags. */
110    if (!ctx->first_instruction_emitted) {
111       ctx->first_instruction_emitted = true;
112 
113       if (ctx->flags & TGSI_EMU_PASSTHROUGH_EDGEFLAG)
114          passthrough_edgeflag(tctx);
115    }
116 
117    /* Clamp color outputs. */
118    if (ctx->flags & TGSI_EMU_CLAMP_COLOR_OUTPUTS) {
119       int i;
120       for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
121          unsigned semantic;
122 
123          if (inst->Dst[i].Register.File != TGSI_FILE_OUTPUT ||
124              inst->Dst[i].Register.Indirect)
125             continue;
126 
127          semantic =
128             ctx->info.output_semantic_name[inst->Dst[i].Register.Index];
129 
130          if (semantic == TGSI_SEMANTIC_COLOR ||
131              semantic == TGSI_SEMANTIC_BCOLOR)
132             inst->Instruction.Saturate = true;
133       }
134    }
135 
136    tctx->emit_instruction(tctx, inst);
137 }
138 
139 const struct tgsi_token *
tgsi_emulate(const struct tgsi_token * tokens,unsigned flags)140 tgsi_emulate(const struct tgsi_token *tokens, unsigned flags)
141 {
142    struct tgsi_emulation_context ctx;
143    struct tgsi_token *newtoks;
144    int newlen;
145 
146    if (!(flags & (TGSI_EMU_CLAMP_COLOR_OUTPUTS |
147                   TGSI_EMU_PASSTHROUGH_EDGEFLAG |
148                   TGSI_EMU_FORCE_PERSAMPLE_INTERP)))
149       return NULL;
150 
151    memset(&ctx, 0, sizeof(ctx));
152    ctx.flags = flags;
153    tgsi_scan_shader(tokens, &ctx.info);
154 
155    if (flags & TGSI_EMU_FORCE_PERSAMPLE_INTERP)
156       ctx.base.transform_declaration = transform_decl;
157 
158    if (flags & (TGSI_EMU_CLAMP_COLOR_OUTPUTS |
159                 TGSI_EMU_PASSTHROUGH_EDGEFLAG))
160       ctx.base.transform_instruction = transform_instr;
161 
162    newlen = tgsi_num_tokens(tokens) + 20;
163    newtoks = tgsi_alloc_tokens(newlen);
164    if (!newtoks)
165       return NULL;
166 
167    tgsi_transform_shader(tokens, newtoks, newlen, &ctx.base);
168    return newtoks;
169 }
170