wined3d: Fixup FBO depth attachments when the depth attachment is larger than the render target.

This commit is contained in:
H. Verbeet 2007-04-09 01:53:32 +02:00 committed by Alexandre Julliard
parent 3d4e054b55
commit c9b178b594
4 changed files with 116 additions and 13 deletions

View file

@ -768,6 +768,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, U
return WINED3DERR_INVALIDCALL;
}
list_init(&object->renderbuffers);
/* Call the private setup routine */
return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
@ -5110,22 +5112,27 @@ static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_
TRACE("Set depth stencil to %p\n", depth_stencil);
if (depth_stencil_impl) {
GLenum texttarget, target;
GLint old_binding = 0;
if (depth_stencil_impl->current_renderbuffer) {
GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
checkGLcall("glFramebufferRenderbufferEXT()");
} else {
GLenum texttarget, target;
GLint old_binding = 0;
texttarget = depth_stencil_impl->glDescription.target;
target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
texttarget = depth_stencil_impl->glDescription.target;
target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
IWineD3DSurface_PreLoad(depth_stencil);
IWineD3DSurface_PreLoad(depth_stencil);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
glBindTexture(target, old_binding);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
glBindTexture(target, old_binding);
GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
checkGLcall("glFramebufferTexture2DEXT()");
GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
checkGLcall("glFramebufferTexture2DEXT()");
}
} else {
GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
checkGLcall("glFramebufferTexture2DEXT()");
@ -5175,6 +5182,22 @@ static void check_fbo_status(IWineD3DDevice *iface) {
}
}
static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
if (!ds_impl) return FALSE;
if (ds_impl->current_renderbuffer) {
return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
}
return (rt_impl->pow2Width != ds_impl->pow2Width ||
rt_impl->pow2Height != ds_impl->pow2Height);
}
void apply_fbo_state(IWineD3DDevice *iface) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
unsigned int i;
@ -5192,7 +5215,13 @@ void apply_fbo_state(IWineD3DDevice *iface) {
}
/* Apply depth targets */
if (This->fbo_depth_attachment != This->stencilBufferTarget) {
if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
if (This->stencilBufferTarget) {
surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
}
set_depth_stencil_fbo(iface, This->stencilBufferTarget);
This->fbo_depth_attachment = This->stencilBufferTarget;
}

View file

@ -804,6 +804,11 @@ static void depth_copy(IWineD3DDevice *iface) {
/* TODO: Make this work for modes other than FBO */
if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
if (depth_stencil->current_renderbuffer) {
FIXME("Not supported with fixed up depth stencil\n");
return;
}
if (This->render_offscreen) {
static GLuint tmp_texture = 0;
GLint old_binding = 0;

View file

@ -8,6 +8,7 @@
* Copyright 2004 Christian Costa
* Copyright 2005 Oliver Stieber
* Copyright 2006 Stefan Dösinger for CodeWeavers
* Copyright 2007 Henri Verbeet
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -237,6 +238,56 @@ static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal,
LEAVE_GL();
}
/* In D3D the depth stencil dimensions have to be greater than or equal to the
* render target dimensions. With FBOs, the dimensions have to be an exact match. */
/* TODO: We should synchronize the renderbuffer's content with the texture's content. */
void surface_set_compatible_renderbuffer(IWineD3DSurface *iface, unsigned int width, unsigned int height) {
IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
renderbuffer_entry_t *entry;
GLuint renderbuffer = 0;
unsigned int src_width, src_height;
src_width = This->pow2Width;
src_height = This->pow2Height;
/* A depth stencil smaller than the render target is not valid */
if (width > src_width || height > src_height) return;
/* Remove any renderbuffer set if the sizes match */
if (width == src_width && height == src_height) {
This->current_renderbuffer = NULL;
return;
}
/* Look if we've already got a renderbuffer of the correct dimensions */
LIST_FOR_EACH_ENTRY(entry, &This->renderbuffers, renderbuffer_entry_t, entry) {
if (entry->width == width && entry->height == height) {
renderbuffer = entry->id;
This->current_renderbuffer = entry;
break;
}
}
if (!renderbuffer) {
const PixelFormatDesc *format_entry = getFormatDescEntry(This->resource.format);
GL_EXTCALL(glGenRenderbuffersEXT(1, &renderbuffer));
GL_EXTCALL(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderbuffer));
GL_EXTCALL(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, format_entry->glFormat, width, height));
entry = HeapAlloc(GetProcessHeap(), 0, sizeof(renderbuffer_entry_t));
entry->width = width;
entry->height = height;
entry->id = renderbuffer;
list_add_head(&This->renderbuffers, &entry->entry);
This->current_renderbuffer = entry;
}
checkGLcall("set_compatible_renderbuffer");
}
/* *******************************************
IWineD3DSurface IUnknown parts follow
******************************************* */
@ -271,6 +322,7 @@ ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
TRACE("(%p) : Releasing from %d\n", This, ref + 1);
if (ref == 0) {
IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
renderbuffer_entry_t *entry, *entry2;
TRACE("(%p) : cleaning up\n", This);
if(iface == device->lastActiveRenderTarget) {
@ -339,6 +391,11 @@ ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
if(iface == device->ddraw_primary)
device->ddraw_primary = NULL;
LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry) {
GL_EXTCALL(glDeleteRenderbuffersEXT(1, &entry->id));
HeapFree(GetProcessHeap(), 0, entry);
}
TRACE("(%p) Released\n", This);
HeapFree(GetProcessHeap(), 0, This);

View file

@ -1003,6 +1003,13 @@ typedef struct wineD3DSurface_DIB {
BOOL client_memory;
} wineD3DSurface_DIB;
typedef struct {
struct list entry;
GLuint id;
UINT width;
UINT height;
} renderbuffer_entry_t;
/*****************************************************************************
* IWineD3DSurface implementation structure
*/
@ -1054,6 +1061,9 @@ struct IWineD3DSurfaceImpl
DWORD CKeyFlags;
DDCOLORKEY glCKey;
struct list renderbuffers;
renderbuffer_entry_t *current_renderbuffer;
};
extern const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl;
@ -1398,6 +1408,8 @@ void set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, WINED3DTEXTURE
void set_tex_op_nvrc(IWineD3DDevice *iface, BOOL is_alpha, int stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3, INT texture_idx);
void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords);
void surface_set_compatible_renderbuffer(IWineD3DSurface *iface, unsigned int width, unsigned int height);
int D3DFmtMakeGlCfg(WINED3DFORMAT BackBufferFormat, WINED3DFORMAT StencilBufferFormat, int *attribs, int* nAttribs, BOOL alternate);
/* Math utils */