st/mesa: implement glBitmap shader transformation using tgsi_transform_shader

Reviewed-by: Dave Airlie <airlied@redhat.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
Tested-by: Brian Paul <brianp@vmware.com>
This commit is contained in:
Marek Olšák
2015-10-04 02:38:55 +02:00
parent 3eedb63371
commit f4ec81032b
7 changed files with 202 additions and 244 deletions

View File

@@ -415,6 +415,7 @@ STATETRACKER_FILES = \
state_tracker/st_cache.h \ state_tracker/st_cache.h \
state_tracker/st_cb_bitmap.c \ state_tracker/st_cb_bitmap.c \
state_tracker/st_cb_bitmap.h \ state_tracker/st_cb_bitmap.h \
state_tracker/st_cb_bitmap_shader.c \
state_tracker/st_cb_blit.c \ state_tracker/st_cb_blit.c \
state_tracker/st_cb_blit.h \ state_tracker/st_cb_blit.h \
state_tracker/st_cb_bufferobjects.c \ state_tracker/st_cb_bufferobjects.c \

View File

@@ -107,151 +107,6 @@ struct bitmap_cache
#define Z_EPSILON 1e-06 #define Z_EPSILON 1e-06
/**
* Make fragment program for glBitmap:
* Sample the texture and kill the fragment if the bit is 0.
* This program will be combined with the user's fragment program.
*/
static struct st_fragment_program *
make_bitmap_fragment_program(struct gl_context *ctx, GLuint samplerIndex)
{
struct st_context *st = st_context(ctx);
struct st_fragment_program *stfp;
struct gl_program *p;
GLuint ic = 0;
p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
if (!p)
return NULL;
p->NumInstructions = 3;
p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
if (!p->Instructions) {
ctx->Driver.DeleteProgram(ctx, p);
return NULL;
}
_mesa_init_instructions(p->Instructions, p->NumInstructions);
/* TEX tmp0, fragment.texcoord[0], texture[0], 2D; */
p->Instructions[ic].Opcode = OPCODE_TEX;
p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY;
p->Instructions[ic].DstReg.Index = 0;
p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
p->Instructions[ic].SrcReg[0].Index = VARYING_SLOT_TEX0;
p->Instructions[ic].TexSrcUnit = samplerIndex;
p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
ic++;
/* KIL if -tmp0 < 0 # texel=0 -> keep / texel=0 -> discard */
p->Instructions[ic].Opcode = OPCODE_KIL;
p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
if (st->bitmap.tex_format == PIPE_FORMAT_L8_UNORM)
p->Instructions[ic].SrcReg[0].Swizzle = SWIZZLE_XXXX;
p->Instructions[ic].SrcReg[0].Index = 0;
p->Instructions[ic].SrcReg[0].Negate = NEGATE_XYZW;
ic++;
/* END; */
p->Instructions[ic++].Opcode = OPCODE_END;
assert(ic == p->NumInstructions);
p->InputsRead = VARYING_BIT_TEX0;
p->OutputsWritten = 0x0;
p->SamplersUsed = (1 << samplerIndex);
stfp = (struct st_fragment_program *) p;
stfp->Base.UsesKill = GL_TRUE;
return stfp;
}
static struct gl_program *
make_bitmap_fragment_program_glsl(struct st_context *st,
struct st_fragment_program *orig,
GLuint samplerIndex)
{
struct gl_context *ctx = st->ctx;
struct st_fragment_program *fp = (struct st_fragment_program *)
ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
if (!fp)
return NULL;
get_bitmap_visitor(fp, orig->glsl_to_tgsi, samplerIndex);
return &fp->Base.Base;
}
static int
find_free_bit(uint bitfield)
{
int i;
for (i = 0; i < 32; i++) {
if ((bitfield & (1 << i)) == 0) {
return i;
}
}
return -1;
}
/**
* Combine basic bitmap fragment program with the user-defined program.
* \param st current context
* \param fpIn the incoming fragment program
* \param fpOut the new fragment program which does fragment culling
* \param bitmap_sampler sampler number for the bitmap texture
*/
void
st_make_bitmap_fragment_program(struct st_context *st,
struct gl_fragment_program *fpIn,
struct gl_fragment_program **fpOut,
GLuint *bitmap_sampler)
{
struct st_fragment_program *bitmap_prog;
struct st_fragment_program *stfpIn = (struct st_fragment_program *) fpIn;
struct gl_program *newProg;
uint sampler;
/*
* Generate new program which is the user-defined program prefixed
* with the bitmap sampler/kill instructions.
*/
sampler = find_free_bit(fpIn->Base.SamplersUsed);
if (stfpIn->glsl_to_tgsi)
newProg = make_bitmap_fragment_program_glsl(st, stfpIn, sampler);
else {
bitmap_prog = make_bitmap_fragment_program(st->ctx, sampler);
newProg = _mesa_combine_programs(st->ctx,
&bitmap_prog->Base.Base,
&fpIn->Base);
/* done with this after combining */
st_reference_fragprog(st, &bitmap_prog, NULL);
}
#if 0
{
printf("Combined bitmap program:\n");
_mesa_print_program(newProg);
printf("InputsRead: 0x%x\n", newProg->InputsRead);
printf("OutputsWritten: 0x%x\n", newProg->OutputsWritten);
_mesa_print_parameter_list(newProg->Parameters);
}
#endif
/* return results */
*fpOut = (struct gl_fragment_program *) newProg;
*bitmap_sampler = sampler;
}
/** /**
* Copy user-provide bitmap bits into texture buffer, expanding * Copy user-provide bitmap bits into texture buffer, expanding
* bits into texels. * bits into texels.

View File

@@ -31,6 +31,7 @@
#include "main/compiler.h" #include "main/compiler.h"
#include <stdbool.h>
struct dd_function_table; struct dd_function_table;
struct st_context; struct st_context;
@@ -46,14 +47,12 @@ st_init_bitmap(struct st_context *st);
extern void extern void
st_destroy_bitmap(struct st_context *st); st_destroy_bitmap(struct st_context *st);
extern void
st_make_bitmap_fragment_program(struct st_context *st,
struct gl_fragment_program *fpIn,
struct gl_fragment_program **fpOut,
GLuint *bitmap_sampler);
extern void extern void
st_flush_bitmap_cache(struct st_context *st); st_flush_bitmap_cache(struct st_context *st);
extern const struct tgsi_token *
st_get_bitmap_shader(const struct tgsi_token *tokens,
unsigned sampler_index,
bool use_texcoord, bool swizzle_xxxx);
#endif /* ST_CB_BITMAP_H */ #endif /* ST_CB_BITMAP_H */

