1
0
Fork 0
mirror of synced 2025-03-07 03:53:26 +01:00

wined3d: Fragment processing using GL_ATI_fragment_shader.

This adds code for handling fixed function fragment processing with the
GL_ATI_fragment_shader extension. This is a sort-of programmable
interface for fragment processing at the level of shader model 1.4 in
d3d. This code is of use on r200, r250 and r280 cards(radeon 8500 to
9200) which do not support GL_ARB_fragment_program, but support pixel
shader 1.4 on Windows. This code is somewhat a counterpart to the
existing fragment processing code using GL_NV_register_combiners and
GL_NV_texture_shader.
This commit is contained in:
Stefan Dösinger 2008-03-22 14:31:52 +01:00 committed by Alexandre Julliard
parent a440051016
commit 4640be8dc8
8 changed files with 1021 additions and 12 deletions

View file

@ -9,6 +9,7 @@ EXTRALIBS = -luuid
C_SRCS = \
arb_program_shader.c \
ati_fragment_shader.c \
baseshader.c \
basetexture.c \
clipper.c \

View file

@ -0,0 +1,789 @@
/*
* Fixed function pipeline replacement using GL_ATI_fragment_shader
*
* Copyright 2008 Stefan Dösinger(for CodeWeavers)
*
* 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);
/* Some private defines, Constant associations, etc */
#define ATI_FFP_CONST_CONSTANT0 GL_CON_0_ATI
#define ATI_FFP_CONST_CONSTANT1 GL_CON_1_ATI
#define ATI_FFP_CONST_CONSTANT2 GL_CON_2_ATI
#define ATI_FFP_CONST_CONSTANT3 GL_CON_3_ATI
#define ATI_FFP_CONST_CONSTANT4 GL_CON_4_ATI
#define ATI_FFP_CONST_CONSTANT5 GL_CON_5_ATI
#define ATI_FFP_CONST_TFACTOR GL_CON_6_ATI
/* GL_ATI_fragment_shader specific fixed function pipeline description. "Inherits" from the common one */
struct atifs_ffp_desc
{
struct ffp_desc parent;
GLuint shader;
};
struct atifs_private_data
{
struct shader_arb_priv parent;
struct list fragment_shaders; /* A linked list to track fragment pipeline replacement shaders */
};
static const char *debug_dstmod(GLuint mod) {
switch(mod) {
case GL_NONE: return "GL_NONE";
case GL_2X_BIT_ATI: return "GL_2X_BIT_ATI";
case GL_4X_BIT_ATI: return "GL_4X_BIT_ATI";
case GL_8X_BIT_ATI: return "GL_8X_BIT_ATI";
case GL_HALF_BIT_ATI: return "GL_HALF_BIT_ATI";
case GL_QUARTER_BIT_ATI: return "GL_QUARTER_BIT_ATI";
case GL_EIGHTH_BIT_ATI: return "GL_EIGHTH_BIT_ATI";
case GL_SATURATE_BIT_ATI: return "GL_SATURATE_BIT_ATI";
default: return "Unexpected modifier\n";
}
}
static const char *debug_argmod(GLuint mod) {
switch(mod) {
case GL_NONE:
return "GL_NONE";
case GL_2X_BIT_ATI:
return "GL_2X_BIT_ATI";
case GL_COMP_BIT_ATI:
return "GL_COMP_BIT_ATI";
case GL_NEGATE_BIT_ATI:
return "GL_NEGATE_BIT_ATI";
case GL_BIAS_BIT_ATI:
return "GL_BIAS_BIT_ATI";
case GL_2X_BIT_ATI | GL_COMP_BIT_ATI:
return "GL_2X_BIT_ATI | GL_COMP_BIT_ATI";
case GL_2X_BIT_ATI | GL_NEGATE_BIT_ATI:
return "GL_2X_BIT_ATI | GL_NEGATE_BIT_ATI";
case GL_2X_BIT_ATI | GL_BIAS_BIT_ATI:
return "GL_2X_BIT_ATI | GL_BIAS_BIT_ATI";
case GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI:
return "GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI";
case GL_COMP_BIT_ATI | GL_BIAS_BIT_ATI:
return "GL_COMP_BIT_ATI | GL_BIAS_BIT_ATI";
case GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI:
return "GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI";
case GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI:
return "GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI";
case GL_2X_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI:
return "GL_2X_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI";
case GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_BIAS_BIT_ATI:
return "GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_BIAS_BIT_ATI";
case GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI:
return "GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI";
case GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI:
return "GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI";
default:
return "Unexpected argmod combination\n";
}
}
static const char *debug_register(GLuint reg) {
switch(reg) {
case GL_REG_0_ATI: return "GL_REG_0_ATI";
case GL_REG_1_ATI: return "GL_REG_1_ATI";
case GL_REG_2_ATI: return "GL_REG_2_ATI";
case GL_REG_3_ATI: return "GL_REG_3_ATI";
case GL_REG_4_ATI: return "GL_REG_4_ATI";
case GL_REG_5_ATI: return "GL_REG_5_ATI";
case GL_CON_0_ATI: return "GL_CON_0_ATI";
case GL_CON_1_ATI: return "GL_CON_1_ATI";
case GL_CON_2_ATI: return "GL_CON_2_ATI";
case GL_CON_3_ATI: return "GL_CON_3_ATI";
case GL_CON_4_ATI: return "GL_CON_4_ATI";
case GL_CON_5_ATI: return "GL_CON_5_ATI";
case GL_CON_6_ATI: return "GL_CON_6_ATI";
case GL_CON_7_ATI: return "GL_CON_7_ATI";
case GL_ZERO: return "GL_ZERO";
case GL_ONE: return "GL_ONE";
case GL_PRIMARY_COLOR: return "GL_PRIMARY_COLOR";
case GL_SECONDARY_INTERPOLATOR_ATI: return "GL_SECONDARY_INTERPOLATOR_ATI";
default: return "Unknown register\n";
}
}
static const char *debug_swizzle(GLuint swizzle) {
switch(swizzle) {
case GL_SWIZZLE_STR_ATI: return "GL_SWIZZLE_STR_ATI";
case GL_SWIZZLE_STQ_ATI: return "GL_SWIZZLE_STQ_ATI";
case GL_SWIZZLE_STR_DR_ATI: return "GL_SWIZZLE_STR_DR_ATI";
case GL_SWIZZLE_STQ_DQ_ATI: return "GL_SWIZZLE_STQ_DQ_ATI";
default: return "unknown swizzle";
}
}
#define GLINFO_LOCATION (*gl_info)
static GLuint register_for_arg(DWORD arg, WineD3D_GL_Info *gl_info, unsigned int stage, GLuint *mod) {
GLenum ret;
if(mod) *mod = GL_NONE;
if(arg == 0xFFFFFFFF) return -1; /* This is the marker for unused registers */
switch(arg & WINED3DTA_SELECTMASK) {
case WINED3DTA_DIFFUSE:
ret = GL_PRIMARY_COLOR;
break;
case WINED3DTA_CURRENT:
/* Note that using GL_REG_0_ATI for the passed on register is safe because
* texture0 is read at stage0, so in the worst case it is read in the
* instruction writing to reg0. Afterwards texture0 is not used any longer.
* If we're reading from current
*/
if(stage == 0) {
ret = GL_PRIMARY_COLOR;
} else {
ret = GL_REG_0_ATI;
}
break;
case WINED3DTA_TEXTURE:
ret = GL_REG_0_ATI + stage;
break;
case WINED3DTA_TFACTOR:
ret = ATI_FFP_CONST_TFACTOR;
break;
case WINED3DTA_SPECULAR:
ret = GL_SECONDARY_INTERPOLATOR_ATI;
break;
case WINED3DTA_TEMP:
FIXME("Unhandled source argument WINED3DTA_TEMP\n");
ret = 0;
break;
case WINED3DTA_CONSTANT:
FIXME("Unhandled source argument WINED3DTA_TEMP\n");
ret = GL_CON_0_ATI;
break;
default:
FIXME("Unknown source argument %d\n", arg);
ret = GL_ZERO;
}
if(arg & WINED3DTA_COMPLEMENT) {
if(mod) *mod |= GL_COMP_BIT_ATI;
}
if(arg & WINED3DTA_ALPHAREPLICATE) {
FIXME("Unhandled read modifier WINED3DTA_ALPHAREPLICATE\n");
}
return ret;
}
static GLuint gen_ati_shader(struct texture_stage_op op[MAX_TEXTURES], WineD3D_GL_Info *gl_info) {
GLuint ret = GL_EXTCALL(glGenFragmentShadersATI(1));
unsigned int stage;
GLuint arg0, arg1, arg2, extrarg;
GLuint dstmod, argmod0, argmod1, argmod2, argmodextra;
GLuint swizzle;
if(!ret) {
ERR("Failed to generate a GL_ATI_fragment_shader shader id\n");
return 0;
}
GL_EXTCALL(glBindFragmentShaderATI(ret));
checkGLcall("GL_EXTCALL(glBindFragmentShaderATI(ret))");
TRACE("glBeginFragmentShaderATI()\n");
GL_EXTCALL(glBeginFragmentShaderATI());
checkGLcall("GL_EXTCALL(glBeginFragmentShaderATI())");
for(stage = 0; stage < GL_LIMITS(textures); stage++) {
if(op[stage].cop == WINED3DTOP_DISABLE) {
break;
}
if(op[stage].projected == proj_none) {
swizzle = GL_SWIZZLE_STR_ATI;
} else if(op[stage].projected == proj_count3) {
/* TODO: D3DTTFF_COUNT3 | D3DTTFF_PROJECTED would be GL_SWIZZLE_STR_DR_ATI.
* However, the FFP vertex processing texture transform matrix handler does
* some transformations in the texture matrix which makes the 3rd coordinate
* arrive in Q, not R in that case. This is needed for opengl fixed function
* fragment processing which always divides by Q. In this backend we can
* handle that properly and be compatible with vertex shader output and avoid
* side effects of the texture matrix games
*/
swizzle = GL_SWIZZLE_STQ_DQ_ATI;
} else {
swizzle = GL_SWIZZLE_STQ_DQ_ATI;
}
if((op[stage].carg0 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE ||
(op[stage].carg1 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE ||
(op[stage].carg2 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE ||
(op[stage].aarg0 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE ||
(op[stage].aarg1 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE ||
(op[stage].aarg2 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE ||
op[stage].cop == WINED3DTOP_BLENDTEXTUREALPHA) {
/* TODO 1: Handle bump mapping. In this case we have to generate a first pass,
* and use GL_REG_x_ATI as source instead of GL_TEXTURE_x.
*/
TRACE("glSampleMapATI(GL_REG_%d_ATI, GL_TEXTURE_%d_ARB, %s)\n",
stage, stage, debug_swizzle(swizzle));
GL_EXTCALL(glSampleMapATI(GL_REG_0_ATI + stage,
GL_TEXTURE0_ARB + stage,
swizzle));
}
}
for(stage = 0; stage < MAX_TEXTURES; stage++) {
if(op[stage].cop == WINED3DTOP_DISABLE) {
if(stage == 0) {
/* Handle complete texture disabling gracefully */
TRACE("glColorFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE, GL_PRIMARY_COLOR, GL_NONE, GL_NONE)\n");
GL_EXTCALL(glColorFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE,
GL_PRIMARY_COLOR, GL_NONE, GL_NONE));
TRACE("glAlphaFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, GL_PRIMARY_COLOR, GL_NONE, GL_NONE)\n");
GL_EXTCALL(glAlphaFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE,
GL_PRIMARY_COLOR, GL_NONE, GL_NONE));
}
break;
}
arg0 = register_for_arg(op[stage].carg0, gl_info, stage, &argmod0);
arg1 = register_for_arg(op[stage].carg1, gl_info, stage, &argmod1);
arg2 = register_for_arg(op[stage].carg2, gl_info, stage, &argmod2);
dstmod = GL_NONE;
argmodextra = GL_NONE;
extrarg = GL_NONE;
switch(op[stage].cop) {
case WINED3DTOP_SELECTARG2:
arg1 = arg2;
argmod1 = argmod2;
case WINED3DTOP_SELECTARG1:
TRACE("glColorFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE, %s, GL_NONE, %s)\n",
debug_register(arg1), debug_argmod(argmod1));
GL_EXTCALL(glColorFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE,
arg1, GL_NONE, argmod1));
break;
case WINED3DTOP_MODULATE4X:
if(dstmod == GL_NONE) dstmod = GL_4X_BIT_ATI;
case WINED3DTOP_MODULATE2X:
if(dstmod == GL_NONE) dstmod = GL_2X_BIT_ATI;
case WINED3DTOP_MODULATE:
TRACE("glColorFragmentOp2ATI(GL_MUL_ATI, GL_REG_0_ATI, GL_NONE, %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
debug_dstmod(dstmod), debug_register(arg1), debug_argmod(argmod1), debug_register(arg2), debug_argmod(argmod2));
GL_EXTCALL(glColorFragmentOp2ATI(GL_MUL_ATI, GL_REG_0_ATI, GL_NONE, dstmod,
arg1, GL_NONE, argmod1,
arg2, GL_NONE, argmod2));
break;
case WINED3DTOP_ADDSIGNED2X:
dstmod = GL_2X_BIT_ATI;
case WINED3DTOP_ADDSIGNED:
argmodextra = GL_BIAS_BIT_ATI;
case WINED3DTOP_ADD:
TRACE("glColorFragmentOp2ATI(GL_ADD_ATI, GL_REG_0_ATI, GL_NONE, %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
debug_dstmod(dstmod), debug_register(arg1), debug_argmod(argmod1), debug_register(arg2), debug_argmod(argmodextra | argmod2));
GL_EXTCALL(glColorFragmentOp2ATI(GL_ADD_ATI, GL_REG_0_ATI, GL_NONE, dstmod,
arg1, GL_NONE, argmod1,
arg2, GL_NONE, argmodextra | argmod2));
break;
case WINED3DTOP_SUBTRACT:
TRACE("glColorFragmentOp2ATI(GL_SUB_ATI, GL_REG_0_ATI, GL_NONE, %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
debug_dstmod(dstmod), debug_register(arg1), debug_argmod(argmod1), debug_register(arg2), debug_argmod(argmod2));
GL_EXTCALL(glColorFragmentOp2ATI(GL_SUB_ATI, GL_REG_0_ATI, GL_NONE, dstmod,
arg1, GL_NONE, argmod1,
arg2, GL_NONE, argmod2));
break;
case WINED3DTOP_ADDSMOOTH:
argmodextra = argmod1 & GL_COMP_BIT_ATI ? argmod1 & ~GL_COMP_BIT_ATI : argmod1 | GL_COMP_BIT_ATI;
TRACE("glColorFragmentOp3ATI(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE, %s, GL_NONE, %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
debug_register(arg2), debug_argmod(argmod2), debug_register(arg1), debug_argmod(argmodextra), debug_register(arg1), debug_argmod(argmod1));
/* Dst = arg1 + * arg2(1 -arg 1)
* = arg2 * (1 - arg1) + arg1
*/
GL_EXTCALL(glColorFragmentOp3ATI(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE,
arg2, GL_NONE, argmod2,
arg1, GL_NONE, argmodextra,
arg1, GL_NONE, argmod1));
break;
case WINED3DTOP_BLENDCURRENTALPHA:
if(extrarg == GL_NONE) extrarg = register_for_arg(WINED3DTA_CURRENT, gl_info, stage, NULL);
case WINED3DTOP_BLENDFACTORALPHA:
if(extrarg == GL_NONE) extrarg = register_for_arg(WINED3DTA_TFACTOR, gl_info, stage, NULL);
case WINED3DTOP_BLENDTEXTUREALPHA:
if(extrarg == GL_NONE) extrarg = register_for_arg(WINED3DTA_TEXTURE, gl_info, stage, NULL);
case WINED3DTOP_BLENDDIFFUSEALPHA:
if(extrarg == GL_NONE) extrarg = register_for_arg(WINED3DTA_DIFFUSE, gl_info, stage, NULL);
TRACE("glColorFragmentOp3ATI(GL_LERP_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE, %s, GL_ALPHA, GL_NONE, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
debug_register(extrarg), debug_register(arg1), debug_argmod(argmod1), debug_register(arg2), debug_argmod(argmod2));
GL_EXTCALL(glColorFragmentOp3ATI(GL_LERP_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE,
extrarg, GL_ALPHA, GL_NONE,
arg1, GL_NONE, argmod1,
arg2, GL_NONE, argmod2));
break;
case WINED3DTOP_BLENDTEXTUREALPHAPM:
arg0 = register_for_arg(WINED3DTA_TEXTURE, gl_info, stage, NULL);
TRACE("glColorFragmentOp3ATI(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE, %s, GL_NONE, %s, %s, GL_ALPHA, GL_COMP_BIT_ATI, %s, GL_NONE, %s)\n",
debug_register(arg2), debug_argmod(argmod2), debug_register(arg0), debug_register(arg1), debug_argmod(argmod1));
GL_EXTCALL(glColorFragmentOp3ATI(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE,
arg2, GL_NONE, argmod2,
arg0, GL_ALPHA, GL_COMP_BIT_ATI,
arg1, GL_NONE, argmod1));
break;
/* D3DTOP_PREMODULATE ???? */
case WINED3DTOP_MODULATEINVALPHA_ADDCOLOR:
argmodextra = argmod1 & GL_COMP_BIT_ATI ? argmod1 & ~GL_COMP_BIT_ATI : argmod1 | GL_COMP_BIT_ATI;
case WINED3DTOP_MODULATEALPHA_ADDCOLOR:
if(!argmodextra) argmodextra = argmod1;
TRACE("glColorFragmentOp3ATI(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE, %s, GL_NONE, %s, %s, GL_ALPHA, %s, %s, GL_NONE, %s)\n",
debug_register(arg2), debug_argmod(argmod2), debug_register(arg1), debug_argmod(argmodextra), debug_register(arg1), debug_argmod(arg1));
GL_EXTCALL(glColorFragmentOp3ATI(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE,
arg2, GL_NONE, argmod2,
arg1, GL_ALPHA, argmodextra,
arg1, GL_NONE, argmod1));
break;
case WINED3DTOP_MODULATEINVCOLOR_ADDALPHA:
argmodextra = argmod1 & GL_COMP_BIT_ATI ? argmod1 & ~GL_COMP_BIT_ATI : argmod1 | GL_COMP_BIT_ATI;
case WINED3DTOP_MODULATECOLOR_ADDALPHA:
if(!argmodextra) argmodextra = argmod1;
TRACE("glColorFragmentOp3ATI(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE, %s, GL_NONE, %s, %s, GL_NONE, %s, %s, GL_ALPHA, %s)\n",
debug_register(arg2), debug_argmod(argmod2), debug_register(arg1), debug_argmod(argmodextra), debug_register(arg1), debug_argmod(argmod1));
GL_EXTCALL(glColorFragmentOp3ATI(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE,
arg2, GL_NONE, argmod2,
arg1, GL_NONE, argmodextra,
arg1, GL_ALPHA, argmod1));
break;
case WINED3DTOP_DOTPRODUCT3:
TRACE("glColorFragmentOp2ATI(GL_DOT3_ATI, GL_REG_0_ATI, GL_NONE, GL_4X_BIT_ATI, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
debug_register(arg1), debug_argmod(argmod1 | GL_BIAS_BIT_ATI), debug_register(arg2), debug_argmod(argmod2 | GL_BIAS_BIT_ATI));
GL_EXTCALL(glColorFragmentOp2ATI(GL_DOT3_ATI, GL_REG_0_ATI, GL_NONE, GL_4X_BIT_ATI,
arg1, GL_NONE, argmod1 | GL_BIAS_BIT_ATI,
arg2, GL_NONE, argmod2 | GL_BIAS_BIT_ATI));
break;
case WINED3DTOP_MULTIPLYADD:
TRACE("glColorFragmentOp3ATI(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE, %s, GL_NONE, %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
debug_register(arg0), debug_argmod(argmod0), debug_register(arg2), debug_argmod(argmod2), debug_register(arg1), debug_argmod(argmod1));
GL_EXTCALL(glColorFragmentOp3ATI(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE,
arg0, GL_NONE, argmod0,
arg2, GL_NONE, argmod2,
arg1, GL_NONE, argmod1));
break;
case WINED3DTOP_LERP:
TRACE("glColorFragmentOp3ATI(GL_LERP_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE, %s, GL_NONE, %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
debug_register(arg1), debug_argmod(argmod1), debug_register(arg2), debug_argmod(argmod2), debug_register(arg0), debug_argmod(argmod0));
GL_EXTCALL(glColorFragmentOp3ATI(GL_LERP_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE,
arg1, GL_NONE, argmod1,
arg2, GL_NONE, argmod2,
arg0, GL_NONE, argmod0));
break;
default: FIXME("Unhandled color operation %d on stage %d\n", op[stage].cop, stage);
}
arg0 = register_for_arg(op[stage].aarg0, gl_info, stage, &argmod0);
arg1 = register_for_arg(op[stage].aarg1, gl_info, stage, &argmod1);
arg2 = register_for_arg(op[stage].aarg2, gl_info, stage, &argmod2);
dstmod = GL_NONE;
argmodextra = GL_NONE;
extrarg = GL_NONE;
switch(op[stage].aop) {
case WINED3DTOP_DISABLE:
/* Get the primary color to the output if on stage 0, otherwise leave register 0 untouched */
if(stage == 0) {
TRACE("glAlphaFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, GL_PRIMARY_COLOR, GL_NONE, GL_NONE)\n");
GL_EXTCALL(glAlphaFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE,
GL_PRIMARY_COLOR, GL_NONE, GL_NONE));
}
break;
case WINED3DTOP_SELECTARG2:
arg1 = arg2;
argmod1 = argmod2;
case WINED3DTOP_SELECTARG1:
TRACE("glAlphaFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, %s, GL_NONE, %s)\n",
debug_register(arg1), debug_argmod(argmod1));
GL_EXTCALL(glAlphaFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE,
arg1, GL_NONE, argmod1));
break;
case WINED3DTOP_MODULATE4X:
if(dstmod == GL_NONE) dstmod = GL_4X_BIT_ATI;
case WINED3DTOP_MODULATE2X:
if(dstmod == GL_NONE) dstmod = GL_2X_BIT_ATI;
case WINED3DTOP_MODULATE:
TRACE("glAlphaFragmentOp2ATI(GL_MUL_ATI, GL_REG_0_ATI, %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
debug_dstmod(dstmod), debug_register(arg1), debug_argmod(argmod1), debug_register(arg2), debug_argmod(argmod2));
GL_EXTCALL(glAlphaFragmentOp2ATI(GL_MUL_ATI, GL_REG_0_ATI, dstmod,
arg1, GL_NONE, argmod1,
arg2, GL_NONE, argmod2));
break;
case WINED3DTOP_ADDSIGNED2X:
dstmod = GL_2X_BIT_ATI;
case WINED3DTOP_ADDSIGNED:
argmodextra = GL_BIAS_BIT_ATI;
case WINED3DTOP_ADD:
TRACE("glAlphaFragmentOp2ATI(GL_ADD_ATI, GL_REG_0_ATI, %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
debug_dstmod(dstmod), debug_register(arg1), debug_argmod(argmod1), debug_register(arg2), debug_argmod(argmodextra | argmod2));
GL_EXTCALL(glAlphaFragmentOp2ATI(GL_ADD_ATI, GL_REG_0_ATI, dstmod,
arg1, GL_NONE, argmod1,
arg2, GL_NONE, argmodextra | argmod2));
break;
case WINED3DTOP_SUBTRACT:
TRACE("glAlphaFragmentOp2ATI(GL_SUB_ATI, GL_REG_0_ATI, GL_NONE, %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
debug_dstmod(dstmod), debug_register(arg1), debug_argmod(argmod1), debug_register(arg2), debug_argmod(argmod2));
GL_EXTCALL(glAlphaFragmentOp2ATI(GL_SUB_ATI, GL_REG_0_ATI, dstmod,
arg1, GL_NONE, argmod1,
arg2, GL_NONE, argmod2));
break;
case WINED3DTOP_ADDSMOOTH:
argmodextra = argmod1 & GL_COMP_BIT_ATI ? argmod1 & ~GL_COMP_BIT_ATI : argmod1 | GL_COMP_BIT_ATI;
TRACE("glAlphaFragmentOp3ATI(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE, %s, GL_NONE, %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
debug_register(arg2), debug_argmod(argmod2), debug_register(arg1), debug_argmod(argmodextra), debug_register(arg1), debug_argmod(argmod1));
/* Dst = arg1 + * arg2(1 -arg 1)
* = arg2 * (1 - arg1) + arg1
*/
GL_EXTCALL(glAlphaFragmentOp3ATI(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE,
arg2, GL_NONE, argmod2,
arg1, GL_NONE, argmodextra,
arg1, GL_NONE, argmod1));
break;
case WINED3DTOP_BLENDCURRENTALPHA:
if(extrarg == GL_NONE) extrarg = register_for_arg(WINED3DTA_CURRENT, gl_info, stage, NULL);
case WINED3DTOP_BLENDFACTORALPHA:
if(extrarg == GL_NONE) extrarg = register_for_arg(WINED3DTA_TFACTOR, gl_info, stage, NULL);
case WINED3DTOP_BLENDTEXTUREALPHA:
if(extrarg == GL_NONE) extrarg = register_for_arg(WINED3DTA_TEXTURE, gl_info, stage, NULL);
case WINED3DTOP_BLENDDIFFUSEALPHA:
if(extrarg == GL_NONE) extrarg = register_for_arg(WINED3DTA_DIFFUSE, gl_info, stage, NULL);
TRACE("glAlphaFragmentOp3ATI(GL_LERP_ATI, GL_REG_0_ATI, GL_NONE, %s, GL_ALPHA, GL_NONE, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
debug_register(extrarg), debug_register(arg1), debug_argmod(argmod1), debug_register(arg2), debug_argmod(argmod2));
GL_EXTCALL(glAlphaFragmentOp3ATI(GL_LERP_ATI, GL_REG_0_ATI, GL_NONE,
extrarg, GL_ALPHA, GL_NONE,
arg1, GL_NONE, argmod1,
arg2, GL_NONE, argmod2));
break;
case WINED3DTOP_BLENDTEXTUREALPHAPM:
arg0 = register_for_arg(WINED3DTA_TEXTURE, gl_info, stage, NULL);
TRACE("glAlphaFragmentOp3ATI(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE, %s, GL_NONE, %s, %s, GL_ALPHA, GL_COMP_BIT_ATI, %s, GL_NONE, %s)\n",
debug_register(arg2), debug_argmod(argmod2), debug_register(arg0), debug_register(arg1), debug_argmod(argmod1));
GL_EXTCALL(glAlphaFragmentOp3ATI(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE,
arg2, GL_NONE, argmod2,
arg0, GL_ALPHA, GL_COMP_BIT_ATI,
arg1, GL_NONE, argmod1));
break;
/* D3DTOP_PREMODULATE ???? */
case WINED3DTOP_DOTPRODUCT3:
TRACE("glAlphaFragmentOp2ATI(GL_DOT3_ATI, GL_REG_0_ATI, GL_NONE, GL_4X_BIT_ATI, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
debug_register(arg1), debug_argmod(argmod1 | GL_BIAS_BIT_ATI), debug_register(arg2), debug_argmod(argmod2 | GL_BIAS_BIT_ATI));
GL_EXTCALL(glAlphaFragmentOp2ATI(GL_DOT3_ATI, GL_REG_0_ATI, GL_4X_BIT_ATI,
arg1, GL_NONE, argmod1 | GL_BIAS_BIT_ATI,
arg2, GL_NONE, argmod2 | GL_BIAS_BIT_ATI));
break;
case WINED3DTOP_MULTIPLYADD:
TRACE("glAlphaFragmentOp3ATI(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE, %s, GL_NONE, %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
debug_register(arg0), debug_argmod(argmod0), debug_register(arg2), debug_argmod(argmod2), debug_register(arg1), debug_argmod(argmod1));
GL_EXTCALL(glAlphaFragmentOp3ATI(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE,
arg0, GL_NONE, argmod0,
arg2, GL_NONE, argmod2,
arg1, GL_NONE, argmod1));
break;
case WINED3DTOP_LERP:
TRACE("glAlphaFragmentOp3ATI(GL_LERP_ATI, GL_REG_0_ATI, GL_NONE, %s, GL_NONE, %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
debug_register(arg1), debug_argmod(argmod1), debug_register(arg2), debug_argmod(argmod2), debug_register(arg0), debug_argmod(argmod0));
GL_EXTCALL(glAlphaFragmentOp3ATI(GL_LERP_ATI, GL_REG_0_ATI, GL_NONE,
arg1, GL_NONE, argmod1,
arg2, GL_NONE, argmod2,
arg0, GL_NONE, argmod0));
break;
case WINED3DTOP_MODULATEINVALPHA_ADDCOLOR:
case WINED3DTOP_MODULATEALPHA_ADDCOLOR:
case WINED3DTOP_MODULATECOLOR_ADDALPHA:
case WINED3DTOP_MODULATEINVCOLOR_ADDALPHA:
case WINED3DTOP_BUMPENVMAP:
case WINED3DTOP_BUMPENVMAPLUMINANCE:
ERR("Application uses an invalid alpha operation\n");
break;
default: FIXME("Unhandled alpha operation %d on stage %d\n", op[stage].aop, stage);
}
}
TRACE("glEndFragmentShaderATI()\n");
GL_EXTCALL(glEndFragmentShaderATI());
checkGLcall("GL_EXTCALL(glEndFragmentShaderATI())");
return ret;
}
#undef GLINFO_LOCATION
#define GLINFO_LOCATION stateblock->wineD3DDevice->adapter->gl_info
static void set_tex_op_atifs(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) {
IWineD3DDeviceImpl *This = stateblock->wineD3DDevice;
struct atifs_ffp_desc *desc;
struct texture_stage_op op[MAX_TEXTURES];
struct atifs_private_data *priv = (struct atifs_private_data *) This->shader_priv;
gen_ffp_op(stateblock, op);
desc = (struct atifs_ffp_desc *) find_ffp_shader(&priv->fragment_shaders, op);
if(!desc) {
desc = HeapAlloc(GetProcessHeap(), 0, sizeof(*desc));
if(!desc) {
ERR("Out of memory\n");
return;
}
memcpy(desc->parent.op, op, sizeof(op));
desc->shader = gen_ati_shader(op, &GLINFO_LOCATION);
add_ffp_shader(&priv->fragment_shaders, &desc->parent);
TRACE("Allocated fixed function replacement shader descriptor %p\n", desc);
}
GL_EXTCALL(glBindFragmentShaderATI(desc->shader));
}
static void state_texfactor_atifs(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) {
float col[4];
D3DCOLORTOGLFLOAT4(stateblock->renderState[WINED3DRS_TEXTUREFACTOR], col);
GL_EXTCALL(glSetFragmentShaderConstantATI(ATI_FFP_CONST_TFACTOR, col));
checkGLcall("glSetFragmentShaderConstantATI(ATI_FFP_CONST_TFACTOR, col)");
}
#undef GLINFO_LOCATION
/* our state table. Borrows lots of stuff from the base implementation */
struct StateEntry ATIFSStateTable[STATE_HIGHEST + 1];
static void init_state_table() {
unsigned int i;
const DWORD rep = STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP);
memcpy(ATIFSStateTable, FFPStateTable, sizeof(ATIFSStateTable));
for(i = 0; i < MAX_TEXTURES; i++) {
ATIFSStateTable[STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP)].apply = set_tex_op_atifs;
ATIFSStateTable[STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP)].representative = rep;
ATIFSStateTable[STATE_TEXTURESTAGE(i, WINED3DTSS_COLORARG1)].apply = set_tex_op_atifs;
ATIFSStateTable[STATE_TEXTURESTAGE(i, WINED3DTSS_COLORARG1)].representative = rep;
ATIFSStateTable[STATE_TEXTURESTAGE(i, WINED3DTSS_COLORARG2)].apply = set_tex_op_atifs;
ATIFSStateTable[STATE_TEXTURESTAGE(i, WINED3DTSS_COLORARG2)].representative = rep;
ATIFSStateTable[STATE_TEXTURESTAGE(i, WINED3DTSS_COLORARG0)].apply = set_tex_op_atifs;
ATIFSStateTable[STATE_TEXTURESTAGE(i, WINED3DTSS_COLORARG0)].representative = rep;
ATIFSStateTable[STATE_TEXTURESTAGE(i, WINED3DTSS_ALPHAOP)].apply = set_tex_op_atifs;
ATIFSStateTable[STATE_TEXTURESTAGE(i, WINED3DTSS_ALPHAOP)].representative = rep;
ATIFSStateTable[STATE_TEXTURESTAGE(i, WINED3DTSS_ALPHAARG1)].apply = set_tex_op_atifs;
ATIFSStateTable[STATE_TEXTURESTAGE(i, WINED3DTSS_ALPHAARG1)].representative = rep;
ATIFSStateTable[STATE_TEXTURESTAGE(i, WINED3DTSS_ALPHAARG2)].apply = set_tex_op_atifs;
ATIFSStateTable[STATE_TEXTURESTAGE(i, WINED3DTSS_ALPHAARG2)].representative = rep;
ATIFSStateTable[STATE_TEXTURESTAGE(i, WINED3DTSS_ALPHAARG0)].apply = set_tex_op_atifs;
ATIFSStateTable[STATE_TEXTURESTAGE(i, WINED3DTSS_ALPHAARG0)].representative = rep;
}
ATIFSStateTable[STATE_RENDER(WINED3DRS_TEXTUREFACTOR)].apply = state_texfactor_atifs;
ATIFSStateTable[STATE_RENDER(WINED3DRS_TEXTUREFACTOR)].representative = STATE_RENDER(WINED3DRS_TEXTUREFACTOR);
}
/* GL_ATI_fragment_shader backend.It borrows a lot from a the
* ARB shader backend, currently the whole vertex processing
* code. This code would also forward pixel shaders, but if
* GL_ARB_fragment_program is supported, the atifs shader backend
* is not used.
*/
static void shader_atifs_select(IWineD3DDevice *iface, BOOL usePS, BOOL useVS) {
arb_program_shader_backend.shader_select(iface, usePS, useVS);
}
static void shader_atifs_select_depth_blt(IWineD3DDevice *iface) {
arb_program_shader_backend.shader_select_depth_blt(iface);
}
static void shader_atifs_destroy_depth_blt(IWineD3DDevice *iface) {
arb_program_shader_backend.shader_destroy_depth_blt(iface);
}
static void shader_atifs_load_constants(IWineD3DDevice *iface, char usePS, char useVS) {
arb_program_shader_backend.shader_load_constants(iface, usePS, useVS);
}
static void shader_atifs_cleanup(IWineD3DDevice *iface) {
arb_program_shader_backend.shader_cleanup(iface);
}
static void shader_atifs_color_correction(SHADER_OPCODE_ARG* arg) {
arb_program_shader_backend.shader_color_correction(arg);
}
static void shader_atifs_destroy(IWineD3DBaseShader *iface) {
arb_program_shader_backend.shader_destroy(iface);
}
static HRESULT shader_atifs_alloc(IWineD3DDevice *iface) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
HRESULT hr;
struct atifs_private_data *priv;
hr = arb_program_shader_backend.shader_alloc_private(iface);
if(FAILED(hr)) return hr;
This->shader_priv = HeapReAlloc(GetProcessHeap(), 0, This->shader_priv,
sizeof(struct atifs_private_data));
priv = (struct atifs_private_data *) This->shader_priv;
list_init(&priv->fragment_shaders);
return WINED3D_OK;
}
#define GLINFO_LOCATION This->adapter->gl_info
static void shader_atifs_free(IWineD3DDevice *iface) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
struct atifs_private_data *priv = (struct atifs_private_data *) This->shader_priv;
struct ffp_desc *entry, *entry2;
struct atifs_ffp_desc *entry_ati;
ENTER_GL();
LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &priv->fragment_shaders, struct ffp_desc, entry) {
entry_ati = (struct atifs_ffp_desc *) entry;
GL_EXTCALL(glDeleteFragmentShaderATI(entry_ati->shader));
checkGLcall("glDeleteFragmentShaderATI(entry->shader)");
list_remove(&entry->entry);
HeapFree(GetProcessHeap(), 0, entry);
}
LEAVE_GL();
/* Not actually needed, but revert what we've done before */
This->shader_priv = HeapReAlloc(GetProcessHeap(), 0, This->shader_priv,
sizeof(struct shader_arb_priv));
arb_program_shader_backend.shader_free_private(iface);
}
#undef GLINFO_LOCATION
static BOOL shader_atifs_dirty_const(IWineD3DDevice *iface) {
return arb_program_shader_backend.shader_dirtifyable_constants(iface);
}
static void shader_atifs_load_init(void) {
init_state_table();
arb_program_shader_backend.shader_dll_load_init();
}
static void shader_atifs_get_caps(WINED3DDEVTYPE devtype, WineD3D_GL_Info *gl_info, struct shader_caps *caps) {
arb_program_shader_backend.shader_get_caps(devtype, gl_info, caps);
caps->TextureOpCaps = WINED3DTEXOPCAPS_DISABLE |
WINED3DTEXOPCAPS_SELECTARG1 |
WINED3DTEXOPCAPS_SELECTARG2 |
WINED3DTEXOPCAPS_MODULATE4X |
WINED3DTEXOPCAPS_MODULATE2X |
WINED3DTEXOPCAPS_MODULATE |
WINED3DTEXOPCAPS_ADDSIGNED2X |
WINED3DTEXOPCAPS_ADDSIGNED |
WINED3DTEXOPCAPS_ADD |
WINED3DTEXOPCAPS_SUBTRACT |
WINED3DTEXOPCAPS_ADDSMOOTH |
WINED3DTEXOPCAPS_BLENDCURRENTALPHA |
WINED3DTEXOPCAPS_BLENDFACTORALPHA |
WINED3DTEXOPCAPS_BLENDTEXTUREALPHA |
WINED3DTEXOPCAPS_BLENDDIFFUSEALPHA |
WINED3DTEXOPCAPS_BLENDTEXTUREALPHAPM |
WINED3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR |
WINED3DTEXOPCAPS_MODULATECOLOR_ADDALPHA |
WINED3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA |
WINED3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR |
WINED3DTEXOPCAPS_DOTPRODUCT3 |
WINED3DTEXOPCAPS_MULTIPLYADD |
WINED3DTEXOPCAPS_LERP;
/* TODO: Implement WINED3DTEXOPCAPS_BUMPENVMAP, WINED3DTEXOPCAPS_BUMPENVMAPLUMINANCE
and WINED3DTEXOPCAPS_PREMODULATE */
/* GL_ATI_fragment_shader only supports up to 6 textures, which was the limit on r200 cards
* which this extension is exclusively focused on(later cards have GL_ARB_fragment_program).
* If the current card has more than 8 fixed function textures in OpenGL's regular fixed
* function pipeline then the ATI_fragment_shader backend imposes a stricter limit. This
* shouldn't be too hard since Nvidia cards have a limit of 4 textures with the default ffp
* pipeline, and almost all games are happy with that. We can however support up to 8
* texture stages because we have a 2nd pass limit of 8 instructions, and per stage we use
* only 1 instruction.
*
* The proper fix for this is not to use GL_ATI_fragment_shader on cards newer than the
* r200 series and use an ARB or GLSL shader instead
*/
if(caps->MaxSimultaneousTextures > 6) {
WARN("OpenGL fixed function supports %d simultaneous textures,\n", caps->MaxSimultaneousTextures);
WARN("but GL_ATI_fragment_shader limits this to 6\n");
caps->MaxSimultaneousTextures = 6;
}
}
static void shader_atifs_generate_pshader(IWineD3DPixelShader *iface, SHADER_BUFFER *buffer) {
ERR("Should not get here\n");
}
static void shader_atifs_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer) {
arb_program_shader_backend.shader_generate_vshader(iface, buffer);
}
const shader_backend_t atifs_shader_backend = {
shader_atifs_select,
shader_atifs_select_depth_blt,
shader_atifs_destroy_depth_blt,
shader_atifs_load_constants,
shader_atifs_cleanup,
shader_atifs_color_correction,
shader_atifs_destroy,
shader_atifs_alloc,
shader_atifs_free,
shader_atifs_dirty_const,
shader_atifs_generate_pshader,
shader_atifs_generate_vshader,
shader_atifs_get_caps,
shader_atifs_load_init,
ATIFSStateTable
};

