/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/**
* TGSI program transformation utility.
*
* Authors: Brian Paul
*/
#include "util/u_debug.h"
#include "tgsi_transform.h"
static void
emit_instruction(struct tgsi_transform_context *ctx,
const struct tgsi_full_instruction *inst)
{
uint ti = ctx->ti;
ti += tgsi_build_full_instruction(inst,
ctx->tokens_out + ti,
ctx->header,
ctx->max_tokens_out - ti);
ctx->ti = ti;
}
static void
emit_declaration(struct tgsi_transform_context *ctx,
const struct tgsi_full_declaration *decl)
{
uint ti = ctx->ti;
ti += tgsi_build_full_declaration(decl,
ctx->tokens_out + ti,
ctx->header,
ctx->max_tokens_out - ti);
ctx->ti = ti;
}
static void
emit_immediate(struct tgsi_transform_context *ctx,
const struct tgsi_full_immediate *imm)
{
uint ti = ctx->ti;
ti += tgsi_build_full_immediate(imm,
ctx->tokens_out + ti,
ctx->header,
ctx->max_tokens_out - ti);
ctx->ti = ti;
}
static void
emit_property(struct tgsi_transform_context *ctx,
const struct tgsi_full_property *prop)
{
uint ti = ctx->ti;
ti += tgsi_build_full_property(prop,
ctx->tokens_out + ti,
ctx->header,
ctx->max_tokens_out - ti);
ctx->ti = ti;
}
/**
* Apply user-defined transformations to the input shader to produce
* the output shader.
* For example, a register search-and-replace operation could be applied
* by defining a transform_instruction() callback that examined and changed
* the instruction src/dest regs.
*
* \return number of tokens emitted
*/
int
tgsi_transform_shader(const struct tgsi_token *tokens_in,
struct tgsi_token *tokens_out,
uint max_tokens_out,
struct tgsi_transform_context *ctx)
{
uint procType;
boolean first_instruction = TRUE;
/* input shader */
struct tgsi_parse_context parse;
/* output shader */
struct tgsi_processor *processor;
/**
** callback context init
**/
ctx->emit_instruction = emit_instruction;
ctx->emit_declaration = emit_declaration;
ctx->emit_immediate = emit_immediate;
ctx->emit_property = emit_property;
ctx->tokens_out = tokens_out;
ctx->max_tokens_out = max_tokens_out;
/**
** Setup to begin parsing input shader
**/
if (tgsi_parse_init( &parse, tokens_in ) != TGSI_PARSE_OK) {
debug_printf("tgsi_parse_init() failed in tgsi_transform_shader()!\n");
return -1;
}
procType = parse.FullHeader.Processor.Processor;
assert(procType == PIPE_SHADER_FRAGMENT ||
procType == PIPE_SHADER_VERTEX ||
procType == PIPE_SHADER_GEOMETRY);
/**
** Setup output shader
**/
ctx->header = (struct tgsi_header *)tokens_out;
*ctx->header = tgsi_build_header();
processor = (struct tgsi_processor *) (tokens_out + 1);
*processor = tgsi_build_processor( procType, ctx->header );
ctx->ti = 2;
/**
** Loop over incoming program tokens/instructions
*/
while( !tgsi_parse_end_of_tokens( &parse ) ) {
tgsi_parse_token( &parse );
switch( parse.FullToken.Token.Type ) {
case TGSI_TOKEN_TYPE_INSTRUCTION:
{
struct tgsi_full_instruction *fullinst
= &parse.FullToken.FullInstruction;
if (first_instruction && ctx->prolog) {
ctx->prolog(ctx);
}
/* XXX Note: we may also want to look for a main/top-level
* TGSI_OPCODE_RET instruction in the future.
*/
if (fullinst->Instruction.Opcode == TGSI_OPCODE_END
&& ctx->epilog) {
/* Emit caller's epilog */
ctx->epilog(ctx);
/* Emit END */
ctx->emit_instruction(ctx, fullinst);
}
else {
if (ctx->transform_instruction)
ctx->transform_instruction(ctx, fullinst);
else
ctx->emit_instruction(ctx, fullinst);
}
first_instruction = FALSE;
}
break;
case TGSI_TOKEN_TYPE_DECLARATION:
{
struct tgsi_full_declaration *fulldecl
= &parse.FullToken.FullDeclaration;
if (ctx->transform_declaration)
ctx->transform_declaration(ctx, fulldecl);
else
ctx->emit_declaration(ctx, fulldecl);
}
break;
case TGSI_TOKEN_TYPE_IMMEDIATE:
{
struct tgsi_full_immediate *fullimm
= &parse.FullToken.FullImmediate;
if (ctx->transform_immediate)
ctx->transform_immediate(ctx, fullimm);
else
ctx->emit_immediate(ctx, fullimm);
}
break;
case TGSI_TOKEN_TYPE_PROPERTY:
{
struct tgsi_full_property *fullprop
= &parse.FullToken.FullProperty;
if (ctx->transform_property)
ctx->transform_property(ctx, fullprop);
else
ctx->emit_property(ctx, fullprop);
}
break;
default:
assert( 0 );
}
}
tgsi_parse_free (&parse);
return ctx->ti;
}
#include "tgsi_text.h"
extern int tgsi_transform_foo( struct tgsi_token *tokens_out,
uint max_tokens_out );
/* This function exists only so that tgsi_text_translate() doesn't get
* magic-ed out of the libtgsi.a archive by the build system. Don't
* remove unless you know this has been fixed - check on mingw/scons
* builds as well.
*/
int
tgsi_transform_foo( struct tgsi_token *tokens_out,
uint max_tokens_out )
{
const char *text =
"FRAG\n"
"DCL IN[0], COLOR, CONSTANT\n"
"DCL OUT[0], COLOR\n"
" 0: MOV OUT[0], IN[0]\n"
" 1: END";
return tgsi_text_translate( text,
tokens_out,
max_tokens_out );
}