Commit 320e33dc authored by Ivan Gyurdiev's avatar Ivan Gyurdiev Committed by Alexandre Julliard

wined3d: Merge register counting pass.

parent aadafd64
...@@ -27,6 +27,15 @@ ...@@ -27,6 +27,15 @@
WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader); WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
inline static BOOL shader_is_version_token(DWORD token) {
return 0xFFFF0000 == (token & 0xFFFF0000) ||
0xFFFE0000 == (token & 0xFFFF0000);
}
inline static BOOL shader_is_comment_token(DWORD token) {
return D3DSIO_COMMENT == (token & D3DSI_OPCODE_MASK);
}
int shader_addline( int shader_addline(
SHADER_BUFFER* buffer, SHADER_BUFFER* buffer,
const char *format, ...) { const char *format, ...) {
...@@ -78,4 +87,76 @@ const SHADER_OPCODE* shader_get_opcode( ...@@ -78,4 +87,76 @@ const SHADER_OPCODE* shader_get_opcode(
return NULL; return NULL;
} }
/* Note: For vertex shaders,
* texUsed = addrUsed, and
* D3DSPR_TEXTURE = D3DSPR_ADDR.
*
* Also note that this does not count the loop register
* as an address register. */
void shader_get_registers_used(
IWineD3DBaseShader *iface,
CONST DWORD* pToken,
DWORD* tempsUsed,
DWORD* texUsed) {
if (pToken == NULL)
return;
*tempsUsed = 0;
*texUsed = 0;
while (D3DVS_END() != *pToken) {
CONST SHADER_OPCODE* curOpcode;
/* Skip version */
if (shader_is_version_token(*pToken)) {
++pToken;
continue;
/* Skip comments */
} else if (shader_is_comment_token(*pToken)) {
DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
++pToken;
pToken += comment_len;
continue;
}
/* Fetch opcode */
curOpcode = shader_get_opcode(iface, *pToken);
++pToken;
/* Unhandled opcode, and its parameters */
if (NULL == curOpcode) {
while (*pToken & 0x80000000)
++pToken;
continue;
/* Skip declarations (for now) */
} else if (D3DSIO_DCL == curOpcode->opcode) {
pToken += curOpcode->num_params;
continue;
/* Skip definitions (for now) */
} else if (D3DSIO_DEF == curOpcode->opcode) {
pToken += curOpcode->num_params;
continue;
/* Set texture registers, and temporary registers */
} else {
int i;
for (i = 0; i < curOpcode->num_params; ++i) {
DWORD regtype = (((*pToken) & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT);
DWORD reg = (*pToken) & D3DSP_REGNUM_MASK;
if (D3DSPR_TEXTURE == regtype)
*texUsed |= (1 << reg);
if (D3DSPR_TEMP == regtype)
*tempsUsed |= (1 << reg);
++pToken;
}
}
}
}
/* TODO: Move other shared code here */ /* TODO: Move other shared code here */
...@@ -899,63 +899,6 @@ inline static int gen_input_modifier_line(const DWORD instr, int tmpreg, char *o ...@@ -899,63 +899,6 @@ inline static int gen_input_modifier_line(const DWORD instr, int tmpreg, char *o
return insert_line; return insert_line;
} }
inline static void pshader_program_get_registers_used(
IWineD3DPixelShaderImpl *This,
CONST DWORD* pToken, DWORD* tempsUsed, DWORD* texUsed) {
if (pToken == NULL)
return;
*tempsUsed = 0;
*texUsed = 0;
while (D3DVS_END() != *pToken) {
CONST SHADER_OPCODE* curOpcode;
/* Skip version */
if (pshader_is_version_token(*pToken)) {
++pToken;
continue;
/* Skip comments */
} else if (pshader_is_comment_token(*pToken)) {
DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
++pToken;
pToken += comment_len;
continue;
}
/* Fetch opcode */
curOpcode = shader_get_opcode((IWineD3DBaseShader*) This, *pToken);
++pToken;
/* Skip declarations (for now) */
if (D3DSIO_DCL == curOpcode->opcode) {
pToken += curOpcode->num_params;
continue;
/* Skip definitions (for now) */
} else if (D3DSIO_DEF == curOpcode->opcode) {
pToken += curOpcode->num_params;
continue;
/* Set texture registers, and temporary registers */
} else {
int i;
for (i = 0; i < curOpcode->num_params; ++i) {
DWORD regtype = shader_get_regtype(*pToken);
DWORD reg = (*pToken) & D3DSP_REGNUM_MASK;
if (D3DSPR_TEXTURE == regtype)
*texUsed |= (1 << reg);
if (D3DSPR_TEMP == regtype)
*tempsUsed |= (1 << reg);
++pToken;
}
}
}
}
void pshader_set_version( void pshader_set_version(
IWineD3DPixelShaderImpl *This, IWineD3DPixelShaderImpl *This,
DWORD version) { DWORD version) {
...@@ -1055,7 +998,7 @@ inline static VOID IWineD3DPixelShaderImpl_GenerateProgramArbHW(IWineD3DPixelSha ...@@ -1055,7 +998,7 @@ inline static VOID IWineD3DPixelShaderImpl_GenerateProgramArbHW(IWineD3DPixelSha
This->constants[i] = 0; This->constants[i] = 0;
/* First pass: figure out which temporary and texture registers are used */ /* First pass: figure out which temporary and texture registers are used */
pshader_program_get_registers_used(This, pToken, &tempsUsed, &texUsed); shader_get_registers_used((IWineD3DBaseShader*) This, pToken, &tempsUsed, &texUsed);
TRACE("Texture registers used: %#lx, Temp registers used %#lx\n", texUsed, tempsUsed); TRACE("Texture registers used: %#lx, Temp registers used %#lx\n", texUsed, tempsUsed);
/* TODO: check register usage against GL/Directx limits, and fail if they're exceeded */ /* TODO: check register usage against GL/Directx limits, and fail if they're exceeded */
......
...@@ -1079,14 +1079,7 @@ inline static VOID IWineD3DVertexShaderImpl_GenerateProgramArbHW(IWineD3DVertexS ...@@ -1079,14 +1079,7 @@ inline static VOID IWineD3DVertexShaderImpl_GenerateProgramArbHW(IWineD3DVertexS
DWORD i; DWORD i;
SHADER_BUFFER buffer; SHADER_BUFFER buffer;
char tmpLine[255]; char tmpLine[255];
DWORD nUseAddressRegister = 0; DWORD addressUsed, tempsUsed;
DWORD nUseTempRegister = 0;
DWORD regtype;
DWORD reg;
BOOL tmpsUsed[32];
#if 0 /* TODO: loope register (just another address register ) */
BOOL hasLoops = FALSE;
#endif
#if 0 /* FIXME: Use the buffer that is held by the device, this is ok since fixups will be skipped for software shaders #if 0 /* FIXME: Use the buffer that is held by the device, this is ok since fixups will be skipped for software shaders
it also requires entering a critical section but cuts down the runtime footprint of wined3d and any memory fragmentation that may occur... */ it also requires entering a critical section but cuts down the runtime footprint of wined3d and any memory fragmentation that may occur... */
...@@ -1102,87 +1095,11 @@ inline static VOID IWineD3DVertexShaderImpl_GenerateProgramArbHW(IWineD3DVertexS ...@@ -1102,87 +1095,11 @@ inline static VOID IWineD3DVertexShaderImpl_GenerateProgramArbHW(IWineD3DVertexS
buffer.bsize = 0; buffer.bsize = 0;
buffer.lineNo = 0; buffer.lineNo = 0;
/* set all the tmpsUsed to not used */ /* First pass: figure out which temporary and texture registers are used */
memset(tmpsUsed, FALSE , sizeof(tmpsUsed)); shader_get_registers_used((IWineD3DBaseShader*) This, pToken, &tempsUsed, &addressUsed);
TRACE("Address registers used: %#lx, Temp registers used %#lx\n", addressUsed, tempsUsed);
/* TODO: renumbering of attributes if the values are higher than the highest supported attribute but the total number of attributes is less than the highest supported attribute */
This->highestConstant = -1;
/**
* First pass to determine what we need to declare:
* - Temporary variables
* - Address variables
*/
if (NULL != pToken) {
while (D3DVS_END() != *pToken) {
if (vshader_is_version_token(*pToken)) {
/** skip version */
++pToken;
continue;
}
if (vshader_is_comment_token(*pToken)) { /** comment */
DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
++pToken;
pToken += comment_len;
continue;
}
curOpcode = shader_get_opcode((IWineD3DBaseShader*) This, *pToken);
++pToken;
/* TODO: dcl's */
/* TODO: Consts */
if (NULL == curOpcode) {
while (*pToken & 0x80000000) {
FIXME("unrecognized opcode: %08lx\n", *pToken);
/* skip unrecognized opcode */
++pToken;
}
} else {
/* Skip declarations, handled earlier */
if (curOpcode->opcode == D3DSIO_DCL){
pToken += 2;
/* Skip definition of immediate constants, handled later */
} else if(curOpcode->opcode == D3DSIO_DEF) {
pToken += 5;
} else {
/* Check to see if and tmp or addressing redisters are used */
if (curOpcode->num_params > 0) {
regtype = shader_get_regtype(*pToken);
reg = ((*pToken) & D3DSP_REGNUM_MASK);
if (D3DSPR_ADDR == regtype && nUseAddressRegister <= reg) nUseAddressRegister = reg + 1;
if (D3DSPR_TEMP == regtype){
tmpsUsed[reg] = TRUE;
if(nUseTempRegister <= reg) nUseTempRegister = reg + 1;
}
++pToken;
for (i = 1; i < curOpcode->num_params; ++i) {
regtype = shader_get_regtype(*pToken);
reg = ((*pToken) & D3DSP_REGNUM_MASK);
if (D3DSPR_ADDR == regtype && nUseAddressRegister <= reg) nUseAddressRegister = reg + 1;
if (D3DSPR_TEMP == regtype){
tmpsUsed[reg] = TRUE;
if(nUseTempRegister <= reg) nUseTempRegister = reg + 1;
}
++pToken;
}
}
}
#if 1 /* TODO: if the shaders uses calls or loops then we need to convert the shader into glsl */
if (curOpcode->glname == GLNAME_REQUIRE_GLSL) {
FIXME("This shader requires gl shader language support\n");
#if 0
This->shaderLanguage = GLSHADER_GLSL;
#endif
}
#endif
}
}
}
/* TODO: validate /* TODO: check register usage against GL/Directx limits, and fail if they're exceeded
nUseAddressRegister < = GL_MAX_PROGRAM_ADDRESS_REGISTERS_AR nUseAddressRegister < = GL_MAX_PROGRAM_ADDRESS_REGISTERS_AR
nUseTempRegister <= GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB nUseTempRegister <= GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB
*/ */
...@@ -1195,17 +1112,18 @@ inline static VOID IWineD3DVertexShaderImpl_GenerateProgramArbHW(IWineD3DVertexS ...@@ -1195,17 +1112,18 @@ inline static VOID IWineD3DVertexShaderImpl_GenerateProgramArbHW(IWineD3DVertexS
/* FIXME: if jumps are used, use GLSL, else use ARB_vertex_program */ /* FIXME: if jumps are used, use GLSL, else use ARB_vertex_program */
shader_addline(&buffer, "!!ARBvp1.0\n"); shader_addline(&buffer, "!!ARBvp1.0\n");
/* Declare necessary things. /* Pre-declare registers */
* FIXME: replace with a bitmap for (i = 0; i < This->baseShader.limits.temporary; i++) {
* FIXME: loop counts as an address register */ if (tempsUsed & (1 << i))
shader_addline(&buffer, "TEMP T%lu;\n", i);
}
for (i = 0; i < nUseTempRegister /* we should check numTemps here */ ; i++) { for (i = 0; i < This->baseShader.limits.address; i++) {
if (tmpsUsed[i]) if (addressUsed & (1 << i))
shader_addline(&buffer, "TEMP T%ld;\n", i); shader_addline(&buffer, "ADDRESS A%ld;\n", i);
} }
for (i = 0; i < nUseAddressRegister; i++)
shader_addline(&buffer, "ADDRESS A%ld;\n", i);
/* Why do we need to alias those? */
shader_addline(&buffer, "PARAM C[%d] = { program.env[0..%d] };\n", shader_addline(&buffer, "PARAM C[%d] = { program.env[0..%d] };\n",
This->baseShader.limits.constant_float, This->baseShader.limits.constant_float,
This->baseShader.limits.constant_float - 1); This->baseShader.limits.constant_float - 1);
...@@ -1355,12 +1273,8 @@ inline static VOID IWineD3DVertexShaderImpl_GenerateProgramArbHW(IWineD3DVertexS ...@@ -1355,12 +1273,8 @@ inline static VOID IWineD3DVertexShaderImpl_GenerateProgramArbHW(IWineD3DVertexS
case D3DSIO_MOV: case D3DSIO_MOV:
/* Address registers must be loaded with the ARL instruction */ /* Address registers must be loaded with the ARL instruction */
if (shader_get_regtype(*pToken) == D3DSPR_ADDR) { if (shader_get_regtype(*pToken) == D3DSPR_ADDR) {
if (((*pToken) & D3DSP_REGNUM_MASK) < nUseAddressRegister) { strcpy(tmpLine, "ARL");
strcpy(tmpLine, "ARL"); break;
break;
} else
FIXME("(%p) Try to load A%ld an undeclared address register!\n",
This, ((*pToken) & D3DSP_REGNUM_MASK));
} }
/* fall through */ /* fall through */
case D3DSIO_ADD: case D3DSIO_ADD:
......
...@@ -1258,6 +1258,12 @@ typedef struct IWineD3DBaseShaderImpl { ...@@ -1258,6 +1258,12 @@ typedef struct IWineD3DBaseShaderImpl {
IWineD3DBaseShaderClass baseShader; IWineD3DBaseShaderClass baseShader;
} IWineD3DBaseShaderImpl; } IWineD3DBaseShaderImpl;
extern void shader_get_registers_used(
IWineD3DBaseShader *iface,
CONST DWORD* pToken,
DWORD* tempsUsed,
DWORD* texUsed);
inline static int shader_get_regtype(const DWORD param) { inline static int shader_get_regtype(const DWORD param) {
return (((param & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT) | return (((param & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT) |
((param & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2)); ((param & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment