Commit 4640be8d authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

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.
parent a4400510
......@@ -9,6 +9,7 @@ EXTRALIBS = -luuid
C_SRCS = \
arb_program_shader.c \
ati_fragment_shader.c \
baseshader.c \
basetexture.c \
clipper.c \
......
......@@ -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);
......
......@@ -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 {
......
......@@ -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;
......
......@@ -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);
}
......@@ -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();
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment