1bf215546Sopenharmony_ci/************************************************************************** 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright 2008 VMware, Inc. 4bf215546Sopenharmony_ci * All Rights Reserved. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 12bf215546Sopenharmony_ci * the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 16bf215546Sopenharmony_ci * of the Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci **************************************************************************/ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci/** 29bf215546Sopenharmony_ci * TGSI program transformation utility. 30bf215546Sopenharmony_ci * 31bf215546Sopenharmony_ci * Authors: Brian Paul 32bf215546Sopenharmony_ci */ 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_ci#include "util/u_debug.h" 35bf215546Sopenharmony_ci#include "util/log.h" 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci#include "tgsi_transform.h" 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci/** 40bf215546Sopenharmony_ci * Increments the next-token index if the tgsi_build_* succeeded, or extends the 41bf215546Sopenharmony_ci * token array and returns true to request a re-emit of the tgsi_build_* by the 42bf215546Sopenharmony_ci * caller. 43bf215546Sopenharmony_ci */ 44bf215546Sopenharmony_cistatic bool 45bf215546Sopenharmony_cineed_re_emit(struct tgsi_transform_context *ctx, uint32_t emitted, struct tgsi_header orig_header) 46bf215546Sopenharmony_ci{ 47bf215546Sopenharmony_ci if (emitted > 0) { 48bf215546Sopenharmony_ci ctx->ti += emitted; 49bf215546Sopenharmony_ci return false; 50bf215546Sopenharmony_ci } else { 51bf215546Sopenharmony_ci uint32_t new_len = ctx->max_tokens_out * 2; 52bf215546Sopenharmony_ci if (new_len < ctx->max_tokens_out) { 53bf215546Sopenharmony_ci ctx->fail = true; 54bf215546Sopenharmony_ci return false; 55bf215546Sopenharmony_ci } 56bf215546Sopenharmony_ci 57bf215546Sopenharmony_ci struct tgsi_token *new_tokens = tgsi_alloc_tokens(new_len); 58bf215546Sopenharmony_ci if (!new_tokens) { 59bf215546Sopenharmony_ci ctx->fail = true; 60bf215546Sopenharmony_ci return false; 61bf215546Sopenharmony_ci } 62bf215546Sopenharmony_ci memcpy(new_tokens, ctx->tokens_out, sizeof(struct tgsi_token) * ctx->ti); 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci tgsi_free_tokens(ctx->tokens_out); 65bf215546Sopenharmony_ci ctx->tokens_out = new_tokens; 66bf215546Sopenharmony_ci ctx->max_tokens_out = new_len; 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_ci /* Point the header at the resized tokens. */ 69bf215546Sopenharmony_ci ctx->header = (struct tgsi_header *)new_tokens; 70bf215546Sopenharmony_ci /* The failing emit may have incremented header/body size, reset it to its state before our attempt. */ 71bf215546Sopenharmony_ci *ctx->header = orig_header; 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci return true; 74bf215546Sopenharmony_ci } 75bf215546Sopenharmony_ci} 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_cistatic void 78bf215546Sopenharmony_ciemit_instruction(struct tgsi_transform_context *ctx, 79bf215546Sopenharmony_ci const struct tgsi_full_instruction *inst) 80bf215546Sopenharmony_ci{ 81bf215546Sopenharmony_ci uint32_t emitted; 82bf215546Sopenharmony_ci struct tgsi_header orig_header = *ctx->header; 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_ci do { 85bf215546Sopenharmony_ci emitted = tgsi_build_full_instruction(inst, 86bf215546Sopenharmony_ci ctx->tokens_out + ctx->ti, 87bf215546Sopenharmony_ci ctx->header, 88bf215546Sopenharmony_ci ctx->max_tokens_out - ctx->ti); 89bf215546Sopenharmony_ci } while (need_re_emit(ctx, emitted, orig_header)); 90bf215546Sopenharmony_ci} 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_cistatic void 94bf215546Sopenharmony_ciemit_declaration(struct tgsi_transform_context *ctx, 95bf215546Sopenharmony_ci const struct tgsi_full_declaration *decl) 96bf215546Sopenharmony_ci{ 97bf215546Sopenharmony_ci uint32_t emitted; 98bf215546Sopenharmony_ci struct tgsi_header orig_header = *ctx->header; 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_ci do { 101bf215546Sopenharmony_ci emitted = tgsi_build_full_declaration(decl, 102bf215546Sopenharmony_ci ctx->tokens_out + ctx->ti, 103bf215546Sopenharmony_ci ctx->header, 104bf215546Sopenharmony_ci ctx->max_tokens_out - ctx->ti); 105bf215546Sopenharmony_ci } while (need_re_emit(ctx, emitted, orig_header)); 106bf215546Sopenharmony_ci} 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_cistatic void 110bf215546Sopenharmony_ciemit_immediate(struct tgsi_transform_context *ctx, 111bf215546Sopenharmony_ci const struct tgsi_full_immediate *imm) 112bf215546Sopenharmony_ci{ 113bf215546Sopenharmony_ci uint32_t emitted; 114bf215546Sopenharmony_ci struct tgsi_header orig_header = *ctx->header; 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_ci do { 117bf215546Sopenharmony_ci emitted = tgsi_build_full_immediate(imm, 118bf215546Sopenharmony_ci ctx->tokens_out + ctx->ti, 119bf215546Sopenharmony_ci ctx->header, 120bf215546Sopenharmony_ci ctx->max_tokens_out - ctx->ti); 121bf215546Sopenharmony_ci } while (need_re_emit(ctx, emitted, orig_header)); 122bf215546Sopenharmony_ci} 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_cistatic void 126bf215546Sopenharmony_ciemit_property(struct tgsi_transform_context *ctx, 127bf215546Sopenharmony_ci const struct tgsi_full_property *prop) 128bf215546Sopenharmony_ci{ 129bf215546Sopenharmony_ci uint32_t emitted; 130bf215546Sopenharmony_ci struct tgsi_header orig_header = *ctx->header; 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ci do { 133bf215546Sopenharmony_ci emitted = tgsi_build_full_property(prop, 134bf215546Sopenharmony_ci ctx->tokens_out + ctx->ti, 135bf215546Sopenharmony_ci ctx->header, 136bf215546Sopenharmony_ci ctx->max_tokens_out - ctx->ti); 137bf215546Sopenharmony_ci } while (need_re_emit(ctx, emitted, orig_header)); 138bf215546Sopenharmony_ci} 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci/** 142bf215546Sopenharmony_ci * Apply user-defined transformations to the input shader to produce 143bf215546Sopenharmony_ci * the output shader. 144bf215546Sopenharmony_ci * For example, a register search-and-replace operation could be applied 145bf215546Sopenharmony_ci * by defining a transform_instruction() callback that examined and changed 146bf215546Sopenharmony_ci * the instruction src/dest regs. 147bf215546Sopenharmony_ci * 148bf215546Sopenharmony_ci * \return new tgsi tokens, or NULL on failure 149bf215546Sopenharmony_ci */ 150bf215546Sopenharmony_cistruct tgsi_token * 151bf215546Sopenharmony_citgsi_transform_shader(const struct tgsi_token *tokens_in, 152bf215546Sopenharmony_ci uint initial_tokens_len, 153bf215546Sopenharmony_ci struct tgsi_transform_context *ctx) 154bf215546Sopenharmony_ci{ 155bf215546Sopenharmony_ci boolean first_instruction = TRUE; 156bf215546Sopenharmony_ci boolean epilog_emitted = FALSE; 157bf215546Sopenharmony_ci int cond_stack = 0; 158bf215546Sopenharmony_ci int call_stack = 0; 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci /* input shader */ 161bf215546Sopenharmony_ci struct tgsi_parse_context parse; 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci /* output shader */ 164bf215546Sopenharmony_ci struct tgsi_processor *processor; 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci /* Always include space for the header. */ 167bf215546Sopenharmony_ci initial_tokens_len = MAX2(initial_tokens_len, 2); 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci /** 170bf215546Sopenharmony_ci ** callback context init 171bf215546Sopenharmony_ci **/ 172bf215546Sopenharmony_ci ctx->emit_instruction = emit_instruction; 173bf215546Sopenharmony_ci ctx->emit_declaration = emit_declaration; 174bf215546Sopenharmony_ci ctx->emit_immediate = emit_immediate; 175bf215546Sopenharmony_ci ctx->emit_property = emit_property; 176bf215546Sopenharmony_ci ctx->tokens_out = tgsi_alloc_tokens(initial_tokens_len); 177bf215546Sopenharmony_ci ctx->max_tokens_out = initial_tokens_len; 178bf215546Sopenharmony_ci ctx->fail = false; 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci if (!ctx->tokens_out) { 181bf215546Sopenharmony_ci mesa_loge("failed to allocate %d tokens\n", initial_tokens_len); 182bf215546Sopenharmony_ci return NULL; 183bf215546Sopenharmony_ci } 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci /** 186bf215546Sopenharmony_ci ** Setup to begin parsing input shader 187bf215546Sopenharmony_ci **/ 188bf215546Sopenharmony_ci if (tgsi_parse_init( &parse, tokens_in ) != TGSI_PARSE_OK) { 189bf215546Sopenharmony_ci debug_printf("tgsi_parse_init() failed in tgsi_transform_shader()!\n"); 190bf215546Sopenharmony_ci return NULL; 191bf215546Sopenharmony_ci } 192bf215546Sopenharmony_ci ctx->processor = parse.FullHeader.Processor.Processor; 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_ci /** 195bf215546Sopenharmony_ci ** Setup output shader 196bf215546Sopenharmony_ci **/ 197bf215546Sopenharmony_ci ctx->header = (struct tgsi_header *)ctx->tokens_out; 198bf215546Sopenharmony_ci *ctx->header = tgsi_build_header(); 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_ci processor = (struct tgsi_processor *) (ctx->tokens_out + 1); 201bf215546Sopenharmony_ci *processor = tgsi_build_processor( ctx->processor, ctx->header ); 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_ci ctx->ti = 2; 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci /** 207bf215546Sopenharmony_ci ** Loop over incoming program tokens/instructions 208bf215546Sopenharmony_ci */ 209bf215546Sopenharmony_ci while( !tgsi_parse_end_of_tokens( &parse ) ) { 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci tgsi_parse_token( &parse ); 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_ci switch( parse.FullToken.Token.Type ) { 214bf215546Sopenharmony_ci case TGSI_TOKEN_TYPE_INSTRUCTION: 215bf215546Sopenharmony_ci { 216bf215546Sopenharmony_ci struct tgsi_full_instruction *fullinst 217bf215546Sopenharmony_ci = &parse.FullToken.FullInstruction; 218bf215546Sopenharmony_ci enum tgsi_opcode opcode = fullinst->Instruction.Opcode; 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci if (first_instruction && ctx->prolog) { 221bf215546Sopenharmony_ci ctx->prolog(ctx); 222bf215546Sopenharmony_ci } 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_ci /* 225bf215546Sopenharmony_ci * XXX Note: we handle the case of ret in main. 226bf215546Sopenharmony_ci * However, the output redirections done by transform 227bf215546Sopenharmony_ci * have their limits with control flow and will generally 228bf215546Sopenharmony_ci * not work correctly. e.g. 229bf215546Sopenharmony_ci * if (cond) { 230bf215546Sopenharmony_ci * oColor = x; 231bf215546Sopenharmony_ci * ret; 232bf215546Sopenharmony_ci * } 233bf215546Sopenharmony_ci * oColor = y; 234bf215546Sopenharmony_ci * end; 235bf215546Sopenharmony_ci * If the color output is redirected to a temp and modified 236bf215546Sopenharmony_ci * by a transform, this will not work (the oColor assignment 237bf215546Sopenharmony_ci * in the conditional will never make it to the actual output). 238bf215546Sopenharmony_ci */ 239bf215546Sopenharmony_ci if ((opcode == TGSI_OPCODE_END || opcode == TGSI_OPCODE_RET) && 240bf215546Sopenharmony_ci call_stack == 0 && ctx->epilog && !epilog_emitted) { 241bf215546Sopenharmony_ci if (opcode == TGSI_OPCODE_RET && cond_stack != 0) { 242bf215546Sopenharmony_ci assert(!"transform ignoring RET in main"); 243bf215546Sopenharmony_ci } else { 244bf215546Sopenharmony_ci assert(cond_stack == 0); 245bf215546Sopenharmony_ci /* Emit caller's epilog */ 246bf215546Sopenharmony_ci ctx->epilog(ctx); 247bf215546Sopenharmony_ci epilog_emitted = TRUE; 248bf215546Sopenharmony_ci } 249bf215546Sopenharmony_ci /* Emit END (or RET) */ 250bf215546Sopenharmony_ci ctx->emit_instruction(ctx, fullinst); 251bf215546Sopenharmony_ci } 252bf215546Sopenharmony_ci else { 253bf215546Sopenharmony_ci switch (opcode) { 254bf215546Sopenharmony_ci case TGSI_OPCODE_IF: 255bf215546Sopenharmony_ci case TGSI_OPCODE_UIF: 256bf215546Sopenharmony_ci case TGSI_OPCODE_SWITCH: 257bf215546Sopenharmony_ci case TGSI_OPCODE_BGNLOOP: 258bf215546Sopenharmony_ci cond_stack++; 259bf215546Sopenharmony_ci break; 260bf215546Sopenharmony_ci case TGSI_OPCODE_CAL: 261bf215546Sopenharmony_ci call_stack++; 262bf215546Sopenharmony_ci break; 263bf215546Sopenharmony_ci case TGSI_OPCODE_ENDIF: 264bf215546Sopenharmony_ci case TGSI_OPCODE_ENDSWITCH: 265bf215546Sopenharmony_ci case TGSI_OPCODE_ENDLOOP: 266bf215546Sopenharmony_ci assert(cond_stack > 0); 267bf215546Sopenharmony_ci cond_stack--; 268bf215546Sopenharmony_ci break; 269bf215546Sopenharmony_ci case TGSI_OPCODE_ENDSUB: 270bf215546Sopenharmony_ci assert(call_stack > 0); 271bf215546Sopenharmony_ci call_stack--; 272bf215546Sopenharmony_ci break; 273bf215546Sopenharmony_ci case TGSI_OPCODE_BGNSUB: 274bf215546Sopenharmony_ci case TGSI_OPCODE_RET: 275bf215546Sopenharmony_ci default: 276bf215546Sopenharmony_ci break; 277bf215546Sopenharmony_ci } 278bf215546Sopenharmony_ci if (ctx->transform_instruction) 279bf215546Sopenharmony_ci ctx->transform_instruction(ctx, fullinst); 280bf215546Sopenharmony_ci else 281bf215546Sopenharmony_ci ctx->emit_instruction(ctx, fullinst); 282bf215546Sopenharmony_ci } 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci first_instruction = FALSE; 285bf215546Sopenharmony_ci } 286bf215546Sopenharmony_ci break; 287bf215546Sopenharmony_ci 288bf215546Sopenharmony_ci case TGSI_TOKEN_TYPE_DECLARATION: 289bf215546Sopenharmony_ci { 290bf215546Sopenharmony_ci struct tgsi_full_declaration *fulldecl 291bf215546Sopenharmony_ci = &parse.FullToken.FullDeclaration; 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_ci if (ctx->transform_declaration) 294bf215546Sopenharmony_ci ctx->transform_declaration(ctx, fulldecl); 295bf215546Sopenharmony_ci else 296bf215546Sopenharmony_ci ctx->emit_declaration(ctx, fulldecl); 297bf215546Sopenharmony_ci } 298bf215546Sopenharmony_ci break; 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci case TGSI_TOKEN_TYPE_IMMEDIATE: 301bf215546Sopenharmony_ci { 302bf215546Sopenharmony_ci struct tgsi_full_immediate *fullimm 303bf215546Sopenharmony_ci = &parse.FullToken.FullImmediate; 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_ci if (ctx->transform_immediate) 306bf215546Sopenharmony_ci ctx->transform_immediate(ctx, fullimm); 307bf215546Sopenharmony_ci else 308bf215546Sopenharmony_ci ctx->emit_immediate(ctx, fullimm); 309bf215546Sopenharmony_ci } 310bf215546Sopenharmony_ci break; 311bf215546Sopenharmony_ci case TGSI_TOKEN_TYPE_PROPERTY: 312bf215546Sopenharmony_ci { 313bf215546Sopenharmony_ci struct tgsi_full_property *fullprop 314bf215546Sopenharmony_ci = &parse.FullToken.FullProperty; 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_ci if (ctx->transform_property) 317bf215546Sopenharmony_ci ctx->transform_property(ctx, fullprop); 318bf215546Sopenharmony_ci else 319bf215546Sopenharmony_ci ctx->emit_property(ctx, fullprop); 320bf215546Sopenharmony_ci } 321bf215546Sopenharmony_ci break; 322bf215546Sopenharmony_ci 323bf215546Sopenharmony_ci default: 324bf215546Sopenharmony_ci assert( 0 ); 325bf215546Sopenharmony_ci } 326bf215546Sopenharmony_ci } 327bf215546Sopenharmony_ci assert(call_stack == 0); 328bf215546Sopenharmony_ci 329bf215546Sopenharmony_ci tgsi_parse_free (&parse); 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_ci if (ctx->fail) { 332bf215546Sopenharmony_ci tgsi_free_tokens(ctx->tokens_out); 333bf215546Sopenharmony_ci return NULL; 334bf215546Sopenharmony_ci } 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci return ctx->tokens_out; 337bf215546Sopenharmony_ci} 338bf215546Sopenharmony_ci 339bf215546Sopenharmony_ci 340bf215546Sopenharmony_ci#include "tgsi_text.h" 341bf215546Sopenharmony_ci 342bf215546Sopenharmony_ciextern int tgsi_transform_foo( struct tgsi_token *tokens_out, 343bf215546Sopenharmony_ci uint max_tokens_out ); 344bf215546Sopenharmony_ci 345bf215546Sopenharmony_ci/* This function exists only so that tgsi_text_translate() doesn't get 346bf215546Sopenharmony_ci * magic-ed out of the libtgsi.a archive by the build system. Don't 347bf215546Sopenharmony_ci * remove unless you know this has been fixed - check on mingw/scons 348bf215546Sopenharmony_ci * builds as well. 349bf215546Sopenharmony_ci */ 350bf215546Sopenharmony_ciint 351bf215546Sopenharmony_citgsi_transform_foo( struct tgsi_token *tokens_out, 352bf215546Sopenharmony_ci uint max_tokens_out ) 353bf215546Sopenharmony_ci{ 354bf215546Sopenharmony_ci const char *text = 355bf215546Sopenharmony_ci "FRAG\n" 356bf215546Sopenharmony_ci "DCL IN[0], COLOR, CONSTANT\n" 357bf215546Sopenharmony_ci "DCL OUT[0], COLOR\n" 358bf215546Sopenharmony_ci " 0: MOV OUT[0], IN[0]\n" 359bf215546Sopenharmony_ci " 1: END"; 360bf215546Sopenharmony_ci 361bf215546Sopenharmony_ci return tgsi_text_translate( text, 362bf215546Sopenharmony_ci tokens_out, 363bf215546Sopenharmony_ci max_tokens_out ); 364bf215546Sopenharmony_ci} 365