[4/7] wined3d: Disable vertex shaders when transformed vertices are
used
H. Verbeet
hverbeet at gmail.com
Mon Mar 12 17:22:00 CDT 2007
When transformed vertices are used, all vertex processing should be
bypassed, including any vertex shaders that are set. A sane
application wouldn't set a vertex shader in the first place in that
case, so it's relatively uncommon for this condition to occur, but
some do. This should also fix bug 6056.
Changelog:
- Disable vertex shaders when transformed vertices are used
-------------- next part --------------
---
dlls/wined3d/drawprim.c | 23 +++++++++++++----------
dlls/wined3d/glsl_shader.c | 8 ++++----
dlls/wined3d/state.c | 30 +++++++++++++++++-------------
dlls/wined3d/vertexbuffer.c | 2 +-
dlls/wined3d/wined3d_private.h | 14 ++++++++++++++
5 files changed, 49 insertions(+), 28 deletions(-)
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index 14fb3e0..ecaaf0d 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -161,6 +161,17 @@ void primitiveDeclarationConvertToStridedData(
memset(isPreLoaded, 0, sizeof(isPreLoaded));
+ /* Check for transformed vertices, disable vertex shader if present */
+ strided->u.s.position_transformed = FALSE;
+ for (i = 0; i < vertexDeclaration->declarationWNumElements - 1; ++i) {
+ element = vertexDeclaration->pDeclarationWine + i;
+
+ if (element->Usage == WINED3DDECLUSAGE_POSITIONT) {
+ strided->u.s.position_transformed = TRUE;
+ useVertexShaderFunction = FALSE;
+ }
+ }
+
/* Translate the declaration into strided data */
for (i = 0 ; i < vertexDeclaration->declarationWNumElements - 1; ++i) {
GLint streamVBO = 0;
@@ -188,7 +199,7 @@ void primitiveDeclarationConvertToStridedData(
data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[element->Stream], 0, &streamVBO);
if(fixup) {
if( streamVBO != 0) *fixup = TRUE;
- else if(*fixup && This->stateBlock->vertexShader == NULL) {
+ else if(*fixup && !useVertexShaderFunction) {
/* This may be bad with the fixed function pipeline */
FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
}
@@ -218,12 +229,6 @@ void primitiveDeclarationConvertToStridedData(
strided->u.input[idx].dwStride = stride;
strided->u.input[idx].VBO = streamVBO;
strided->u.input[idx].streamNo = element->Stream;
- if (!useVertexShaderFunction) {
- if (element->Usage == WINED3DDECLUSAGE_POSITION)
- strided->u.s.position_transformed = FALSE;
- else if (element->Usage == WINED3DDECLUSAGE_POSITIONT)
- strided->u.s.position_transformed = TRUE;
- }
}
}
/* Now call PreLoad on all the vertex buffers. In the very rare case
@@ -796,9 +801,7 @@ static void depth_blt(IWineD3DDevice *iface, GLuint texture) {
* and this seems easier and more efficient than providing the shader backend with a private
* storage to read and restore the old shader settings
*/
- This->shader_backend->shader_select(iface,
- This->stateBlock->pixelShader && ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function,
- This->stateBlock->vertexShader && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function);
+ This->shader_backend->shader_select(iface, use_ps(This), use_vs(This));
}
static void depth_copy(IWineD3DDevice *iface) {
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index af038b5..a9d01e0 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -2049,7 +2049,7 @@ void delete_glsl_program_entry(IWineD3DDevice *iface, struct glsl_shader_prog_li
* the program in the hash table. If it creates a program, it will link the
* given objects, too.
*/
-static void set_glsl_shader_program(IWineD3DDevice *iface) {
+static void set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use_vs) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
WineD3D_GL_Info *gl_info = &((IWineD3DImpl *)(This->wineD3D))->gl_info;
IWineD3DPixelShader *pshader = This->stateBlock->pixelShader;
@@ -2059,8 +2059,8 @@ static void set_glsl_shader_program(IWineD3DDevice *iface) {
int i;
char glsl_name[8];
- GLhandleARB vshader_id = (vshader && This->vs_selected_mode == SHADER_GLSL) ? ((IWineD3DBaseShaderImpl*)vshader)->baseShader.prgId : 0;
- GLhandleARB pshader_id = (pshader && This->ps_selected_mode == SHADER_GLSL) ? ((IWineD3DBaseShaderImpl*)pshader)->baseShader.prgId : 0;
+ GLhandleARB vshader_id = use_vs ? ((IWineD3DBaseShaderImpl*)vshader)->baseShader.prgId : 0;
+ GLhandleARB pshader_id = use_ps ? ((IWineD3DBaseShaderImpl*)pshader)->baseShader.prgId : 0;
entry = get_glsl_program_entry(This, vshader_id, pshader_id);
if (entry) {
This->stateBlock->glsl_program = entry;
@@ -2179,7 +2179,7 @@ static void shader_glsl_select(IWineD3DDevice *iface, BOOL usePS, BOOL useVS) {
WineD3D_GL_Info *gl_info = &((IWineD3DImpl *)(This->wineD3D))->gl_info;
GLhandleARB program_id = 0;
- if (useVS || usePS) set_glsl_shader_program(iface);
+ if (useVS || usePS) set_glsl_shader_program(iface, usePS, useVS);
else This->stateBlock->glsl_program = NULL;
program_id = This->stateBlock->glsl_program ? This->stateBlock->glsl_program->programId : 0;
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index 0e12a23..5b4a304 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -395,7 +395,7 @@ static void state_clipping(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine
DWORD enable = 0xFFFFFFFF;
DWORD disable = 0x00000000;
- if(stateblock->vertexShader) {
+ if (use_vs(stateblock->wineD3DDevice)) {
/* The spec says that opengl clipping planes are disabled when using shaders. Direct3D planes aren't,
* so that is an issue. The MacOS ATI driver keeps clipping planes activated with shaders in some
* contitions I got sick of tracking down. The shader state handler disables all clip planes because
@@ -709,8 +709,8 @@ static void state_fog(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCo
fogend = tmpvalue.f;
/* Activate when vertex shaders are in the state table */
- if(stateblock->vertexShader && ((IWineD3DVertexShaderImpl *)stateblock->vertexShader)->baseShader.function &&
- ((IWineD3DVertexShaderImpl *)stateblock->vertexShader)->usesFog) {
+ if (use_vs(stateblock->wineD3DDevice)
+ && ((IWineD3DVertexShaderImpl *)stateblock->vertexShader)->usesFog) {
glFogi(GL_FOG_MODE, GL_LINEAR);
checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
if (stateblock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE) {
@@ -1977,17 +1977,16 @@ static void shaderconstant(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine
return;
}
- device->shader_backend->shader_load_constants((IWineD3DDevice *) device,
- stateblock->pixelShader && ((IWineD3DPixelShaderImpl *)stateblock->pixelShader)->baseShader.function,
- stateblock->vertexShader && ((IWineD3DVertexShaderImpl *)stateblock->vertexShader)->baseShader.function);
+ device->shader_backend->shader_load_constants((IWineD3DDevice *) device, use_ps(device), use_vs(device));
}
static void pixelshader(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) {
- BOOL use_ps = stateblock->pixelShader && ((IWineD3DPixelShaderImpl *)stateblock->pixelShader)->baseShader.function != NULL;
- BOOL use_vs = stateblock->vertexShader && ((IWineD3DVertexShaderImpl *)stateblock->vertexShader)->baseShader.function != NULL;
+ IWineD3DDeviceImpl *device = stateblock->wineD3DDevice;
+ BOOL use_pshader = use_ps(device);
+ BOOL use_vshader = use_vs(device);
int i;
- if (use_ps) {
+ if (use_pshader) {
if(!context->last_was_pshader) {
/* Former draw without a pixel shader, some samplers
* may be disabled because of WINED3DTSS_COLOROP = WINED3DTOP_DISABLE
@@ -2018,14 +2017,14 @@ static void pixelshader(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D
}
if(!isStateDirty(context, StateTable[STATE_VSHADER].representative)) {
- stateblock->wineD3DDevice->shader_backend->shader_select((IWineD3DDevice *)stateblock->wineD3DDevice, use_ps, use_vs);
+ device->shader_backend->shader_select((IWineD3DDevice *)stateblock->wineD3DDevice, use_pshader, use_vshader);
- if(!isStateDirty(context, STATE_VERTEXSHADERCONSTANT) && (use_vs || use_ps)) {
+ if (!isStateDirty(context, STATE_VERTEXSHADERCONSTANT) && (use_vshader || use_pshader)) {
shaderconstant(STATE_VERTEXSHADERCONSTANT, stateblock, context);
}
}
- context->last_was_pshader = use_ps;
+ context->last_was_pshader = use_pshader;
}
static void tex_bumpenvmat(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) {
@@ -2827,6 +2826,10 @@ static inline void handleStreams(IWineD3DStateBlockImpl *stateblock, BOOL useVer
}
}
+ if (dataLocations->u.s.position_transformed) {
+ useVertexShaderFunction = FALSE;
+ }
+
/* Unload the old arrays before loading the new ones to get old junk out */
if(context->numberedArraysLoaded) {
unloadNumberedArrays(stateblock);
@@ -2906,6 +2909,7 @@ static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock, W
transformed = ((device->strided_streams.u.s.position.lpData != NULL ||
device->strided_streams.u.s.position.VBO != 0) &&
device->strided_streams.u.s.position_transformed) ? TRUE : FALSE;
+ if (transformed) useVertexShaderFunction = FALSE;
if(transformed != context->last_was_rhw && !useVertexShaderFunction) {
updateFog = TRUE;
@@ -2916,7 +2920,7 @@ static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock, W
state_lighting(STATE_RENDER(WINED3DRS_LIGHTING), stateblock, context);
}
- if (!useVertexShaderFunction && transformed) {
+ if (transformed) {
context->last_was_rhw = TRUE;
} else {
diff --git a/dlls/wined3d/vertexbuffer.c b/dlls/wined3d/vertexbuffer.c
index 2e97c20..63b381a 100644
--- a/dlls/wined3d/vertexbuffer.c
+++ b/dlls/wined3d/vertexbuffer.c
@@ -197,7 +197,7 @@ inline BOOL WINAPI IWineD3DVertexBufferImpl_FindDecl(IWineD3DVertexBufferImpl *T
* FALSE: otherwise
*/
- if(device->stateBlock->vertexShader && ((IWineD3DVertexShaderImpl *) device->stateBlock->vertexShader)->baseShader.function) {
+ if (use_vs(device)) {
/* Assume no conversion */
memset(&strided, 0, sizeof(strided));
} else {
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index dab9f35..f7b9dbd 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1936,4 +1936,18 @@ typedef struct {
} PixelFormatDesc;
const PixelFormatDesc *getFormatDescEntry(WINED3DFORMAT fmt);
+
+inline static BOOL use_vs(IWineD3DDeviceImpl *device) {
+ return (device->vs_selected_mode != SHADER_NONE
+ && device->stateBlock->vertexShader
+ && ((IWineD3DVertexShaderImpl *)device->stateBlock->vertexShader)->baseShader.function
+ && !device->strided_streams.u.s.position_transformed);
+}
+
+inline static BOOL use_ps(IWineD3DDeviceImpl *device) {
+ return (device->ps_selected_mode != SHADER_NONE
+ && device->stateBlock->pixelShader
+ && ((IWineD3DPixelShaderImpl *)device->stateBlock->pixelShader)->baseShader.function);
+}
+
#endif
More information about the wine-patches
mailing list