mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 16:08:04 +02:00
tgsi: add missing support for two dimensional arrays in various places
in particular asm text parsing and sanity checking were missing code to handle multi-dimensional arrays/geometry shaders
This commit is contained in:
parent
8a39f5dfdd
commit
22370990f2
3 changed files with 500 additions and 211 deletions
|
|
@ -183,6 +183,12 @@ _dump_register(
|
|||
int last )
|
||||
{
|
||||
ENM( file, file_names );
|
||||
|
||||
/* all geometry shader inputs are two dimensional */
|
||||
if (file == TGSI_FILE_INPUT &&
|
||||
ctx->iter.processor.Processor == TGSI_PROCESSOR_GEOMETRY)
|
||||
TXT("[]");
|
||||
|
||||
CHR( '[' );
|
||||
SID( first );
|
||||
if (first != last) {
|
||||
|
|
|
|||
|
|
@ -26,32 +26,112 @@
|
|||
**************************************************************************/
|
||||
|
||||
#include "util/u_debug.h"
|
||||
#include "util/u_memory.h"
|
||||
#include "pipe/p_inlines.h"
|
||||
#include "cso_cache/cso_hash.h"
|
||||
#include "tgsi_sanity.h"
|
||||
#include "tgsi_info.h"
|
||||
#include "tgsi_iterate.h"
|
||||
|
||||
typedef uint reg_flag;
|
||||
|
||||
#define BITS_IN_REG_FLAG (sizeof( reg_flag ) * 8)
|
||||
|
||||
#define MAX_REGISTERS 1024
|
||||
#define MAX_REG_FLAGS ((MAX_REGISTERS + BITS_IN_REG_FLAG - 1) / BITS_IN_REG_FLAG)
|
||||
typedef struct {
|
||||
uint file : 28;
|
||||
/* max 2 dimensions */
|
||||
uint dimensions : 4;
|
||||
uint indices[2];
|
||||
} scan_register;
|
||||
|
||||
struct sanity_check_ctx
|
||||
{
|
||||
struct tgsi_iterate_context iter;
|
||||
struct cso_hash *regs_decl;
|
||||
struct cso_hash *regs_used;
|
||||
struct cso_hash *regs_ind_used;
|
||||
|
||||
reg_flag regs_decl[TGSI_FILE_COUNT][MAX_REG_FLAGS];
|
||||
reg_flag regs_used[TGSI_FILE_COUNT][MAX_REG_FLAGS];
|
||||
boolean regs_ind_used[TGSI_FILE_COUNT];
|
||||
uint num_imms;
|
||||
uint num_instructions;
|
||||
uint index_of_END;
|
||||
|
||||
uint errors;
|
||||
uint warnings;
|
||||
uint implied_array_size;
|
||||
};
|
||||
|
||||
static INLINE unsigned
|
||||
scan_register_key(const scan_register *reg)
|
||||
{
|
||||
unsigned key = reg->file;
|
||||
key |= (reg->indices[0] << 4);
|
||||
key |= (reg->indices[1] << 18);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static void
|
||||
fill_scan_register1d(scan_register *reg,
|
||||
uint file, uint index)
|
||||
{
|
||||
reg->file = file;
|
||||
reg->dimensions = 1;
|
||||
reg->indices[0] = index;
|
||||
reg->indices[1] = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
fill_scan_register2d(scan_register *reg,
|
||||
uint file, uint index1, uint index2)
|
||||
{
|
||||
reg->file = file;
|
||||
reg->dimensions = 2;
|
||||
reg->indices[0] = index1;
|
||||
reg->indices[1] = index2;
|
||||
}
|
||||
|
||||
static void
|
||||
scan_register_dst(scan_register *reg,
|
||||
struct tgsi_full_dst_register *dst)
|
||||
{
|
||||
fill_scan_register1d(reg,
|
||||
dst->Register.File,
|
||||
dst->Register.Index);
|
||||
}
|
||||
|
||||
static void
|
||||
scan_register_src(scan_register *reg,
|
||||
struct tgsi_full_src_register *src)
|
||||
{
|
||||
if (src->Register.Dimension) {
|
||||
/*FIXME: right now we don't support indirect
|
||||
* multidimensional addressing */
|
||||
debug_assert(!src->Dimension.Indirect);
|
||||
fill_scan_register2d(reg,
|
||||
src->Register.File,
|
||||
src->Register.Index,
|
||||
src->Dimension.Index);
|
||||
} else {
|
||||
fill_scan_register1d(reg,
|
||||
src->Register.File,
|
||||
src->Register.Index);
|
||||
}
|
||||
}
|
||||
|
||||
static scan_register *
|
||||
create_scan_register_src(struct tgsi_full_src_register *src)
|
||||
{
|
||||
scan_register *reg = MALLOC(sizeof(scan_register));
|
||||
scan_register_src(reg, src);
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
static scan_register *
|
||||
create_scan_register_dst(struct tgsi_full_dst_register *dst)
|
||||
{
|
||||
scan_register *reg = MALLOC(sizeof(scan_register));
|
||||
scan_register_dst(reg, dst);
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
static void
|
||||
report_error(
|
||||
struct sanity_check_ctx *ctx,
|
||||
|
|
@ -99,12 +179,12 @@ check_file_name(
|
|||
static boolean
|
||||
is_register_declared(
|
||||
struct sanity_check_ctx *ctx,
|
||||
uint file,
|
||||
int index )
|
||||
const scan_register *reg)
|
||||
{
|
||||
assert( index >= 0 && index < MAX_REGISTERS );
|
||||
|
||||
return (ctx->regs_decl[file][index / BITS_IN_REG_FLAG] & (1 << (index % BITS_IN_REG_FLAG))) ? TRUE : FALSE;
|
||||
void *data = cso_hash_find_data_from_template(
|
||||
ctx->regs_decl, scan_register_key(reg),
|
||||
(void*)reg, sizeof(scan_register));
|
||||
return data ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static boolean
|
||||
|
|
@ -112,23 +192,37 @@ is_any_register_declared(
|
|||
struct sanity_check_ctx *ctx,
|
||||
uint file )
|
||||
{
|
||||
uint i;
|
||||
struct cso_hash_iter iter =
|
||||
cso_hash_first_node(ctx->regs_decl);
|
||||
|
||||
for (i = 0; i < MAX_REG_FLAGS; i++)
|
||||
if (ctx->regs_decl[file][i])
|
||||
while (cso_hash_iter_is_null(iter)) {
|
||||
scan_register *reg = (scan_register *)cso_hash_iter_data(iter);
|
||||
if (reg->file == file)
|
||||
return TRUE;
|
||||
iter = cso_hash_iter_next(iter);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static boolean
|
||||
is_register_used(
|
||||
struct sanity_check_ctx *ctx,
|
||||
uint file,
|
||||
int index )
|
||||
scan_register *reg)
|
||||
{
|
||||
assert( index < MAX_REGISTERS );
|
||||
void *data = cso_hash_find_data_from_template(
|
||||
ctx->regs_used, scan_register_key(reg),
|
||||
reg, sizeof(scan_register));
|
||||
return data ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
return (ctx->regs_used[file][index / BITS_IN_REG_FLAG] & (1 << (index % BITS_IN_REG_FLAG))) ? TRUE : FALSE;
|
||||
|
||||
static boolean
|
||||
is_ind_register_used(
|
||||
struct sanity_check_ctx *ctx,
|
||||
scan_register *reg)
|
||||
{
|
||||
return cso_hash_contains(ctx->regs_ind_used, reg->file);
|
||||
}
|
||||
|
||||
static const char *file_names[TGSI_FILE_COUNT] =
|
||||
|
|
@ -148,31 +242,40 @@ static const char *file_names[TGSI_FILE_COUNT] =
|
|||
static boolean
|
||||
check_register_usage(
|
||||
struct sanity_check_ctx *ctx,
|
||||
uint file,
|
||||
int index,
|
||||
scan_register *reg,
|
||||
const char *name,
|
||||
boolean indirect_access )
|
||||
{
|
||||
if (!check_file_name( ctx, file ))
|
||||
if (!check_file_name( ctx, reg->file )) {
|
||||
free(reg);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (indirect_access) {
|
||||
/* Note that 'index' is an offset relative to the value of the
|
||||
* address register. No range checking done here.
|
||||
*/
|
||||
if (!is_any_register_declared( ctx, file ))
|
||||
report_error( ctx, "%s: Undeclared %s register", file_names[file], name );
|
||||
ctx->regs_ind_used[file] = TRUE;
|
||||
* address register. No range checking done here.*/
|
||||
reg->indices[0] = 0;
|
||||
reg->indices[1] = 0;
|
||||
if (!is_any_register_declared( ctx, reg->file ))
|
||||
report_error( ctx, "%s: Undeclared %s register", file_names[reg->file], name );
|
||||
if (!is_ind_register_used(ctx, reg))
|
||||
cso_hash_insert(ctx->regs_ind_used, reg->file, reg);
|
||||
else
|
||||
free(reg);
|
||||
}
|
||||
else {
|
||||
if (index < 0 || index >= MAX_REGISTERS) {
|
||||
report_error( ctx, "%s[%d]: Invalid %s index", file_names[file], index, name );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!is_register_declared( ctx, file, index ))
|
||||
report_error( ctx, "%s[%d]: Undeclared %s register", file_names[file], index, name );
|
||||
ctx->regs_used[file][index / BITS_IN_REG_FLAG] |= (1 << (index % BITS_IN_REG_FLAG));
|
||||
if (!is_register_declared( ctx, reg )) {
|
||||
if (reg->dimensions == 2)
|
||||
report_error( ctx, "%s[%d][%d]: Undeclared %s register", file_names[reg->file],
|
||||
reg->indices[0], reg->indices[1], name );
|
||||
else
|
||||
report_error( ctx, "%s[%d]: Undeclared %s register", file_names[reg->file],
|
||||
reg->indices[0], name );
|
||||
}
|
||||
if (!is_register_used( ctx, reg ))
|
||||
cso_hash_insert(ctx->regs_used, scan_register_key(reg), reg);
|
||||
else
|
||||
free(reg);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -210,33 +313,33 @@ iter_instruction(
|
|||
* Mark the registers as used.
|
||||
*/
|
||||
for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
|
||||
scan_register *reg = create_scan_register_dst(&inst->Dst[i]);
|
||||
check_register_usage(
|
||||
ctx,
|
||||
inst->Dst[i].Register.File,
|
||||
inst->Dst[i].Register.Index,
|
||||
reg,
|
||||
"destination",
|
||||
FALSE );
|
||||
}
|
||||
for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
|
||||
scan_register *reg = create_scan_register_src(&inst->Src[i]);
|
||||
check_register_usage(
|
||||
ctx,
|
||||
inst->Src[i].Register.File,
|
||||
inst->Src[i].Register.Index,
|
||||
reg,
|
||||
"source",
|
||||
(boolean)inst->Src[i].Register.Indirect );
|
||||
if (inst->Src[i].Register.Indirect) {
|
||||
uint file;
|
||||
int index;
|
||||
scan_register *ind_reg = MALLOC(sizeof(scan_register));
|
||||
|
||||
file = inst->Src[i].Indirect.File;
|
||||
index = inst->Src[i].Indirect.Index;
|
||||
fill_scan_register1d(ind_reg,
|
||||
inst->Src[i].Indirect.File,
|
||||
inst->Src[i].Indirect.Index);
|
||||
check_register_usage(
|
||||
ctx,
|
||||
file,
|
||||
index,
|
||||
reg,
|
||||
"indirect",
|
||||
FALSE );
|
||||
if (!(file == TGSI_FILE_ADDRESS || file == TGSI_FILE_LOOP) || index != 0) {
|
||||
if (!(reg->file == TGSI_FILE_ADDRESS || reg->file == TGSI_FILE_LOOP) ||
|
||||
reg->indices[0] != 0) {
|
||||
report_warning(ctx, "Indirect register neither ADDR[0] nor LOOP[0]");
|
||||
}
|
||||
}
|
||||
|
|
@ -266,6 +369,19 @@ iter_instruction(
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
check_and_declare(struct sanity_check_ctx *ctx,
|
||||
scan_register *reg)
|
||||
{
|
||||
if (is_register_declared( ctx, reg))
|
||||
report_error( ctx, "%s[%u]: The same register declared more than once",
|
||||
file_names[reg->file], reg->indices[0] );
|
||||
cso_hash_insert(ctx->regs_decl,
|
||||
scan_register_key(reg),
|
||||
reg);
|
||||
}
|
||||
|
||||
|
||||
static boolean
|
||||
iter_declaration(
|
||||
struct tgsi_iterate_context *iter,
|
||||
|
|
@ -287,9 +403,21 @@ iter_declaration(
|
|||
if (!check_file_name( ctx, file ))
|
||||
return TRUE;
|
||||
for (i = decl->Range.First; i <= decl->Range.Last; i++) {
|
||||
if (is_register_declared( ctx, file, i ))
|
||||
report_error( ctx, "%s[%u]: The same register declared more than once", file_names[file], i );
|
||||
ctx->regs_decl[file][i / BITS_IN_REG_FLAG] |= (1 << (i % BITS_IN_REG_FLAG));
|
||||
/* declared TGSI_FILE_INPUT's for geometry processor
|
||||
* have an implied second dimension */
|
||||
if (file == TGSI_FILE_INPUT &&
|
||||
ctx->iter.processor.Processor == TGSI_PROCESSOR_GEOMETRY) {
|
||||
uint vert;
|
||||
for (vert = 0; vert < ctx->implied_array_size; ++vert) {
|
||||
scan_register *reg = MALLOC(sizeof(scan_register));
|
||||
fill_scan_register2d(reg, file, vert, i);
|
||||
check_and_declare(ctx, reg);
|
||||
}
|
||||
} else {
|
||||
scan_register *reg = MALLOC(sizeof(scan_register));
|
||||
fill_scan_register1d(reg, file, i);
|
||||
check_and_declare(ctx, reg);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
|
@ -301,8 +429,7 @@ iter_immediate(
|
|||
struct tgsi_full_immediate *imm )
|
||||
{
|
||||
struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;
|
||||
|
||||
assert( ctx->num_imms < MAX_REGISTERS );
|
||||
scan_register *reg;
|
||||
|
||||
/* No immediates allowed after the first instruction.
|
||||
*/
|
||||
|
|
@ -311,7 +438,9 @@ iter_immediate(
|
|||
|
||||
/* Mark the register as declared.
|
||||
*/
|
||||
ctx->regs_decl[TGSI_FILE_IMMEDIATE][ctx->num_imms / BITS_IN_REG_FLAG] |= (1 << (ctx->num_imms % BITS_IN_REG_FLAG));
|
||||
reg = MALLOC(sizeof(scan_register));
|
||||
fill_scan_register1d(reg, TGSI_FILE_IMMEDIATE, ctx->num_imms);
|
||||
cso_hash_insert(ctx->regs_decl, scan_register_key(reg), reg);
|
||||
ctx->num_imms++;
|
||||
|
||||
/* Check data type validity.
|
||||
|
|
@ -330,8 +459,13 @@ iter_property(
|
|||
struct tgsi_iterate_context *iter,
|
||||
struct tgsi_full_property *prop )
|
||||
{
|
||||
/*struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;*/
|
||||
struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;
|
||||
|
||||
if (iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY &&
|
||||
prop->Property.PropertyName == TGSI_PROPERTY_GS_INPUT_PRIM) {
|
||||
ctx->implied_array_size =
|
||||
pipe_vertices_per_primitive(prop->u[0].Data);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -340,7 +474,6 @@ epilog(
|
|||
struct tgsi_iterate_context *iter )
|
||||
{
|
||||
struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;
|
||||
uint file;
|
||||
|
||||
/* There must be an END instruction somewhere.
|
||||
*/
|
||||
|
|
@ -350,13 +483,17 @@ epilog(
|
|||
|
||||
/* Check if all declared registers were used.
|
||||
*/
|
||||
for (file = TGSI_FILE_NULL; file < TGSI_FILE_COUNT; file++) {
|
||||
uint i;
|
||||
{
|
||||
struct cso_hash_iter iter =
|
||||
cso_hash_first_node(ctx->regs_decl);
|
||||
|
||||
for (i = 0; i < MAX_REGISTERS; i++) {
|
||||
if (is_register_declared( ctx, file, i ) && !is_register_used( ctx, file, i ) && !ctx->regs_ind_used[file]) {
|
||||
report_warning( ctx, "%s[%u]: Register never used", file_names[file], i );
|
||||
while (cso_hash_iter_is_null(iter)) {
|
||||
scan_register *reg = (scan_register *)cso_hash_iter_data(iter);
|
||||
if (!is_register_used(ctx, reg) && !is_ind_register_used(ctx, reg)) {
|
||||
report_warning( ctx, "%s[%u]: Register never used",
|
||||
file_names[reg->file], reg->indices[0] );
|
||||
}
|
||||
iter = cso_hash_iter_next(iter);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -368,6 +505,18 @@ epilog(
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
regs_hash_destroy(struct cso_hash *hash)
|
||||
{
|
||||
struct cso_hash_iter iter = cso_hash_first_node(hash);
|
||||
while (!cso_hash_iter_is_null(iter)) {
|
||||
scan_register *reg = (scan_register *)cso_hash_iter_data(iter);
|
||||
iter = cso_hash_erase(hash, iter);
|
||||
free(reg);
|
||||
}
|
||||
cso_hash_delete(hash);
|
||||
}
|
||||
|
||||
boolean
|
||||
tgsi_sanity_check(
|
||||
const struct tgsi_token *tokens )
|
||||
|
|
@ -381,18 +530,23 @@ tgsi_sanity_check(
|
|||
ctx.iter.iterate_property = iter_property;
|
||||
ctx.iter.epilog = epilog;
|
||||
|
||||
memset( ctx.regs_decl, 0, sizeof( ctx.regs_decl ) );
|
||||
memset( ctx.regs_used, 0, sizeof( ctx.regs_used ) );
|
||||
memset( ctx.regs_ind_used, 0, sizeof( ctx.regs_ind_used ) );
|
||||
ctx.regs_decl = cso_hash_create();
|
||||
ctx.regs_used = cso_hash_create();
|
||||
ctx.regs_ind_used = cso_hash_create();
|
||||
|
||||
ctx.num_imms = 0;
|
||||
ctx.num_instructions = 0;
|
||||
ctx.index_of_END = ~0;
|
||||
|
||||
ctx.errors = 0;
|
||||
ctx.warnings = 0;
|
||||
ctx.implied_array_size = 0;
|
||||
|
||||
if (!tgsi_iterate_shader( tokens, &ctx.iter ))
|
||||
return FALSE;
|
||||
|
||||
regs_hash_destroy(ctx.regs_decl);
|
||||
regs_hash_destroy(ctx.regs_used);
|
||||
regs_hash_destroy(ctx.regs_ind_used);
|
||||
return ctx.errors == 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "util/u_debug.h"
|
||||
#include "util/u_memory.h"
|
||||
#include "pipe/p_defines.h"
|
||||
#include "pipe/p_inlines.h"
|
||||
#include "tgsi_text.h"
|
||||
#include "tgsi_build.h"
|
||||
#include "tgsi_info.h"
|
||||
|
|
@ -193,6 +194,8 @@ struct translate_ctx
|
|||
struct tgsi_token *tokens_cur;
|
||||
struct tgsi_token *tokens_end;
|
||||
struct tgsi_header *header;
|
||||
unsigned processor : 4;
|
||||
int implied_array_size : 5;
|
||||
};
|
||||
|
||||
static void report_error( struct translate_ctx *ctx, const char *msg )
|
||||
|
|
@ -242,6 +245,7 @@ static boolean parse_header( struct translate_ctx *ctx )
|
|||
if (ctx->tokens_cur >= ctx->tokens_end)
|
||||
return FALSE;
|
||||
*(struct tgsi_processor *) ctx->tokens_cur++ = tgsi_build_processor( processor, ctx->header );
|
||||
ctx->processor = processor;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -338,6 +342,125 @@ parse_opt_writemask(
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static boolean
|
||||
parse_register_dst( struct translate_ctx *ctx,
|
||||
uint *file,
|
||||
int *index );
|
||||
|
||||
struct parsed_src_bracket {
|
||||
int index;
|
||||
|
||||
uint ind_file;
|
||||
int ind_index;
|
||||
uint ind_comp;
|
||||
};
|
||||
|
||||
|
||||
static boolean
|
||||
parse_register_src_bracket(
|
||||
struct translate_ctx *ctx,
|
||||
struct parsed_src_bracket *brackets)
|
||||
{
|
||||
const char *cur;
|
||||
uint uindex;
|
||||
|
||||
memset(brackets, 0, sizeof(struct parsed_src_bracket));
|
||||
|
||||
eat_opt_white( &ctx->cur );
|
||||
|
||||
cur = ctx->cur;
|
||||
if (parse_file( &cur, &brackets->ind_file )) {
|
||||
if (!parse_register_dst( ctx, &brackets->ind_file,
|
||||
&brackets->ind_index ))
|
||||
return FALSE;
|
||||
eat_opt_white( &ctx->cur );
|
||||
|
||||
if (*ctx->cur == '.') {
|
||||
ctx->cur++;
|
||||
eat_opt_white(&ctx->cur);
|
||||
|
||||
switch (uprcase(*ctx->cur)) {
|
||||
case 'X':
|
||||
brackets->ind_comp = TGSI_SWIZZLE_X;
|
||||
break;
|
||||
case 'Y':
|
||||
brackets->ind_comp = TGSI_SWIZZLE_Y;
|
||||
break;
|
||||
case 'Z':
|
||||
brackets->ind_comp = TGSI_SWIZZLE_Z;
|
||||
break;
|
||||
case 'W':
|
||||
brackets->ind_comp = TGSI_SWIZZLE_W;
|
||||
break;
|
||||
default:
|
||||
report_error(ctx, "Expected indirect register swizzle component `x', `y', `z' or `w'");
|
||||
return FALSE;
|
||||
}
|
||||
ctx->cur++;
|
||||
eat_opt_white(&ctx->cur);
|
||||
}
|
||||
|
||||
if (*ctx->cur == '+' || *ctx->cur == '-') {
|
||||
boolean negate;
|
||||
|
||||
negate = *ctx->cur == '-';
|
||||
ctx->cur++;
|
||||
eat_opt_white( &ctx->cur );
|
||||
if (!parse_uint( &ctx->cur, &uindex )) {
|
||||
report_error( ctx, "Expected literal unsigned integer" );
|
||||
return FALSE;
|
||||
}
|
||||
if (negate)
|
||||
brackets->index = -(int) uindex;
|
||||
else
|
||||
brackets->index = (int) uindex;
|
||||
}
|
||||
else {
|
||||
brackets->index = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!parse_uint( &ctx->cur, &uindex )) {
|
||||
report_error( ctx, "Expected literal unsigned integer" );
|
||||
return FALSE;
|
||||
}
|
||||
brackets->index = (int) uindex;
|
||||
brackets->ind_file = TGSI_FILE_NULL;
|
||||
brackets->ind_index = 0;
|
||||
}
|
||||
eat_opt_white( &ctx->cur );
|
||||
if (*ctx->cur != ']') {
|
||||
report_error( ctx, "Expected `]'" );
|
||||
return FALSE;
|
||||
}
|
||||
ctx->cur++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static boolean
|
||||
parse_opt_register_src_bracket(
|
||||
struct translate_ctx *ctx,
|
||||
struct parsed_src_bracket *brackets,
|
||||
int *parsed_brackets)
|
||||
{
|
||||
const char *cur = ctx->cur;
|
||||
|
||||
*parsed_brackets = 0;
|
||||
|
||||
eat_opt_white( &cur );
|
||||
if (cur[0] == '[') {
|
||||
++cur;
|
||||
ctx->cur = cur;
|
||||
|
||||
if (!parse_register_src_bracket(ctx, brackets))
|
||||
return FALSE;
|
||||
|
||||
*parsed_brackets = 1;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* <register_file_bracket> ::= <file> `['
|
||||
*/
|
||||
static boolean
|
||||
|
|
@ -379,6 +502,128 @@ parse_register_file_bracket_index(
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* Parse source register operand.
|
||||
* <register_src> ::= <register_file_bracket_index> `]' |
|
||||
* <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `]' |
|
||||
* <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `+' <uint> `]' |
|
||||
* <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `-' <uint> `]'
|
||||
*/
|
||||
static boolean
|
||||
parse_register_src(
|
||||
struct translate_ctx *ctx,
|
||||
uint *file,
|
||||
struct parsed_src_bracket *brackets)
|
||||
{
|
||||
|
||||
brackets->ind_comp = TGSI_SWIZZLE_X;
|
||||
if (!parse_register_file_bracket( ctx, file ))
|
||||
return FALSE;
|
||||
if (!parse_register_src_bracket( ctx, brackets ))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct parsed_dcl_bracket {
|
||||
uint first;
|
||||
uint last;
|
||||
};
|
||||
|
||||
static boolean
|
||||
parse_register_dcl_bracket(
|
||||
struct translate_ctx *ctx,
|
||||
struct parsed_dcl_bracket *bracket)
|
||||
{
|
||||
uint uindex;
|
||||
memset(bracket, 0, sizeof(struct parsed_dcl_bracket));
|
||||
|
||||
eat_opt_white( &ctx->cur );
|
||||
|
||||
if (!parse_uint( &ctx->cur, &uindex )) {
|
||||
/* it can be an empty bracket [] which means its range
|
||||
* is from 0 to some implied size */
|
||||
if (ctx->cur[0] == ']' && ctx->implied_array_size != 0) {
|
||||
bracket->first = 0;
|
||||
bracket->last = ctx->implied_array_size - 1;
|
||||
goto cleanup;
|
||||
}
|
||||
report_error( ctx, "Expected literal unsigned integer" );
|
||||
return FALSE;
|
||||
}
|
||||
bracket->first = (int) uindex;
|
||||
|
||||
eat_opt_white( &ctx->cur );
|
||||
|
||||
if (ctx->cur[0] == '.' && ctx->cur[1] == '.') {
|
||||
uint uindex;
|
||||
|
||||
ctx->cur += 2;
|
||||
eat_opt_white( &ctx->cur );
|
||||
if (!parse_uint( &ctx->cur, &uindex )) {
|
||||
report_error( ctx, "Expected literal integer" );
|
||||
return FALSE;
|
||||
}
|
||||
bracket->last = (int) uindex;
|
||||
eat_opt_white( &ctx->cur );
|
||||
}
|
||||
else {
|
||||
bracket->last = bracket->first;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (*ctx->cur != ']') {
|
||||
report_error( ctx, "Expected `]' or `..'" );
|
||||
return FALSE;
|
||||
}
|
||||
ctx->cur++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Parse register declaration.
|
||||
* <register_dcl> ::= <register_file_bracket_index> `]' |
|
||||
* <register_file_bracket_index> `..' <index> `]'
|
||||
*/
|
||||
static boolean
|
||||
parse_register_dcl(
|
||||
struct translate_ctx *ctx,
|
||||
uint *file,
|
||||
struct parsed_dcl_bracket *brackets,
|
||||
int *num_brackets)
|
||||
{
|
||||
const char *cur;
|
||||
|
||||
*num_brackets = 0;
|
||||
|
||||
if (!parse_register_file_bracket( ctx, file ))
|
||||
return FALSE;
|
||||
if (!parse_register_dcl_bracket( ctx, &brackets[0] ))
|
||||
return FALSE;
|
||||
|
||||
*num_brackets = 1;
|
||||
|
||||
cur = ctx->cur;
|
||||
eat_opt_white( &cur );
|
||||
|
||||
if (cur[0] == '[') {
|
||||
++cur;
|
||||
ctx->cur = cur;
|
||||
if (!parse_register_dcl_bracket( ctx, &brackets[1] ))
|
||||
return FALSE;
|
||||
/* for geometry shader we don't really care about
|
||||
* the first brackets it's always the size of the
|
||||
* input primitive. so we want to declare just
|
||||
* the index relevant to the semantics which is in
|
||||
* the second bracket */
|
||||
if (ctx->processor == TGSI_PROCESSOR_GEOMETRY) {
|
||||
brackets[0] = brackets[1];
|
||||
}
|
||||
*num_brackets = 2;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Parse destination register operand.
|
||||
* <register_dst> ::= <register_file_bracket_index> `]'
|
||||
*/
|
||||
|
|
@ -399,134 +644,6 @@ parse_register_dst(
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* Parse source register operand.
|
||||
* <register_src> ::= <register_file_bracket_index> `]' |
|
||||
* <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `]' |
|
||||
* <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `+' <uint> `]' |
|
||||
* <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `-' <uint> `]'
|
||||
*/
|
||||
static boolean
|
||||
parse_register_src(
|
||||
struct translate_ctx *ctx,
|
||||
uint *file,
|
||||
int *index,
|
||||
uint *ind_file,
|
||||
int *ind_index,
|
||||
uint *ind_comp)
|
||||
{
|
||||
const char *cur;
|
||||
uint uindex;
|
||||
|
||||
*ind_comp = TGSI_SWIZZLE_X;
|
||||
if (!parse_register_file_bracket( ctx, file ))
|
||||
return FALSE;
|
||||
eat_opt_white( &ctx->cur );
|
||||
cur = ctx->cur;
|
||||
if (parse_file( &cur, ind_file )) {
|
||||
if (!parse_register_dst( ctx, ind_file, ind_index ))
|
||||
return FALSE;
|
||||
eat_opt_white( &ctx->cur );
|
||||
|
||||
if (*ctx->cur == '.') {
|
||||
ctx->cur++;
|
||||
eat_opt_white(&ctx->cur);
|
||||
|
||||
switch (uprcase(*ctx->cur)) {
|
||||
case 'X':
|
||||
*ind_comp = TGSI_SWIZZLE_X;
|
||||
break;
|
||||
case 'Y':
|
||||
*ind_comp = TGSI_SWIZZLE_Y;
|
||||
break;
|
||||
case 'Z':
|
||||
*ind_comp = TGSI_SWIZZLE_Z;
|
||||
break;
|
||||
case 'W':
|
||||
*ind_comp = TGSI_SWIZZLE_W;
|
||||
break;
|
||||
default:
|
||||
report_error(ctx, "Expected indirect register swizzle component `x', `y', `z' or `w'");
|
||||
return FALSE;
|
||||
}
|
||||
ctx->cur++;
|
||||
eat_opt_white(&ctx->cur);
|
||||
}
|
||||
|
||||
if (*ctx->cur == '+' || *ctx->cur == '-') {
|
||||
boolean negate;
|
||||
|
||||
negate = *ctx->cur == '-';
|
||||
ctx->cur++;
|
||||
eat_opt_white( &ctx->cur );
|
||||
if (!parse_uint( &ctx->cur, &uindex )) {
|
||||
report_error( ctx, "Expected literal unsigned integer" );
|
||||
return FALSE;
|
||||
}
|
||||
if (negate)
|
||||
*index = -(int) uindex;
|
||||
else
|
||||
*index = (int) uindex;
|
||||
}
|
||||
else {
|
||||
*index = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!parse_uint( &ctx->cur, &uindex )) {
|
||||
report_error( ctx, "Expected literal unsigned integer" );
|
||||
return FALSE;
|
||||
}
|
||||
*index = (int) uindex;
|
||||
*ind_file = TGSI_FILE_NULL;
|
||||
*ind_index = 0;
|
||||
}
|
||||
eat_opt_white( &ctx->cur );
|
||||
if (*ctx->cur != ']') {
|
||||
report_error( ctx, "Expected `]'" );
|
||||
return FALSE;
|
||||
}
|
||||
ctx->cur++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Parse register declaration.
|
||||
* <register_dcl> ::= <register_file_bracket_index> `]' |
|
||||
* <register_file_bracket_index> `..' <index> `]'
|
||||
*/
|
||||
static boolean
|
||||
parse_register_dcl(
|
||||
struct translate_ctx *ctx,
|
||||
uint *file,
|
||||
int *first,
|
||||
int *last )
|
||||
{
|
||||
if (!parse_register_file_bracket_index( ctx, file, first ))
|
||||
return FALSE;
|
||||
eat_opt_white( &ctx->cur );
|
||||
if (ctx->cur[0] == '.' && ctx->cur[1] == '.') {
|
||||
uint uindex;
|
||||
|
||||
ctx->cur += 2;
|
||||
eat_opt_white( &ctx->cur );
|
||||
if (!parse_uint( &ctx->cur, &uindex )) {
|
||||
report_error( ctx, "Expected literal integer" );
|
||||
return FALSE;
|
||||
}
|
||||
*last = (int) uindex;
|
||||
eat_opt_white( &ctx->cur );
|
||||
}
|
||||
else {
|
||||
*last = *first;
|
||||
}
|
||||
if (*ctx->cur != ']') {
|
||||
report_error( ctx, "Expected `]' or `..'" );
|
||||
return FALSE;
|
||||
}
|
||||
ctx->cur++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static boolean
|
||||
parse_dst_operand(
|
||||
struct translate_ctx *ctx,
|
||||
|
|
@ -595,37 +712,44 @@ parse_src_operand(
|
|||
struct tgsi_full_src_register *src )
|
||||
{
|
||||
uint file;
|
||||
int index;
|
||||
uint ind_file;
|
||||
int ind_index;
|
||||
uint ind_comp;
|
||||
uint swizzle[4];
|
||||
boolean parsed_swizzle;
|
||||
struct parsed_src_bracket bracket[2];
|
||||
int parsed_opt_brackets;
|
||||
|
||||
if (*ctx->cur == '-') {
|
||||
ctx->cur++;
|
||||
eat_opt_white( &ctx->cur );
|
||||
src->Register.Negate = 1;
|
||||
}
|
||||
|
||||
|
||||
if (*ctx->cur == '|') {
|
||||
ctx->cur++;
|
||||
eat_opt_white( &ctx->cur );
|
||||
src->Register.Absolute = 1;
|
||||
}
|
||||
|
||||
if (!parse_register_src(ctx, &file, &index, &ind_file, &ind_index, &ind_comp))
|
||||
if (!parse_register_src(ctx, &file, &bracket[0]))
|
||||
return FALSE;
|
||||
if (!parse_opt_register_src_bracket(ctx, &bracket[1], &parsed_opt_brackets))
|
||||
return FALSE;
|
||||
|
||||
src->Register.File = file;
|
||||
src->Register.Index = index;
|
||||
if (ind_file != TGSI_FILE_NULL) {
|
||||
src->Register.Index = bracket[0].index;
|
||||
if (bracket[0].ind_file != TGSI_FILE_NULL) {
|
||||
src->Register.Indirect = 1;
|
||||
src->Indirect.File = ind_file;
|
||||
src->Indirect.Index = ind_index;
|
||||
src->Indirect.SwizzleX = ind_comp;
|
||||
src->Indirect.SwizzleY = ind_comp;
|
||||
src->Indirect.SwizzleZ = ind_comp;
|
||||
src->Indirect.SwizzleW = ind_comp;
|
||||
src->Indirect.File = bracket[0].ind_file;
|
||||
src->Indirect.Index = bracket[0].ind_index;
|
||||
src->Indirect.SwizzleX = bracket[0].ind_comp;
|
||||
src->Indirect.SwizzleY = bracket[0].ind_comp;
|
||||
src->Indirect.SwizzleZ = bracket[0].ind_comp;
|
||||
src->Indirect.SwizzleW = bracket[0].ind_comp;
|
||||
}
|
||||
if (parsed_opt_brackets) {
|
||||
src->Register.Dimension = 1;
|
||||
src->Dimension.Indirect = 0;
|
||||
src->Dimension.Dimension = 0;
|
||||
src->Dimension.Index = bracket[1].index;
|
||||
}
|
||||
|
||||
/* Parse optional swizzle.
|
||||
|
|
@ -820,8 +944,8 @@ static boolean parse_declaration( struct translate_ctx *ctx )
|
|||
{
|
||||
struct tgsi_full_declaration decl;
|
||||
uint file;
|
||||
int first;
|
||||
int last;
|
||||
struct parsed_dcl_bracket brackets[2];
|
||||
int num_brackets;
|
||||
uint writemask;
|
||||
const char *cur;
|
||||
uint advance;
|
||||
|
|
@ -833,7 +957,7 @@ static boolean parse_declaration( struct translate_ctx *ctx )
|
|||
report_error( ctx, "Syntax error" );
|
||||
return FALSE;
|
||||
}
|
||||
if (!parse_register_dcl( ctx, &file, &first, &last ))
|
||||
if (!parse_register_dcl( ctx, &file, brackets, &num_brackets))
|
||||
return FALSE;
|
||||
if (!parse_opt_writemask( ctx, &writemask ))
|
||||
return FALSE;
|
||||
|
|
@ -841,8 +965,8 @@ static boolean parse_declaration( struct translate_ctx *ctx )
|
|||
decl = tgsi_default_full_declaration();
|
||||
decl.Declaration.File = file;
|
||||
decl.Declaration.UsageMask = writemask;
|
||||
decl.Range.First = first;
|
||||
decl.Range.Last = last;
|
||||
decl.Range.First = brackets[0].first;
|
||||
decl.Range.Last = brackets[0].last;
|
||||
|
||||
cur = ctx->cur;
|
||||
eat_opt_white( &cur );
|
||||
|
|
@ -1059,6 +1183,11 @@ static boolean parse_property( struct translate_ctx *ctx )
|
|||
report_error( ctx, "Unknown primitive name as property!" );
|
||||
return FALSE;
|
||||
}
|
||||
if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM &&
|
||||
ctx->processor == TGSI_PROCESSOR_GEOMETRY) {
|
||||
ctx->implied_array_size =
|
||||
pipe_vertices_per_primitive(values[0]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!parse_uint(&ctx->cur, &values[0] )) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue