101e04c3fSmrg/*
201e04c3fSmrg * Copyright (C) 2015 Advanced Micro Devices, Inc.
301e04c3fSmrg * All Rights Reserved.
401e04c3fSmrg *
501e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
601e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
701e04c3fSmrg * to deal in the Software without restriction, including without limitation
801e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
901e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
1001e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1101e04c3fSmrg *
1201e04c3fSmrg * The above copyright notice and this permission notice (including the next
1301e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1401e04c3fSmrg * Software.
1501e04c3fSmrg *
1601e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1701e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1801e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1901e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2001e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2101e04c3fSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2201e04c3fSmrg * SOFTWARE.
2301e04c3fSmrg *
2401e04c3fSmrg */
2501e04c3fSmrg
2601e04c3fSmrg#include "tgsi/tgsi_transform.h"
2701e04c3fSmrg#include "tgsi/tgsi_scan.h"
2801e04c3fSmrg#include "tgsi/tgsi_dump.h"
2901e04c3fSmrg#include "util/u_debug.h"
3001e04c3fSmrg
3101e04c3fSmrg#include "tgsi_emulate.h"
3201e04c3fSmrg
3301e04c3fSmrgstruct tgsi_emulation_context {
3401e04c3fSmrg   struct tgsi_transform_context base;
3501e04c3fSmrg   struct tgsi_shader_info info;
3601e04c3fSmrg   unsigned flags;
3701e04c3fSmrg   bool first_instruction_emitted;
3801e04c3fSmrg};
3901e04c3fSmrg
4001e04c3fSmrgstatic inline struct tgsi_emulation_context *
4101e04c3fSmrgtgsi_emulation_context(struct tgsi_transform_context *tctx)
4201e04c3fSmrg{
4301e04c3fSmrg   return (struct tgsi_emulation_context *)tctx;
4401e04c3fSmrg}
4501e04c3fSmrg
4601e04c3fSmrgstatic void
4701e04c3fSmrgtransform_decl(struct tgsi_transform_context *tctx,
4801e04c3fSmrg               struct tgsi_full_declaration *decl)
4901e04c3fSmrg{
5001e04c3fSmrg   struct tgsi_emulation_context *ctx = tgsi_emulation_context(tctx);
5101e04c3fSmrg
5201e04c3fSmrg   if (ctx->flags & TGSI_EMU_FORCE_PERSAMPLE_INTERP &&
5301e04c3fSmrg       decl->Declaration.File == TGSI_FILE_INPUT) {
5401e04c3fSmrg      assert(decl->Declaration.Interpolate);
5501e04c3fSmrg      decl->Interp.Location = TGSI_INTERPOLATE_LOC_SAMPLE;
5601e04c3fSmrg   }
5701e04c3fSmrg
5801e04c3fSmrg   tctx->emit_declaration(tctx, decl);
5901e04c3fSmrg}
6001e04c3fSmrg
6101e04c3fSmrgstatic void
6201e04c3fSmrgpassthrough_edgeflag(struct tgsi_transform_context *tctx)
6301e04c3fSmrg{
6401e04c3fSmrg   struct tgsi_emulation_context *ctx = tgsi_emulation_context(tctx);
6501e04c3fSmrg   struct tgsi_full_declaration decl;
6601e04c3fSmrg   struct tgsi_full_instruction new_inst;
6701e04c3fSmrg
6801e04c3fSmrg   /* Input */
6901e04c3fSmrg   decl = tgsi_default_full_declaration();
7001e04c3fSmrg   decl.Declaration.File = TGSI_FILE_INPUT;
7101e04c3fSmrg   decl.Range.First = decl.Range.Last = ctx->info.num_inputs;
7201e04c3fSmrg   tctx->emit_declaration(tctx, &decl);
7301e04c3fSmrg
7401e04c3fSmrg   /* Output */
7501e04c3fSmrg   decl = tgsi_default_full_declaration();
7601e04c3fSmrg   decl.Declaration.File = TGSI_FILE_OUTPUT;
7701e04c3fSmrg   decl.Declaration.Semantic = true;
7801e04c3fSmrg   decl.Range.First = decl.Range.Last = ctx->info.num_outputs;
7901e04c3fSmrg   decl.Semantic.Name = TGSI_SEMANTIC_EDGEFLAG;
8001e04c3fSmrg   decl.Semantic.Index = 0;
8101e04c3fSmrg   tctx->emit_declaration(tctx, &decl);
8201e04c3fSmrg
8301e04c3fSmrg   /* MOV */
8401e04c3fSmrg   new_inst = tgsi_default_full_instruction();
8501e04c3fSmrg   new_inst.Instruction.Opcode = TGSI_OPCODE_MOV;
8601e04c3fSmrg
8701e04c3fSmrg   new_inst.Instruction.NumDstRegs = 1;
8801e04c3fSmrg   new_inst.Dst[0].Register.File  = TGSI_FILE_OUTPUT;
8901e04c3fSmrg   new_inst.Dst[0].Register.Index = ctx->info.num_outputs;
9001e04c3fSmrg   new_inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZW;
9101e04c3fSmrg
9201e04c3fSmrg   new_inst.Instruction.NumSrcRegs = 1;
9301e04c3fSmrg   new_inst.Src[0].Register.File  = TGSI_FILE_INPUT;
9401e04c3fSmrg   new_inst.Src[0].Register.Index = ctx->info.num_inputs;
9501e04c3fSmrg   new_inst.Src[0].Register.SwizzleX = TGSI_SWIZZLE_X;
9601e04c3fSmrg   new_inst.Src[0].Register.SwizzleY = TGSI_SWIZZLE_X;
9701e04c3fSmrg   new_inst.Src[0].Register.SwizzleZ = TGSI_SWIZZLE_X;
9801e04c3fSmrg   new_inst.Src[0].Register.SwizzleW = TGSI_SWIZZLE_X;
9901e04c3fSmrg
10001e04c3fSmrg   tctx->emit_instruction(tctx, &new_inst);
10101e04c3fSmrg}
10201e04c3fSmrg
10301e04c3fSmrgstatic void
10401e04c3fSmrgtransform_instr(struct tgsi_transform_context *tctx,
10501e04c3fSmrg                struct tgsi_full_instruction *inst)
10601e04c3fSmrg{
10701e04c3fSmrg   struct tgsi_emulation_context *ctx = tgsi_emulation_context(tctx);
10801e04c3fSmrg
10901e04c3fSmrg   /* Pass through edgeflags. */
11001e04c3fSmrg   if (!ctx->first_instruction_emitted) {
11101e04c3fSmrg      ctx->first_instruction_emitted = true;
11201e04c3fSmrg
11301e04c3fSmrg      if (ctx->flags & TGSI_EMU_PASSTHROUGH_EDGEFLAG)
11401e04c3fSmrg         passthrough_edgeflag(tctx);
11501e04c3fSmrg   }
11601e04c3fSmrg
11701e04c3fSmrg   /* Clamp color outputs. */
11801e04c3fSmrg   if (ctx->flags & TGSI_EMU_CLAMP_COLOR_OUTPUTS) {
11901e04c3fSmrg      int i;
12001e04c3fSmrg      for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
12101e04c3fSmrg         unsigned semantic;
12201e04c3fSmrg
12301e04c3fSmrg         if (inst->Dst[i].Register.File != TGSI_FILE_OUTPUT ||
12401e04c3fSmrg             inst->Dst[i].Register.Indirect)
12501e04c3fSmrg            continue;
12601e04c3fSmrg
12701e04c3fSmrg         semantic =
12801e04c3fSmrg            ctx->info.output_semantic_name[inst->Dst[i].Register.Index];
12901e04c3fSmrg
13001e04c3fSmrg         if (semantic == TGSI_SEMANTIC_COLOR ||
13101e04c3fSmrg             semantic == TGSI_SEMANTIC_BCOLOR)
13201e04c3fSmrg            inst->Instruction.Saturate = true;
13301e04c3fSmrg      }
13401e04c3fSmrg   }
13501e04c3fSmrg
13601e04c3fSmrg   tctx->emit_instruction(tctx, inst);
13701e04c3fSmrg}
13801e04c3fSmrg
13901e04c3fSmrgconst struct tgsi_token *
14001e04c3fSmrgtgsi_emulate(const struct tgsi_token *tokens, unsigned flags)
14101e04c3fSmrg{
14201e04c3fSmrg   struct tgsi_emulation_context ctx;
14301e04c3fSmrg   struct tgsi_token *newtoks;
14401e04c3fSmrg   int newlen;
14501e04c3fSmrg
14601e04c3fSmrg   if (!(flags & (TGSI_EMU_CLAMP_COLOR_OUTPUTS |
14701e04c3fSmrg                  TGSI_EMU_PASSTHROUGH_EDGEFLAG |
14801e04c3fSmrg                  TGSI_EMU_FORCE_PERSAMPLE_INTERP)))
14901e04c3fSmrg      return NULL;
15001e04c3fSmrg
15101e04c3fSmrg   memset(&ctx, 0, sizeof(ctx));
15201e04c3fSmrg   ctx.flags = flags;
15301e04c3fSmrg   tgsi_scan_shader(tokens, &ctx.info);
15401e04c3fSmrg
15501e04c3fSmrg   if (flags & TGSI_EMU_FORCE_PERSAMPLE_INTERP)
15601e04c3fSmrg      ctx.base.transform_declaration = transform_decl;
15701e04c3fSmrg
15801e04c3fSmrg   if (flags & (TGSI_EMU_CLAMP_COLOR_OUTPUTS |
15901e04c3fSmrg                TGSI_EMU_PASSTHROUGH_EDGEFLAG))
16001e04c3fSmrg      ctx.base.transform_instruction = transform_instr;
16101e04c3fSmrg
16201e04c3fSmrg   newlen = tgsi_num_tokens(tokens) + 20;
16301e04c3fSmrg   newtoks = tgsi_alloc_tokens(newlen);
16401e04c3fSmrg   if (!newtoks)
16501e04c3fSmrg      return NULL;
16601e04c3fSmrg
16701e04c3fSmrg   tgsi_transform_shader(tokens, newtoks, newlen, &ctx.base);
16801e04c3fSmrg   return newtoks;
16901e04c3fSmrg}
170