Path: blob/21.2-virgl/src/gallium/auxiliary/tgsi/tgsi_transform.c
4565 views
/**************************************************************************1*2* Copyright 2008 VMware, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/2627/**28* TGSI program transformation utility.29*30* Authors: Brian Paul31*/3233#include "util/u_debug.h"3435#include "tgsi_transform.h"36373839static void40emit_instruction(struct tgsi_transform_context *ctx,41const struct tgsi_full_instruction *inst)42{43uint ti = ctx->ti;4445ti += tgsi_build_full_instruction(inst,46ctx->tokens_out + ti,47ctx->header,48ctx->max_tokens_out - ti);49ctx->ti = ti;50}515253static void54emit_declaration(struct tgsi_transform_context *ctx,55const struct tgsi_full_declaration *decl)56{57uint ti = ctx->ti;5859ti += tgsi_build_full_declaration(decl,60ctx->tokens_out + ti,61ctx->header,62ctx->max_tokens_out - ti);63ctx->ti = ti;64}656667static void68emit_immediate(struct tgsi_transform_context *ctx,69const struct tgsi_full_immediate *imm)70{71uint ti = ctx->ti;7273ti += tgsi_build_full_immediate(imm,74ctx->tokens_out + ti,75ctx->header,76ctx->max_tokens_out - ti);77ctx->ti = ti;78}798081static void82emit_property(struct tgsi_transform_context *ctx,83const struct tgsi_full_property *prop)84{85uint ti = ctx->ti;8687ti += tgsi_build_full_property(prop,88ctx->tokens_out + ti,89ctx->header,90ctx->max_tokens_out - ti);91ctx->ti = ti;92}939495/**96* Apply user-defined transformations to the input shader to produce97* the output shader.98* For example, a register search-and-replace operation could be applied99* by defining a transform_instruction() callback that examined and changed100* the instruction src/dest regs.101*102* \return number of tokens emitted103*/104int105tgsi_transform_shader(const struct tgsi_token *tokens_in,106struct tgsi_token *tokens_out,107uint max_tokens_out,108struct tgsi_transform_context *ctx)109{110uint procType;111boolean first_instruction = TRUE;112boolean epilog_emitted = FALSE;113int cond_stack = 0;114int call_stack = 0;115116/* input shader */117struct tgsi_parse_context parse;118119/* output shader */120struct tgsi_processor *processor;121122123/**124** callback context init125**/126ctx->emit_instruction = emit_instruction;127ctx->emit_declaration = emit_declaration;128ctx->emit_immediate = emit_immediate;129ctx->emit_property = emit_property;130ctx->tokens_out = tokens_out;131ctx->max_tokens_out = max_tokens_out;132133134/**135** Setup to begin parsing input shader136**/137if (tgsi_parse_init( &parse, tokens_in ) != TGSI_PARSE_OK) {138debug_printf("tgsi_parse_init() failed in tgsi_transform_shader()!\n");139return -1;140}141procType = parse.FullHeader.Processor.Processor;142143/**144** Setup output shader145**/146ctx->header = (struct tgsi_header *)tokens_out;147*ctx->header = tgsi_build_header();148149processor = (struct tgsi_processor *) (tokens_out + 1);150*processor = tgsi_build_processor( procType, ctx->header );151152ctx->ti = 2;153154155/**156** Loop over incoming program tokens/instructions157*/158while( !tgsi_parse_end_of_tokens( &parse ) ) {159160tgsi_parse_token( &parse );161162switch( parse.FullToken.Token.Type ) {163case TGSI_TOKEN_TYPE_INSTRUCTION:164{165struct tgsi_full_instruction *fullinst166= &parse.FullToken.FullInstruction;167enum tgsi_opcode opcode = fullinst->Instruction.Opcode;168169if (first_instruction && ctx->prolog) {170ctx->prolog(ctx);171}172173/*174* XXX Note: we handle the case of ret in main.175* However, the output redirections done by transform176* have their limits with control flow and will generally177* not work correctly. e.g.178* if (cond) {179* oColor = x;180* ret;181* }182* oColor = y;183* end;184* If the color output is redirected to a temp and modified185* by a transform, this will not work (the oColor assignment186* in the conditional will never make it to the actual output).187*/188if ((opcode == TGSI_OPCODE_END || opcode == TGSI_OPCODE_RET) &&189call_stack == 0 && ctx->epilog && !epilog_emitted) {190if (opcode == TGSI_OPCODE_RET && cond_stack != 0) {191assert(!"transform ignoring RET in main");192} else {193assert(cond_stack == 0);194/* Emit caller's epilog */195ctx->epilog(ctx);196epilog_emitted = TRUE;197}198/* Emit END (or RET) */199ctx->emit_instruction(ctx, fullinst);200}201else {202switch (opcode) {203case TGSI_OPCODE_IF:204case TGSI_OPCODE_UIF:205case TGSI_OPCODE_SWITCH:206case TGSI_OPCODE_BGNLOOP:207cond_stack++;208break;209case TGSI_OPCODE_CAL:210call_stack++;211break;212case TGSI_OPCODE_ENDIF:213case TGSI_OPCODE_ENDSWITCH:214case TGSI_OPCODE_ENDLOOP:215assert(cond_stack > 0);216cond_stack--;217break;218case TGSI_OPCODE_ENDSUB:219assert(call_stack > 0);220call_stack--;221break;222case TGSI_OPCODE_BGNSUB:223case TGSI_OPCODE_RET:224default:225break;226}227if (ctx->transform_instruction)228ctx->transform_instruction(ctx, fullinst);229else230ctx->emit_instruction(ctx, fullinst);231}232233first_instruction = FALSE;234}235break;236237case TGSI_TOKEN_TYPE_DECLARATION:238{239struct tgsi_full_declaration *fulldecl240= &parse.FullToken.FullDeclaration;241242if (ctx->transform_declaration)243ctx->transform_declaration(ctx, fulldecl);244else245ctx->emit_declaration(ctx, fulldecl);246}247break;248249case TGSI_TOKEN_TYPE_IMMEDIATE:250{251struct tgsi_full_immediate *fullimm252= &parse.FullToken.FullImmediate;253254if (ctx->transform_immediate)255ctx->transform_immediate(ctx, fullimm);256else257ctx->emit_immediate(ctx, fullimm);258}259break;260case TGSI_TOKEN_TYPE_PROPERTY:261{262struct tgsi_full_property *fullprop263= &parse.FullToken.FullProperty;264265if (ctx->transform_property)266ctx->transform_property(ctx, fullprop);267else268ctx->emit_property(ctx, fullprop);269}270break;271272default:273assert( 0 );274}275}276assert(call_stack == 0);277278tgsi_parse_free (&parse);279280return ctx->ti;281}282283284#include "tgsi_text.h"285286extern int tgsi_transform_foo( struct tgsi_token *tokens_out,287uint max_tokens_out );288289/* This function exists only so that tgsi_text_translate() doesn't get290* magic-ed out of the libtgsi.a archive by the build system. Don't291* remove unless you know this has been fixed - check on mingw/scons292* builds as well.293*/294int295tgsi_transform_foo( struct tgsi_token *tokens_out,296uint max_tokens_out )297{298const char *text =299"FRAG\n"300"DCL IN[0], COLOR, CONSTANT\n"301"DCL OUT[0], COLOR\n"302" 0: MOV OUT[0], IN[0]\n"303" 1: END";304305return tgsi_text_translate( text,306tokens_out,307max_tokens_out );308}309310311