#include "pipe/p_compiler.h"
#include "pipe/p_shader_tokens.h"
#include "pipe/p_state.h"
+#include "pipe/p_context.h"
#include "tgsi/tgsi_ureg.h"
#include "st_mesa_to_tgsi.h"
+#include "st_context.h"
#include "shader/prog_instruction.h"
#include "shader/prog_parameter.h"
-#include "shader/prog_print.h"
#include "util/u_debug.h"
#include "util/u_math.h"
#include "util/u_memory.h"
unsigned token;
};
+
+/**
+ * Intermediate state used during shader translation.
+ */
struct st_translate {
struct ureg_program *ureg;
struct ureg_src inputs[PIPE_MAX_SHADER_INPUTS];
struct ureg_dst address[1];
struct ureg_src samplers[PIPE_MAX_SAMPLERS];
+ struct ureg_dst psizregreal;
+ struct ureg_src pointSizeConst;
+ GLint psizoutindex;
+ GLboolean prevInstWrotePsiz;
const GLuint *inputMapping;
const GLuint *outputMapping;
return t->temps[index];
case PROGRAM_OUTPUT:
+ if (index == t->psizoutindex)
+ t->prevInstWrotePsiz = GL_TRUE;
return t->outputs[t->outputMapping[index]];
case PROGRAM_ADDRESS:
static struct ureg_src
src_register( struct st_translate *t,
gl_register_file file,
- GLuint index )
+ GLint index )
{
switch( file ) {
case PROGRAM_UNDEFINED:
return ureg_src_undef();
case PROGRAM_TEMPORARY:
+ ASSERT(index >= 0);
if (ureg_dst_is_undef(t->temps[index]))
t->temps[index] = ureg_DECL_temporary( t->ureg );
return ureg_src(t->temps[index]);
- case PROGRAM_STATE_VAR:
case PROGRAM_NAMED_PARAM:
case PROGRAM_ENV_PARAM:
+ case PROGRAM_LOCAL_PARAM:
case PROGRAM_UNIFORM:
- case PROGRAM_CONSTANT: /* ie, immediate */
+ ASSERT(index >= 0);
return t->constants[index];
+ case PROGRAM_STATE_VAR:
+ case PROGRAM_CONSTANT: /* ie, immediate */
+ if (index < 0)
+ return ureg_DECL_constant( t->ureg, 0 );
+ else
+ return t->constants[index];
case PROGRAM_INPUT:
return t->inputs[t->inputMapping[index]];
if (SrcReg->Abs)
src = ureg_abs(src);
- if (SrcReg->RelAddr)
+ if (SrcReg->RelAddr) {
src = ureg_src_indirect( src, ureg_src(t->address[0]));
-
+ /* If SrcReg->Index was negative, it was set to zero in
+ * src_register(). Reassign it now.
+ */
+ src.Index = SrcReg->Index;
+ }
+
return src;
}
}
+/**
+ * Negate the value of DDY to match GL semantics where (0,0) is the
+ * lower-left corner of the window.
+ * Note that the GL_ARB_fragment_coord_conventions extension will
+ * effect this someday.
+ */
+static void emit_ddy( struct st_translate *t,
+ struct ureg_dst dst,
+ const struct prog_src_register *SrcReg )
+{
+ struct ureg_program *ureg = t->ureg;
+ struct ureg_src src = translate_src( t, SrcReg );
+ src = ureg_negate( src );
+ ureg_DDY( ureg, dst, src );
+}
+
+
static unsigned
translate_opcode( unsigned op )
ureg_MOV( ureg, dst[0], ureg_imm1f(ureg, 0.5) );
break;
-
+ case OPCODE_DDY:
+ emit_ddy( t, dst[0], &inst->SrcReg[0] );
+ break;
default:
ureg_insn( ureg,
}
}
+/**
+ * Emit the TGSI instructions to adjust the WPOS pixel center convention
+ */
+static void
+emit_adjusted_wpos( struct st_translate *t,
+ const struct gl_program *program, GLfloat value)
+{
+ struct ureg_program *ureg = t->ureg;
+ struct ureg_dst wpos_temp = ureg_DECL_temporary(ureg);
+ struct ureg_src wpos_input = t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]];
+
+ ureg_ADD(ureg, ureg_writemask(wpos_temp, TGSI_WRITEMASK_X | TGSI_WRITEMASK_Y),
+ wpos_input, ureg_imm1f(ureg, value));
+
+ t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]] = ureg_src(wpos_temp);
+}
/**
* Emit the TGSI instructions for inverting the WPOS y coordinate.
winSizeState);
struct ureg_src winsize = ureg_DECL_constant( ureg, winHeightConst );
- struct ureg_dst wpos_temp = ureg_DECL_temporary( ureg );
+ struct ureg_dst wpos_temp;
struct ureg_src wpos_input = t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]];
/* MOV wpos_temp, input[wpos]
*/
- ureg_MOV( ureg, wpos_temp, wpos_input );
+ if (wpos_input.File == TGSI_FILE_TEMPORARY)
+ wpos_temp = ureg_dst(wpos_input);
+ else {
+ wpos_temp = ureg_DECL_temporary( ureg );
+ ureg_MOV( ureg, wpos_temp, wpos_input );
+ }
/* SUB wpos_temp.y, winsize_const, wpos_input
*/
}
+/**
+ * OpenGL's fragment gl_FrontFace input is 1 for front-facing, 0 for back.
+ * TGSI uses +1 for front, -1 for back.
+ * This function converts the TGSI value to the GL value. Simply clamping/
+ * saturating the value to [0,1] does the job.
+ */
+static void
+emit_face_var( struct st_translate *t,
+ const struct gl_program *program )
+{
+ struct ureg_program *ureg = t->ureg;
+ struct ureg_dst face_temp = ureg_DECL_temporary( ureg );
+ struct ureg_src face_input = t->inputs[t->inputMapping[FRAG_ATTRIB_FACE]];
+
+ /* MOV_SAT face_temp, input[face]
+ */
+ face_temp = ureg_saturate( face_temp );
+ ureg_MOV( ureg, face_temp, face_input );
+
+ /* Use face_temp as face input from here on:
+ */
+ t->inputs[t->inputMapping[FRAG_ATTRIB_FACE]] = ureg_src(face_temp);
+}
+
+
+static void
+emit_edgeflags( struct st_translate *t,
+ const struct gl_program *program )
+{
+ struct ureg_program *ureg = t->ureg;
+ struct ureg_dst edge_dst = t->outputs[t->outputMapping[VERT_RESULT_EDGE]];
+ struct ureg_src edge_src = t->inputs[t->inputMapping[VERT_ATTRIB_EDGEFLAG]];
+
+ ureg_MOV( ureg, edge_dst, edge_src );
+}
+
+
/**
* Translate Mesa program to TGSI format.
* \param program the program to translate
* \param outputSemanticIndex the semantic index (ex: which texcoord) for
* each output
*
- * \return array of translated tokens, caller's responsibility to free
+ * \return PIPE_OK or PIPE_ERROR_OUT_OF_MEMORY
*/
-const struct tgsi_token *
+enum pipe_error
st_translate_mesa_program(
GLcontext *ctx,
uint procType,
+ struct ureg_program *ureg,
const struct gl_program *program,
GLuint numInputs,
const GLuint inputMapping[],
const ubyte inputSemanticName[],
const ubyte inputSemanticIndex[],
const GLuint interpMode[],
- const GLbitfield inputFlags[],
GLuint numOutputs,
const GLuint outputMapping[],
const ubyte outputSemanticName[],
const ubyte outputSemanticIndex[],
- const GLbitfield outputFlags[] )
+ boolean passthrough_edgeflags )
{
struct st_translate translate, *t;
- struct ureg_program *ureg;
- const struct tgsi_token *tokens = NULL;
unsigned i;
+ enum pipe_error ret = PIPE_OK;
t = &translate;
memset(t, 0, sizeof *t);
t->procType = procType;
t->inputMapping = inputMapping;
t->outputMapping = outputMapping;
- t->ureg = ureg_create( procType );
- if (t->ureg == NULL)
- return NULL;
-
- ureg = t->ureg;
+ t->ureg = ureg;
+ t->psizoutindex = -1;
+ t->prevInstWrotePsiz = GL_FALSE;
/*_mesa_print_program(program);*/
* Declare input attributes.
*/
if (procType == TGSI_PROCESSOR_FRAGMENT) {
+ struct gl_fragment_program* fp = (struct gl_fragment_program*)program;
for (i = 0; i < numInputs; i++) {
- t->inputs[i] = ureg_DECL_fs_input(ureg,
- inputSemanticName[i],
- inputSemanticIndex[i],
- interpMode[i]);
+ if (program->InputFlags[0] & PROG_PARAM_BIT_CYL_WRAP) {
+ t->inputs[i] = ureg_DECL_fs_input_cyl(ureg,
+ inputSemanticName[i],
+ inputSemanticIndex[i],
+ interpMode[i],
+ TGSI_CYLINDRICAL_WRAP_X);
+ }
+ else {
+ t->inputs[i] = ureg_DECL_fs_input(ureg,
+ inputSemanticName[i],
+ inputSemanticIndex[i],
+ interpMode[i]);
+ }
}
if (program->InputsRead & FRAG_BIT_WPOS) {
/* Must do this after setting up t->inputs, and before
* emitting constant references, below:
*/
- emit_inverted_wpos( t, program );
+ struct pipe_screen* pscreen = st_context(ctx)->pipe->screen;
+ boolean invert = FALSE;
+
+ if (fp->OriginUpperLeft) {
+ if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT)) {
+ }
+ else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT)) {
+ ureg_property_fs_coord_origin(ureg, TGSI_FS_COORD_ORIGIN_LOWER_LEFT);
+ invert = TRUE;
+ }
+ else
+ assert(0);
+ }
+ else {
+ if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT))
+ ureg_property_fs_coord_origin(ureg, TGSI_FS_COORD_ORIGIN_LOWER_LEFT);
+ else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT))
+ invert = TRUE;
+ else
+ assert(0);
+ }
+
+ if (fp->PixelCenterInteger) {
+ if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER))
+ ureg_property_fs_coord_pixel_center(ureg, TGSI_FS_COORD_PIXEL_CENTER_INTEGER);
+ else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER))
+ emit_adjusted_wpos(t, program, invert ? 0.5f : -0.5f);
+ else
+ assert(0);
+ }
+ else {
+ if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER)) {
+ }
+ else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER)) {
+ ureg_property_fs_coord_pixel_center(ureg, TGSI_FS_COORD_PIXEL_CENTER_INTEGER);
+ emit_adjusted_wpos(t, program, invert ? -0.5f : 0.5f);
+ }
+ else
+ assert(0);
+ }
+
+ /* we invert after adjustment so that we avoid the MOV to temporary,
+ * and reuse the adjustment ADD instead */
+ if (invert)
+ emit_inverted_wpos(t, program);
+ }
+
+ if (program->InputsRead & FRAG_BIT_FACE) {
+ emit_face_var( t, program );
}
/*
t->outputs[i] = ureg_DECL_output( ureg,
outputSemanticName[i],
outputSemanticIndex[i] );
+ if ((outputSemanticName[i] == TGSI_SEMANTIC_PSIZE) && program->Id) {
+ static const gl_state_index pointSizeClampState[STATE_LENGTH]
+ = { STATE_INTERNAL, STATE_POINT_SIZE_IMPL_CLAMP, 0, 0, 0 };
+ /* XXX: note we are modifying the incoming shader here! Need to
+ * do this before emitting the constant decls below, or this
+ * will be missed:
+ */
+ unsigned pointSizeClampConst = _mesa_add_state_reference(program->Parameters,
+ pointSizeClampState);
+ struct ureg_dst psizregtemp = ureg_DECL_temporary( ureg );
+ t->pointSizeConst = ureg_DECL_constant( ureg, pointSizeClampConst );
+ t->psizregreal = t->outputs[i];
+ t->psizoutindex = i;
+ t->outputs[i] = psizregtemp;
+ }
}
+ if (passthrough_edgeflags)
+ emit_edgeflags( t, program );
}
/* Declare address register.
t->constants = CALLOC( program->Parameters->NumParameters,
sizeof t->constants[0] );
- if (t->constants == NULL)
+ if (t->constants == NULL) {
+ ret = PIPE_ERROR_OUT_OF_MEMORY;
goto out;
+ }
for (i = 0; i < program->Parameters->NumParameters; i++) {
switch (program->Parameters->Parameters[i].Type) {
case PROGRAM_ENV_PARAM:
+ case PROGRAM_LOCAL_PARAM:
case PROGRAM_STATE_VAR:
case PROGRAM_NAMED_PARAM:
case PROGRAM_UNIFORM:
for (i = 0; i < program->NumInstructions; i++) {
set_insn_start( t, ureg_get_instruction_number( ureg ));
compile_instruction( t, &program->Instructions[i] );
+
+ /* note can't do that easily at the end of prog due to
+ possible early return */
+ if (t->prevInstWrotePsiz && program->Id) {
+ set_insn_start( t, ureg_get_instruction_number( ureg ));
+ ureg_MAX( t->ureg, ureg_writemask(t->outputs[t->psizoutindex], WRITEMASK_X),
+ ureg_src(t->outputs[t->psizoutindex]),
+ ureg_swizzle(t->pointSizeConst, 1,1,1,1));
+ ureg_MIN( t->ureg, ureg_writemask(t->psizregreal, WRITEMASK_X),
+ ureg_src(t->outputs[t->psizoutindex]),
+ ureg_swizzle(t->pointSizeConst, 2,2,2,2));
+ }
+ t->prevInstWrotePsiz = GL_FALSE;
}
/* Fix up all emitted labels:
t->insn[t->labels[i].branch_target] );
}
- tokens = ureg_get_tokens( ureg, NULL );
- ureg_destroy( ureg );
-
out:
FREE(t->insn);
FREE(t->labels);
if (t->error) {
debug_printf("%s: translate error flag set\n", __FUNCTION__);
- FREE((void *)tokens);
- tokens = NULL;
- }
-
- if (!tokens) {
- debug_printf("%s: failed to translate Mesa program:\n", __FUNCTION__);
- _mesa_print_program(program);
- debug_assert(0);
}
- return tokens;
+ return ret;
}
/**
- * Tokens cannot be free with _mesa_free otherwise the builtin gallium
+ * Tokens cannot be free with free otherwise the builtin gallium
* malloc debugging will get confused.
*/
void