From: José Fonseca Date: Wed, 23 Feb 2011 18:45:04 +0000 (+0000) Subject: svga: Coalesce multiple shader constants in a single command. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=fd69fc87444af8ead30b4af64598a98df7969397;p=mesa.git svga: Coalesce multiple shader constants in a single command. HWv8 feature. Tested with GoogleEarth, Mesa demos. --- diff --git a/src/gallium/drivers/svga/svga_cmd.c b/src/gallium/drivers/svga/svga_cmd.c index ebcd4bcaf10..d7611d4d042 100644 --- a/src/gallium/drivers/svga/svga_cmd.c +++ b/src/gallium/drivers/svga/svga_cmd.c @@ -758,6 +758,59 @@ SVGA3D_SetShaderConst(struct svga_winsys_context *swc, } +/* + *---------------------------------------------------------------------- + * + * SVGA3D_SetShaderConsts -- + * + * Set the value of successive shader constants. + * + * Shader constants are analogous to uniform variables in GLSL, + * except that they belong to the render context rather than to + * an individual shader. + * + * Constants may have one of three types: A 4-vector of floats, + * a 4-vector of integers, or a single boolean flag. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +enum pipe_error +SVGA3D_SetShaderConsts(struct svga_winsys_context *swc, + uint32 reg, // IN + uint32 numRegs, // IN + SVGA3dShaderType type, // IN + SVGA3dShaderConstType ctype, // IN + const void *values) // IN +{ + SVGA3dCmdSetShaderConst *cmd; + + cmd = SVGA3D_FIFOReserve(swc, + SVGA_3D_CMD_SET_SHADER_CONST, + sizeof *cmd + (numRegs - 1) * sizeof cmd->values, + 0); + if(!cmd) + return PIPE_ERROR_OUT_OF_MEMORY; + + cmd->cid = swc->cid; + cmd->reg = reg; + cmd->type = type; + cmd->ctype = ctype; + + memcpy(&cmd->values, values, numRegs * sizeof cmd->values); + + swc->commit(swc); + + return PIPE_OK; +} + + diff --git a/src/gallium/drivers/svga/svga_cmd.h b/src/gallium/drivers/svga/svga_cmd.h index 223ab17df81..9bbe95f18b8 100644 --- a/src/gallium/drivers/svga/svga_cmd.h +++ b/src/gallium/drivers/svga/svga_cmd.h @@ -210,6 +210,14 @@ SVGA3D_SetShaderConst(struct svga_winsys_context *swc, uint32 reg, SVGA3dShaderType type, SVGA3dShaderConstType ctype, const void *value); +enum pipe_error +SVGA3D_SetShaderConsts(struct svga_winsys_context *swc, + uint32 reg, + uint32 numRegs, + SVGA3dShaderType type, + SVGA3dShaderConstType ctype, + const void *values); + enum pipe_error SVGA3D_SetShader(struct svga_winsys_context *swc, SVGA3dShaderType type, uint32 shid); diff --git a/src/gallium/drivers/svga/svga_state_constants.c b/src/gallium/drivers/svga/svga_state_constants.c index 6c3275e74c0..a28fcf91225 100644 --- a/src/gallium/drivers/svga/svga_state_constants.c +++ b/src/gallium/drivers/svga/svga_state_constants.c @@ -26,6 +26,7 @@ #include "util/u_inlines.h" #include "pipe/p_defines.h" +#include "svga_screen.h" #include "svga_context.h" #include "svga_state.h" #include "svga_cmd.h" @@ -34,6 +35,13 @@ #include "svga_hw_reg.h" + +/* + * Don't try to send more than 4k of successive constants. + */ +#define MAX_CONST_REG_COUNT 256 /* 4k */ + + /*********************************************************************** * Hardware update */ @@ -48,7 +56,9 @@ static int svga_shader_type( int shader ) return shader + 1; } - +/* + * Check and emit one shader constant register. + */ static int emit_const( struct svga_context *svga, int unit, int i, @@ -56,6 +66,8 @@ static int emit_const( struct svga_context *svga, { int ret = PIPE_OK; + assert(i < CB_MAX); + if (memcmp(svga->state.hw_draw.cb[unit][i], value, 4 * sizeof(float)) != 0) { if (SVGA_DEBUG & DEBUG_CONSTS) debug_printf("%s %s %d: %f %f %f %f\n", @@ -81,10 +93,103 @@ static int emit_const( struct svga_context *svga, return ret; } +/* + * Check and emit a range of shader constant registers, trying to coalesce + * successive shader constant updates in a single command in order to save + * space on the command buffer. This is a HWv8 feature. + */ +static enum pipe_error emit_const_range( struct svga_context *svga, + unsigned unit, + unsigned offset, + unsigned count, + const float (*values)[4] ) +{ + unsigned i, j; + enum pipe_error ret; + + assert(offset + count < CB_MAX); + + i = 0; + while (i < count) { + if (memcmp(svga->state.hw_draw.cb[unit][offset + i], + values[i], + 4 * sizeof(float)) != 0) { + + /* + * Found one dirty constant + */ + + if (SVGA_DEBUG & DEBUG_CONSTS) + debug_printf("%s %s %d: %f %f %f %f\n", + __FUNCTION__, + unit == PIPE_SHADER_VERTEX ? "VERT" : "FRAG", + offset + i, + values[i][0], + values[i][1], + values[i][2], + values[i][3]); + + /* + * Look for more consecutive dirty constants. + */ + + j = i + 1; + while (j < count && + j < i + MAX_CONST_REG_COUNT && + memcmp(svga->state.hw_draw.cb[unit][offset + j], + values[j], + 4 * sizeof(float)) != 0) { + + if (SVGA_DEBUG & DEBUG_CONSTS) + debug_printf("%s %s %d: %f %f %f %f\n", + __FUNCTION__, + unit == PIPE_SHADER_VERTEX ? "VERT" : "FRAG", + offset + j, + values[j][0], + values[j][1], + values[j][2], + values[j][3]); + + ++j; + } + + assert(j >= i + 1); + + /* + * Send them all together. + */ + + ret = SVGA3D_SetShaderConsts(svga->swc, + offset + i, j - i, + svga_shader_type(unit), + SVGA3D_CONST_TYPE_FLOAT, + values + i); + if (ret != PIPE_OK) { + return ret; + } + + /* + * Local copy of the hardware state. + */ + + memcpy(svga->state.hw_draw.cb[unit][offset + i], + values[i], + (j - i) * 4 * sizeof(float)); + + i = j + 1; + } else { + ++i; + } + } + + return PIPE_OK; +} + static int emit_consts( struct svga_context *svga, int offset, int unit ) { + struct svga_screen *ss = svga_screen(svga->pipe.screen); struct pipe_transfer *transfer = NULL; unsigned count; const float (*data)[4] = NULL; @@ -105,10 +210,18 @@ static int emit_consts( struct svga_context *svga, goto done; } - for (i = 0; i < count; i++) { - ret = emit_const( svga, unit, offset + i, data[i] ); - if (ret) + if (ss->hw_version >= SVGA3D_HWVERSION_WS8_B1) { + ret = emit_const_range( svga, unit, offset, count, data ); + if (ret != PIPE_OK) { goto done; + } + } else { + for (i = 0; i < count; i++) { + ret = emit_const( svga, unit, offset + i, data[i] ); + if (ret != PIPE_OK) { + goto done; + } + } } done: