📄 arb_program_shader.c
字号:
/*
* Pixel and vertex shaders implementation using ARB_vertex_program
* and ARB_fragment_program GL extensions.
*
* Copyright 2002-2003 Jason Edmeades
* Copyright 2002-2003 Raphael Junqueira
* Copyright 2004 Christian Costa
* Copyright 2005 Oliver Stieber
* Copyright 2006 Ivan Gyurdiev
* Copyright 2006 Jason Green
* Copyright 2006 Henri Verbeet
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include <math.h>
#include <stdio.h>
#include "wined3d_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
WINE_DECLARE_DEBUG_CHANNEL(d3d_constants);
#define GLINFO_LOCATION (*gl_info)
/********************************************************
* ARB_[vertex/fragment]_program helper functions follow
********************************************************/
/**
* Loads floating point constants into the currently set ARB_vertex/fragment_program.
* When constant_list == NULL, it will load all the constants.
*
* @target_type should be either GL_VERTEX_PROGRAM_ARB (for vertex shaders)
* or GL_FRAGMENT_PROGRAM_ARB (for pixel shaders)
*/
static void shader_arb_load_constantsF(IWineD3DBaseShaderImpl* This, WineD3D_GL_Info *gl_info, GLuint target_type,
unsigned int max_constants, float* constants, struct list *constant_list) {
constants_entry *constant;
local_constant* lconst;
DWORD i, j;
DWORD *idx;
if (TRACE_ON(d3d_shader)) {
LIST_FOR_EACH_ENTRY(constant, constant_list, constants_entry, entry) {
idx = constant->idx;
j = constant->count;
while (j--) {
i = *idx++;
TRACE_(d3d_constants)("Loading constants %i: %f, %f, %f, %f\n", i,
constants[i * 4 + 0], constants[i * 4 + 1],
constants[i * 4 + 2], constants[i * 4 + 3]);
}
}
}
LIST_FOR_EACH_ENTRY(constant, constant_list, constants_entry, entry) {
idx = constant->idx;
j = constant->count;
while (j--) {
i = *idx++;
GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, constants + (i * 4)));
}
}
checkGLcall("glProgramEnvParameter4fvARB()");
/* Load immediate constants */
if (TRACE_ON(d3d_shader)) {
LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) {
GLfloat* values = (GLfloat*)lconst->value;
TRACE_(d3d_constants)("Loading local constants %i: %f, %f, %f, %f\n", lconst->idx,
values[0], values[1], values[2], values[3]);
}
}
LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) {
GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, lconst->idx, (GLfloat*)lconst->value));
}
checkGLcall("glProgramEnvParameter4fvARB()");
}
/**
* Loads the app-supplied constants into the currently set ARB_[vertex/fragment]_programs.
*
* We only support float constants in ARB at the moment, so don't
* worry about the Integers or Booleans
*/
void shader_arb_load_constants(
IWineD3DDevice* device,
char usePixelShader,
char useVertexShader) {
IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) device;
IWineD3DStateBlockImpl* stateBlock = deviceImpl->stateBlock;
WineD3D_GL_Info *gl_info = &deviceImpl->adapter->gl_info;
if (useVertexShader) {
IWineD3DBaseShaderImpl* vshader = (IWineD3DBaseShaderImpl*) stateBlock->vertexShader;
/* Load DirectX 9 float constants for vertex shader */
shader_arb_load_constantsF(vshader, gl_info, GL_VERTEX_PROGRAM_ARB,
GL_LIMITS(vshader_constantsF),
stateBlock->vertexShaderConstantF,
&stateBlock->set_vconstantsF);
/* Upload the position fixup */
GL_EXTCALL(glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, ARB_SHADER_PRIVCONST_POS, deviceImpl->posFixup));
}
if (usePixelShader) {
IWineD3DBaseShaderImpl* pshader = (IWineD3DBaseShaderImpl*) stateBlock->pixelShader;
/* Load DirectX 9 float constants for pixel shader */
shader_arb_load_constantsF(pshader, gl_info, GL_FRAGMENT_PROGRAM_ARB,
GL_LIMITS(pshader_constantsF),
stateBlock->pixelShaderConstantF,
&stateBlock->set_pconstantsF);
if(((IWineD3DPixelShaderImpl *) pshader)->bumpenvmatconst) {
/* needsbumpmat stores the stage number from where to load the matrix. bumpenvmatconst stores the
* number of the constant to load the matrix into.
* The state manager takes care that this function is always called if the bump env matrix changes
*/
IWineD3DPixelShaderImpl *psi = (IWineD3DPixelShaderImpl *) pshader;
float *data = (float *) &stateBlock->textureState[(int) psi->needsbumpmat][WINED3DTSS_BUMPENVMAT00];
GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, psi->bumpenvmatconst, data));
}
}
}
/* Generate the variable & register declarations for the ARB_vertex_program output target */
void shader_generate_arb_declarations(
IWineD3DBaseShader *iface,
shader_reg_maps* reg_maps,
SHADER_BUFFER* buffer,
WineD3D_GL_Info* gl_info) {
IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
DWORD i;
char pshader = shader_is_pshader_version(This->baseShader.hex_version);
unsigned max_constantsF = min(This->baseShader.limits.constant_float,
(pshader ? GL_LIMITS(pshader_constantsF) : GL_LIMITS(vshader_constantsF)));
/* Temporary Output register */
shader_addline(buffer, "TEMP TMP_OUT;\n");
for(i = 0; i < This->baseShader.limits.temporary; i++) {
if (reg_maps->temporary[i])
shader_addline(buffer, "TEMP R%u;\n", i);
}
for (i = 0; i < This->baseShader.limits.address; i++) {
if (reg_maps->address[i])
shader_addline(buffer, "ADDRESS A%d;\n", i);
}
for(i = 0; i < This->baseShader.limits.texcoord; i++) {
if (reg_maps->texcoord[i])
shader_addline(buffer,"TEMP T%u;\n", i);
}
/* Texture coordinate registers must be pre-loaded */
for (i = 0; i < This->baseShader.limits.texcoord; i++) {
if (reg_maps->texcoord[i])
shader_addline(buffer, "MOV T%u, fragment.texcoord[%u];\n", i, i);
}
if(reg_maps->bumpmat != -1 /* Only a pshader can use texbem */) {
/* If the shader does not use all available constants, use the next free constant to load the bump mapping environment matrix from
* the stateblock into the shader. If no constant is available don't load, texbem will then just sample the texture without applying
* bump mapping.
*/
if(max_constantsF < GL_LIMITS(pshader_constantsF)) {
((IWineD3DPixelShaderImpl *)This)->bumpenvmatconst = max_constantsF;
shader_addline(buffer, "PARAM bumpenvmat = program.env[%d];\n", ((IWineD3DPixelShaderImpl *)This)->bumpenvmatconst);
} else {
FIXME("No free constant found to load environemnt bump mapping matrix into the shader. texbem instruction will not apply bump mapping\n");
}
}
/* Need to PARAM the environment parameters (constants) so we can use relative addressing */
shader_addline(buffer, "PARAM C[%d] = { program.env[0..%d] };\n",
max_constantsF, max_constantsF - 1);
}
static const char * const shift_tab[] = {
"dummy", /* 0 (none) */
"coefmul.x", /* 1 (x2) */
"coefmul.y", /* 2 (x4) */
"coefmul.z", /* 3 (x8) */
"coefmul.w", /* 4 (x16) */
"dummy", /* 5 (x32) */
"dummy", /* 6 (x64) */
"dummy", /* 7 (x128) */
"dummy", /* 8 (d256) */
"dummy", /* 9 (d128) */
"dummy", /* 10 (d64) */
"dummy", /* 11 (d32) */
"coefdiv.w", /* 12 (d16) */
"coefdiv.z", /* 13 (d8) */
"coefdiv.y", /* 14 (d4) */
"coefdiv.x" /* 15 (d2) */
};
static void shader_arb_get_write_mask(const DWORD param, char *write_mask) {
char *ptr = write_mask;
if ((param & WINED3DSP_WRITEMASK_ALL) != WINED3DSP_WRITEMASK_ALL) {
*ptr++ = '.';
if (param & WINED3DSP_WRITEMASK_0) *ptr++ = 'x';
if (param & WINED3DSP_WRITEMASK_1) *ptr++ = 'y';
if (param & WINED3DSP_WRITEMASK_2) *ptr++ = 'z';
if (param & WINED3DSP_WRITEMASK_3) *ptr++ = 'w';
}
*ptr = '\0';
}
static void shader_arb_get_swizzle(const DWORD param, BOOL fixup, char *swizzle_str) {
/* For registers of type WINED3DDECLTYPE_D3DCOLOR, data is stored as "bgra",
* but addressed as "rgba". To fix this we need to swap the register's x
* and z components. */
const char *swizzle_chars = fixup ? "zyxw" : "xyzw";
char *ptr = swizzle_str;
/* swizzle bits fields: wwzzyyxx */
DWORD swizzle = (param & WINED3DSP_SWIZZLE_MASK) >> WINED3DSP_SWIZZLE_SHIFT;
DWORD swizzle_x = swizzle & 0x03;
DWORD swizzle_y = (swizzle >> 2) & 0x03;
DWORD swizzle_z = (swizzle >> 4) & 0x03;
DWORD swizzle_w = (swizzle >> 6) & 0x03;
/* If the swizzle is the default swizzle (ie, "xyzw"), we don't need to
* generate a swizzle string. Unless we need to our own swizzling. */
if ((WINED3DSP_NOSWIZZLE >> WINED3DSP_SWIZZLE_SHIFT) != swizzle || fixup) {
*ptr++ = '.';
if (swizzle_x == swizzle_y && swizzle_x == swizzle_z && swizzle_x == swizzle_w) {
*ptr++ = swizzle_chars[swizzle_x];
} else {
*ptr++ = swizzle_chars[swizzle_x];
*ptr++ = swizzle_chars[swizzle_y];
*ptr++ = swizzle_chars[swizzle_z];
*ptr++ = swizzle_chars[swizzle_w];
}
}
*ptr = '\0';
}
static void pshader_get_register_name(
const DWORD param, char* regstr) {
DWORD reg = param & WINED3DSP_REGNUM_MASK;
DWORD regtype = shader_get_regtype(param);
switch (regtype) {
case WINED3DSPR_TEMP:
sprintf(regstr, "R%u", reg);
break;
case WINED3DSPR_INPUT:
if (reg==0) {
strcpy(regstr, "fragment.color.primary");
} else {
strcpy(regstr, "fragment.color.secondary");
}
break;
case WINED3DSPR_CONST:
sprintf(regstr, "C[%u]", reg);
break;
case WINED3DSPR_TEXTURE: /* case WINED3DSPR_ADDR: */
sprintf(regstr,"T%u", reg);
break;
case WINED3DSPR_COLOROUT:
if (reg == 0)
sprintf(regstr, "TMP_COLOR");
else {
/* TODO: See GL_ARB_draw_buffers */
FIXME("Unsupported write to render target %u\n", reg);
sprintf(regstr, "unsupported_register");
}
break;
case WINED3DSPR_DEPTHOUT:
sprintf(regstr, "result.depth");
break;
case WINED3DSPR_ATTROUT:
sprintf(regstr, "oD[%u]", reg);
break;
case WINED3DSPR_TEXCRDOUT:
sprintf(regstr, "oT[%u]", reg);
break;
default:
FIXME("Unhandled register name Type(%d)\n", regtype);
sprintf(regstr, "unrecognized_register");
break;
}
}
/* TODO: merge with pixel shader */
static void vshader_program_add_param(SHADER_OPCODE_ARG *arg, const DWORD param, BOOL is_input, char *hwLine) {
IWineD3DVertexShaderImpl* This = (IWineD3DVertexShaderImpl*) arg->shader;
/* oPos, oFog and oPts in D3D */
static const char * const hwrastout_reg_names[] = { "TMP_OUT", "result.fogcoord", "result.pointsize" };
DWORD reg = param & WINED3DSP_REGNUM_MASK;
DWORD regtype = shader_get_regtype(param);
char tmpReg[255];
BOOL is_color = FALSE;
if ((param & WINED3DSP_SRCMOD_MASK) == WINED3DSPSM_NEG) {
strcat(hwLine, " -");
} else {
strcat(hwLine, " ");
}
switch (regtype) {
case WINED3DSPR_TEMP:
sprintf(tmpReg, "R%u", reg);
strcat(hwLine, tmpReg);
break;
case WINED3DSPR_INPUT:
if (vshader_input_is_color((IWineD3DVertexShader*) This, reg))
is_color = TRUE;
sprintf(tmpReg, "vertex.attrib[%u]", reg);
strcat(hwLine, tmpReg);
break;
case WINED3DSPR_CONST:
sprintf(tmpReg, "C[%s%u]", (param & WINED3DSHADER_ADDRMODE_RELATIVE) ? "A0.x + " : "", reg);
strcat(hwLine, tmpReg);
break;
case WINED3DSPR_ADDR: /*case D3DSPR_TEXTURE:*/
sprintf(tmpReg, "A%u", reg);
strcat(hwLine, tmpReg);
break;
case WINED3DSPR_RASTOUT:
sprintf(tmpReg, "%s", hwrastout_reg_names[reg]);
strcat(hwLine, tmpReg);
break;
case WINED3DSPR_ATTROUT:
if (reg==0) {
strcat(hwLine, "result.color.primary");
} else {
strcat(hwLine, "result.color.secondary");
}
break;
case WINED3DSPR_TEXCRDOUT:
sprintf(tmpReg, "result.texcoord[%u]", reg);
strcat(hwLine, tmpReg);
break;
default:
FIXME("Unknown reg type %d %d\n", regtype, reg);
strcat(hwLine, "unrecognized_register");
break;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -