wined3d: Don't call shader_select() in depth_blt().
Calling shader_select() from inside depth_blt() isn't necessarily
safe. shader_select() assumes CompileShader() has been called for the
current shaders, but that depends on STATE_VSHADER / STATE_PIXELSHADER
being applied. That isn't always true when depth_blt() gets called,
with the result that sometimes GLSL programs could be created with no
shader objects attached.
diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index a62aed7..ee0a7c8 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -1766,22 +1766,24 @@
static void shader_arb_select(IWineD3DDevice *iface, BOOL usePS, BOOL useVS) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ struct shader_arb_priv *priv = (struct shader_arb_priv *) This->shader_priv;
WineD3D_GL_Info *gl_info = &This->adapter->gl_info;
if (useVS) {
TRACE("Using vertex shader\n");
+ priv->current_vprogram_id = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId;
+
/* Bind the vertex program */
- GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB,
- ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId));
+ GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, priv->current_vprogram_id));
checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertexShader->prgId);");
/* Enable OpenGL vertex programs */
glEnable(GL_VERTEX_PROGRAM_ARB);
checkGLcall("glEnable(GL_VERTEX_PROGRAM_ARB);");
- TRACE("(%p) : Bound vertex program %u and enabled GL_VERTEX_PROGRAM_ARB\n",
- This, ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId);
+ TRACE("(%p) : Bound vertex program %u and enabled GL_VERTEX_PROGRAM_ARB\n", This, priv->current_vprogram_id);
} else if(GL_SUPPORT(ARB_VERTEX_PROGRAM)) {
+ priv->current_vprogram_id = 0;
glDisable(GL_VERTEX_PROGRAM_ARB);
checkGLcall("glDisable(GL_VERTEX_PROGRAM_ARB)");
}
@@ -1789,17 +1791,18 @@
if (usePS) {
TRACE("Using pixel shader\n");
+ priv->current_fprogram_id = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId;
+
/* Bind the fragment program */
- GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB,
- ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId));
+ GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, priv->current_fprogram_id));
checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixelShader->prgId);");
/* Enable OpenGL fragment programs */
glEnable(GL_FRAGMENT_PROGRAM_ARB);
checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);");
- TRACE("(%p) : Bound fragment program %u and enabled GL_FRAGMENT_PROGRAM_ARB\n",
- This, ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId);
+ TRACE("(%p) : Bound fragment program %u and enabled GL_FRAGMENT_PROGRAM_ARB\n", This, priv->current_fprogram_id);
} else if(GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) {
+ priv->current_fprogram_id = 0;
glDisable(GL_FRAGMENT_PROGRAM_ARB);
checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)");
}
@@ -1819,6 +1822,38 @@
glEnable(GL_FRAGMENT_PROGRAM_ARB);
}
+static void shader_arb_deselect_depth_blt(IWineD3DDevice *iface) {
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ struct shader_arb_priv *priv = (struct shader_arb_priv *) This->shader_priv;
+ WineD3D_GL_Info *gl_info = &This->adapter->gl_info;
+
+ if (priv->current_vprogram_id) {
+ GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, priv->current_vprogram_id));
+ checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertexShader->prgId);");
+
+ glEnable(GL_VERTEX_PROGRAM_ARB);
+ checkGLcall("glEnable(GL_VERTEX_PROGRAM_ARB);");
+
+ TRACE("(%p) : Bound vertex program %u and enabled GL_VERTEX_PROGRAM_ARB\n", This, priv->current_vprogram_id);
+ } else {
+ glDisable(GL_VERTEX_PROGRAM_ARB);
+ checkGLcall("glDisable(GL_VERTEX_PROGRAM_ARB)");
+ }
+
+ if (priv->current_fprogram_id) {
+ GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, priv->current_fprogram_id));
+ checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixelShader->prgId);");
+
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+ checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);");
+
+ TRACE("(%p) : Bound fragment program %u and enabled GL_FRAGMENT_PROGRAM_ARB\n", This, priv->current_fprogram_id);
+ } else if(GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) {
+ glDisable(GL_FRAGMENT_PROGRAM_ARB);
+ checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)");
+ }
+}
+
static void shader_arb_cleanup(IWineD3DDevice *iface) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
WineD3D_GL_Info *gl_info = &This->adapter->gl_info;
@@ -2092,6 +2127,7 @@
const shader_backend_t arb_program_shader_backend = {
shader_arb_select,
shader_arb_select_depth_blt,
+ shader_arb_deselect_depth_blt,
shader_arb_load_constants,
shader_arb_cleanup,
shader_arb_color_correction,
diff --git a/dlls/wined3d/ati_fragment_shader.c b/dlls/wined3d/ati_fragment_shader.c
index 0c34474..853f6f2 100644
--- a/dlls/wined3d/ati_fragment_shader.c
+++ b/dlls/wined3d/ati_fragment_shader.c
@@ -976,6 +976,10 @@
arb_program_shader_backend.shader_select_depth_blt(iface);
}
+static void shader_atifs_deselect_depth_blt(IWineD3DDevice *iface) {
+ arb_program_shader_backend.shader_deselect_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);
}
@@ -1107,6 +1111,7 @@
const shader_backend_t atifs_shader_backend = {
shader_atifs_select,
shader_atifs_select_depth_blt,
+ shader_atifs_deselect_depth_blt,
shader_atifs_load_constants,
shader_atifs_cleanup,
shader_atifs_color_correction,
diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c
index a8806d3..6b019d3 100644
--- a/dlls/wined3d/baseshader.c
+++ b/dlls/wined3d/baseshader.c
@@ -1091,6 +1091,7 @@
static void shader_none_select(IWineD3DDevice *iface, BOOL usePS, BOOL useVS) {}
static void shader_none_select_depth_blt(IWineD3DDevice *iface) {}
+static void shader_none_deselect_depth_blt(IWineD3DDevice *iface) {}
static void shader_none_load_constants(IWineD3DDevice *iface, char usePS, char useVS) {}
static void shader_none_cleanup(IWineD3DDevice *iface) {}
static void shader_none_color_correction(SHADER_OPCODE_ARG* arg) {}
@@ -1201,6 +1202,7 @@
const shader_backend_t none_shader_backend = {
shader_none_select,
shader_none_select_depth_blt,
+ shader_none_deselect_depth_blt,
shader_none_load_constants,
shader_none_cleanup,
shader_none_color_correction,
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index f07980a..9a47f8b 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -753,11 +753,7 @@
glPopAttrib();
- /* Reselect the old shaders. There doesn't seem to be any glPushAttrib bit for arb shaders,
- * 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, use_ps(This), use_vs(This));
+ This->shader_backend->shader_deselect_depth_blt(iface);
}
static inline void drawStridedInstanced(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd, UINT numberOfVertices,
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 1ff7e11..762e130 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -3398,6 +3398,19 @@
GL_EXTCALL(glUniform1iARB(loc, 0));
}
+static void shader_glsl_deselect_depth_blt(IWineD3DDevice *iface) {
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ WineD3D_GL_Info *gl_info = &This->adapter->gl_info;
+ struct shader_glsl_priv *priv = (struct shader_glsl_priv *) This->shader_priv;
+ GLhandleARB program_id;
+
+ program_id = priv->glsl_program ? priv->glsl_program->programId : 0;
+ if (program_id) TRACE("Using GLSL program %u\n", program_id);
+
+ GL_EXTCALL(glUseProgramObjectARB(program_id));
+ checkGLcall("glUseProgramObjectARB");
+}
+
static void shader_glsl_cleanup(IWineD3DDevice *iface) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
WineD3D_GL_Info *gl_info = &This->adapter->gl_info;
@@ -3695,6 +3708,7 @@
const shader_backend_t glsl_shader_backend = {
shader_glsl_select,
shader_glsl_select_depth_blt,
+ shader_glsl_deselect_depth_blt,
shader_glsl_load_constants,
shader_glsl_cleanup,
shader_glsl_color_correction,
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index b11a3f5..35cb760 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -242,6 +242,7 @@
typedef struct {
void (*shader_select)(IWineD3DDevice *iface, BOOL usePS, BOOL useVS);
void (*shader_select_depth_blt)(IWineD3DDevice *iface);
+ void (*shader_deselect_depth_blt)(IWineD3DDevice *iface);
void (*shader_load_constants)(IWineD3DDevice *iface, char usePS, char useVS);
void (*shader_cleanup)(IWineD3DDevice *iface);
void (*shader_color_correction)(struct SHADER_OPCODE_ARG *arg);
@@ -269,6 +270,8 @@
/* ARB_program_shader private data */
struct shader_arb_priv {
+ GLuint current_vprogram_id;
+ GLuint current_fprogram_id;
GLuint depth_blt_vprogram_id;
GLuint depth_blt_fprogram_id;
};