2006-05-08 21:44:25 +02:00
|
|
|
/*
|
|
|
|
* shaders implementation
|
|
|
|
*
|
|
|
|
* Copyright 2002-2003 Jason Edmeades
|
|
|
|
* Copyright 2002-2003 Raphael Junqueira
|
|
|
|
* 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-06-12 08:54:30 +02:00
|
|
|
FIXME("Unsupported opcode %#lx(%ld) masked %#lx, shader version %#lx\n",
|
|
|
|
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;
|
|
|
|
|
|
|
|
FIXME("Unrecognized opcode param: token=%08lX "
|
|
|
|
"addr_token=%08lX 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-06-12 08:53:32 +02:00
|
|
|
static void shader_parse_decl_usage(
|
|
|
|
DWORD *semantics_map,
|
|
|
|
DWORD usage_token, DWORD param) {
|
|
|
|
|
|
|
|
unsigned int usage = (usage_token & D3DSP_DCL_USAGE_MASK) >> D3DSP_DCL_USAGE_SHIFT;
|
|
|
|
unsigned int usage_idx = (usage_token & D3DSP_DCL_USAGEINDEX_MASK) >> D3DSP_DCL_USAGEINDEX_SHIFT;
|
|
|
|
unsigned int regnum = param & D3DSP_REGNUM_MASK;
|
|
|
|
|
|
|
|
switch(usage) {
|
|
|
|
case D3DDECLUSAGE_POSITION:
|
|
|
|
if (usage_idx == 0) { /* tween data */
|
|
|
|
TRACE("Setting position to %d\n", regnum);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_POSITION] = param;
|
|
|
|
} else {
|
|
|
|
/* TODO: position indexes go from 0-8!!*/
|
|
|
|
TRACE("Setting position 2 to %d because usage_idx = %d\n", regnum, usage_idx);
|
|
|
|
/* robots uses positions up to 8, the position arrays are just packed.*/
|
|
|
|
if (usage_idx > 1) {
|
|
|
|
TRACE("Loaded for position %d (greater than 2)\n", usage_idx);
|
|
|
|
}
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_POSITION2 + usage_idx-1] = param;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case D3DDECLUSAGE_BLENDINDICES:
|
|
|
|
TRACE("Setting BLENDINDICES to %d\n", regnum);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_BLENDINDICES] = param;
|
|
|
|
if (usage_idx != 0) FIXME("Extended BLENDINDICES\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case D3DDECLUSAGE_BLENDWEIGHT:
|
|
|
|
TRACE("Setting BLENDWEIGHT to %d\n", regnum);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_BLENDWEIGHT] = param;
|
|
|
|
if (usage_idx != 0) FIXME("Extended blend weights\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case D3DDECLUSAGE_NORMAL:
|
|
|
|
if (usage_idx == 0) { /* tween data */
|
|
|
|
TRACE("Setting normal to %d\n", regnum);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_NORMAL] = param;
|
|
|
|
} else {
|
|
|
|
TRACE("Setting normal 2 to %d because usage = %d\n", regnum, usage_idx);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_NORMAL2] = param;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case D3DDECLUSAGE_PSIZE:
|
|
|
|
TRACE("Setting PSIZE to %d\n", regnum);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_PSIZE] = param;
|
|
|
|
if (usage_idx != 0) FIXME("Extended PSIZE\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case D3DDECLUSAGE_COLOR:
|
|
|
|
if (usage_idx == 0) {
|
|
|
|
TRACE("Setting DIFFUSE to %d\n", regnum);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_DIFFUSE] = param;
|
|
|
|
} else {
|
|
|
|
TRACE("Setting SPECULAR to %d\n", regnum);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_SPECULAR] = param;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case D3DDECLUSAGE_TEXCOORD:
|
|
|
|
if (usage_idx > 7) {
|
|
|
|
FIXME("Program uses texture coordinate %d but only 0-7 have been "
|
|
|
|
"implemented\n", usage_idx);
|
|
|
|
} else {
|
|
|
|
TRACE("Setting TEXCOORD %d to %d\n", usage_idx, regnum);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_TEXCOORD0 + usage_idx] = param;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case D3DDECLUSAGE_TANGENT:
|
|
|
|
TRACE("Setting TANGENT to %d\n", regnum);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_TANGENT] = param;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case D3DDECLUSAGE_BINORMAL:
|
|
|
|
TRACE("Setting BINORMAL to %d\n", regnum);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_BINORMAL] = param;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case D3DDECLUSAGE_TESSFACTOR:
|
|
|
|
TRACE("Setting TESSFACTOR to %d\n", regnum);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_TESSFACTOR] = param;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case D3DDECLUSAGE_POSITIONT:
|
|
|
|
if (usage_idx == 0) { /* tween data */
|
|
|
|
FIXME("Setting positiont to %d\n", regnum);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_POSITIONT] = param;
|
|
|
|
} else {
|
|
|
|
FIXME("Setting positiont 2 to %d because usage = %d\n", regnum, usage_idx);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_POSITIONT2] = param;
|
|
|
|
if (usage_idx != 0) FIXME("Extended positiont\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case D3DDECLUSAGE_FOG:
|
|
|
|
TRACE("Setting FOG to %d\n", regnum);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_FOG] = param;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case D3DDECLUSAGE_DEPTH:
|
|
|
|
TRACE("Setting DEPTH to %d\n", regnum);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_DEPTH] = param;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case D3DDECLUSAGE_SAMPLE:
|
|
|
|
TRACE("Setting SAMPLE to %d\n", regnum);
|
|
|
|
semantics_map[WINED3DSHADERDECLUSAGE_SAMPLE] = param;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
FIXME("Unrecognised dcl %#x", usage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-06-12 08:53:32 +02:00
|
|
|
void 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-05-10 04:31:09 +02:00
|
|
|
CONST DWORD* pToken) {
|
|
|
|
|
|
|
|
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)
|
|
|
|
return;
|
|
|
|
|
|
|
|
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-06-12 08:53:32 +02:00
|
|
|
shader_parse_decl_usage(reg_maps->semantics_in, usage, param);
|
|
|
|
|
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-06-12 08:53:32 +02:00
|
|
|
shader_parse_decl_usage(reg_maps->semantics_out, usage, param);
|
|
|
|
|
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
|
|
|
|
|
|
|
/* Skip definitions (for now) */
|
|
|
|
} else if (D3DSIO_DEF == curOpcode->opcode) {
|
|
|
|
pToken += curOpcode->num_params;
|
|
|
|
|
2006-06-16 22:13:01 +02:00
|
|
|
/* If there's a loop in the shader */
|
|
|
|
} else if (D3DSIO_LOOP == curOpcode->opcode) {
|
|
|
|
reg_maps->loop = 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;
|
|
|
|
reg_maps->samplers[sampler_code] = (0x1 << 31) | D3DSTT_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;
|
|
|
|
reg_maps->samplers[sampler_code] = (0x1 << 31) | D3DSTT_CUBE;
|
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-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) {
|
|
|
|
DWORD ttype = decl & D3DSP_TEXTURETYPE_MASK;
|
|
|
|
|
|
|
|
switch (ttype) {
|
2006-07-03 08:03:47 +02:00
|
|
|
case D3DSTT_2D: TRACE("_2d"); break;
|
|
|
|
case D3DSTT_CUBE: TRACE("_cube"); break;
|
|
|
|
case D3DSTT_VOLUME: TRACE("_volume"); break;
|
|
|
|
default: TRACE("_unknown_ttype(%08lx)", 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:
|
|
|
|
TRACE("%s%ld", "position", idx);
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_BLENDINDICES:
|
|
|
|
TRACE("%s", "blend");
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_BLENDWEIGHT:
|
|
|
|
TRACE("%s", "weight");
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_NORMAL:
|
|
|
|
TRACE("%s%ld", "normal", idx);
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_PSIZE:
|
|
|
|
TRACE("%s", "psize");
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_COLOR:
|
|
|
|
if(idx == 0) {
|
|
|
|
TRACE("%s", "color");
|
|
|
|
} else {
|
|
|
|
TRACE("%s%ld", "specular", (idx - 1));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_TEXCOORD:
|
|
|
|
TRACE("%s%ld", "texture", idx);
|
|
|
|
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:
|
|
|
|
TRACE("%s%ld", "positionT", idx);
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_FOG:
|
|
|
|
TRACE("%s", "fog");
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_DEPTH:
|
|
|
|
TRACE("%s", "depth");
|
|
|
|
break;
|
|
|
|
case D3DDECLUSAGE_SAMPLE:
|
|
|
|
TRACE("%s", "sample");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
FIXME("unknown_semantics(%08lx)", usage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* 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) {
|
|
|
|
if ( ((param & D3DSP_SRCMOD_MASK) == D3DSPSM_NEG) ||
|
|
|
|
((param & D3DSP_SRCMOD_MASK) == D3DSPSM_BIASNEG) ||
|
|
|
|
((param & D3DSP_SRCMOD_MASK) == D3DSPSM_SIGNNEG) ||
|
|
|
|
((param & D3DSP_SRCMOD_MASK) == D3DSPSM_X2NEG) )
|
|
|
|
TRACE("-");
|
|
|
|
else if ((param & D3DSP_SRCMOD_MASK) == D3DSPSM_COMP)
|
|
|
|
TRACE("1-");
|
2006-05-18 03:09:56 +02:00
|
|
|
else if ((param & D3DSP_SRCMOD_MASK) == D3DSPSM_NOT)
|
|
|
|
TRACE("!");
|
2006-05-14 15:43:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (regtype) {
|
|
|
|
case D3DSPR_TEMP:
|
|
|
|
TRACE("r%lu", reg);
|
|
|
|
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 */
|
|
|
|
TRACE("%c%lu", (pshader? 't':'a'), reg);
|
|
|
|
break;
|
|
|
|
case D3DSPR_RASTOUT:
|
|
|
|
TRACE("%s", rastout_reg_names[reg]);
|
|
|
|
break;
|
|
|
|
case D3DSPR_COLOROUT:
|
|
|
|
TRACE("oC%lu", reg);
|
|
|
|
break;
|
|
|
|
case D3DSPR_DEPTHOUT:
|
|
|
|
TRACE("oDepth");
|
|
|
|
break;
|
|
|
|
case D3DSPR_ATTROUT:
|
|
|
|
TRACE("oD%lu", reg);
|
|
|
|
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
|
|
|
|
TRACE("oT%lu", 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:
|
|
|
|
TRACE("l%lu", reg);
|
|
|
|
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:
|
|
|
|
TRACE("s%lu", reg);
|
|
|
|
break;
|
2006-05-18 03:08:29 +02:00
|
|
|
case D3DSPR_PREDICATE:
|
|
|
|
TRACE("p%lu", reg);
|
|
|
|
break;
|
2006-05-14 15:43:31 +02:00
|
|
|
default:
|
2006-05-18 03:08:29 +02:00
|
|
|
TRACE("unhandled_rtype(%#lx)", 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;
|
|
|
|
|
|
|
|
if (0 != (param & D3DSP_SRCMOD_MASK)) {
|
|
|
|
DWORD mask = param & D3DSP_SRCMOD_MASK;
|
|
|
|
switch (mask) {
|
|
|
|
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;
|
|
|
|
default:
|
2006-05-18 03:09:56 +02:00
|
|
|
TRACE("_unknown_modifier(%#lx)", mask >> 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-17 08:00:47 +02:00
|
|
|
DWORD opcode_token;
|
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 */
|
2006-05-17 08:00:47 +02:00
|
|
|
opcode_token = *pToken++;
|
|
|
|
curOpcode = shader_get_opcode(iface, 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) {
|
|
|
|
FIXME("Unrecognized opcode: token=%08lX\n", opcode_token);
|
|
|
|
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 ||
|
|
|
|
D3DSIO_NOP == curOpcode->opcode) {
|
|
|
|
|
|
|
|
pToken += shader_skip_opcode(This, curOpcode, opcode_token);
|
|
|
|
|
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 */
|
|
|
|
if (opcode_token & D3DSHADER_INSTRUCTION_PREDICATED)
|
|
|
|
hw_arg.predicate = *pToken++;
|
2006-05-18 03:09:56 +02:00
|
|
|
|
2006-06-12 12:57:04 +02:00
|
|
|
/* Other source tokens */
|
|
|
|
for (i = curOpcode->dst_token; i < curOpcode->num_params; i++) {
|
2006-05-17 08:04:30 +02:00
|
|
|
|
2006-06-12 12:57:04 +02:00
|
|
|
DWORD param, addr_token = 0;
|
2006-05-17 08:04:30 +02:00
|
|
|
|
2006-06-12 12:57:04 +02:00
|
|
|
/* DEF* instructions have constant src parameters, not registers */
|
|
|
|
if (curOpcode->opcode == D3DSIO_DEF ||
|
|
|
|
curOpcode->opcode == D3DSIO_DEFI ||
|
|
|
|
curOpcode->opcode == D3DSIO_DEFB) {
|
|
|
|
param = *pToken++;
|
|
|
|
|
|
|
|
} else
|
|
|
|
pToken += shader_get_param(iface, pToken, ¶m, &addr_token);
|
|
|
|
|
|
|
|
hw_arg.src[i-1] = param;
|
|
|
|
hw_arg.src_addr[i-1] = 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);
|
|
|
|
pToken += shader_skip_opcode(This, curOpcode, 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;
|
|
|
|
default: TRACE("_unhandled_shift(%ld)", shift); break;
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
FIXME("_unrecognized_modifier(%#lx)", 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;
|
|
|
|
TRACE("%s_%lu_%lu\n", shader_is_pshader_version(This->baseShader.hex_version)? "ps": "vs",
|
|
|
|
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;
|
|
|
|
FIXME("Unrecognized opcode: token=%08lX\n", opcode_token);
|
|
|
|
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) {
|
|
|
|
|
|
|
|
TRACE("defi i%lu = %ld, %ld, %ld, %ld", *pToken & D3DSP_REGNUM_MASK,
|
|
|
|
(long) *(pToken + 1),
|
|
|
|
(long) *(pToken + 2),
|
|
|
|
(long) *(pToken + 3),
|
|
|
|
(long) *(pToken + 4));
|
|
|
|
|
|
|
|
pToken += 5;
|
|
|
|
len += 5;
|
|
|
|
|
|
|
|
} else if (curOpcode->opcode == D3DSIO_DEFB) {
|
|
|
|
|
|
|
|
TRACE("defb b%lu = %s", *pToken & D3DSP_REGNUM_MASK,
|
|
|
|
*(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
|
|
|
|
|
|
|
/* 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-05-08 21:44:25 +02:00
|
|
|
/* TODO: Move other shared code here */
|