View file

@ -407,7 +407,11 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar
glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB + s - 1);
checkGLcall("glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, ...\n");
}
} else if(GL_SUPPORT(ATI_FRAGMENT_SHADER)) {
glEnable(GL_FRAGMENT_SHADER_ATI);
checkGLcall("glEnable(GL_FRAGMENT_SHADER_ATI)");
}
if(GL_SUPPORT(ARB_POINT_SPRITE)) {
for(s = 0; s < GL_LIMITS(textures); s++) {
GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + s));
@ -667,6 +671,9 @@ static inline void SetupForBlit(IWineD3DDeviceImpl *This, WineD3DContext *contex
if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
glDisable(GL_TEXTURE_SHADER_NV);
checkGLcall("glDisable(GL_TEXTURE_SHADER_NV)");
} else if(GL_SUPPORT(ATI_FRAGMENT_SHADER)) {
glDisable(GL_FRAGMENT_SHADER_ATI);
checkGLcall("glDisable(GL_FRAGMENT_SHADER_ATI)");
}
}
@ -945,9 +952,14 @@ void ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, ContextU
break;
case CTXUSAGE_CLEAR:
if(context->last_was_blit && GL_SUPPORT(NV_TEXTURE_SHADER2)) {
glEnable(GL_TEXTURE_SHADER_NV);
checkGLcall("glEnable(GL_TEXTURE_SHADER_NV)");
if(context->last_was_blit) {
if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
glEnable(GL_TEXTURE_SHADER_NV);
checkGLcall("glEnable(GL_TEXTURE_SHADER_NV)");
} else if(GL_SUPPORT(ATI_FRAGMENT_SHADER)) {
glEnable(GL_FRAGMENT_SHADER_ATI);
checkGLcall("glEnable(GL_FRAGMENT_SHADER_ATI)");
}
}
glEnable(GL_SCISSOR_TEST);
@ -959,9 +971,14 @@ void ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, ContextU
case CTXUSAGE_DRAWPRIM:
/* This needs all dirty states applied */
if(context->last_was_blit && GL_SUPPORT(NV_TEXTURE_SHADER2)) {
glEnable(GL_TEXTURE_SHADER_NV);
checkGLcall("glEnable(GL_TEXTURE_SHADER_NV)");
if(context->last_was_blit) {
if(GL_SUPPORT(NV_TEXTURE_SHADER2)) {
glEnable(GL_TEXTURE_SHADER_NV);
checkGLcall("glEnable(GL_TEXTURE_SHADER_NV)");
} else if(GL_SUPPORT(ATI_FRAGMENT_SHADER)) {
glEnable(GL_FRAGMENT_SHADER_ATI);
checkGLcall("glEnable(GL_FRAGMENT_SHADER_ATI)");
}
}
IWineD3DDeviceImpl_FindTexUnitMap(This);

View file

@ -377,6 +377,8 @@ void select_shader_mode(
*ps_selected = SHADER_GLSL;
} else if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) {
*ps_selected = SHADER_ARB;
} else if (gl_info->supported[ATI_FRAGMENT_SHADER]) {
*ps_selected = SHADER_ATI;
} else {
*ps_selected = SHADER_NONE;
}
@ -821,6 +823,13 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) {
* Won't occur in any real world situation though
*/
gl_info->supported[ATI_ENVMAP_BUMPMAP] = FALSE;
if(gl_info->supported[NV_REGISTER_COMBINERS]) {
/* Also disable ATI_FRAGMENT_SHADER if register combienrs and texture_shader2
* are supported. The nv extensions provide the same functionality as the
* ATI one, and a bit more(signed pixelformats)
*/
gl_info->supported[ATI_FRAGMENT_SHADER] = FALSE;
}
}
if (gl_info->supported[ARB_DRAW_BUFFERS]) {
glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &gl_max);
@ -971,6 +980,19 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) {
*/
gl_info->supported[ARB_TEXTURE_RECTANGLE] = FALSE;
}
if(gl_info->supported[ATI_FRAGMENT_SHADER]) {
/* Disable NV_register_combiners and fragment shader if this is supported.
* generally the NV extensions are prefered over the ATI one, and this
* extension is disabled if register_combiners and texture_shader2 are both
* supported. So we reach this place only if we have incomplete NV dxlevel 8
* fragment processing support
*/
gl_info->supported[NV_REGISTER_COMBINERS] = FALSE;
gl_info->supported[NV_REGISTER_COMBINERS2] = FALSE;
gl_info->supported[NV_TEXTURE_SHADER] = FALSE;
gl_info->supported[NV_TEXTURE_SHADER2] = FALSE;
gl_info->supported[NV_TEXTURE_SHADER3] = FALSE;
}
}
checkGLcall("extension detection\n");
@ -2647,6 +2669,9 @@ static const shader_backend_t *select_shader_backend(UINT Adapter, WINED3DDEVTYP
select_shader_mode(&GLINFO_LOCATION, DeviceType, &ps_selected_mode, &vs_selected_mode);
if (vs_selected_mode == SHADER_GLSL || ps_selected_mode == SHADER_GLSL) {
ret = &glsl_shader_backend;
} else if (vs_selected_mode == SHADER_ARB && ps_selected_mode != SHADER_NONE &&
!GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) {
ret = &atifs_shader_backend;
} else if (vs_selected_mode == SHADER_ARB || ps_selected_mode == SHADER_ARB) {
ret = &arb_program_shader_backend;
} else {

View file

@ -435,7 +435,8 @@ static void state_blend(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D
/* colorkey fixup for stage 0 alphaop depends on WINED3DRS_ALPHABLENDENABLE state,
so it may need updating */
if (stateblock->renderState[WINED3DRS_COLORKEYENABLE]) {
FFPStateTable[STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP)].apply(STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP), stateblock, context);
const struct StateEntry *StateTable = stateblock->wineD3DDevice->shader_backend->StateTable;
StateTable[STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP)].apply(STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP), stateblock, context);
}
}
@ -484,7 +485,8 @@ static void state_alpha(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D
}
if(enable_ckey || context->last_was_ckey) {
FFPStateTable[STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP)].apply(STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP), stateblock, context);
const struct StateEntry *StateTable = stateblock->wineD3DDevice->shader_backend->StateTable;
StateTable[STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP)].apply(STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP), stateblock, context);
}
context->last_was_ckey = enable_ckey;

