tgsi/transform: Make tgsi_transform_shader() manage token allocation.

Previously, the caller allocated storage and tgsi_transform_shader() would
emit into that, returning how many tokens it emitted.  All the callers had
to guess at how much storage was necessary, trying not to over-allocate
but also getting enough that you wouldn't (effectively) silently run out
of space.

Instead, make tgsi_transform_shader() do the allocation for you, taking
just a hint of how much space you think you need, and internally double
size when necessary.  Fixes failures on virgl with fp64 since we've added
more fp64 virglrenderer workarounds and its old "XXX: is this enough?"
allocation wasn't any more.

Reviewed-by: Mihai Preda <mhpreda@gmail.com>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15782>
This commit is contained in:
Emma Anholt 2022-04-06 15:14:08 -07:00 committed by Marge Bot
parent e15154a735
commit ef9f2e8829
17 changed files with 118 additions and 149 deletions

View file

@ -281,9 +281,6 @@ generate_aaline_fs(struct aaline_stage *aaline)
const uint newLen = tgsi_num_tokens(orig_fs->tokens) + NUM_NEW_TOKENS;
aaline_fs = *orig_fs; /* copy to init */
aaline_fs.tokens = tgsi_alloc_tokens(newLen);
if (aaline_fs.tokens == NULL)
return FALSE;
memset(&transform, 0, sizeof(transform));
transform.colorOutput = -1;
@ -296,9 +293,9 @@ generate_aaline_fs(struct aaline_stage *aaline)
transform.base.transform_instruction = aa_transform_inst;
transform.base.transform_declaration = aa_transform_decl;
tgsi_transform_shader(orig_fs->tokens,
(struct tgsi_token *) aaline_fs.tokens,
newLen, &transform.base);
aaline_fs.tokens = tgsi_transform_shader(orig_fs->tokens, newLen, &transform.base);
if (!aaline_fs.tokens)
return false;
#if 0 /* DEBUG */
debug_printf("draw_aaline, orig shader:\n");

View file

@ -368,9 +368,6 @@ generate_aapoint_fs(struct aapoint_stage *aapoint)
aapoint_fs = *orig_fs; /* copy to init */
assert(aapoint_fs.type == PIPE_SHADER_IR_TGSI);
aapoint_fs.tokens = tgsi_alloc_tokens(newLen);
if (aapoint_fs.tokens == NULL)
return FALSE;
memset(&transform, 0, sizeof(transform));
transform.colorOutput = -1;
@ -383,9 +380,9 @@ generate_aapoint_fs(struct aapoint_stage *aapoint)
transform.base.transform_instruction = aa_transform_inst;
transform.base.transform_declaration = aa_transform_decl;
tgsi_transform_shader(orig_fs->tokens,
(struct tgsi_token *) aapoint_fs.tokens,
newLen, &transform.base);
aapoint_fs.tokens = tgsi_transform_shader(orig_fs->tokens, newLen, &transform.base);
if (!aapoint_fs.tokens)
return false;
#if 0 /* DEBUG */
debug_printf("draw_aapoint, orig shader:\n");

View file

