From c9b178b594ee5b0668cd05de821faa9a8313faba Mon Sep 17 00:00:00 2001 From: "H. Verbeet" Date: Mon, 9 Apr 2007 01:53:32 +0200 Subject: [PATCH] wined3d: Fixup FBO depth attachments when the depth attachment is larger than the render target. --- dlls/wined3d/device.c | 55 ++++++++++++++++++++++++++++++---------- dlls/wined3d/drawprim.c | 5 ++++ dlls/wined3d/surface.c | 57 ++++++++++++++++++++++++++++++++++++++++++ dlls/wined3d/wined3d_private.h | 12 +++++++++ 4 files changed, 116 insertions(+), 13 deletions(-) diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 4e1c08674f1..2b5a16831c2 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -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; } diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c index a9a719f73a9..b8d0fcca077 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -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; diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 526c3113e4f..34b8e5b8d98 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -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); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index bed5cade378..6b290c6c440 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -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 */ -- 2.11.4.GIT