View file

@ -3156,3 +3156,149 @@ void *hash_table_get(hash_table_t *table, void *key)
return entry ? entry->value : NULL;
}
#define GLINFO_LOCATION stateblock->wineD3DDevice->adapter->gl_info
void gen_ffp_op(IWineD3DStateBlockImpl *stateblock, struct texture_stage_op op[MAX_TEXTURES]) {
#define ARG1 0x01
#define ARG2 0x02
#define ARG0 0x04
static const unsigned char args[WINED3DTOP_LERP + 1] = {
/* undefined */ 0,
/* D3DTOP_DISABLE */ 0,
/* D3DTOP_SELECTARG1 */ ARG1,
/* D3DTOP_SELECTARG2 */ ARG2,
/* D3DTOP_MODULATE */ ARG1 | ARG2,
/* D3DTOP_MODULATE2X */ ARG1 | ARG2,
/* D3DTOP_MODULATE4X */ ARG1 | ARG2,
/* D3DTOP_ADD */ ARG1 | ARG2,
/* D3DTOP_ADDSIGNED */ ARG1 | ARG2,
/* D3DTOP_ADDSIGNED2X */ ARG1 | ARG2,
/* D3DTOP_SUBTRACT */ ARG1 | ARG2,
/* D3DTOP_ADDSMOOTH */ ARG1 | ARG2,
/* D3DTOP_BLENDDIFFUSEALPHA */ ARG1 | ARG2,
/* D3DTOP_BLENDTEXTUREALPHA */ ARG1 | ARG2,
/* D3DTOP_BLENDFACTORALPHA */ ARG1 | ARG2,
/* D3DTOP_BLENDTEXTUREALPHAPM */ ARG1 | ARG2,
/* D3DTOP_BLENDCURRENTALPHA */ ARG1 | ARG2,
/* D3DTOP_PREMODULATE */ ARG1 | ARG2,
/* D3DTOP_MODULATEALPHA_ADDCOLOR */ ARG1 | ARG2,
/* D3DTOP_MODULATECOLOR_ADDALPHA */ ARG1 | ARG2,
/* D3DTOP_MODULATEINVALPHA_ADDCOLOR */ ARG1 | ARG2,
/* D3DTOP_MODULATEINVCOLOR_ADDALPHA */ ARG1 | ARG2,
/* D3DTOP_BUMPENVMAP */ ARG1 | ARG2,
/* D3DTOP_BUMPENVMAPLUMINANCE */ ARG1 | ARG2,
/* D3DTOP_DOTPRODUCT3 */ ARG1 | ARG2,
/* D3DTOP_MULTIPLYADD */ ARG1 | ARG2 | ARG0,
/* D3DTOP_LERP */ ARG1 | ARG2 | ARG0
};
unsigned int i;
DWORD ttff;
for(i = 0; i < GL_LIMITS(texture_stages); i++) {
if(stateblock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
op[i].cop = WINED3DTOP_DISABLE;
op[i].aop = WINED3DTOP_DISABLE;
op[i].carg0 = op[i].carg1 = op[i].carg2 = 0xffffffff;
op[i].aarg0 = op[i].aarg1 = op[i].aarg2 = 0xffffffff;
op[i].color_correction = WINED3DFMT_UNKNOWN;
i++;
break;
}
op[i].color_correction = WINED3DFMT_UNKNOWN;
op[i].cop = stateblock->textureState[i][WINED3DTSS_COLOROP];
op[i].aop = stateblock->textureState[i][WINED3DTSS_ALPHAOP];
op[i].carg1 = (args[op[i].cop] & ARG1) ? stateblock->textureState[i][WINED3DTSS_COLORARG1] : 0xffffffff;
op[i].carg2 = (args[op[i].cop] & ARG2) ? stateblock->textureState[i][WINED3DTSS_COLORARG2] : 0xffffffff;
op[i].carg0 = (args[op[i].cop] & ARG0) ? stateblock->textureState[i][WINED3DTSS_COLORARG0] : 0xffffffff;
if(is_invalid_op(stateblock->wineD3DDevice, i, op[i].cop, op[i].carg1, op[i].carg2, op[i].carg0)) {
op[i].carg0 = 0xffffffff;
op[i].carg2 = 0xffffffff;
op[i].carg1 = WINED3DTA_CURRENT;
op[i].cop = WINED3DTOP_SELECTARG1;
}
op[i].aarg1 = (args[op[i].aop] & ARG1) ? stateblock->textureState[i][WINED3DTSS_ALPHAARG1] : 0xffffffff;
op[i].aarg2 = (args[op[i].aop] & ARG2) ? stateblock->textureState[i][WINED3DTSS_ALPHAARG2] : 0xffffffff;
op[i].aarg0 = (args[op[i].aop] & ARG0) ? stateblock->textureState[i][WINED3DTSS_ALPHAARG0] : 0xffffffff;
if(is_invalid_op(stateblock->wineD3DDevice, i, op[i].aop, op[i].aarg1, op[i].aarg2, op[i].aarg0)) {
op[i].aarg0 = 0xffffffff;
op[i].aarg2 = 0xffffffff;
op[i].aarg1 = WINED3DTA_CURRENT;
op[i].aop = WINED3DTOP_SELECTARG1;
} else if(i == 0 && stateblock->textures[0] &&
stateblock->renderState[WINED3DRS_COLORKEYENABLE] &&
(stateblock->textureDimensions[0] == GL_TEXTURE_2D ||
stateblock->textureDimensions[0] == GL_TEXTURE_RECTANGLE_ARB)) {
IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *) stateblock->textures[0])->surfaces[0];
if(surf->CKeyFlags & WINEDDSD_CKSRCBLT &&
getFormatDescEntry(surf->resource.format, NULL, NULL)->alphaMask == 0x00000000) {
if(op[0].aop == WINED3DTOP_DISABLE) {
op[0].aarg1 = WINED3DTA_TEXTURE;
op[0].aop = WINED3DTOP_SELECTARG1;
}
else if(op[0].aop == WINED3DTOP_SELECTARG1 && op[0].aarg1 != WINED3DTA_TEXTURE) {
if (stateblock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
op[0].aarg2 = WINED3DTA_TEXTURE;
op[0].aop = WINED3DTOP_MODULATE;
}
else op[0].aarg1 = WINED3DTA_TEXTURE;
}
else if(op[0].aop == WINED3DTOP_SELECTARG2 && op[0].aarg2 != WINED3DTA_TEXTURE) {
if (stateblock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
op[0].aarg1 = WINED3DTA_TEXTURE;
op[0].aop = WINED3DTOP_MODULATE;
}
else op[0].aarg2 = WINED3DTA_TEXTURE;
}
}
}
if(op[i].carg1 == WINED3DTA_TEXTURE || op[i].carg2 == WINED3DTA_TEXTURE || op[i].carg0 == WINED3DTA_TEXTURE ||
op[i].aarg1 == WINED3DTA_TEXTURE || op[i].aarg2 == WINED3DTA_TEXTURE || op[i].aarg0 == WINED3DTA_TEXTURE) {
ttff = stateblock->textureState[i][WINED3DTSS_TEXTURETRANSFORMFLAGS];
if(ttff == (WINED3DTTFF_PROJECTED | WINED3DTTFF_COUNT3)) {
op[i].projected = proj_count3;
} else if(ttff == (WINED3DTTFF_PROJECTED | WINED3DTTFF_COUNT4)) {
op[i].projected = proj_count4;
} else {
op[i].projected = proj_none;
}
} else {
op[i].projected = proj_none;
}
}
/* Clear unsupported stages */
for(; i < MAX_TEXTURES; i++) {
memset(&op[i], 0xff, sizeof(op[i]));
}
}
#undef GLINFO_LOCATION
struct ffp_desc *find_ffp_shader(struct list *shaders, struct texture_stage_op op[MAX_TEXTURES])
{
struct ffp_desc *entry;
/* TODO: Optimize this. Finding the shader can be optimized by e.g. sorting the list,
* or maybe consider using hashtables
*/
LIST_FOR_EACH_ENTRY(entry, shaders, struct ffp_desc, entry) {
if(memcmp(op, entry->op, sizeof(struct texture_stage_op) * MAX_TEXTURES) == 0) {
TRACE("Found shader entry %p. size %d\n", entry, sizeof(struct texture_stage_op) * MAX_TEXTURES);
return entry;
}
}
TRACE("Shader not found\n");
return NULL;
}
void add_ffp_shader(struct list *shaders, struct ffp_desc *desc) {
list_add_head(shaders, &desc->entry);
}