@ -276,12 +276,6 @@ tgsi_add_aa_point(const struct tgsi_token *tokens_in,
struct aa_transform_context transform;
const uint num_new_tokens = 200; /* should be enough */
const uint new_len = tgsi_num_tokens(tokens_in) + num_new_tokens;
struct tgsi_token *new_tokens;
/* allocate new tokens buffer */
new_tokens = tgsi_alloc_tokens(new_len);
if (!new_tokens)
return NULL;
/* setup transformation context */
memset(&transform, 0, sizeof(transform));
@ -302,8 +296,5 @@ tgsi_add_aa_point(const struct tgsi_token *tokens_in,
transform.num_imm = 0;
transform.num_input = 0;
/* transform the shader */
tgsi_transform_shader(tokens_in, new_tokens, new_len, &transform.base);
return new_tokens;
return tgsi_transform_shader(tokens_in, new_len, &transform.base);
}

View file

@ -332,7 +332,6 @@ tgsi_remove_dynamic_indexing(const struct tgsi_token *tokens_in,
struct dIndexing_transform_context transform;
const uint num_new_tokens = 1000; /* should be enough */
const uint new_len = tgsi_num_tokens(tokens_in) + num_new_tokens;
struct tgsi_token *new_tokens;
/* setup transformation context */
memset(&transform, 0, sizeof(transform));
@ -347,15 +346,7 @@ tgsi_remove_dynamic_indexing(const struct tgsi_token *tokens_in,
transform.num_samplers = log2(samplers_declared_bitmask + 1);
transform.num_iterations = 0;
/* allocate new tokens buffer */
new_tokens = tgsi_alloc_tokens(new_len);
if (!new_tokens)
return NULL;
/* transform the shader */
tgsi_transform_shader(tokens_in, new_tokens, new_len, &transform.base);
return new_tokens;
return tgsi_transform_shader(tokens_in, new_len, &transform.base);
}

View file

@ -140,7 +140,6 @@ const struct tgsi_token *
tgsi_emulate(const struct tgsi_token *tokens, unsigned flags)
{
struct tgsi_emulation_context ctx;
struct tgsi_token *newtoks;
int newlen;
if (!(flags & (TGSI_EMU_CLAMP_COLOR_OUTPUTS |
@ -160,10 +159,6 @@ tgsi_emulate(const struct tgsi_token *tokens, unsigned flags)
ctx.base.transform_instruction = transform_instr;
newlen = tgsi_num_tokens(tokens) + 20;
newtoks = tgsi_alloc_tokens(newlen);
if (!newtoks)
return NULL;
tgsi_transform_shader(tokens, newtoks, newlen, &ctx.base);
return newtoks;
return tgsi_transform_shader(tokens, newlen, &ctx.base);
}

View file

@ -1573,12 +1573,10 @@ tgsi_transform_lowering(const struct tgsi_lowering_config *config,
newlen += 2 * numtmp;
newlen += 5; /* immediate */
newtoks = tgsi_alloc_tokens(newlen);
newtoks = tgsi_transform_shader(tokens, newlen, &ctx.base);
if (!newtoks)
return NULL;
tgsi_transform_shader(tokens, newtoks, newlen, &ctx.base);
tgsi_scan_shader(newtoks, info);
#if 0 /* debug */

View file

@ -568,13 +568,7 @@ tgsi_add_point_sprite(const struct tgsi_token *tokens_in,
}
/* allocate new tokens buffer */
new_tokens = tgsi_alloc_tokens(new_len);
if (!new_tokens)
return NULL;
/* transform the shader */
tgsi_transform_shader(tokens_in, new_tokens, new_len, &transform.base);
new_tokens = tgsi_transform_shader(tokens_in, new_len, &transform.base);
if (aa_point_coord_index)
*aa_point_coord_index = transform.point_coord_aa;

View file

@ -32,22 +32,61 @@
*/
#include "util/u_debug.h"
#include "util/log.h"
#include "tgsi_transform.h"
/**
* Increments the next-token index if the tgsi_build_* succeeded, or extends the
* token array and returns true to request a re-emit of the tgsi_build_* by the
* caller.
*/
static bool
need_re_emit(struct tgsi_transform_context *ctx, uint32_t emitted, struct tgsi_header orig_header)
{
if (emitted > 0) {
ctx->ti += emitted;
return false;
} else {
uint32_t new_len = ctx->max_tokens_out * 2;
if (new_len < ctx->max_tokens_out) {
ctx->fail = true;
return false;
}
struct tgsi_token *new_tokens = tgsi_alloc_tokens(new_len);
if (!new_tokens) {
ctx->fail = true;
return false;
}
memcpy(new_tokens, ctx->tokens_out, sizeof(struct tgsi_token) * ctx->ti);
tgsi_free_tokens(ctx->tokens_out);
ctx->tokens_out = new_tokens;
ctx->max_tokens_out = new_len;
/* Point the header at the resized tokens. */
ctx->header = (struct tgsi_header *)new_tokens;
/* The failing emit may have incremented header/body size, reset it to its state before our attempt. */
*ctx->header = orig_header;
return true;
}
}
static void
emit_instruction(struct tgsi_transform_context *ctx,
const struct tgsi_full_instruction *inst)
{
uint ti = ctx->ti;
uint32_t emitted;
struct tgsi_header orig_header = *ctx->header;
ti += tgsi_build_full_instruction(inst,
ctx->tokens_out + ti,
ctx->header,
ctx->max_tokens_out - ti);
ctx->ti = ti;
do {
emitted = tgsi_build_full_instruction(inst,
ctx->tokens_out + ctx->ti,
ctx->header,
ctx->max_tokens_out - ctx->ti);
} while (need_re_emit(ctx, emitted, orig_header));
}
@ -55,13 +94,15 @@ static void
emit_declaration(struct tgsi_transform_context *ctx,
const struct tgsi_full_declaration *decl)
{
uint ti = ctx->ti;
uint32_t emitted;
struct tgsi_header orig_header = *ctx->header;
ti += tgsi_build_full_declaration(decl,
ctx->tokens_out + ti,
ctx->header,
ctx->max_tokens_out - ti);
ctx->ti = ti;
do {
emitted = tgsi_build_full_declaration(decl,
ctx->tokens_out + ctx->ti,
ctx->header,
ctx->max_tokens_out - ctx->ti);
} while (need_re_emit(ctx, emitted, orig_header));
}
@ -69,13 +110,15 @@ static void
emit_immediate(struct tgsi_transform_context *ctx,
const struct tgsi_full_immediate *imm)
{
uint ti = ctx->ti;
uint32_t emitted;
struct tgsi_header orig_header = *ctx->header;
ti += tgsi_build_full_immediate(imm,
ctx->tokens_out + ti,
ctx->header,
ctx->max_tokens_out - ti);
ctx->ti = ti;
do {
emitted = tgsi_build_full_immediate(imm,
ctx->tokens_out + ctx->ti,
ctx->header,
ctx->max_tokens_out - ctx->ti);
} while (need_re_emit(ctx, emitted, orig_header));
}
@ -83,13 +126,15 @@ static void
emit_property(struct tgsi_transform_context *ctx,
const struct tgsi_full_property *prop)
{
uint ti = ctx->ti;
uint32_t emitted;
struct tgsi_header orig_header = *ctx->header;
ti += tgsi_build_full_property(prop,
ctx->tokens_out + ti,
ctx->header,
ctx->max_tokens_out - ti);
ctx->ti = ti;
do {
emitted = tgsi_build_full_property(prop,
ctx->tokens_out + ctx->ti,
ctx->header,
ctx->max_tokens_out - ctx->ti);
} while (need_re_emit(ctx, emitted, orig_header));
}
@ -100,12 +145,11 @@ emit_property(struct tgsi_transform_context *ctx,
* by defining a transform_instruction() callback that examined and changed
* the instruction src/dest regs.
*
* \return number of tokens emitted
* \return new tgsi tokens, or NULL on failure
*/
int
struct tgsi_token *
tgsi_transform_shader(const struct tgsi_token *tokens_in,
struct tgsi_token *tokens_out,
uint max_tokens_out,
uint initial_tokens_len,
struct tgsi_transform_context *ctx)
{
boolean first_instruction = TRUE;
@ -119,6 +163,8 @@ tgsi_transform_shader(const struct tgsi_token *tokens_in,
/* output shader */
struct tgsi_processor *processor;
/* Always include space for the header. */
initial_tokens_len = MAX2(initial_tokens_len, 2);
/**
** callback context init
@ -127,26 +173,31 @@ tgsi_transform_shader(const struct tgsi_token *tokens_in,
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;
ctx->tokens_out = tgsi_alloc_tokens(initial_tokens_len);
ctx->max_tokens_out = initial_tokens_len;
ctx->fail = false;
if (!ctx->tokens_out) {
mesa_loge("failed to allocate %d tokens\n", initial_tokens_len);
return NULL;
}
/**
** 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;
return NULL;
}
ctx->processor = parse.FullHeader.Processor.Processor;
/**
** Setup output shader
**/
ctx->header = (struct tgsi_header *)tokens_out;
ctx->header = (struct tgsi_header *)ctx->tokens_out;
*ctx->header = tgsi_build_header();
processor = (struct tgsi_processor *) (tokens_out + 1);
processor = (struct tgsi_processor *) (ctx->tokens_out + 1);
*processor = tgsi_build_processor( ctx->processor, ctx->header );
ctx->ti = 2;
@ -277,7 +328,12 @@ tgsi_transform_shader(const struct tgsi_token *tokens_in,
tgsi_parse_free (&parse);
return ctx->ti;
if (ctx->fail) {
tgsi_free_tokens(ctx->tokens_out);
return NULL;
}
return ctx->tokens_out;
}

View file

@ -90,6 +90,7 @@ struct tgsi_transform_context
uint max_tokens_out;
struct tgsi_token *tokens_out;
uint ti;
bool fail;
};
@ -572,10 +573,9 @@ tgsi_transform_tex_inst(struct tgsi_transform_context *ctx,
}
extern int
extern struct tgsi_token *
tgsi_transform_shader(const struct tgsi_token *tokens_in,
struct tgsi_token *tokens_out,
uint max_tokens_out,
uint initial_tokens_len,
struct tgsi_transform_context *ctx);

View file

@ -202,7 +202,6 @@ tgsi_add_two_side(const struct tgsi_token *tokens_in)
struct two_side_transform_context transform;
const uint num_new_tokens = 100; /* should be enough */
const uint new_len = tgsi_num_tokens(tokens_in) + num_new_tokens;
struct tgsi_token *new_tokens;
/* setup transformation context */
memset(&transform, 0, sizeof(transform));
@ -217,13 +216,5 @@ tgsi_add_two_side(const struct tgsi_token *tokens_in)
transform.back_color_input[0] = INVALID_INDEX;
transform.back_color_input[1] = INVALID_INDEX;
/* allocate new tokens buffer */
new_tokens = tgsi_alloc_tokens(new_len);
if (!new_tokens)
return NULL;
/* transform the shader */
tgsi_transform_shader(tokens_in, new_tokens, new_len, &transform.base);
return new_tokens;
return tgsi_transform_shader(tokens_in, new_len, &transform.base);
}

View file

@ -87,7 +87,6 @@ tgsi_write_vpos(const struct tgsi_token *tokens_in,
struct write_vpos_context transform;
const uint num_new_tokens = 1000; /* should be enough */
const uint new_len = tgsi_num_tokens(tokens_in) + num_new_tokens;
struct tgsi_token *new_tokens;
/* setup transformation context */
memset(&transform, 0, sizeof(transform));
@ -95,15 +94,7 @@ tgsi_write_vpos(const struct tgsi_token *tokens_in,
transform.imm_index = num_immediates;
/* allocate new tokens buffer */
new_tokens = tgsi_alloc_tokens(new_len);
if (!new_tokens)
return NULL;
/* transform the shader */
tgsi_transform_shader(tokens_in, new_tokens, new_len, &transform.base);
return new_tokens;
return tgsi_transform_shader(tokens_in, new_len, &transform.base);
}

View file

@ -381,11 +381,6 @@ util_pstipple_create_fragment_shader(const struct tgsi_token *tokens,
const uint newLen = tgsi_num_tokens(tokens) + NUM_NEW_TOKENS;
struct tgsi_token *new_tokens;
new_tokens = tgsi_alloc_tokens(newLen);
if (!new_tokens) {
return NULL;
}
/* Setup shader transformation info/context.
*/
memset(&transform, 0, sizeof(transform));
@ -404,7 +399,9 @@ util_pstipple_create_fragment_shader(const struct tgsi_token *tokens,
transform.coordOrigin =
transform.info.properties[TGSI_PROPERTY_FS_COORD_ORIGIN];
tgsi_transform_shader(tokens, new_tokens, newLen, &transform.base);
new_tokens = tgsi_transform_shader(tokens, newLen, &transform.base);
if (!new_tokens)
return NULL;
#if 0 /* DEBUG */
tgsi_dump(fs->tokens, 0);

View file

@ -314,7 +314,7 @@ void r300_draw_init_vertex_shader(struct r300_context *r300,
struct draw_context *draw = r300->draw;
struct tgsi_shader_info info;
struct vs_transform_context transform;
const uint newLen = tgsi_num_tokens(vs->state.tokens) + 100 /* XXX */;
const uint newLen = tgsi_num_tokens(vs->state.tokens) + 100;
struct pipe_shader_state new_vs = {
.type = PIPE_SHADER_IR_TGSI,
.tokens = tgsi_alloc_tokens(newLen)
@ -323,9 +323,6 @@ void r300_draw_init_vertex_shader(struct r300_context *r300,
tgsi_scan_shader(vs->state.tokens, &info);
if (new_vs.tokens == NULL)
return;
memset(&transform, 0, sizeof(transform));
for (i = 0; i < ARRAY_SIZE(transform.out_remap); i++) {
transform.out_remap[i] = i;
@ -350,9 +347,9 @@ void r300_draw_init_vertex_shader(struct r300_context *r300,
}
}
tgsi_transform_shader(vs->state.tokens,
(struct tgsi_token*)new_vs.tokens,
newLen, &transform.base);
new_vs.tokens = tgsi_transform_shader(vs->state.tokens, newLen, &transform.base);
if (!new_vs.tokens)
return;
#if 0
printf("----------------------------------------------\norig shader:\n");

View file

@ -360,12 +360,7 @@ virgl_tgsi_transform_instruction(struct tgsi_transform_context *ctx,
struct tgsi_token *virgl_tgsi_transform(struct virgl_screen *vscreen, const struct tgsi_token *tokens_in)
{
struct virgl_transform_context transform;
const uint newLen = tgsi_num_tokens(tokens_in) * 2 /* XXX: how many to allocate? */;
struct tgsi_token *new_tokens;
new_tokens = tgsi_alloc_tokens(newLen);
if (!new_tokens)
return NULL;
const uint newLen = tgsi_num_tokens(tokens_in);
memset(&transform, 0, sizeof(transform));
transform.base.transform_declaration = virgl_tgsi_transform_declaration;
@ -382,7 +377,5 @@ struct tgsi_token *virgl_tgsi_transform(struct virgl_screen *vscreen, const stru
tgsi_scan_shader(tokens_in, &transform.info);
tgsi_transform_shader(tokens_in, new_tokens, newLen, &transform.base);
return new_tokens;
return tgsi_transform_shader(tokens_in, newLen, &transform.base);
}

View file

@ -132,7 +132,6 @@ st_get_bitmap_shader(const struct tgsi_token *tokens,
bool use_texcoord, bool swizzle_xxxx)
{
struct tgsi_bitmap_transform ctx;
struct tgsi_token *newtoks;
int newlen;
assert(tex_target == PIPE_TEXTURE_2D ||
@ -147,10 +146,6 @@ st_get_bitmap_shader(const struct tgsi_token *tokens,
tgsi_scan_shader(tokens, &ctx.info);
newlen = tgsi_num_tokens(tokens) + 20;
newtoks = tgsi_alloc_tokens(newlen);
if (!newtoks)
return NULL;
tgsi_transform_shader(tokens, newtoks, newlen, &ctx.base);
return newtoks;
return tgsi_transform_shader(tokens, newlen, &ctx.base);
}

View file

@ -221,7 +221,6 @@ st_get_drawpix_shader(const struct tgsi_token *tokens, bool use_texcoord,
unsigned texcoord_const, unsigned tex_target)
{
struct tgsi_drawpix_transform ctx;
struct tgsi_token *newtoks;
int newlen;
assert(tex_target == PIPE_TEXTURE_2D ||
@ -241,10 +240,6 @@ st_get_drawpix_shader(const struct tgsi_token *tokens, bool use_texcoord,
tgsi_scan_shader(tokens, &ctx.info);
newlen = tgsi_num_tokens(tokens) + 60;
newtoks = tgsi_alloc_tokens(newlen);
if (!newtoks)
return NULL;
tgsi_transform_shader(tokens, newtoks, newlen, &ctx.base);
return newtoks;
return tgsi_transform_shader(tokens, newlen, &ctx.base);
}

View file

@ -423,7 +423,6 @@ st_tgsi_lower_yuv(const struct tgsi_token *tokens, unsigned free_slots,
unsigned lower_nv12, unsigned lower_iyuv)
{
struct tgsi_yuv_transform ctx;
struct tgsi_token *newtoks;
int newlen;
assert(!(lower_nv12 & lower_iyuv)); /* bitmasks should be mutually exclusive */
@ -442,14 +441,6 @@ st_tgsi_lower_yuv(const struct tgsi_token *tokens, unsigned free_slots,
* this is a pain about tgsi_transform :-/
*/
newlen = tgsi_num_tokens(tokens) + 300;
newtoks = tgsi_alloc_tokens(newlen);
if (!newtoks)
return NULL;
tgsi_transform_shader(tokens, newtoks, newlen, &ctx.base);
// tgsi_dump(newtoks, 0);
// debug_printf("\n");
return newtoks;
return tgsi_transform_shader(tokens, newlen, &ctx.base);
}