[5/5] wined3d: Allow the depth buffer to be shared between onscreen
and offscreen rendering modes
H. Verbeet
hverbeet at gmail.com
Fri Nov 17 06:24:04 CST 2006
The current implementation is for FBOs, but it should be possible to
make this work for PBuffers as well.
Changelog:
- Allow the depth buffer to be shared between onscreen and offscreen
rendering modes
-------------- next part --------------
---
dlls/wined3d/device.c | 8 +
dlls/wined3d/drawprim.c | 196 ++++++++++++++++++++++++++++++++++
dlls/wined3d/wined3d_private.h | 1
dlls/wined3d/wined3d_private_types.h | 7 +
4 files changed, 212 insertions(+), 0 deletions(-)
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index ef0e046..ab7ab10 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -7006,6 +7006,8 @@ static void set_depth_stencil_fbo(IWineD
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
+ This->depth_copy_state = WINED3D_DCS_NO_COPY;
+
bind_fbo(iface);
if (depth_stencil_impl) {
@@ -7275,6 +7277,9 @@ static void device_render_to_texture(IWi
BOOL oldRecording;
IWineD3DStateBlockImpl *oldUpdateStateBlock;
+ /* Nothing to update, return. */
+ if (This->render_offscreen == isTexture) return;
+
/* Disable recording */
oldUpdateStateBlock = This->updateStateBlock;
oldRecording= This->isRecordingState;
@@ -7282,6 +7287,9 @@ static void device_render_to_texture(IWi
This->updateStateBlock = This->stateBlock;
This->render_offscreen = isTexture;
+ if (This->depth_copy_state != WINED3D_DCS_NO_COPY) {
+ This->depth_copy_state = WINED3D_DCS_COPY;
+ }
This->last_was_rhw = FALSE;
This->proj_valid = FALSE;
IWineD3DDevice_GetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, &cullMode);
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index 4a1bd8e..8ddb017 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -5,6 +5,7 @@
* Copyright 2002-2004 Raphael Junqueira
* Copyright 2004 Christian Costa
* Copyright 2005 Oliver Stieber
+ * 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
@@ -2088,6 +2089,196 @@ static void check_fbo_status(IWineD3DDev
}
}
+static GLuint create_arb_blt_vertex_program(IWineD3DDevice *iface) {
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+
+ GLuint program_id = 0;
+ const char *blt_vprogram =
+ "!!ARBvp1.0\n"
+ "PARAM c[1] = { { 1, 0.5 } };\n"
+ "MOV result.position, vertex.position;\n"
+ "MOV result.color, c[0].x;\n"
+ "MAD result.texcoord[0].y, -vertex.position, c[0], c[0];\n"
+ "MAD result.texcoord[0].x, vertex.position, c[0].y, c[0].y;\n"
+ "END\n";
+
+ GL_EXTCALL(glGenProgramsARB(1, &program_id));
+ GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, program_id));
+ GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(blt_vprogram), blt_vprogram));
+
+ if (glGetError() == GL_INVALID_OPERATION) {
+ GLint pos;
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
+ FIXME("Vertex program error at position %d: %s\n", pos,
+ debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
+ }
+
+ return program_id;
+}
+
+static GLuint create_arb_blt_fragment_program(IWineD3DDevice *iface) {
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+
+ GLuint program_id = 0;
+ const char *blt_fprogram =
+ "!!ARBfp1.0\n"
+ "TEMP R0;\n"
+ "TEX R0.x, fragment.texcoord[0], texture[0], 2D;\n"
+ "MOV result.depth.z, R0.x;\n"
+ "END\n";
+
+ GL_EXTCALL(glGenProgramsARB(1, &program_id));
+ GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, program_id));
+ GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(blt_fprogram), blt_fprogram));
+
+ if (glGetError() == GL_INVALID_OPERATION) {
+ GLint pos;
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
+ FIXME("Fragment program error at position %d: %s\n", pos,
+ debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
+ }
+
+ return program_id;
+}
+
+static GLhandleARB create_glsl_blt_shader(IWineD3DDevice *iface) {
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+
+ GLhandleARB program_id;
+ GLhandleARB vshader_id, pshader_id;
+ const char *blt_vshader[] = {
+ "void main(void)\n"
+ "{\n"
+ " gl_Position = gl_Vertex;\n"
+ " gl_FrontColor = vec4(1.0);\n"
+ " gl_TexCoord[0].x = (gl_Vertex.x * 0.5) + 0.5;\n"
+ " gl_TexCoord[0].y = (-gl_Vertex.y * 0.5) + 0.5;\n"
+ "}\n"
+ };
+
+ const char *blt_pshader[] = {
+ "uniform sampler2D sampler;\n"
+ "void main(void)\n"
+ "{\n"
+ " gl_FragDepth = texture2D(sampler, gl_TexCoord[0].xy).x;\n"
+ "}\n"
+ };
+
+ vshader_id = GL_EXTCALL(glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB));
+ GL_EXTCALL(glShaderSourceARB(vshader_id, 1, blt_vshader, NULL));
+ GL_EXTCALL(glCompileShaderARB(vshader_id));
+
+ pshader_id = GL_EXTCALL(glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB));
+ GL_EXTCALL(glShaderSourceARB(pshader_id, 1, blt_pshader, NULL));
+ GL_EXTCALL(glCompileShaderARB(pshader_id));
+
+ program_id = GL_EXTCALL(glCreateProgramObjectARB());
+ GL_EXTCALL(glAttachObjectARB(program_id, vshader_id));
+ GL_EXTCALL(glAttachObjectARB(program_id, pshader_id));
+ GL_EXTCALL(glLinkProgramARB(program_id));
+
+ print_glsl_info_log(&GLINFO_LOCATION, program_id);
+
+ return program_id;
+}
+
+static void depth_blt(IWineD3DDevice *iface, GLuint texture) {
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ BOOL glsl_mode = This->vs_selected_mode == SHADER_GLSL || This->ps_selected_mode == SHADER_GLSL;
+
+ glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_BLEND);
+ glDisable(GL_ALPHA_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_ALWAYS);
+
+ GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glEnable(GL_TEXTURE_2D);
+
+ if (glsl_mode) {
+ static GLhandleARB program_id = 0;
+ static GLhandleARB loc = -1;
+
+ if (!program_id) {
+ program_id = create_glsl_blt_shader(iface);
+ loc = GL_EXTCALL(glGetUniformLocationARB(program_id, "sampler"));
+ }
+
+ GL_EXTCALL(glUseProgramObjectARB(program_id));
+ GL_EXTCALL(glUniform1iARB(loc, 0));
+ } else {
+ static GLuint vprogram_id = 0;
+ static GLuint fprogram_id = 0;
+
+ if (!vprogram_id) vprogram_id = create_arb_blt_vertex_program(iface);
+ GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vprogram_id));
+ glEnable(GL_VERTEX_PROGRAM_ARB);
+
+ if (!fprogram_id) fprogram_id = create_arb_blt_fragment_program(iface);
+ GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, fprogram_id));
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+ }
+
+ glBegin(GL_TRIANGLE_STRIP);
+ glVertex2f(-1.0f, -1.0f);
+ glVertex2f(1.0f, -1.0f);
+ glVertex2f(-1.0f, 1.0f);
+ glVertex2f(1.0f, 1.0f);
+ glEnd();
+
+ glPopAttrib();
+}
+
+static void depth_copy(IWineD3DDevice *iface) {
+ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *)This->depthStencilBuffer;
+
+ /* TODO: Make this work for modes other than FBO */
+ if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
+
+ if (This->render_offscreen) {
+ static GLuint tmp_texture = 0;
+
+ TRACE("Copying onscreen depth buffer to offscreen surface\n");
+
+ if (!tmp_texture) {
+ glGenTextures(1, &tmp_texture);
+ }
+
+ /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
+ * directly on the FBO texture. That's because we need to flip. */
+ GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
+ glBindTexture(GL_TEXTURE_2D, tmp_texture);
+ glCopyTexImage2D(depth_stencil->glDescription.target,
+ depth_stencil->glDescription.level,
+ depth_stencil->glDescription.glFormatInternal,
+ 0,
+ 0,
+ depth_stencil->currentDesc.Width,
+ depth_stencil->currentDesc.Height,
+ 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
+
+ GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
+ checkGLcall("glBindFramebuffer()");
+ depth_blt(iface, tmp_texture);
+ checkGLcall("depth_blt");
+ } else {
+ TRACE("Copying offscreen surface to onscreen depth buffer\n");
+
+ GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
+ checkGLcall("glBindFramebuffer()");
+ depth_blt(iface, depth_stencil->glDescription.textureName);
+ checkGLcall("depth_blt");
+ }
+}
+
/* Routine common to the draw primitive and draw indexed primitive routines */
void drawPrimitive(IWineD3DDevice *iface,
int PrimitiveType,
@@ -2115,6 +2306,11 @@ void drawPrimitive(IWineD3DDevice *iface
check_fbo_status(iface);
}
+ if (This->depth_copy_state == WINED3D_DCS_COPY) {
+ depth_copy(iface);
+ }
+ This->depth_copy_state = WINED3D_DCS_INITIAL;
+
/* Shaders can be implemented using ARB_PROGRAM, GLSL, or software -
* here simply check whether a shader was set, or the user disabled shaders */
if (This->vs_selected_mode != SHADER_NONE && This->stateBlock->vertexShader &&
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 6a4894c..8b0a315 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -551,6 +551,7 @@ #define NEEDS_DI
/* For rendering to a texture using glCopyTexImage */
BOOL render_offscreen;
+ WINED3D_DEPTHCOPYSTATE depth_copy_state;
GLuint fbo;
/* Cursor management */
diff --git a/dlls/wined3d/wined3d_private_types.h b/dlls/wined3d/wined3d_private_types.h
index f02e980..5531a80 100644
--- a/dlls/wined3d/wined3d_private_types.h
+++ b/dlls/wined3d/wined3d_private_types.h
@@ -23,6 +23,13 @@
#ifndef __WINE_WINED3D_TYPES_INTERNAL_H
#define __WINE_WINED3D_TYPES_INTERNAL_H
+/* Depth copy state */
+typedef enum {
+ WINED3D_DCS_INITIAL = 0,
+ WINED3D_DCS_COPY = 1,
+ WINED3D_DCS_NO_COPY = 2
+} WINED3D_DEPTHCOPYSTATE;
+
/** DCL usage masks **/
#define WINED3DSP_DCL_USAGE_SHIFT 0
#define WINED3DSP_DCL_USAGE_MASK 0x0000000f
More information about the wine-patches
mailing list