View File

@@ -0,0 +1,174 @@
/**************************************************************************
*
* Copyright (C) 2015 Advanced Micro Devices, Inc.
* Copyright 2007 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.
*
**************************************************************************/
#include "st_cb_bitmap.h"
#include "tgsi/tgsi_transform.h"
#include "tgsi/tgsi_scan.h"
#include "tgsi/tgsi_dump.h"
#include "util/u_debug.h"
struct tgsi_bitmap_transform {
struct tgsi_transform_context base;
struct tgsi_shader_info info;
unsigned sampler_index;
bool use_texcoord;
bool swizzle_xxxx;
bool first_instruction_emitted;
};
static inline struct tgsi_bitmap_transform *
tgsi_bitmap_transform(struct tgsi_transform_context *tctx)
{
return (struct tgsi_bitmap_transform *)tctx;
}
static void
transform_instr(struct tgsi_transform_context *tctx,
struct tgsi_full_instruction *current_inst)
{
struct tgsi_bitmap_transform *ctx = tgsi_bitmap_transform(tctx);
struct tgsi_full_declaration decl;
struct tgsi_full_instruction inst;
unsigned i, semantic;
int texcoord_index = -1;
if (ctx->first_instruction_emitted) {
tctx->emit_instruction(tctx, current_inst);
return;
}
ctx->first_instruction_emitted = true;
/* Add TEMP[0] if it's missing. */
if (ctx->info.file_max[TGSI_FILE_TEMPORARY] == -1) {
decl = tgsi_default_full_declaration();
decl.Declaration.File = TGSI_FILE_TEMPORARY;
tctx->emit_declaration(tctx, &decl);
}
/* Add TEXCOORD[0] if it's missing. */
semantic = ctx->use_texcoord ? TGSI_SEMANTIC_TEXCOORD :
TGSI_SEMANTIC_GENERIC;
for (i = 0; i < ctx->info.num_inputs; i++) {
if (ctx->info.input_semantic_name[i] == semantic &&
ctx->info.input_semantic_index[i] == 0) {
texcoord_index = i;
break;
}
}
if (texcoord_index == -1) {
decl = tgsi_default_full_declaration();
decl.Declaration.File = TGSI_FILE_INPUT;
decl.Declaration.Semantic = 1;
decl.Semantic.Name = semantic;
decl.Declaration.Interpolate = 1;
decl.Interp.Interpolate = TGSI_INTERPOLATE_PERSPECTIVE;
decl.Range.First = decl.Range.Last = ctx->info.num_inputs;
texcoord_index = ctx->info.num_inputs;
tctx->emit_declaration(tctx, &decl);
}
/* Declare the sampler. */
decl = tgsi_default_full_declaration();
decl.Declaration.File = TGSI_FILE_SAMPLER;
decl.Range.First = decl.Range.Last = ctx->sampler_index;
tctx->emit_declaration(tctx, &decl);
/* TEX tmp0, fragment.texcoord[0], texture[0], 2D; */
inst = tgsi_default_full_instruction();
inst.Instruction.Opcode = TGSI_OPCODE_TEX;
inst.Instruction.Texture = 1;
inst.Texture.Texture = TGSI_TEXTURE_2D;
inst.Instruction.NumDstRegs = 1;
inst.Dst[0].Register.File = TGSI_FILE_TEMPORARY;
inst.Dst[0].Register.Index = 0;
inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZW;
inst.Instruction.NumSrcRegs = 2;
inst.Src[0].Register.File = TGSI_FILE_INPUT;
inst.Src[0].Register.Index = texcoord_index;
inst.Src[0].Register.SwizzleX = TGSI_SWIZZLE_X;
inst.Src[0].Register.SwizzleY = TGSI_SWIZZLE_Y;
inst.Src[0].Register.SwizzleZ = TGSI_SWIZZLE_Z;
inst.Src[0].Register.SwizzleW = TGSI_SWIZZLE_W;
inst.Src[1].Register.File = TGSI_FILE_SAMPLER;
inst.Src[1].Register.Index = ctx->sampler_index;
tctx->emit_instruction(tctx, &inst);
/* KIL if -tmp0 < 0 # texel=0 -> keep / texel=0 -> discard */
inst = tgsi_default_full_instruction();
inst.Instruction.Opcode = TGSI_OPCODE_KILL_IF;
inst.Instruction.NumDstRegs = 0;
inst.Instruction.NumSrcRegs = 1;
inst.Src[0].Register.File = TGSI_FILE_TEMPORARY;
inst.Src[0].Register.Index = 0;
inst.Src[0].Register.Negate = 1;
inst.Src[0].Register.SwizzleX = TGSI_SWIZZLE_X;
if (ctx->swizzle_xxxx) {
inst.Src[0].Register.SwizzleY = TGSI_SWIZZLE_X;
inst.Src[0].Register.SwizzleZ = TGSI_SWIZZLE_X;
inst.Src[0].Register.SwizzleW = TGSI_SWIZZLE_X;
} else {
inst.Src[0].Register.SwizzleY = TGSI_SWIZZLE_Y;
inst.Src[0].Register.SwizzleZ = TGSI_SWIZZLE_Z;
inst.Src[0].Register.SwizzleW = TGSI_SWIZZLE_W;
}
tctx->emit_instruction(tctx, &inst);
/* And emit the instruction we got. */
tctx->emit_instruction(tctx, current_inst);
}
const struct tgsi_token *
st_get_bitmap_shader(const struct tgsi_token *tokens,
unsigned sampler_index,
bool use_texcoord, bool swizzle_xxxx)
{
struct tgsi_bitmap_transform ctx;
struct tgsi_token *newtoks;
int newlen;
memset(&ctx, 0, sizeof(ctx));
ctx.base.transform_instruction = transform_instr;
ctx.sampler_index = sampler_index;
ctx.use_texcoord = use_texcoord;
ctx.swizzle_xxxx = swizzle_xxxx;
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;
}

