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