wined3d: Allow the depth buffer to be shared between onscreen and offscreen rendering modes.

This commit is contained in:
H. Verbeet 2006-11-17 13:24:04 +01:00 committed by Alexandre Julliard
parent 6d66085150
commit ef2c062c09
4 changed files with 212 additions and 0 deletions

View File

@ -7006,6 +7006,8 @@ static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_
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(IWineD3DDeviceImpl* This, BOOL isTexture) {
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(IWineD3DDeviceImpl* This, BOOL isTexture) {
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);

View File

@ -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(IWineD3DDevice *iface) {
}
}
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 &&

View File

@ -551,6 +551,7 @@ typedef struct IWineD3DDeviceImpl
/* For rendering to a texture using glCopyTexImage */
BOOL render_offscreen;
WINED3D_DEPTHCOPYSTATE depth_copy_state;
GLuint fbo;
/* Cursor management */

View File

@ -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