2006-05-08 21:44:25 +02:00
|
|
|
/*
|
|
|
|
* shaders implementation
|
|
|
|
*
|
|
|
|
* Copyright 2002-2003 Jason Edmeades
|
|
|
|
* Copyright 2002-2003 Raphael Junqueira
|
2006-07-17 20:35:14 +02:00
|
|
|
* Copyright 2004 Christian Costa
|
2006-05-08 21:44:25 +02:00
|
|
|
* Copyright 2005 Oliver Stieber
|
2006-05-17 08:04:30 +02:00
|
|
|
* Copyright 2006 Ivan Gyurdiev
|
2006-05-08 21:44:25 +02:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
2006-05-18 14:49:52 +02:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2006-05-08 21:44:25 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "wined3d_private.h"
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
|
|
|
|
|
2006-05-10 04:32:34 +02:00
|
|
|
#define GLNAME_REQUIRE_GLSL ((const char *)1)
|
2006-05-21 23:16:17 +02:00
|
|
|
|
2006-05-10 00:03:09 +02:00
|
|
|
inline static BOOL shader_is_version_token(DWORD token) {
|
2006-05-14 15:43:31 +02:00
|
|
|
return shader_is_pshader_version(token) ||
|
|
|
|
shader_is_vshader_version(token);
|
2006-05-10 00:03:09 +02:00
|
|
|
}
|
|
|
|
|
2006-05-08 21:44:25 +02:00
|
|
|
int shader_addline(
|
|
|
|
SHADER_BUFFER* buffer,
|
|
|
|
const char *format, ...) {
|
|
|
|
|
|
|
|
char* base = buffer->buffer + buffer->bsize;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
|
|
rc = vsnprintf(base, SHADER_PGMSIZE - 1 - buffer->bsize, format, args);
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
if (rc < 0 || /* C89 */
|
|
|
|
rc > SHADER_PGMSIZE - 1 - buffer->bsize) { /* C99 */
|
|
|
|
|
|
|
|
ERR("The buffer allocated for the shader program string "
|
|
|
|
"is too small at %d bytes.\n", SHADER_PGMSIZE);
|
|
|
|
buffer->bsize = SHADER_PGMSIZE - 1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer->bsize += rc;
|
|
|
|
buffer->lineNo++;
|
|
|
|
TRACE("GL HW (%u, %u) : %s", buffer->lineNo, buffer->bsize, base);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-05-09 13:57:36 +02:00
|
|
|
const SHADER_OPCODE* shader_get_opcode(
|
|
|
|
IWineD3DBaseShader *iface, const DWORD code) {
|
|
|
|
|
|
|
|
IWineD3DBaseShaderImpl *This = (IWineD3DBaseShaderImpl*) iface;
|
|
|
|
|
|
|
|
DWORD i = 0;
|
|
|
|
DWORD hex_version = This->baseShader.hex_version;
|
|
|
|
const SHADER_OPCODE *shader_ins = This->baseShader.shader_ins;
|
|
|
|
|
|
|
|
/** TODO: use dichotomic search */
|
|
|
|
while (NULL != shader_ins[i].name) {
|
|
|
|
if (((code & D3DSI_OPCODE_MASK) == shader_ins[i].opcode) &&
|
|
|
|
(((hex_version >= shader_ins[i].min_version) && (hex_version <= shader_ins[i].max_version)) ||
|
|
|
|
((shader_ins[i].min_version == 0) && (shader_ins[i].max_version == 0)))) {
|
|
|
|
return &shader_ins[i];
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
}
|
2006-10-01 05:20:10 +02:00
|
|
|
FIXME("Unsupported opcode %#x(%d) masked %#x, shader version %#x\n",
|
2006-06-12 08:54:30 +02:00
|
|
|
code, code, code & D3DSI_OPCODE_MASK, hex_version);
|
2006-05-09 13:57:36 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-05-17 08:02:36 +02:00
|
|
|
/* Read a parameter opcode from the input stream,
|
|
|
|
* and possibly a relative addressing token.
|
|
|
|
* Return the number of tokens read */
|
|
|
|
int shader_get_param(
|
|
|
|
IWineD3DBaseShader* iface,
|
|
|
|
const DWORD* pToken,
|
|
|
|
DWORD* param,
|
|
|
|
DWORD* addr_token) {
|
|
|
|
|
|
|
|
/* PS >= 3.0 have relative addressing (with token)
|
|
|
|
* VS >= 2.0 have relative addressing (with token)
|
|
|
|
* VS >= 1.0 < 2.0 have relative addressing (without token)
|
|
|
|
* The version check below should work in general */
|
|
|
|
|
|
|
|
IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
|
|
|
|
char rel_token = D3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 2 &&
|
|
|
|
((*pToken & D3DSHADER_ADDRESSMODE_MASK) == D3DSHADER_ADDRMODE_RELATIVE);
|
|
|
|
|
|
|
|
*param = *pToken;
|
|
|
|
*addr_token = rel_token? *(pToken + 1): 0;
|
|
|
|
return rel_token? 2:1;
|
|
|
|
}
|
|
|
|
|
2006-05-17 08:00:47 +02:00
|
|
|
/* Return the number of parameters to skip for an opcode */
|
|
|
|
static inline int shader_skip_opcode(
|
|
|
|
IWineD3DBaseShaderImpl* This,
|
|
|
|
const SHADER_OPCODE* curOpcode,
|
|
|
|
DWORD opcode_token) {
|
|
|
|
|
|
|
|
/* Shaders >= 2.0 may contain address tokens, but fortunately they
|
|
|
|
* have a useful legnth mask - use it here. Shaders 1.0 contain no such tokens */
|
|
|
|
|
|
|
|
return (D3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 2)?
|
|
|
|
((opcode_token & D3DSI_INSTLENGTH_MASK) >> D3DSI_INSTLENGTH_SHIFT):
|
|
|
|
curOpcode->num_params;
|
|
|
|
}
|
|
|
|
|
2006-05-17 08:02:36 +02:00
|
|
|
/* Read the parameters of an unrecognized opcode from the input stream
|
|
|
|
* Return the number of tokens read.
|
|
|
|
*
|
|
|
|
* Note: This function assumes source or destination token format.
|
|
|
|
* It will not work with specially-formatted tokens like DEF or DCL,
|
|
|
|
* but hopefully those would be recognized */
|
|
|
|
|
|
|
|
int shader_skip_unrecognized(
|
|
|
|
IWineD3DBaseShader* iface,
|
|
|
|
const DWORD* pToken) {
|
|
|
|
|
|
|
|
int tokens_read = 0;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
/* TODO: Think of a good name for 0x80000000 and replace it with a constant */
|
|
|
|
while (*pToken & 0x80000000) {
|
|
|
|
|
|
|
|
DWORD param, addr_token;
|
|
|
|
tokens_read += shader_get_param(iface, pToken, ¶m, &addr_token);
|
|
|
|
pToken += tokens_read;
|
|
|
|
|
2006-10-01 05:20:10 +02:00
|
|
|
FIXME("Unrecognized opcode param: token=%08x "
|
|
|
|
"addr_token=%08x name=", param, addr_token);
|
2006-05-17 08:05:49 +02:00
|
|
|
shader_dump_param(iface, param, addr_token, i);
|
2006-05-17 08:02:36 +02:00
|
|
|
FIXME("\n");
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
return tokens_read;
|
|
|
|
}
|
|
|
|
|
2006-06-06 08:40:08 +02:00
|
|
|
/* Convert floating point offset relative
|
|
|
|
* to a register file to an absolute offset for float constants */
|
|
|
|
|
|
|
|
unsigned int shader_get_float_offset(const DWORD reg) {
|
|
|
|
|
|
|
|
unsigned int regnum = reg & D3DSP_REGNUM_MASK;
|
|
|
|
int regtype = shader_get_regtype(reg);
|
|
|
|
|
|
|
|
switch (regtype) {
|
|
|
|
case D3DSPR_CONST: return regnum;
|
|
|
|
case D3DSPR_CONST2: return 2048 + regnum;
|
|
|
|
case D3DSPR_CONST3: return 4096 + regnum;
|
|
|
|
case D3DSPR_CONST4: return 6144 + regnum;
|
|
|
|
default:
|
|
|
|
FIXME("Unsupported register type: %d\n", regtype);
|
|
|
|
return regnum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-21 23:16:17 +02:00
|
|
|
/* Note that this does not count the loop register
|
|
|
|
* as an address register. */
|
2006-05-10 00:03:09 +02:00
|
|
|
|
2006-07-10 06:51:03 +02:00
|
|
|
HRESULT shader_get_registers_used(
|
2006-05-10 00:03:09 +02:00
|
|
|
IWineD3DBaseShader *iface,
|
2006-05-21 23:16:17 +02:00
|
|
|
shader_reg_maps* reg_maps,
|
2006-07-07 08:27:38 +02:00
|
|
|
semantic* semantics_in,
|
|
|
|
semantic* semantics_out,
|
2006-08-27 19:16:01 +02:00
|
|
|
CONST DWORD* pToken,
|
|
|
|
IWineD3DStateBlockImpl *stateBlock) {
|
2006-05-10 04:31:09 +02:00
|
|
|
|
|
|
|
IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
|
2006-05-10 00:03:09 +02:00
|
|
|
|
2006-06-12 08:55:30 +02:00
|
|
|
/* There are some minor differences between pixel and vertex shaders */
|
|
|
|
char pshader = shader_is_pshader_version(This->baseShader.hex_version);
|
|
|
|
|
2006-05-10 00:03:09 +02:00
|
|
|
if (pToken == NULL)
|
2006-07-10 06:51:03 +02:00
|
|
|
return WINED3D_OK;
|
2006-05-10 00:03:09 +02:00
|
|
|
|
|
|
|
while (D3DVS_END() != *pToken) {
|
|
|
|
CONST SHADER_OPCODE* curOpcode;
|
2006-05-18 03:09:56 +02:00
|
|
|
DWORD opcode_token;
|
2006-05-10 00:03:09 +02:00
|
|
|
|
|
|
|
/* Skip version */
|
|
|
|
if (shader_is_version_token(*pToken)) {
|
|
|
|
++pToken;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Skip comments */
|
2006-05-14 15:43:31 +02:00
|
|
|
} else if (shader_is_comment(*pToken)) {
|
2006-05-10 00:03:09 +02:00
|
|
|
DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
|
|
|
|
++pToken;
|
|
|
|
pToken += comment_len;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fetch opcode */
|
2006-05-18 03:09:56 +02:00
|
|
|
opcode_token = *pToken++;
|
|
|
|
curOpcode = shader_get_opcode(iface, opcode_token);
|
2006-05-10 00:03:09 +02:00
|
|
|
|
|
|
|
/* Unhandled opcode, and its parameters */
|
|
|
|
if (NULL == curOpcode) {
|
|
|
|
while (*pToken & 0x80000000)
|
|
|
|
++pToken;
|
|
|
|
|
2006-06-12 08:53:32 +02:00
|
|
|
/* Handle declarations */
|
2006-05-10 00:03:09 +02:00
|
|
|
} else if (D3DSIO_DCL == curOpcode->opcode) {
|
2006-06-12 08:53:32 +02:00
|
|
|
|
|
|
|
DWORD usage = *pToken++;
|
|
|
|
DWORD param = *pToken++;
|
|
|
|
DWORD regtype = shader_get_regtype(param);
|
2006-06-12 08:55:30 +02:00
|
|
|
unsigned int regnum = param & D3DSP_REGNUM_MASK;
|
2006-06-12 08:53:32 +02:00
|
|
|
|
2006-06-12 08:59:16 +02:00
|
|
|
/* Vshader: mark attributes used
|
|
|
|
Pshader: mark 3.0 input registers used, save token */
|
2006-06-12 08:53:32 +02:00
|
|
|
if (D3DSPR_INPUT == regtype) {
|
2006-06-12 08:55:30 +02:00
|
|
|
|
|
|
|
if (!pshader)
|
|
|
|
reg_maps->attributes[regnum] = 1;
|
2006-06-12 08:57:07 +02:00
|
|
|
else
|
|
|
|
reg_maps->packed_input[regnum] = 1;
|
2006-06-12 08:55:30 +02:00
|
|
|
|
2006-07-07 08:27:38 +02:00
|
|
|
semantics_in[regnum].usage = usage;
|
|
|
|
semantics_in[regnum].reg = param;
|
2006-06-12 08:53:32 +02:00
|
|
|
|
2006-06-12 08:59:16 +02:00
|
|
|
/* Vshader: mark 3.0 output registers used, save token */
|
2006-06-12 08:53:32 +02:00
|
|
|
} else if (D3DSPR_OUTPUT == regtype) {
|
2006-06-12 08:57:07 +02:00
|
|
|
reg_maps->packed_output[regnum] = 1;
|
2006-07-07 08:27:38 +02:00
|
|
|
semantics_out[regnum].usage = usage;
|
|
|
|
semantics_out[regnum].reg = param;
|
2006-06-12 08:53:32 +02:00
|
|
|
|
2006-06-12 08:59:16 +02:00
|
|
|
/* Save sampler usage token */
|
|
|
|
} else if (D3DSPR_SAMPLER == regtype)
|
|
|
|
reg_maps->samplers[regnum] = usage;
|
2006-05-10 00:03:09 +02:00
|
|
|
|
|
|
|
} else if (D3DSIO_DEF == curOpcode->opcode) {
|
2006-07-10 06:51:03 +02:00
|
|
|
|
|
|
|
local_constant* lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant));
|
|
|
|
if (!lconst) return E_OUTOFMEMORY;
|
|
|
|
lconst->idx = *pToken & D3DSP_REGNUM_MASK;
|
|
|
|
memcpy(&lconst->value, pToken + 1, 4 * sizeof(DWORD));
|
|
|
|
list_add_head(&This->baseShader.constantsF, &lconst->entry);
|
|
|
|
pToken += curOpcode->num_params;
|
|
|
|
|
|
|
|
} else if (D3DSIO_DEFI == curOpcode->opcode) {
|
|
|
|
|
|
|
|
local_constant* lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant));
|
|
|
|
if (!lconst) return E_OUTOFMEMORY;
|
|
|
|
lconst->idx = *pToken & D3DSP_REGNUM_MASK;
|
|
|
|
memcpy(&lconst->value, pToken + 1, 4 * sizeof(DWORD));
|
|
|
|
list_add_head(&This->baseShader.constantsI, &lconst->entry);
|
|
|
|
pToken += curOpcode->num_params;
|
|
|
|
|
|
|
|
} else if (D3DSIO_DEFB == curOpcode->opcode) {
|
|
|
|
|
|
|
|
local_constant* lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant));
|
|
|
|
if (!lconst) return E_OUTOFMEMORY;
|
|
|
|
lconst->idx = *pToken & D3DSP_REGNUM_MASK;
|
|
|
|
memcpy(&lconst->value, pToken + 1, 1 * sizeof(DWORD));
|
|
|
|
list_add_head(&This->baseShader.constantsB, &lconst->entry);
|
2006-05-10 00:03:09 +02:00
|
|
|
pToken += curOpcode->num_params;
|
|
|
|
|
2006-06-16 22:13:01 +02:00
|
|
|
/* If there's a loop in the shader */
|
wined3d: More flow control instructions
- Implement if, else, endif, rep, endrep, break
- Implement ifc, breakc, using undocumented comparison bits in the instruction token
- Fix bug in main loop processing of codes with no dst token
- Fix bug in GLSL output modifier processing of codes with no dst token
- Fix bug in loop implementation (src1 contains the integer data, src0 is aL)
- Add versioning for all the instructions above, and remove
GLSL_REQUIRED thing, which is useless and should be removed from all
opcodes in general.
2006-07-10 11:11:35 +02:00
|
|
|
} else if (D3DSIO_LOOP == curOpcode->opcode ||
|
|
|
|
D3DSIO_REP == curOpcode->opcode) {
|
2006-06-16 22:13:01 +02:00
|
|
|
reg_maps->loop = 1;
|
|
|
|
pToken += curOpcode->num_params;
|
2006-07-10 12:35:15 +02:00
|
|
|
|
|
|
|
/* For subroutine prototypes */
|
|
|
|
} else if (D3DSIO_LABEL == curOpcode->opcode) {
|
|
|
|
|
|
|
|
DWORD snum = *pToken & D3DSP_REGNUM_MASK;
|
|
|
|
reg_maps->labels[snum] = 1;
|
|
|
|
pToken += curOpcode->num_params;
|
|
|
|
|
2006-06-12 08:59:16 +02:00
|
|
|
/* Set texture, address, temporary registers */
|
2006-05-10 00:03:09 +02:00
|
|
|
} else {
|
2006-05-18 03:09:56 +02:00
|
|
|
int i, limit;
|
2006-05-10 00:03:09 +02:00
|
|
|
|
2006-06-12 08:59:16 +02:00
|
|
|
/* Declare 1.X samplers implicitly, based on the destination reg. number */
|
|
|
|
if (D3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) == 1 &&
|
|
|
|
(D3DSIO_TEX == curOpcode->opcode ||
|
2006-06-27 08:00:02 +02:00
|
|
|
D3DSIO_TEXBEM == curOpcode->opcode ||
|
2006-06-12 08:59:16 +02:00
|
|
|
D3DSIO_TEXM3x2TEX == curOpcode->opcode ||
|
2006-06-29 00:32:47 +02:00
|
|
|
D3DSIO_TEXM3x3TEX == curOpcode->opcode)) {
|
2006-06-12 08:59:16 +02:00
|
|
|
|
|
|
|
/* Fake sampler usage, only set reserved bit and ttype */
|
|
|
|
DWORD sampler_code = *pToken & D3DSP_REGNUM_MASK;
|
2006-08-27 19:16:01 +02:00
|
|
|
|
|
|
|
if(!stateBlock->textures[sampler_code]) {
|
2006-10-01 05:20:10 +02:00
|
|
|
ERR("No texture bound to sampler %d\n", sampler_code);
|
2006-08-27 19:16:01 +02:00
|
|
|
reg_maps->samplers[sampler_code] = (0x1 << 31) | WINED3DSTT_2D;
|
|
|
|
} else {
|
|
|
|
int texType = IWineD3DBaseTexture_GetTextureDimensions(stateBlock->textures[sampler_code]);
|
|
|
|
switch(texType) {
|
|
|
|
case GL_TEXTURE_1D:
|
|
|
|
reg_maps->samplers[sampler_code] = (0x1 << 31) | WINED3DSTT_1D;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_TEXTURE_2D:
|
|
|
|
reg_maps->samplers[sampler_code] = (0x1 << 31) | WINED3DSTT_2D;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_TEXTURE_3D:
|
|
|
|
reg_maps->samplers[sampler_code] = (0x1 << 31) | WINED3DSTT_VOLUME;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GLTEXTURECUBEMAP:
|
|
|
|
reg_maps->samplers[sampler_code] = (0x1 << 31) | WINED3DSTT_CUBE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ERR("Unexpected gl texture type found: %d\n", texType);
|
|
|
|
reg_maps->samplers[sampler_code] = (0x1 << 31) | WINED3DSTT_2D;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-06-29 00:32:47 +02:00
|
|
|
} else if (D3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) == 1 &&
|
|
|
|
(D3DSIO_TEXM3x3SPEC == curOpcode->opcode ||
|
|
|
|
D3DSIO_TEXM3x3VSPEC == curOpcode->opcode)) {
|
|
|
|
|
|
|
|
/* 3D sampler usage, only set reserved bit and ttype
|
|
|
|
* FIXME: This could be either Cube or Volume, but we wouldn't know unless
|
|
|
|
* we waited to generate the shader until the textures were all bound.
|
|
|
|
* For now, use Cube textures because they are more common. */
|
|
|
|
DWORD sampler_code = *pToken & D3DSP_REGNUM_MASK;
|
2006-07-28 21:34:39 +02:00
|
|
|
reg_maps->samplers[sampler_code] = (0x1 << 31) | WINED3DSTT_CUBE;
|
|
|
|
} else if (D3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) == 1 &&
|
|
|
|
(D3DSIO_TEXDP3TEX == curOpcode->opcode)) {
|
|
|
|
|
|
|
|
/* 1D Sampler usage */
|
|
|
|
DWORD sampler_code = *pToken & D3DSP_REGNUM_MASK;
|
|
|
|
reg_maps->samplers[sampler_code] = (0x1 << 31) | WINED3DSTT_1D;
|
2006-06-12 08:59:16 +02:00
|
|
|
}
|
|
|
|
|
2006-05-18 03:09:56 +02:00
|
|
|
/* This will loop over all the registers and try to
|
|
|
|
* make a bitmask of the ones we're interested in.
|
|
|
|
*
|
|
|
|
* Relative addressing tokens are ignored, but that's
|
|
|
|
* okay, since we'll catch any address registers when
|
|
|
|
* they are initialized (required by spec) */
|
|
|
|
|
|
|
|
limit = (opcode_token & D3DSHADER_INSTRUCTION_PREDICATED)?
|
|
|
|
curOpcode->num_params + 1: curOpcode->num_params;
|
|
|
|
|
|
|
|
for (i = 0; i < limit; ++i) {
|
2006-05-17 08:04:30 +02:00
|
|
|
|
|
|
|
DWORD param, addr_token, reg, regtype;
|
|
|
|
pToken += shader_get_param(iface, pToken, ¶m, &addr_token);
|
|
|
|
|
2006-07-03 03:28:25 +02:00
|
|
|
regtype = shader_get_regtype(param);
|
2006-05-17 08:04:30 +02:00
|
|
|
reg = param & D3DSP_REGNUM_MASK;
|
|
|
|
|
2006-05-21 23:16:17 +02:00
|
|
|
if (D3DSPR_TEXTURE == regtype) { /* vs: D3DSPR_ADDR */
|
|
|
|
|
2006-06-12 08:55:30 +02:00
|
|
|
if (pshader)
|
|
|
|
reg_maps->texcoord[reg] = 1;
|
2006-05-21 23:16:17 +02:00
|
|
|
else
|
2006-06-12 08:55:30 +02:00
|
|
|
reg_maps->address[reg] = 1;
|
2006-05-21 23:16:17 +02:00
|
|
|
}
|
|
|
|
|
2006-06-12 08:55:30 +02:00
|
|
|
else if (D3DSPR_TEMP == regtype)
|
|
|
|
reg_maps->temporary[reg] = 1;
|
|
|
|
|
|
|
|
else if (D3DSPR_INPUT == regtype && !pshader)
|
|
|
|
reg_maps->attributes[reg] = 1;
|
2006-07-17 07:41:53 +02:00
|
|
|
|
|
|
|
else if (D3DSPR_RASTOUT == regtype && reg == 1)
|
|
|
|
reg_maps->fog = 1;
|
2006-05-10 00:03:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-07-10 06:51:03 +02:00
|
|
|
|
|
|
|
return WINED3D_OK;
|
2006-05-10 00:03:09 +02:00
|
|
|
}
|
|
|
|
|
2006-06-12 08:54:30 +02:00
|
|
|
static void shader_dump_decl_usage(
|
2006-07-03 08:03:47 +02:00
|
|
|
IWineD3DBaseShaderImpl* This,
|
2006-05-10 04:26:05 +02:00
|
|
|
DWORD decl,
|
|
|
|
DWORD param) {
|
|
|
|
|
|
|
|
DWORD regtype = shader_get_regtype(param);
|
2006-07-03 08:03:47 +02:00
|
|
|
|
|
|
|
TRACE("dcl");
|
2006-05-10 04:26:05 +02:00
|
|
|
|
|
|
|
if (regtype == D3DSPR_SAMPLER) {
|
2006-07-28 21:34:39 +02:00
|
|
|
DWORD ttype = decl & WINED3DSP_TEXTURETYPE_MASK;
|
2006-05-10 04:26:05 +02:00
|
|
|
|
|
|
|
switch (ttype) {
|
2006-07-28 21:34:39 +02:00
|
|
|
case WINED3DSTT_2D: TRACE("_2d"); break;
|
|
|
|
case WINED3DSTT_CUBE: TRACE("_cube"); break;
|
|
|
|
case WINED3DSTT_VOLUME: TRACE("_volume"); break;
|
2006-10-01 05:20:10 +02:00
|
|
|
default: TRACE("_unknown_ttype(%08x)", ttype);
|
2006-05-10 04:26:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
DWORD usage = decl & D3DSP_DCL_USAGE_MASK;
|
|
|
|
DWORD idx = (decl & D3DSP_DCL_USAGEINDEX_MASK) >> D3DSP_DCL_USAGEINDEX_SHIFT;
|
|
|
|
|
2006-07-03 08:03:47 +02:00
|
|
|
/* Pixel shaders 3.0 don't have usage semantics */
|
|
|
|
char pshader = shader_is_pshader_version(This->baseShader.hex_version);
|
|
|
|
if (pshader && This->baseShader.hex_version < D3DPS_VERSION(3,0))
|
|
|
|
return;
|
|
|
|
else
|
|
|
|
TRACE("_");
|
|
|
|
|
2006-05-10 04:26:05 +02:00
|
|
|
switch(usage) {
|
|
|
|
case D3DDECLUSAGE_POSITION:
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("%s%d", "position", idx);
|
2006-05-10 04:26:05 +02:00
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_BLENDINDICES:
|
|
|
|
TRACE("%s", "blend");
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_BLENDWEIGHT:
|
|
|
|
TRACE("%s", "weight");
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_NORMAL:
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("%s%d", "normal", idx);
|
2006-05-10 04:26:05 +02:00
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_PSIZE:
|
|
|
|
TRACE("%s", "psize");
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_COLOR:
|
|
|
|
if(idx == 0) {
|
|
|
|
TRACE("%s", "color");
|
|
|
|
} else {
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("%s%d", "specular", (idx - 1));
|
2006-05-10 04:26:05 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_TEXCOORD:
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("%s%d", "texture", idx);
|
2006-05-10 04:26:05 +02:00
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_TANGENT:
|
|
|
|
TRACE("%s", "tangent");
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_BINORMAL:
|
|
|
|
TRACE("%s", "binormal");
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_TESSFACTOR:
|
|
|
|
TRACE("%s", "tessfactor");
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_POSITIONT:
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("%s%d", "positionT", idx);
|
2006-05-10 04:26:05 +02:00
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_FOG:
|
|
|
|
TRACE("%s", "fog");
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_DEPTH:
|
|
|
|
TRACE("%s", "depth");
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_SAMPLE:
|
|
|
|
TRACE("%s", "sample");
|
|
|
|
break;
|
|
|
|
default:
|
2006-10-01 05:20:10 +02:00
|
|
|
FIXME("unknown_semantics(%08x)", usage);
|
2006-05-10 04:26:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-17 08:05:49 +02:00
|
|
|
static void shader_dump_arr_entry(
|
|
|
|
IWineD3DBaseShader *iface,
|
|
|
|
const DWORD param,
|
|
|
|
const DWORD addr_token,
|
2006-06-06 08:40:08 +02:00
|
|
|
unsigned int reg,
|
2006-05-17 08:05:49 +02:00
|
|
|
int input) {
|
|
|
|
|
|
|
|
char relative =
|
|
|
|
((param & D3DSHADER_ADDRESSMODE_MASK) == D3DSHADER_ADDRMODE_RELATIVE);
|
|
|
|
|
|
|
|
if (relative) {
|
2006-06-06 08:40:08 +02:00
|
|
|
TRACE("[");
|
2006-05-17 08:05:49 +02:00
|
|
|
if (addr_token)
|
|
|
|
shader_dump_param(iface, addr_token, 0, input);
|
|
|
|
else
|
|
|
|
TRACE("a0.x");
|
|
|
|
TRACE(" + ");
|
|
|
|
}
|
2006-06-06 08:40:08 +02:00
|
|
|
TRACE("%u", reg);
|
|
|
|
if (relative)
|
|
|
|
TRACE("]");
|
2006-05-17 08:05:49 +02:00
|
|
|
}
|
|
|
|
|
2006-05-14 15:43:31 +02:00
|
|
|
void shader_dump_param(
|
|
|
|
IWineD3DBaseShader *iface,
|
|
|
|
const DWORD param,
|
2006-05-17 08:05:49 +02:00
|
|
|
const DWORD addr_token,
|
2006-05-14 15:43:31 +02:00
|
|
|
int input) {
|
|
|
|
|
|
|
|
IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
|
|
|
|
static const char* rastout_reg_names[] = { "oPos", "oFog", "oPts" };
|
|
|
|
char swizzle_reg_chars[4];
|
|
|
|
|
|
|
|
DWORD reg = param & D3DSP_REGNUM_MASK;
|
|
|
|
DWORD regtype = shader_get_regtype(param);
|
2006-07-07 08:29:39 +02:00
|
|
|
DWORD modifier = param & D3DSP_SRCMOD_MASK;
|
2006-05-14 15:43:31 +02:00
|
|
|
|
|
|
|
/* There are some minor differences between pixel and vertex shaders */
|
2006-06-12 08:59:16 +02:00
|
|
|
char pshader = shader_is_pshader_version(This->baseShader.hex_version);
|
2006-05-14 15:43:31 +02:00
|
|
|
|
|
|
|
/* For one, we'd prefer color components to be shown for pshaders.
|
|
|
|
* FIXME: use the swizzle function for this */
|
|
|
|
|
|
|
|
swizzle_reg_chars[0] = pshader? 'r': 'x';
|
|
|
|
swizzle_reg_chars[1] = pshader? 'g': 'y';
|
|
|
|
swizzle_reg_chars[2] = pshader? 'b': 'z';
|
|
|
|
swizzle_reg_chars[3] = pshader? 'a': 'w';
|
|
|
|
|
|
|
|
if (input) {
|
2006-07-07 08:29:39 +02:00
|
|
|
if ( (modifier == D3DSPSM_NEG) ||
|
|
|
|
(modifier == D3DSPSM_BIASNEG) ||
|
|
|
|
(modifier == D3DSPSM_SIGNNEG) ||
|
|
|
|
(modifier == D3DSPSM_X2NEG) ||
|
|
|
|
(modifier == D3DSPSM_ABSNEG) )
|
2006-05-14 15:43:31 +02:00
|
|
|
TRACE("-");
|
2006-07-07 08:29:39 +02:00
|
|
|
else if (modifier == D3DSPSM_COMP)
|
2006-05-14 15:43:31 +02:00
|
|
|
TRACE("1-");
|
2006-07-07 08:29:39 +02:00
|
|
|
else if (modifier == D3DSPSM_NOT)
|
2006-05-18 03:09:56 +02:00
|
|
|
TRACE("!");
|
2006-07-07 08:29:39 +02:00
|
|
|
|
|
|
|
if (modifier == D3DSPSM_ABS || modifier == D3DSPSM_ABSNEG)
|
|
|
|
TRACE("abs(");
|
2006-05-14 15:43:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (regtype) {
|
|
|
|
case D3DSPR_TEMP:
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("r%u", reg);
|
2006-05-14 15:43:31 +02:00
|
|
|
break;
|
|
|
|
case D3DSPR_INPUT:
|
2006-06-06 08:40:08 +02:00
|
|
|
TRACE("v");
|
|
|
|
shader_dump_arr_entry(iface, param, addr_token, reg, input);
|
2006-05-14 15:43:31 +02:00
|
|
|
break;
|
|
|
|
case D3DSPR_CONST:
|
2006-06-06 08:40:08 +02:00
|
|
|
case D3DSPR_CONST2:
|
|
|
|
case D3DSPR_CONST3:
|
|
|
|
case D3DSPR_CONST4:
|
2006-05-17 08:05:49 +02:00
|
|
|
TRACE("c");
|
2006-06-06 08:40:08 +02:00
|
|
|
shader_dump_arr_entry(iface, param, addr_token, shader_get_float_offset(param), input);
|
2006-05-14 15:43:31 +02:00
|
|
|
break;
|
|
|
|
case D3DSPR_TEXTURE: /* vs: case D3DSPR_ADDR */
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("%c%u", (pshader? 't':'a'), reg);
|
2006-05-14 15:43:31 +02:00
|
|
|
break;
|
|
|
|
case D3DSPR_RASTOUT:
|
|
|
|
TRACE("%s", rastout_reg_names[reg]);
|
|
|
|
break;
|
|
|
|
case D3DSPR_COLOROUT:
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("oC%u", reg);
|
2006-05-14 15:43:31 +02:00
|
|
|
break;
|
|
|
|
case D3DSPR_DEPTHOUT:
|
|
|
|
TRACE("oDepth");
|
|
|
|
break;
|
|
|
|
case D3DSPR_ATTROUT:
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("oD%u", reg);
|
2006-05-14 15:43:31 +02:00
|
|
|
break;
|
2006-05-18 03:08:29 +02:00
|
|
|
case D3DSPR_TEXCRDOUT:
|
|
|
|
|
|
|
|
/* Vertex shaders >= 3.0 use general purpose output registers
|
|
|
|
* (D3DSPR_OUTPUT), which can include an address token */
|
|
|
|
|
|
|
|
if (D3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 3) {
|
|
|
|
TRACE("o");
|
2006-06-06 08:40:08 +02:00
|
|
|
shader_dump_arr_entry(iface, param, addr_token, reg, input);
|
2006-05-18 03:08:29 +02:00
|
|
|
}
|
|
|
|
else
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("oT%u", reg);
|
2006-05-14 15:43:31 +02:00
|
|
|
break;
|
|
|
|
case D3DSPR_CONSTINT:
|
2006-05-17 08:05:49 +02:00
|
|
|
TRACE("i");
|
2006-06-06 08:40:08 +02:00
|
|
|
shader_dump_arr_entry(iface, param, addr_token, reg, input);
|
2006-05-14 15:43:31 +02:00
|
|
|
break;
|
|
|
|
case D3DSPR_CONSTBOOL:
|
2006-05-17 08:05:49 +02:00
|
|
|
TRACE("b");
|
2006-06-06 08:40:08 +02:00
|
|
|
shader_dump_arr_entry(iface, param, addr_token, reg, input);
|
2006-05-14 15:43:31 +02:00
|
|
|
break;
|
|
|
|
case D3DSPR_LABEL:
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("l%u", reg);
|
2006-05-14 15:43:31 +02:00
|
|
|
break;
|
|
|
|
case D3DSPR_LOOP:
|
2006-05-17 08:05:49 +02:00
|
|
|
TRACE("aL");
|
2006-05-14 15:43:31 +02:00
|
|
|
break;
|
|
|
|
case D3DSPR_SAMPLER:
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("s%u", reg);
|
2006-05-14 15:43:31 +02:00
|
|
|
break;
|
2006-05-18 03:08:29 +02:00
|
|
|
case D3DSPR_PREDICATE:
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("p%u", reg);
|
2006-05-18 03:08:29 +02:00
|
|
|
break;
|
2006-05-14 15:43:31 +02:00
|
|
|
default:
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("unhandled_rtype(%#x)", regtype);
|
2006-05-14 15:43:31 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!input) {
|
|
|
|
/* operand output (for modifiers and shift, see dump_ins_modifiers) */
|
|
|
|
|
|
|
|
if ((param & D3DSP_WRITEMASK_ALL) != D3DSP_WRITEMASK_ALL) {
|
|
|
|
TRACE(".");
|
|
|
|
if (param & D3DSP_WRITEMASK_0) TRACE("%c", swizzle_reg_chars[0]);
|
|
|
|
if (param & D3DSP_WRITEMASK_1) TRACE("%c", swizzle_reg_chars[1]);
|
|
|
|
if (param & D3DSP_WRITEMASK_2) TRACE("%c", swizzle_reg_chars[2]);
|
|
|
|
if (param & D3DSP_WRITEMASK_3) TRACE("%c", swizzle_reg_chars[3]);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/** operand input */
|
|
|
|
DWORD swizzle = (param & D3DSP_SWIZZLE_MASK) >> D3DSP_SWIZZLE_SHIFT;
|
|
|
|
DWORD swizzle_r = swizzle & 0x03;
|
|
|
|
DWORD swizzle_g = (swizzle >> 2) & 0x03;
|
|
|
|
DWORD swizzle_b = (swizzle >> 4) & 0x03;
|
|
|
|
DWORD swizzle_a = (swizzle >> 6) & 0x03;
|
|
|
|
|
2006-07-07 08:29:39 +02:00
|
|
|
if (0 != modifier) {
|
|
|
|
switch (modifier) {
|
2006-05-14 15:43:31 +02:00
|
|
|
case D3DSPSM_NONE: break;
|
|
|
|
case D3DSPSM_NEG: break;
|
2006-05-18 03:09:56 +02:00
|
|
|
case D3DSPSM_NOT: break;
|
2006-05-14 15:43:31 +02:00
|
|
|
case D3DSPSM_BIAS: TRACE("_bias"); break;
|
|
|
|
case D3DSPSM_BIASNEG: TRACE("_bias"); break;
|
|
|
|
case D3DSPSM_SIGN: TRACE("_bx2"); break;
|
|
|
|
case D3DSPSM_SIGNNEG: TRACE("_bx2"); break;
|
|
|
|
case D3DSPSM_COMP: break;
|
|
|
|
case D3DSPSM_X2: TRACE("_x2"); break;
|
|
|
|
case D3DSPSM_X2NEG: TRACE("_x2"); break;
|
|
|
|
case D3DSPSM_DZ: TRACE("_dz"); break;
|
|
|
|
case D3DSPSM_DW: TRACE("_dw"); break;
|
2006-07-07 08:29:39 +02:00
|
|
|
case D3DSPSM_ABSNEG: TRACE(")"); break;
|
|
|
|
case D3DSPSM_ABS: TRACE(")"); break;
|
2006-05-14 15:43:31 +02:00
|
|
|
default:
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("_unknown_modifier(%#x)", modifier >> D3DSP_SRCMOD_SHIFT);
|
2006-05-14 15:43:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* swizzle bits fields:
|
|
|
|
* RRGGBBAA
|
|
|
|
*/
|
|
|
|
if ((D3DVS_NOSWIZZLE >> D3DVS_SWIZZLE_SHIFT) != swizzle) { /* ! D3DVS_NOSWIZZLE == 0xE4 << D3DVS_SWIZZLE_SHIFT */
|
|
|
|
if (swizzle_r == swizzle_g &&
|
|
|
|
swizzle_r == swizzle_b &&
|
|
|
|
swizzle_r == swizzle_a) {
|
|
|
|
TRACE(".%c", swizzle_reg_chars[swizzle_r]);
|
|
|
|
} else {
|
|
|
|
TRACE(".%c%c%c%c",
|
|
|
|
swizzle_reg_chars[swizzle_r],
|
|
|
|
swizzle_reg_chars[swizzle_g],
|
|
|
|
swizzle_reg_chars[swizzle_b],
|
|
|
|
swizzle_reg_chars[swizzle_a]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-10 04:32:34 +02:00
|
|
|
/** Shared code in order to generate the bulk of the shader string.
|
|
|
|
Use the shader_header_fct & shader_footer_fct to add strings
|
|
|
|
that are specific to pixel or vertex functions
|
|
|
|
NOTE: A description of how to parse tokens can be found at:
|
|
|
|
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/graphics/hh/graphics/usermodedisplaydriver_shader_cc8e4e05-f5c3-4ec0-8853-8ce07c1551b2.xml.asp */
|
2006-06-12 08:53:32 +02:00
|
|
|
void shader_generate_main(
|
2006-05-10 04:32:34 +02:00
|
|
|
IWineD3DBaseShader *iface,
|
|
|
|
SHADER_BUFFER* buffer,
|
2006-06-12 08:53:32 +02:00
|
|
|
shader_reg_maps* reg_maps,
|
2006-05-10 04:32:34 +02:00
|
|
|
CONST DWORD* pFunction) {
|
|
|
|
|
|
|
|
IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
|
|
|
|
const DWORD *pToken = pFunction;
|
|
|
|
const SHADER_OPCODE *curOpcode = NULL;
|
2006-05-18 19:43:32 +02:00
|
|
|
SHADER_HANDLER hw_fct = NULL;
|
2006-05-10 04:32:34 +02:00
|
|
|
DWORD i;
|
2006-06-09 09:33:33 +02:00
|
|
|
SHADER_OPCODE_ARG hw_arg;
|
|
|
|
|
2006-05-10 04:32:34 +02:00
|
|
|
/* Initialize current parsing state */
|
2006-06-07 05:40:16 +02:00
|
|
|
hw_arg.shader = iface;
|
|
|
|
hw_arg.buffer = buffer;
|
2006-06-12 08:53:32 +02:00
|
|
|
hw_arg.reg_maps = reg_maps;
|
2006-05-10 04:32:34 +02:00
|
|
|
This->baseShader.parse_state.current_row = 0;
|
|
|
|
|
|
|
|
/* Second pass, process opcodes */
|
|
|
|
if (NULL != pToken) {
|
|
|
|
while (D3DPS_END() != *pToken) {
|
|
|
|
|
|
|
|
/* Skip version token */
|
|
|
|
if (shader_is_version_token(*pToken)) {
|
|
|
|
++pToken;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Skip comment tokens */
|
2006-05-14 15:43:31 +02:00
|
|
|
if (shader_is_comment(*pToken)) {
|
2006-05-10 04:32:34 +02:00
|
|
|
DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
|
|
|
|
++pToken;
|
|
|
|
TRACE("#%s\n", (char*)pToken);
|
|
|
|
pToken += comment_len;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read opcode */
|
wined3d: More flow control instructions
- Implement if, else, endif, rep, endrep, break
- Implement ifc, breakc, using undocumented comparison bits in the instruction token
- Fix bug in main loop processing of codes with no dst token
- Fix bug in GLSL output modifier processing of codes with no dst token
- Fix bug in loop implementation (src1 contains the integer data, src0 is aL)
- Add versioning for all the instructions above, and remove
GLSL_REQUIRED thing, which is useless and should be removed from all
opcodes in general.
2006-07-10 11:11:35 +02:00
|
|
|
hw_arg.opcode_token = *pToken++;
|
|
|
|
curOpcode = shader_get_opcode(iface, hw_arg.opcode_token);
|
wined3d: Rework shader mode selection.
- currently half the shader selection code (GLSL vs ARB) is in
fillGLcaps. The parts that check for software shaders are in
GetDeviceCaps. That placement, will work, but is definitely not optimal.
FillGLcaps should detect support - it should not make decision as to
what's used, because that's not what the purpose of the function is.
GetDeviceCaps should report support as it has already been selected.
Instead, select shader mode in its own function, called in the
appropriate places.
- unifying pixel and vertex shaders into a single selection is a
mistake. A software vertex shader can be coupled with a hardware arb or
glsl pixel shader, or no shader at all. Split them back into two and add
a SHADER_NONE variant.
- drawprim is doing support checks for ARB_PROGRAM, and making shader
decisions based on that - that's wrong, support has already been
checked, and decided upon, and shaders can be implemented via software,
ARB_PROGRAm or GLSL, so that support check isn't valid.
- Store the shader selected mode into the shader itself. Different types
of shaders can be combined, so this is an improvement. In fact, storing
the mode into the settings globally is a mistake as well - it should be
done per device, since different cards have different capabilities.
2006-07-04 09:21:53 +02:00
|
|
|
|
|
|
|
/* Select handler */
|
|
|
|
if (curOpcode == NULL)
|
|
|
|
hw_fct = NULL;
|
|
|
|
else if (This->baseShader.shader_mode == SHADER_GLSL)
|
|
|
|
hw_fct = curOpcode->hw_glsl_fct;
|
|
|
|
else if (This->baseShader.shader_mode == SHADER_ARB)
|
|
|
|
hw_fct = curOpcode->hw_fct;
|
2006-05-10 04:32:34 +02:00
|
|
|
|
|
|
|
/* Unknown opcode and its parameters */
|
2006-06-07 05:40:16 +02:00
|
|
|
if (NULL == curOpcode) {
|
2006-10-01 05:20:10 +02:00
|
|
|
FIXME("Unrecognized opcode: token=%08x\n", hw_arg.opcode_token);
|
2006-06-07 05:40:16 +02:00
|
|
|
pToken += shader_skip_unrecognized(iface, pToken);
|
2006-05-10 04:32:34 +02:00
|
|
|
|
2006-06-12 08:51:58 +02:00
|
|
|
/* Nothing to do */
|
|
|
|
} else if (D3DSIO_DCL == curOpcode->opcode ||
|
2006-07-10 06:51:03 +02:00
|
|
|
D3DSIO_NOP == curOpcode->opcode ||
|
|
|
|
D3DSIO_DEF == curOpcode->opcode ||
|
|
|
|
D3DSIO_DEFI == curOpcode->opcode ||
|
2006-07-10 12:35:15 +02:00
|
|
|
D3DSIO_DEFB == curOpcode->opcode ||
|
2006-07-28 21:35:39 +02:00
|
|
|
D3DSIO_PHASE == curOpcode->opcode ||
|
2006-07-10 12:35:15 +02:00
|
|
|
D3DSIO_RET == curOpcode->opcode) {
|
2006-06-12 08:51:58 +02:00
|
|
|
|
wined3d: More flow control instructions
- Implement if, else, endif, rep, endrep, break
- Implement ifc, breakc, using undocumented comparison bits in the instruction token
- Fix bug in main loop processing of codes with no dst token
- Fix bug in GLSL output modifier processing of codes with no dst token
- Fix bug in loop implementation (src1 contains the integer data, src0 is aL)
- Add versioning for all the instructions above, and remove
GLSL_REQUIRED thing, which is useless and should be removed from all
opcodes in general.
2006-07-10 11:11:35 +02:00
|
|
|
pToken += shader_skip_opcode(This, curOpcode, hw_arg.opcode_token);
|
2006-06-12 08:51:58 +02:00
|
|
|
|
2006-05-10 04:47:35 +02:00
|
|
|
/* If a generator function is set for current shader target, use it */
|
2006-05-18 19:43:32 +02:00
|
|
|
} else if (hw_fct != NULL) {
|
2006-05-10 04:32:34 +02:00
|
|
|
|
|
|
|
hw_arg.opcode = curOpcode;
|
2006-05-17 08:04:30 +02:00
|
|
|
|
2006-06-12 12:57:04 +02:00
|
|
|
/* Destination token */
|
|
|
|
if (curOpcode->dst_token) {
|
2006-05-10 04:32:34 +02:00
|
|
|
|
2006-05-17 08:04:30 +02:00
|
|
|
DWORD param, addr_token = 0;
|
2006-06-12 08:51:58 +02:00
|
|
|
pToken += shader_get_param(iface, pToken, ¶m, &addr_token);
|
2006-05-17 08:04:30 +02:00
|
|
|
hw_arg.dst = param;
|
|
|
|
hw_arg.dst_addr = addr_token;
|
2006-06-12 12:57:04 +02:00
|
|
|
}
|
2006-05-17 08:04:30 +02:00
|
|
|
|
2006-06-12 12:57:04 +02:00
|
|
|
/* Predication token */
|
wined3d: More flow control instructions
- Implement if, else, endif, rep, endrep, break
- Implement ifc, breakc, using undocumented comparison bits in the instruction token
- Fix bug in main loop processing of codes with no dst token
- Fix bug in GLSL output modifier processing of codes with no dst token
- Fix bug in loop implementation (src1 contains the integer data, src0 is aL)
- Add versioning for all the instructions above, and remove
GLSL_REQUIRED thing, which is useless and should be removed from all
opcodes in general.
2006-07-10 11:11:35 +02:00
|
|
|
if (hw_arg.opcode_token & D3DSHADER_INSTRUCTION_PREDICATED)
|
2006-06-12 12:57:04 +02:00
|
|
|
hw_arg.predicate = *pToken++;
|
2006-05-18 03:09:56 +02:00
|
|
|
|
2006-06-12 12:57:04 +02:00
|
|
|
/* Other source tokens */
|
wined3d: More flow control instructions
- Implement if, else, endif, rep, endrep, break
- Implement ifc, breakc, using undocumented comparison bits in the instruction token
- Fix bug in main loop processing of codes with no dst token
- Fix bug in GLSL output modifier processing of codes with no dst token
- Fix bug in loop implementation (src1 contains the integer data, src0 is aL)
- Add versioning for all the instructions above, and remove
GLSL_REQUIRED thing, which is useless and should be removed from all
opcodes in general.
2006-07-10 11:11:35 +02:00
|
|
|
for (i = 0; i < (curOpcode->num_params - curOpcode->dst_token); i++) {
|
2006-05-17 08:04:30 +02:00
|
|
|
|
2006-06-12 12:57:04 +02:00
|
|
|
DWORD param, addr_token = 0;
|
2006-07-10 06:51:03 +02:00
|
|
|
pToken += shader_get_param(iface, pToken, ¶m, &addr_token);
|
wined3d: More flow control instructions
- Implement if, else, endif, rep, endrep, break
- Implement ifc, breakc, using undocumented comparison bits in the instruction token
- Fix bug in main loop processing of codes with no dst token
- Fix bug in GLSL output modifier processing of codes with no dst token
- Fix bug in loop implementation (src1 contains the integer data, src0 is aL)
- Add versioning for all the instructions above, and remove
GLSL_REQUIRED thing, which is useless and should be removed from all
opcodes in general.
2006-07-10 11:11:35 +02:00
|
|
|
hw_arg.src[i] = param;
|
|
|
|
hw_arg.src_addr[i] = addr_token;
|
2006-05-10 04:32:34 +02:00
|
|
|
}
|
|
|
|
|
2006-05-10 04:47:35 +02:00
|
|
|
/* Call appropriate function for output target */
|
2006-05-18 19:43:32 +02:00
|
|
|
hw_fct(&hw_arg);
|
2006-05-10 04:47:35 +02:00
|
|
|
|
2006-06-14 04:32:14 +02:00
|
|
|
/* Process instruction modifiers for GLSL apps ( _sat, etc. ) */
|
wined3d: Rework shader mode selection.
- currently half the shader selection code (GLSL vs ARB) is in
fillGLcaps. The parts that check for software shaders are in
GetDeviceCaps. That placement, will work, but is definitely not optimal.
FillGLcaps should detect support - it should not make decision as to
what's used, because that's not what the purpose of the function is.
GetDeviceCaps should report support as it has already been selected.
Instead, select shader mode in its own function, called in the
appropriate places.
- unifying pixel and vertex shaders into a single selection is a
mistake. A software vertex shader can be coupled with a hardware arb or
glsl pixel shader, or no shader at all. Split them back into two and add
a SHADER_NONE variant.
- drawprim is doing support checks for ARB_PROGRAM, and making shader
decisions based on that - that's wrong, support has already been
checked, and decided upon, and shaders can be implemented via software,
ARB_PROGRAm or GLSL, so that support check isn't valid.
- Store the shader selected mode into the shader itself. Different types
of shaders can be combined, so this is an improvement. In fact, storing
the mode into the settings globally is a mistake as well - it should be
done per device, since different cards have different capabilities.
2006-07-04 09:21:53 +02:00
|
|
|
if (This->baseShader.shader_mode == SHADER_GLSL)
|
2006-06-14 04:32:14 +02:00
|
|
|
shader_glsl_add_instruction_modifiers(&hw_arg);
|
|
|
|
|
2006-06-12 08:51:58 +02:00
|
|
|
/* Unhandled opcode */
|
2006-05-10 04:32:34 +02:00
|
|
|
} else {
|
|
|
|
|
2006-06-12 08:51:58 +02:00
|
|
|
FIXME("Can't handle opcode %s in hwShader\n", curOpcode->name);
|
wined3d: More flow control instructions
- Implement if, else, endif, rep, endrep, break
- Implement ifc, breakc, using undocumented comparison bits in the instruction token
- Fix bug in main loop processing of codes with no dst token
- Fix bug in GLSL output modifier processing of codes with no dst token
- Fix bug in loop implementation (src1 contains the integer data, src0 is aL)
- Add versioning for all the instructions above, and remove
GLSL_REQUIRED thing, which is useless and should be removed from all
opcodes in general.
2006-07-10 11:11:35 +02:00
|
|
|
pToken += shader_skip_opcode(This, curOpcode, hw_arg.opcode_token);
|
2006-05-10 04:32:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* TODO: What about result.depth? */
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-10 19:53:07 +02:00
|
|
|
void shader_dump_ins_modifiers(const DWORD output) {
|
|
|
|
|
|
|
|
DWORD shift = (output & D3DSP_DSTSHIFT_MASK) >> D3DSP_DSTSHIFT_SHIFT;
|
|
|
|
DWORD mmask = output & D3DSP_DSTMOD_MASK;
|
|
|
|
|
|
|
|
switch (shift) {
|
|
|
|
case 0: break;
|
|
|
|
case 13: TRACE("_d8"); break;
|
|
|
|
case 14: TRACE("_d4"); break;
|
|
|
|
case 15: TRACE("_d2"); break;
|
|
|
|
case 1: TRACE("_x2"); break;
|
|
|
|
case 2: TRACE("_x4"); break;
|
|
|
|
case 3: TRACE("_x8"); break;
|
2006-10-01 05:20:10 +02:00
|
|
|
default: TRACE("_unhandled_shift(%d)", shift); break;
|
2006-05-10 19:53:07 +02:00
|
|
|
}
|
|
|
|
|
2006-05-17 07:58:19 +02:00
|
|
|
if (mmask & D3DSPDM_SATURATE) TRACE("_sat");
|
|
|
|
if (mmask & D3DSPDM_PARTIALPRECISION) TRACE("_pp");
|
|
|
|
if (mmask & D3DSPDM_MSAMPCENTROID) TRACE("_centroid");
|
|
|
|
|
|
|
|
mmask &= ~(D3DSPDM_SATURATE | D3DSPDM_PARTIALPRECISION | D3DSPDM_MSAMPCENTROID);
|
|
|
|
if (mmask)
|
2006-10-01 05:20:10 +02:00
|
|
|
FIXME("_unrecognized_modifier(%#x)", mmask >> D3DSP_DSTMOD_SHIFT);
|
2006-05-10 19:53:07 +02:00
|
|
|
}
|
|
|
|
|
2006-06-12 08:54:30 +02:00
|
|
|
/* First pass: trace shader, initialize length and version */
|
|
|
|
void shader_trace_init(
|
|
|
|
IWineD3DBaseShader *iface,
|
|
|
|
const DWORD* pFunction) {
|
|
|
|
|
|
|
|
IWineD3DBaseShaderImpl *This =(IWineD3DBaseShaderImpl *)iface;
|
|
|
|
|
|
|
|
const DWORD* pToken = pFunction;
|
|
|
|
const SHADER_OPCODE* curOpcode = NULL;
|
|
|
|
DWORD opcode_token;
|
|
|
|
unsigned int len = 0;
|
|
|
|
DWORD i;
|
|
|
|
|
|
|
|
TRACE("(%p) : Parsing programme\n", This);
|
|
|
|
|
|
|
|
if (NULL != pToken) {
|
|
|
|
while (D3DVS_END() != *pToken) {
|
|
|
|
if (shader_is_version_token(*pToken)) { /** version */
|
|
|
|
This->baseShader.hex_version = *pToken;
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("%s_%u_%u\n", shader_is_pshader_version(This->baseShader.hex_version)? "ps": "vs",
|
2006-06-12 08:54:30 +02:00
|
|
|
D3DSHADER_VERSION_MAJOR(This->baseShader.hex_version),
|
|
|
|
D3DSHADER_VERSION_MINOR(This->baseShader.hex_version));
|
|
|
|
++pToken;
|
|
|
|
++len;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (shader_is_comment(*pToken)) { /** comment */
|
|
|
|
DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
|
|
|
|
++pToken;
|
|
|
|
TRACE("//%s\n", (char*)pToken);
|
|
|
|
pToken += comment_len;
|
|
|
|
len += comment_len + 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
opcode_token = *pToken++;
|
|
|
|
curOpcode = shader_get_opcode(iface, opcode_token);
|
|
|
|
len++;
|
|
|
|
|
|
|
|
if (NULL == curOpcode) {
|
|
|
|
int tokens_read;
|
2006-10-01 05:20:10 +02:00
|
|
|
FIXME("Unrecognized opcode: token=%08x\n", opcode_token);
|
2006-06-12 08:54:30 +02:00
|
|
|
tokens_read = shader_skip_unrecognized(iface, pToken);
|
|
|
|
pToken += tokens_read;
|
|
|
|
len += tokens_read;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (curOpcode->opcode == D3DSIO_DCL) {
|
|
|
|
|
|
|
|
DWORD usage = *pToken;
|
|
|
|
DWORD param = *(pToken + 1);
|
|
|
|
|
2006-07-03 08:03:47 +02:00
|
|
|
shader_dump_decl_usage(This, usage, param);
|
2006-06-12 08:54:30 +02:00
|
|
|
shader_dump_ins_modifiers(param);
|
|
|
|
TRACE(" ");
|
|
|
|
shader_dump_param(iface, param, 0, 0);
|
|
|
|
pToken += 2;
|
|
|
|
len += 2;
|
|
|
|
|
|
|
|
} else if (curOpcode->opcode == D3DSIO_DEF) {
|
|
|
|
|
|
|
|
unsigned int offset = shader_get_float_offset(*pToken);
|
|
|
|
|
|
|
|
TRACE("def c%u = %f, %f, %f, %f", offset,
|
|
|
|
*(float *)(pToken + 1),
|
|
|
|
*(float *)(pToken + 2),
|
|
|
|
*(float *)(pToken + 3),
|
|
|
|
*(float *)(pToken + 4));
|
|
|
|
|
|
|
|
pToken += 5;
|
|
|
|
len += 5;
|
|
|
|
} else if (curOpcode->opcode == D3DSIO_DEFI) {
|
|
|
|
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("defi i%u = %d, %d, %d, %d", *pToken & D3DSP_REGNUM_MASK,
|
|
|
|
*(pToken + 1),
|
|
|
|
*(pToken + 2),
|
|
|
|
*(pToken + 3),
|
|
|
|
*(pToken + 4));
|
2006-06-12 08:54:30 +02:00
|
|
|
|
|
|
|
pToken += 5;
|
|
|
|
len += 5;
|
|
|
|
|
|
|
|
} else if (curOpcode->opcode == D3DSIO_DEFB) {
|
|
|
|
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("defb b%u = %s", *pToken & D3DSP_REGNUM_MASK,
|
2006-06-12 08:54:30 +02:00
|
|
|
*(pToken + 1)? "true": "false");
|
|
|
|
|
|
|
|
pToken += 2;
|
|
|
|
len += 2;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
DWORD param, addr_token;
|
|
|
|
int tokens_read;
|
|
|
|
|
|
|
|
/* Print out predication source token first - it follows
|
|
|
|
* the destination token. */
|
|
|
|
if (opcode_token & D3DSHADER_INSTRUCTION_PREDICATED) {
|
|
|
|
TRACE("(");
|
|
|
|
shader_dump_param(iface, *(pToken + 2), 0, 1);
|
|
|
|
TRACE(") ");
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("%s", curOpcode->name);
|
2006-06-12 12:57:04 +02:00
|
|
|
|
wined3d: More flow control instructions
- Implement if, else, endif, rep, endrep, break
- Implement ifc, breakc, using undocumented comparison bits in the instruction token
- Fix bug in main loop processing of codes with no dst token
- Fix bug in GLSL output modifier processing of codes with no dst token
- Fix bug in loop implementation (src1 contains the integer data, src0 is aL)
- Add versioning for all the instructions above, and remove
GLSL_REQUIRED thing, which is useless and should be removed from all
opcodes in general.
2006-07-10 11:11:35 +02:00
|
|
|
if (curOpcode->opcode == D3DSIO_IFC ||
|
|
|
|
curOpcode->opcode == D3DSIO_BREAKC) {
|
|
|
|
|
|
|
|
DWORD op = (opcode_token & INST_CONTROLS_MASK) >> INST_CONTROLS_SHIFT;
|
|
|
|
switch (op) {
|
|
|
|
case COMPARISON_GT: TRACE("_gt"); break;
|
|
|
|
case COMPARISON_EQ: TRACE("_eq"); break;
|
|
|
|
case COMPARISON_GE: TRACE("_ge"); break;
|
|
|
|
case COMPARISON_LT: TRACE("_lt"); break;
|
|
|
|
case COMPARISON_NE: TRACE("_ne"); break;
|
|
|
|
case COMPARISON_LE: TRACE("_le"); break;
|
|
|
|
default:
|
2006-10-01 05:20:10 +02:00
|
|
|
TRACE("_(%u)", op);
|
wined3d: More flow control instructions
- Implement if, else, endif, rep, endrep, break
- Implement ifc, breakc, using undocumented comparison bits in the instruction token
- Fix bug in main loop processing of codes with no dst token
- Fix bug in GLSL output modifier processing of codes with no dst token
- Fix bug in loop implementation (src1 contains the integer data, src0 is aL)
- Add versioning for all the instructions above, and remove
GLSL_REQUIRED thing, which is useless and should be removed from all
opcodes in general.
2006-07-10 11:11:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-06-12 12:57:04 +02:00
|
|
|
/* Destination token */
|
|
|
|
if (curOpcode->dst_token) {
|
2006-06-12 08:54:30 +02:00
|
|
|
|
|
|
|
/* Destination token */
|
|
|
|
tokens_read = shader_get_param(iface, pToken, ¶m, &addr_token);
|
|
|
|
pToken += tokens_read;
|
|
|
|
len += tokens_read;
|
|
|
|
|
|
|
|
shader_dump_ins_modifiers(param);
|
|
|
|
TRACE(" ");
|
|
|
|
shader_dump_param(iface, param, addr_token, 0);
|
2006-06-12 12:57:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Predication token - already printed out, just skip it */
|
|
|
|
if (opcode_token & D3DSHADER_INSTRUCTION_PREDICATED) {
|
|
|
|
pToken++;
|
|
|
|
len++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Other source tokens */
|
|
|
|
for (i = curOpcode->dst_token; i < curOpcode->num_params; ++i) {
|
|
|
|
|
|
|
|
tokens_read = shader_get_param(iface, pToken, ¶m, &addr_token);
|
|
|
|
pToken += tokens_read;
|
|
|
|
len += tokens_read;
|
2006-06-12 08:54:30 +02:00
|
|
|
|
2006-06-12 12:57:04 +02:00
|
|
|
TRACE((i == 0)? " " : ", ");
|
|
|
|
shader_dump_param(iface, param, addr_token, 1);
|
2006-06-12 08:54:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
TRACE("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
This->baseShader.functionLength = (len + 1) * sizeof(DWORD);
|
|
|
|
} else {
|
|
|
|
This->baseShader.functionLength = 1; /* no Function defined use fixed function vertex processing */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-10 06:51:03 +02:00
|
|
|
void shader_delete_constant_list(
|
|
|
|
struct list* clist) {
|
|
|
|
|
|
|
|
struct list *ptr;
|
|
|
|
struct local_constant* constant;
|
|
|
|
|
|
|
|
ptr = list_head(clist);
|
|
|
|
while (ptr) {
|
|
|
|
constant = LIST_ENTRY(ptr, struct local_constant, entry);
|
|
|
|
ptr = list_next(clist, ptr);
|
|
|
|
HeapFree(GetProcessHeap(), 0, constant);
|
|
|
|
}
|
|
|
|
}
|