X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_mesa_to_tgsi.c;h=7a686b199d57f3cd97140369fd248db1dcb2e01b;hb=72eb5a3cfe29eabdd0a2386642b36f9648a911fc;hp=fdf023d6ae39b674bf9207c2bfb29fcaa63dbb45;hpb=7c6a89727543e7f0b72b792ec77f02565337e923;p=mesa.git diff --git a/src/mesa/state_tracker/st_mesa_to_tgsi.c b/src/mesa/state_tracker/st_mesa_to_tgsi.c index fdf023d6ae3..7a686b199d5 100644 --- a/src/mesa/state_tracker/st_mesa_to_tgsi.c +++ b/src/mesa/state_tracker/st_mesa_to_tgsi.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2007-2008 VMware, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -18,7 +18,7 @@ * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * 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. @@ -32,9 +32,10 @@ */ #include "pipe/p_compiler.h" +#include "pipe/p_context.h" +#include "pipe/p_screen.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" @@ -43,6 +44,13 @@ #include "util/u_debug.h" #include "util/u_math.h" #include "util/u_memory.h" +#include "st_glsl_to_tgsi.h" /* for _mesa_sysval_to_semantic */ + + +#define PROGRAM_ANY_CONST ((1 << PROGRAM_STATE_VAR) | \ + (1 << PROGRAM_CONSTANT) | \ + (1 << PROGRAM_UNIFORM)) + struct label { unsigned branch_target; @@ -62,12 +70,7 @@ struct st_translate { struct ureg_src inputs[PIPE_MAX_SHADER_INPUTS]; struct ureg_dst address[1]; struct ureg_src samplers[PIPE_MAX_SAMPLERS]; - - /* Extra info for handling point size clamping in vertex shader */ - struct ureg_dst pointSizeResult; /**< Actual point size output register */ - struct ureg_src pointSizeConst; /**< Point size range constant register */ - GLint pointSizeOutIndex; /**< Temp point size output register */ - GLboolean prevInstWrotePointSize; + struct ureg_src systemValues[SYSTEM_VALUE_MAX]; const GLuint *inputMapping; const GLuint *outputMapping; @@ -106,11 +109,8 @@ static unsigned *get_label( struct st_translate *t, unsigned i; if (t->labels_count + 1 >= t->labels_size) { - unsigned old_size = t->labels_size; t->labels_size = 1 << (util_logbase2(t->labels_size) + 1); - t->labels = REALLOC( t->labels, - old_size * sizeof t->labels[0], - t->labels_size * sizeof t->labels[0] ); + t->labels = realloc(t->labels, t->labels_size * sizeof t->labels[0]); if (t->labels == NULL) { static unsigned dummy; t->error = TRUE; @@ -134,11 +134,8 @@ static void set_insn_start( struct st_translate *t, unsigned start ) { if (t->insn_count + 1 >= t->insn_size) { - unsigned old_size = t->insn_size; t->insn_size = 1 << (util_logbase2(t->insn_size) + 1); - t->insn = REALLOC( t->insn, - old_size * sizeof t->insn[0], - t->insn_size * sizeof t->insn[0] ); + t->insn = realloc(t->insn, t->insn_size * sizeof t->insn[0]); if (t->insn == NULL) { t->error = TRUE; return; @@ -168,17 +165,14 @@ dst_register( struct st_translate *t, return t->temps[index]; case PROGRAM_OUTPUT: - if (t->procType == TGSI_PROCESSOR_VERTEX && index == VERT_RESULT_PSIZ) - t->prevInstWrotePointSize = GL_TRUE; - if (t->procType == TGSI_PROCESSOR_VERTEX) - assert(index < VERT_RESULT_MAX); + assert(index < VARYING_SLOT_MAX); else if (t->procType == TGSI_PROCESSOR_FRAGMENT) assert(index < FRAG_RESULT_MAX); else - assert(0 && "geom shaders not handled in dst_register() yet"); + assert(index < VARYING_SLOT_MAX); - assert(t->outputMapping[index] < Elements(t->outputs)); + assert(t->outputMapping[index] < ARRAY_SIZE(t->outputs)); return t->outputs[t->outputMapping[index]]; @@ -205,17 +199,14 @@ src_register( struct st_translate *t, return ureg_src_undef(); case PROGRAM_TEMPORARY: - ASSERT(index >= 0); + assert(index >= 0); + assert(index < ARRAY_SIZE(t->temps)); if (ureg_dst_is_undef(t->temps[index])) t->temps[index] = ureg_DECL_temporary( t->ureg ); - assert(index < Elements(t->temps)); return ureg_src(t->temps[index]); - case PROGRAM_NAMED_PARAM: - case PROGRAM_ENV_PARAM: - case PROGRAM_LOCAL_PARAM: case PROGRAM_UNIFORM: - ASSERT(index >= 0); + assert(index >= 0); return t->constants[index]; case PROGRAM_STATE_VAR: case PROGRAM_CONSTANT: /* ie, immediate */ @@ -225,16 +216,20 @@ src_register( struct st_translate *t, return t->constants[index]; case PROGRAM_INPUT: - assert(t->inputMapping[index] < Elements(t->inputs)); + assert(t->inputMapping[index] < ARRAY_SIZE(t->inputs)); return t->inputs[t->inputMapping[index]]; case PROGRAM_OUTPUT: - assert(t->outputMapping[index] < Elements(t->outputs)); + assert(t->outputMapping[index] < ARRAY_SIZE(t->outputs)); return ureg_src(t->outputs[t->outputMapping[index]]); /* not needed? */ case PROGRAM_ADDRESS: return ureg_src(t->address[index]); + case PROGRAM_SYSTEM_VALUE: + assert(index < ARRAY_SIZE(t->systemValues)); + return t->systemValues[index]; + default: debug_assert( 0 ); return ureg_src_undef(); @@ -245,39 +240,82 @@ src_register( struct st_translate *t, /** * Map mesa texture target to TGSI texture target. */ -static unsigned -translate_texture_target( GLuint textarget, - GLboolean shadow ) +unsigned +st_translate_texture_target(GLuint textarget, GLboolean shadow) { if (shadow) { - switch( textarget ) { - case TEXTURE_1D_INDEX: return TGSI_TEXTURE_SHADOW1D; - case TEXTURE_2D_INDEX: return TGSI_TEXTURE_SHADOW2D; - case TEXTURE_RECT_INDEX: return TGSI_TEXTURE_SHADOWRECT; - default: break; + switch (textarget) { + case TEXTURE_1D_INDEX: + return TGSI_TEXTURE_SHADOW1D; + case TEXTURE_2D_INDEX: + return TGSI_TEXTURE_SHADOW2D; + case TEXTURE_RECT_INDEX: + return TGSI_TEXTURE_SHADOWRECT; + case TEXTURE_1D_ARRAY_INDEX: + return TGSI_TEXTURE_SHADOW1D_ARRAY; + case TEXTURE_2D_ARRAY_INDEX: + return TGSI_TEXTURE_SHADOW2D_ARRAY; + case TEXTURE_CUBE_INDEX: + return TGSI_TEXTURE_SHADOWCUBE; + case TEXTURE_CUBE_ARRAY_INDEX: + return TGSI_TEXTURE_SHADOWCUBE_ARRAY; + default: + break; } } - switch( textarget ) { - case TEXTURE_1D_INDEX: return TGSI_TEXTURE_1D; - case TEXTURE_2D_INDEX: return TGSI_TEXTURE_2D; - case TEXTURE_3D_INDEX: return TGSI_TEXTURE_3D; - case TEXTURE_CUBE_INDEX: return TGSI_TEXTURE_CUBE; - case TEXTURE_RECT_INDEX: return TGSI_TEXTURE_RECT; + switch (textarget) { + case TEXTURE_2D_MULTISAMPLE_INDEX: + return TGSI_TEXTURE_2D_MSAA; + case TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX: + return TGSI_TEXTURE_2D_ARRAY_MSAA; + case TEXTURE_BUFFER_INDEX: + return TGSI_TEXTURE_BUFFER; + case TEXTURE_1D_INDEX: + return TGSI_TEXTURE_1D; + case TEXTURE_2D_INDEX: + return TGSI_TEXTURE_2D; + case TEXTURE_3D_INDEX: + return TGSI_TEXTURE_3D; + case TEXTURE_CUBE_INDEX: + return TGSI_TEXTURE_CUBE; + case TEXTURE_CUBE_ARRAY_INDEX: + return TGSI_TEXTURE_CUBE_ARRAY; + case TEXTURE_RECT_INDEX: + return TGSI_TEXTURE_RECT; + case TEXTURE_1D_ARRAY_INDEX: + return TGSI_TEXTURE_1D_ARRAY; + case TEXTURE_2D_ARRAY_INDEX: + return TGSI_TEXTURE_2D_ARRAY; + case TEXTURE_EXTERNAL_INDEX: + return TGSI_TEXTURE_2D; default: - debug_assert( 0 ); + debug_assert(!"unexpected texture target index"); return TGSI_TEXTURE_1D; } } +/** + * Translate a (1 << TEXTURE_x_INDEX) bit into a TGSI_TEXTURE_x enum. + */ +static unsigned +translate_texture_index(GLbitfield texBit, bool shadow) +{ + int index = ffs(texBit); + assert(index > 0); + assert(index - 1 < NUM_TEXTURE_TARGETS); + return st_translate_texture_target(index - 1, shadow); +} + + /** * Create a TGSI ureg_dst register from a Mesa dest register. */ static struct ureg_dst translate_dst( struct st_translate *t, const struct prog_dst_register *DstReg, - boolean saturate ) + boolean saturate) { struct ureg_dst dst = dst_register( t, DstReg->File, @@ -314,9 +352,6 @@ translate_src( struct st_translate *t, if (SrcReg->Negate == NEGATE_XYZW) src = ureg_negate(src); - if (SrcReg->Abs) - src = ureg_abs(src); - if (SrcReg->RelAddr) { src = ureg_src_indirect( src, ureg_src(t->address[0])); if (SrcReg->File != PROGRAM_INPUT && @@ -460,24 +495,6 @@ static void emit_swz( struct st_translate *t, } -/** - * 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 ) { @@ -492,8 +509,6 @@ translate_opcode( unsigned op ) return TGSI_OPCODE_BGNLOOP; case OPCODE_BGNSUB: return TGSI_OPCODE_BGNSUB; - case OPCODE_BRA: - return TGSI_OPCODE_BRA; case OPCODE_BRK: return TGSI_OPCODE_BRK; case OPCODE_CAL: @@ -510,8 +525,6 @@ translate_opcode( unsigned op ) return TGSI_OPCODE_DDY; case OPCODE_DP2: return TGSI_OPCODE_DP2; - case OPCODE_DP2A: - return TGSI_OPCODE_DP2A; case OPCODE_DP3: return TGSI_OPCODE_DP3; case OPCODE_DP4: @@ -522,10 +535,6 @@ translate_opcode( unsigned op ) return TGSI_OPCODE_DST; case OPCODE_ELSE: return TGSI_OPCODE_ELSE; - case OPCODE_EMIT_VERTEX: - return TGSI_OPCODE_EMIT; - case OPCODE_END_PRIMITIVE: - return TGSI_OPCODE_ENDPRIM; case OPCODE_ENDIF: return TGSI_OPCODE_ENDIF; case OPCODE_ENDLOOP: @@ -545,9 +554,7 @@ translate_opcode( unsigned op ) case OPCODE_TRUNC: return TGSI_OPCODE_TRUNC; case OPCODE_KIL: - return TGSI_OPCODE_KIL; - case OPCODE_KIL_NV: - return TGSI_OPCODE_KILP; + return TGSI_OPCODE_KILL_IF; case OPCODE_LG2: return TGSI_OPCODE_LG2; case OPCODE_LOG: @@ -568,18 +575,12 @@ translate_opcode( unsigned op ) return TGSI_OPCODE_MUL; case OPCODE_NOP: return TGSI_OPCODE_NOP; - case OPCODE_NRM3: - return TGSI_OPCODE_NRM; - case OPCODE_NRM4: - return TGSI_OPCODE_NRM4; case OPCODE_POW: return TGSI_OPCODE_POW; case OPCODE_RCP: return TGSI_OPCODE_RCP; case OPCODE_RET: return TGSI_OPCODE_RET; - case OPCODE_RSQ: - return TGSI_OPCODE_RSQ; case OPCODE_SCS: return TGSI_OPCODE_SCS; case OPCODE_SEQ: @@ -623,12 +624,13 @@ translate_opcode( unsigned op ) static void compile_instruction( + struct gl_context *ctx, struct st_translate *t, - const struct prog_instruction *inst ) + const struct prog_instruction *inst) { struct ureg_program *ureg = t->ureg; GLuint i; - struct ureg_dst dst[1]; + struct ureg_dst dst[1] = { { 0 } }; struct ureg_src src[4]; unsigned num_dst; unsigned num_src; @@ -639,7 +641,7 @@ compile_instruction( if (num_dst) dst[0] = translate_dst( t, &inst->DstReg, - inst->SaturateMode ); + inst->Saturate); for (i = 0; i < num_src; i++) src[i] = translate_src( t, &inst->SrcReg[i] ); @@ -653,7 +655,6 @@ compile_instruction( case OPCODE_CAL: case OPCODE_ELSE: case OPCODE_ENDLOOP: - case OPCODE_IF: debug_assert(num_dst == 0); ureg_label_insn( ureg, translate_opcode( inst->Opcode ), @@ -661,6 +662,14 @@ compile_instruction( get_label( t, inst->BranchTarget )); return; + case OPCODE_IF: + debug_assert(num_dst == 0); + ureg_label_insn( ureg, + ctx->Const.NativeIntegers ? TGSI_OPCODE_UIF : TGSI_OPCODE_IF, + src, num_src, + get_label( t, inst->BranchTarget )); + return; + case OPCODE_TEX: case OPCODE_TXB: case OPCODE_TXD: @@ -670,8 +679,9 @@ compile_instruction( ureg_tex_insn( ureg, translate_opcode( inst->Opcode ), dst, num_dst, - translate_texture_target( inst->TexSrcTarget, + st_translate_texture_target( inst->TexSrcTarget, inst->TexShadow ), + NULL, 0, src, num_src ); return; @@ -703,9 +713,9 @@ compile_instruction( */ ureg_MOV( ureg, dst[0], ureg_imm1f(ureg, 0.5) ); break; - - case OPCODE_DDY: - emit_ddy( t, dst[0], &inst->SrcReg[0] ); + + case OPCODE_RSQ: + ureg_RSQ( ureg, dst[0], ureg_abs(src[0]) ); break; default: @@ -719,30 +729,16 @@ compile_instruction( /** - * 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. + * Emit the TGSI instructions for inverting and adjusting WPOS. + * This code is unavoidable because it also depends on whether + * a FBO is bound (STATE_FB_WPOS_Y_TRANSFORM). */ static void -emit_inverted_wpos( struct st_translate *t, - const struct gl_program *program ) +emit_wpos_adjustment(struct gl_context *ctx, + struct st_translate *t, + const struct gl_program *program, + boolean invert, + GLfloat adjX, GLfloat adjY[2]) { struct ureg_program *ureg = t->ureg; @@ -750,44 +746,79 @@ emit_inverted_wpos( struct st_translate *t, * Need to replace instances of INPUT[WPOS] with temp T * where T = INPUT[WPOS] by y is inverted. */ - static const gl_state_index winSizeState[STATE_LENGTH] - = { STATE_INTERNAL, STATE_FB_SIZE, 0, 0, 0 }; + static const gl_state_index wposTransformState[STATE_LENGTH] + = { STATE_INTERNAL, STATE_FB_WPOS_Y_TRANSFORM, 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 winHeightConst = _mesa_add_state_reference(program->Parameters, - winSizeState); - - struct ureg_src winsize = ureg_DECL_constant( ureg, winHeightConst ); - struct ureg_dst wpos_temp; - struct ureg_src wpos_input = t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]]; - - /* MOV wpos_temp, input[wpos] - */ - if (wpos_input.File == TGSI_FILE_TEMPORARY) - wpos_temp = ureg_dst(wpos_input); - else { - wpos_temp = ureg_DECL_temporary( ureg ); + unsigned wposTransConst = _mesa_add_state_reference(program->Parameters, + wposTransformState); + + struct ureg_src wpostrans = ureg_DECL_constant( ureg, wposTransConst ); + struct ureg_dst wpos_temp = ureg_DECL_temporary( ureg ); + struct ureg_src *wpos = + ctx->Const.GLSLFragCoordIsSysVal ? + &t->systemValues[SYSTEM_VALUE_FRAG_COORD] : + &t->inputs[t->inputMapping[VARYING_SLOT_POS]]; + struct ureg_src wpos_input = *wpos; + + /* First, apply the coordinate shift: */ + if (adjX || adjY[0] || adjY[1]) { + if (adjY[0] != adjY[1]) { + /* Adjust the y coordinate by adjY[1] or adjY[0] respectively + * depending on whether inversion is actually going to be applied + * or not, which is determined by testing against the inversion + * state variable used below, which will be either +1 or -1. + */ + struct ureg_dst adj_temp = ureg_DECL_temporary(ureg); + + ureg_CMP(ureg, adj_temp, + ureg_scalar(wpostrans, invert ? 2 : 0), + ureg_imm4f(ureg, adjX, adjY[0], 0.0f, 0.0f), + ureg_imm4f(ureg, adjX, adjY[1], 0.0f, 0.0f)); + ureg_ADD(ureg, wpos_temp, wpos_input, ureg_src(adj_temp)); + } else { + ureg_ADD(ureg, wpos_temp, wpos_input, + ureg_imm4f(ureg, adjX, adjY[0], 0.0f, 0.0f)); + } + wpos_input = ureg_src(wpos_temp); + } else { + /* MOV wpos_temp, input[wpos] + */ ureg_MOV( ureg, wpos_temp, wpos_input ); } - /* SUB wpos_temp.y, winsize_const, wpos_input + /* Now the conditional y flip: STATE_FB_WPOS_Y_TRANSFORM.xy/zw will be + * inversion/identity, or the other way around if we're drawing to an FBO. */ - ureg_SUB( ureg, - ureg_writemask(wpos_temp, TGSI_WRITEMASK_Y ), - winsize, - wpos_input); + if (invert) { + /* MAD wpos_temp.y, wpos_input, wpostrans.xxxx, wpostrans.yyyy + */ + ureg_MAD( ureg, + ureg_writemask(wpos_temp, TGSI_WRITEMASK_Y ), + wpos_input, + ureg_scalar(wpostrans, 0), + ureg_scalar(wpostrans, 1)); + } else { + /* MAD wpos_temp.y, wpos_input, wpostrans.zzzz, wpostrans.wwww + */ + ureg_MAD( ureg, + ureg_writemask(wpos_temp, TGSI_WRITEMASK_Y ), + wpos_input, + ureg_scalar(wpostrans, 2), + ureg_scalar(wpostrans, 3)); + } /* Use wpos_temp as position input from here on: */ - t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]] = ureg_src(wpos_temp); + *wpos = ureg_src(wpos_temp); } /** - * Emit fragment position/ooordinate code. + * Emit fragment position/coordinate code. */ static void emit_wpos(struct st_context *st, @@ -798,41 +829,91 @@ emit_wpos(struct st_context *st, const struct gl_fragment_program *fp = (const struct gl_fragment_program *) program; struct pipe_screen *pscreen = st->pipe->screen; + GLfloat adjX = 0.0f; + GLfloat adjY[2] = { 0.0f, 0.0f }; boolean invert = FALSE; + /* Query the pixel center conventions supported by the pipe driver and set + * adjX, adjY to help out if it cannot handle the requested one internally. + * + * The bias of the y-coordinate depends on whether y-inversion takes place + * (adjY[1]) or not (adjY[0]), which is in turn dependent on whether we are + * drawing to an FBO (causes additional inversion), and whether the the pipe + * driver origin and the requested origin differ (the latter condition is + * stored in the 'invert' variable). + * + * For height = 100 (i = integer, h = half-integer, l = lower, u = upper): + * + * center shift only: + * i -> h: +0.5 + * h -> i: -0.5 + * + * inversion only: + * l,i -> u,i: ( 0.0 + 1.0) * -1 + 100 = 99 + * l,h -> u,h: ( 0.5 + 0.0) * -1 + 100 = 99.5 + * u,i -> l,i: (99.0 + 1.0) * -1 + 100 = 0 + * u,h -> l,h: (99.5 + 0.0) * -1 + 100 = 0.5 + * + * inversion and center shift: + * l,i -> u,h: ( 0.0 + 0.5) * -1 + 100 = 99.5 + * l,h -> u,i: ( 0.5 + 0.5) * -1 + 100 = 99 + * u,i -> l,h: (99.0 + 0.5) * -1 + 100 = 0.5 + * u,h -> l,i: (99.5 + 0.5) * -1 + 100 = 0 + */ if (fp->OriginUpperLeft) { + /* Fragment shader wants origin in upper-left */ if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT)) { + /* the driver supports upper-left origin */ } 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); + /* the driver supports lower-left origin, need to invert Y */ + ureg_property(ureg, TGSI_PROPERTY_FS_COORD_ORIGIN, + TGSI_FS_COORD_ORIGIN_LOWER_LEFT); invert = TRUE; } else assert(0); } else { + /* Fragment shader wants origin in lower-left */ 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); + /* the driver supports lower-left origin */ + ureg_property(ureg, TGSI_PROPERTY_FS_COORD_ORIGIN, + TGSI_FS_COORD_ORIGIN_LOWER_LEFT); else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT)) + /* the driver supports upper-left origin, need to invert Y */ 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); + /* Fragment shader wants pixel center integer */ + if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER)) { + /* the driver supports pixel center integer */ + adjY[1] = 1.0f; + ureg_property(ureg, TGSI_PROPERTY_FS_COORD_PIXEL_CENTER, + TGSI_FS_COORD_PIXEL_CENTER_INTEGER); + } + else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER)) { + /* the driver supports pixel center half integer, need to bias X,Y */ + adjX = -0.5f; + adjY[0] = -0.5f; + adjY[1] = 0.5f; + } else assert(0); } else { + /* Fragment shader wants pixel center half integer */ if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER)) { + /* the driver supports 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); + /* the driver supports pixel center integer, need to bias X,Y */ + adjX = adjY[0] = adjY[1] = 0.5f; + ureg_property(ureg, TGSI_PROPERTY_FS_COORD_PIXEL_CENTER, + TGSI_FS_COORD_PIXEL_CENTER_INTEGER); } else assert(0); @@ -840,45 +921,7 @@ emit_wpos(struct st_context *st, /* 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); -} - - -/** - * 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 ); + emit_wpos_adjustment(st->ctx, t, program, invert, adjX, adjY); } @@ -903,7 +946,7 @@ emit_edgeflags( struct st_translate *t, */ enum pipe_error st_translate_mesa_program( - GLcontext *ctx, + struct gl_context *ctx, uint procType, struct ureg_program *ureg, const struct gl_program *program, @@ -915,15 +958,14 @@ st_translate_mesa_program( GLuint numOutputs, const GLuint outputMapping[], const ubyte outputSemanticName[], - const ubyte outputSemanticIndex[], - boolean passthrough_edgeflags ) + const ubyte outputSemanticIndex[]) { struct st_translate translate, *t; unsigned i; enum pipe_error ret = PIPE_OK; - assert(numInputs <= Elements(t->inputs)); - assert(numOutputs <= Elements(t->outputs)); + assert(numInputs <= ARRAY_SIZE(t->inputs)); + assert(numOutputs <= ARRAY_SIZE(t->outputs)); t = &translate; memset(t, 0, sizeof *t); @@ -932,8 +974,6 @@ st_translate_mesa_program( t->inputMapping = inputMapping; t->outputMapping = outputMapping; t->ureg = ureg; - t->pointSizeOutIndex = -1; - t->prevInstWrotePointSize = GL_FALSE; /*_mesa_print_program(program);*/ @@ -942,32 +982,19 @@ st_translate_mesa_program( */ if (procType == TGSI_PROCESSOR_FRAGMENT) { for (i = 0; i < numInputs; 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]); - } + t->inputs[i] = ureg_DECL_fs_input(ureg, + inputSemanticName[i], + inputSemanticIndex[i], + interpMode[i]); } - if (program->InputsRead & FRAG_BIT_WPOS) { + if (program->InputsRead & VARYING_BIT_POS) { /* Must do this after setting up t->inputs, and before * emitting constant references, below: */ emit_wpos(st_context(ctx), t, program, ureg); } - if (program->InputsRead & FRAG_BIT_FACE) { - emit_face_var( t, program ); - } - /* * Declare output attributes. */ @@ -981,6 +1008,13 @@ st_translate_mesa_program( t->outputs[i] = ureg_writemask( t->outputs[i], TGSI_WRITEMASK_Z ); break; + case TGSI_SEMANTIC_STENCIL: + t->outputs[i] = ureg_DECL_output( ureg, + TGSI_SEMANTIC_STENCIL, /* Stencil */ + outputSemanticIndex[i] ); + t->outputs[i] = ureg_writemask( t->outputs[i], + TGSI_WRITEMASK_Y ); + break; case TGSI_SEMANTIC_COLOR: t->outputs[i] = ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, @@ -994,10 +1028,9 @@ st_translate_mesa_program( } else if (procType == TGSI_PROCESSOR_GEOMETRY) { for (i = 0; i < numInputs; i++) { - t->inputs[i] = ureg_DECL_gs_input(ureg, - i, - inputSemanticName[i], - inputSemanticIndex[i]); + t->inputs[i] = ureg_DECL_input(ureg, + inputSemanticName[i], + inputSemanticIndex[i], 0, 1); } for (i = 0; i < numOutputs; i++) { @@ -1017,28 +1050,14 @@ st_translate_mesa_program( t->outputs[i] = ureg_DECL_output( ureg, outputSemanticName[i], outputSemanticIndex[i] ); - if ((outputSemanticName[i] == TGSI_SEMANTIC_PSIZE) && program->Id) { - /* Writing to the point size result register requires special - * handling to implement clamping. - */ - 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->pointSizeResult = t->outputs[i]; - t->pointSizeOutIndex = i; - t->outputs[i] = psizregtemp; - } + if (outputSemanticName[i] == TGSI_SEMANTIC_FOG) { + /* force register to contain a fog coordinate in the form (F, 0, 0, 1). */ + ureg_MOV(ureg, + ureg_writemask(t->outputs[i], TGSI_WRITEMASK_YZW), + ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 1.0f)); + t->outputs[i] = ureg_writemask(t->outputs[i], TGSI_WRITEMASK_X); + } } - if (passthrough_edgeflags) - emit_edgeflags( t, program ); } /* Declare address register. @@ -1048,39 +1067,88 @@ st_translate_mesa_program( t->address[0] = ureg_DECL_address( ureg ); } + /* Declare misc input registers + */ + { + GLbitfield sysInputs = program->SystemValuesRead; + + for (i = 0; sysInputs; i++) { + if (sysInputs & (1 << i)) { + unsigned semName = _mesa_sysval_to_semantic[i]; + + t->systemValues[i] = ureg_DECL_system_value(ureg, semName, 0); + + if (semName == TGSI_SEMANTIC_INSTANCEID || + semName == TGSI_SEMANTIC_VERTEXID) { + /* From Gallium perspective, these system values are always + * integer, and require native integer support. However, if + * native integer is supported on the vertex stage but not the + * pixel stage (e.g, i915g + draw), Mesa will generate IR that + * assumes these system values are floats. To resolve the + * inconsistency, we insert a U2F. + */ + struct st_context *st = st_context(ctx); + struct pipe_screen *pscreen = st->pipe->screen; + assert(procType == TGSI_PROCESSOR_VERTEX); + assert(pscreen->get_shader_param(pscreen, PIPE_SHADER_VERTEX, PIPE_SHADER_CAP_INTEGERS)); + (void) pscreen; /* silence non-debug build warnings */ + if (!ctx->Const.NativeIntegers) { + struct ureg_dst temp = ureg_DECL_local_temporary(t->ureg); + ureg_U2F( t->ureg, ureg_writemask(temp, TGSI_WRITEMASK_X), t->systemValues[i]); + t->systemValues[i] = ureg_scalar(ureg_src(temp), 0); + } + } + + if (procType == TGSI_PROCESSOR_FRAGMENT && + semName == TGSI_SEMANTIC_POSITION) + emit_wpos(st_context(ctx), t, program, ureg); + + sysInputs &= ~(1 << i); + } + } + } + + if (program->IndirectRegisterFiles & (1 << PROGRAM_TEMPORARY)) { + /* If temps are accessed with indirect addressing, declare temporaries + * in sequential order. Else, we declare them on demand elsewhere. + */ + for (i = 0; i < program->NumTemporaries; i++) { + /* XXX use TGSI_FILE_TEMPORARY_ARRAY when it's supported by ureg */ + t->temps[i] = ureg_DECL_temporary( t->ureg ); + } + } + /* Emit constants and immediates. Mesa uses a single index space * for these, so we put all the translated regs in t->constants. */ if (program->Parameters) { - t->constants = CALLOC( program->Parameters->NumParameters, + t->constants = calloc( program->Parameters->NumParameters, sizeof t->constants[0] ); 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: t->constants[i] = ureg_DECL_constant( ureg, i ); break; - /* Emit immediates only when there is no address register - * in use. FIXME: Be smarter and recognize param arrays: + /* Emit immediates only when there's no indirect addressing of + * the const buffer. + * FIXME: Be smarter and recognize param arrays: * indirect addressing is only valid within the referenced * array. */ case PROGRAM_CONSTANT: - if (program->NumAddressRegs > 0) + if (program->IndirectRegisterFiles & PROGRAM_ANY_CONST) t->constants[i] = ureg_DECL_constant( ureg, i ); else t->constants[i] = ureg_DECL_immediate( ureg, - program->Parameters->ParameterValues[i], + (const float*) program->Parameters->ParameterValues[i], 4 ); break; default: @@ -1090,9 +1158,18 @@ st_translate_mesa_program( } /* texture samplers */ - for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) { + for (i = 0; i < ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTextureImageUnits; i++) { if (program->SamplersUsed & (1 << i)) { + unsigned target = + translate_texture_index(program->TexturesUsed[i], + !!(program->ShadowSamplers & (1 << i))); t->samplers[i] = ureg_DECL_sampler( ureg, i ); + ureg_DECL_sampler_view(ureg, i, target, + TGSI_RETURN_TYPE_FLOAT, + TGSI_RETURN_TYPE_FLOAT, + TGSI_RETURN_TYPE_FLOAT, + TGSI_RETURN_TYPE_FLOAT); + } } @@ -1100,26 +1177,7 @@ st_translate_mesa_program( */ for (i = 0; i < program->NumInstructions; i++) { set_insn_start( t, ureg_get_instruction_number( ureg )); - compile_instruction( t, &program->Instructions[i] ); - - if (t->prevInstWrotePointSize && program->Id) { - /* The previous instruction wrote to the (fake) vertex point size - * result register. Now we need to clamp that value to the min/max - * point size range, putting the result into the real point size - * register. - * Note that we can't do this easily at the end of program due to - * possible early return. - */ - set_insn_start( t, ureg_get_instruction_number( ureg )); - ureg_MAX( t->ureg, - ureg_writemask(t->outputs[t->pointSizeOutIndex], WRITEMASK_X), - ureg_src(t->outputs[t->pointSizeOutIndex]), - ureg_swizzle(t->pointSizeConst, 1,1,1,1)); - ureg_MIN( t->ureg, ureg_writemask(t->pointSizeResult, WRITEMASK_X), - ureg_src(t->outputs[t->pointSizeOutIndex]), - ureg_swizzle(t->pointSizeConst, 2,2,2,2)); - } - t->prevInstWrotePointSize = GL_FALSE; + compile_instruction(ctx, t, &program->Instructions[i]); } /* Fix up all emitted labels: @@ -1131,24 +1189,13 @@ st_translate_mesa_program( } out: - FREE(t->insn); - FREE(t->labels); - FREE(t->constants); + free(t->insn); + free(t->labels); + free(t->constants); if (t->error) { - debug_printf("%s: translate error flag set\n", __FUNCTION__); + debug_printf("%s: translate error flag set\n", __func__); } return ret; } - - -/** - * Tokens cannot be free with free otherwise the builtin gallium - * malloc debugging will get confused. - */ -void -st_free_tokens(const struct tgsi_token *tokens) -{ - FREE((void *)tokens); -}