View File

@@ -4466,84 +4466,6 @@ get_pixel_transfer_visitor(struct st_fragment_program *fp,
fp->glsl_to_tgsi = v; fp->glsl_to_tgsi = v;
} }
/**
* Make fragment program for glBitmap:
* Sample the texture and kill the fragment if the bit is 0.
* This program will be combined with the user's fragment program.
*
* Based on make_bitmap_fragment_program in st_cb_bitmap.c.
*/
extern "C" void
get_bitmap_visitor(struct st_fragment_program *fp,
glsl_to_tgsi_visitor *original, int samplerIndex)
{
glsl_to_tgsi_visitor *v = new glsl_to_tgsi_visitor();
struct st_context *st = st_context(original->ctx);
struct gl_program *prog = &fp->Base.Base;
st_src_reg coord, src0;
st_dst_reg dst0;
glsl_to_tgsi_instruction *inst;
/* Copy attributes of the glsl_to_tgsi_visitor in the original shader. */
v->ctx = original->ctx;
v->prog = prog;
v->shader_program = NULL;
v->shader = NULL;
v->glsl_version = original->glsl_version;
v->native_integers = original->native_integers;
v->options = original->options;
v->next_temp = original->next_temp;
v->num_address_regs = original->num_address_regs;
v->samplers_used = prog->SamplersUsed = original->samplers_used;
v->indirect_addr_consts = original->indirect_addr_consts;
memcpy(&v->immediates, &original->immediates, sizeof(v->immediates));
v->num_immediates = original->num_immediates;
/* TEX tmp0, fragment.texcoord[0], texture[0], 2D; */
coord = st_src_reg(PROGRAM_INPUT, VARYING_SLOT_TEX0, glsl_type::vec2_type);
src0 = v->get_temp(glsl_type::vec4_type);
dst0 = st_dst_reg(src0);
inst = v->emit_asm(NULL, TGSI_OPCODE_TEX, dst0, coord);
inst->sampler.index = samplerIndex;
inst->sampler_array_size = 1;
inst->tex_target = TEXTURE_2D_INDEX;
prog->InputsRead |= VARYING_BIT_TEX0;
prog->SamplersUsed |= (1 << samplerIndex); /* mark sampler as used */
v->samplers_used |= (1 << samplerIndex);
/* KIL if -tmp0 < 0 # texel=0 -> keep / texel=0 -> discard */
src0.negate = NEGATE_XYZW;
if (st->bitmap.tex_format == PIPE_FORMAT_L8_UNORM)
src0.swizzle = SWIZZLE_XXXX;
inst = v->emit_asm(NULL, TGSI_OPCODE_KILL_IF, undef_dst, src0);
/* Now copy the instructions from the original glsl_to_tgsi_visitor into the
* new visitor. */
foreach_in_list(glsl_to_tgsi_instruction, inst, &original->instructions) {
glsl_to_tgsi_instruction *newinst;
st_src_reg src_regs[4];
if (inst->dst[0].file == PROGRAM_OUTPUT)
prog->OutputsWritten |= BITFIELD64_BIT(inst->dst[0].index);
for (int i = 0; i < 4; i++) {
src_regs[i] = inst->src[i];
if (src_regs[i].file == PROGRAM_INPUT)
prog->InputsRead |= BITFIELD64_BIT(src_regs[i].index);
}
newinst = v->emit_asm(NULL, inst->op, inst->dst[0], src_regs[0], src_regs[1], src_regs[2], src_regs[3]);
newinst->tex_target = inst->tex_target;
newinst->sampler_array_size = inst->sampler_array_size;
}
/* Make modifications to fragment program info. */
prog->Parameters = _mesa_clone_parameter_list(original->prog->Parameters);
count_resources(v, prog);
fp->glsl_to_tgsi = v;
}
/* ------------------------- TGSI conversion stuff -------------------------- */ /* ------------------------- TGSI conversion stuff -------------------------- */
struct label { struct label {
unsigned branch_target; unsigned branch_target;

View File

@@ -58,9 +58,6 @@ void free_glsl_to_tgsi_visitor(struct glsl_to_tgsi_visitor *v);
void get_pixel_transfer_visitor(struct st_fragment_program *fp, void get_pixel_transfer_visitor(struct st_fragment_program *fp,
struct glsl_to_tgsi_visitor *original, struct glsl_to_tgsi_visitor *original,
int scale_and_bias, int pixel_maps); int scale_and_bias, int pixel_maps);
void get_bitmap_visitor(struct st_fragment_program *fp,
struct glsl_to_tgsi_visitor *original,
int samplerIndex);
GLboolean st_link_shader(struct gl_context *ctx, struct gl_shader_program *prog); GLboolean st_link_shader(struct gl_context *ctx, struct gl_shader_program *prog);

View File

@@ -567,18 +567,7 @@ st_translate_fragment_program(struct st_context *st,
assert(!(key->bitmap && key->drawpixels)); assert(!(key->bitmap && key->drawpixels));
memset(inputSlotToAttr, ~0, sizeof(inputSlotToAttr)); memset(inputSlotToAttr, ~0, sizeof(inputSlotToAttr));
if (key->bitmap) { if (key->drawpixels) {
/* glBitmap drawing */
struct gl_fragment_program *fp; /* we free this temp program below */
st_make_bitmap_fragment_program(st, &stfp->Base,
&fp, &variant->bitmap_sampler);
variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters);
stfp = st_fragment_program(fp);
deleteFP = GL_TRUE;
}
else if (key->drawpixels) {
/* glDrawPixels drawing */ /* glDrawPixels drawing */
struct gl_fragment_program *fp; /* we free this temp program below */ struct gl_fragment_program *fp; /* we free this temp program below */
@@ -892,6 +881,27 @@ st_translate_fragment_program(struct st_context *st,
fprintf(stderr, "mesa: cannot emulate deprecated features\n"); fprintf(stderr, "mesa: cannot emulate deprecated features\n");
} }
/* glBitmap */
if (key->bitmap) {
const struct tgsi_token *tokens;
variant->bitmap_sampler = ffs(~stfp->Base.Base.SamplersUsed) - 1;
tokens = st_get_bitmap_shader(variant->tgsi.tokens,
variant->bitmap_sampler,
st->needs_texcoord_semantic,
st->bitmap.tex_format ==
PIPE_FORMAT_L8_UNORM);
if (tokens) {
tgsi_free_tokens(variant->tgsi.tokens);
variant->tgsi.tokens = tokens;
variant->parameters =
_mesa_clone_parameter_list(stfp->Base.Base.Parameters);
} else
fprintf(stderr, "mesa: cannot create a shader for glBitmap\n");
}
if (ST_DEBUG & DEBUG_TGSI) { if (ST_DEBUG & DEBUG_TGSI) {
tgsi_dump(variant->tgsi.tokens, 0/*TGSI_DUMP_VERBOSE*/); tgsi_dump(variant->tgsi.tokens, 0/*TGSI_DUMP_VERBOSE*/);
debug_printf("\n"); debug_printf("\n");