View file

@ -93,6 +93,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
DWORD len;
WNDCLASSA wc;
atifs_shader_backend.shader_dll_load_init();
glsl_shader_backend.shader_dll_load_init();
arb_program_shader_backend.shader_dll_load_init();
none_shader_backend.shader_dll_load_init();

View file

@ -217,7 +217,8 @@ static inline unsigned short float_32_to_16(const float *in) {
#define SHADER_ARB 1
#define SHADER_GLSL 2
#define SHADER_NONE 3
#define SHADER_ATI 3
#define SHADER_NONE 4
#define RTL_DISABLE -1
#define RTL_AUTO 0
@ -295,6 +296,7 @@ typedef struct {
const struct StateEntry *StateTable;
} shader_backend_t;
extern const shader_backend_t atifs_shader_backend;
extern const shader_backend_t glsl_shader_backend;
extern const shader_backend_t arb_program_shader_backend;
extern const shader_backend_t none_shader_backend;
@ -712,6 +714,35 @@ struct WineD3DRectPatch
HRESULT tesselate_rectpatch(IWineD3DDeviceImpl *This, struct WineD3DRectPatch *patch);
enum projection_types
{
proj_none,
proj_count3,
proj_count4
};
/*****************************************************************************
* Fixed function pipeline replacements
*/
struct texture_stage_op
{
WINED3DTEXTUREOP cop, aop;
DWORD carg1, carg2, carg0;
DWORD aarg1, aarg2, aarg0;
WINED3DFORMAT color_correction;
enum projection_types projected;
};
struct ffp_desc
{
struct texture_stage_op op[MAX_TEXTURES];
struct list entry;
};
void gen_ffp_op(IWineD3DStateBlockImpl *stateblock,struct texture_stage_op op[MAX_TEXTURES]);
struct ffp_desc *find_ffp_shader(struct list *shaders, struct texture_stage_op op[MAX_TEXTURES]);
void add_ffp_shader(struct list *shaders, struct ffp_desc *desc);
/*****************************************************************************
* IWineD3D implementation structure
*/
@ -790,9 +821,6 @@ struct IWineD3DDeviceImpl
struct list shaders; /* a linked list to track shaders (pixel and vertex) */
unsigned int highest_dirty_ps_const, highest_dirty_vs_const;
/* TODO: Move this into the shader model private data */
struct list fragment_shaders; /* A linked list to track fragment pipeline replacement shaders */
/* Render Target Support */
IWineD3DSurface **render_targets;
IWineD3DSurface *auto_depth_stencil_buffer;