Commit c9b178b5 authored by H. Verbeet's avatar H. Verbeet Committed by Alexandre Julliard

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

parent 3d4e054b
...@@ -768,6 +768,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, U ...@@ -768,6 +768,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, U
return WINED3DERR_INVALIDCALL; return WINED3DERR_INVALIDCALL;
} }
list_init(&object->renderbuffers);
/* Call the private setup routine */ /* Call the private setup routine */
return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object ); return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
...@@ -5110,22 +5112,27 @@ static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_ ...@@ -5110,22 +5112,27 @@ static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_
TRACE("Set depth stencil to %p\n", depth_stencil); TRACE("Set depth stencil to %p\n", depth_stencil);
if (depth_stencil_impl) { if (depth_stencil_impl) {
GLenum texttarget, target; if (depth_stencil_impl->current_renderbuffer) {
GLint old_binding = 0; 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; texttarget = depth_stencil_impl->glDescription.target;
target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB; 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); 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_MIN_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE); glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
glBindTexture(target, old_binding); glBindTexture(target, old_binding);
GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0)); GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
checkGLcall("glFramebufferTexture2DEXT()"); checkGLcall("glFramebufferTexture2DEXT()");
}
} else { } else {
GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0)); GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
checkGLcall("glFramebufferTexture2DEXT()"); checkGLcall("glFramebufferTexture2DEXT()");
...@@ -5175,6 +5182,22 @@ static void check_fbo_status(IWineD3DDevice *iface) { ...@@ -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) { void apply_fbo_state(IWineD3DDevice *iface) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
unsigned int i; unsigned int i;
...@@ -5192,7 +5215,13 @@ void apply_fbo_state(IWineD3DDevice *iface) { ...@@ -5192,7 +5215,13 @@ void apply_fbo_state(IWineD3DDevice *iface) {
} }
/* Apply depth targets */ /* 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); set_depth_stencil_fbo(iface, This->stencilBufferTarget);
This->fbo_depth_attachment = This->stencilBufferTarget; This->fbo_depth_attachment = This->stencilBufferTarget;
} }
......
...@@ -804,6 +804,11 @@ static void depth_copy(IWineD3DDevice *iface) { ...@@ -804,6 +804,11 @@ static void depth_copy(IWineD3DDevice *iface) {
/* TODO: Make this work for modes other than FBO */ /* TODO: Make this work for modes other than FBO */
if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return; 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) { if (This->render_offscreen) {
static GLuint tmp_texture = 0; static GLuint tmp_texture = 0;
GLint old_binding = 0; GLint old_binding = 0;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
* Copyright 2004 Christian Costa * Copyright 2004 Christian Costa
* Copyright 2005 Oliver Stieber * Copyright 2005 Oliver Stieber
* Copyright 2006 Stefan Dsinger for CodeWeavers * Copyright 2006 Stefan Dsinger for CodeWeavers
* Copyright 2007 Henri Verbeet
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
...@@ -237,6 +238,56 @@ static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, ...@@ -237,6 +238,56 @@ static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal,
LEAVE_GL(); 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 IWineD3DSurface IUnknown parts follow
******************************************* */ ******************************************* */
...@@ -271,6 +322,7 @@ ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) { ...@@ -271,6 +322,7 @@ ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
TRACE("(%p) : Releasing from %d\n", This, ref + 1); TRACE("(%p) : Releasing from %d\n", This, ref + 1);
if (ref == 0) { if (ref == 0) {
IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice; IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
renderbuffer_entry_t *entry, *entry2;
TRACE("(%p) : cleaning up\n", This); TRACE("(%p) : cleaning up\n", This);
if(iface == device->lastActiveRenderTarget) { if(iface == device->lastActiveRenderTarget) {
...@@ -339,6 +391,11 @@ ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) { ...@@ -339,6 +391,11 @@ ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
if(iface == device->ddraw_primary) if(iface == device->ddraw_primary)
device->ddraw_primary = NULL; 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); TRACE("(%p) Released\n", This);
HeapFree(GetProcessHeap(), 0, This); HeapFree(GetProcessHeap(), 0, This);
......
...@@ -1003,6 +1003,13 @@ typedef struct wineD3DSurface_DIB { ...@@ -1003,6 +1003,13 @@ typedef struct wineD3DSurface_DIB {
BOOL client_memory; BOOL client_memory;
} wineD3DSurface_DIB; } wineD3DSurface_DIB;
typedef struct {
struct list entry;
GLuint id;
UINT width;
UINT height;
} renderbuffer_entry_t;
/***************************************************************************** /*****************************************************************************
* IWineD3DSurface implementation structure * IWineD3DSurface implementation structure
*/ */
...@@ -1054,6 +1061,9 @@ struct IWineD3DSurfaceImpl ...@@ -1054,6 +1061,9 @@ struct IWineD3DSurfaceImpl
DWORD CKeyFlags; DWORD CKeyFlags;
DDCOLORKEY glCKey; DDCOLORKEY glCKey;
struct list renderbuffers;
renderbuffer_entry_t *current_renderbuffer;
}; };
extern const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl; extern const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl;
...@@ -1398,6 +1408,8 @@ void set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, WINED3DTEXTURE ...@@ -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_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 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); int D3DFmtMakeGlCfg(WINED3DFORMAT BackBufferFormat, WINED3DFORMAT StencilBufferFormat, int *attribs, int* nAttribs, BOOL alternate);
/* Math utils */ /* Math utils */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment