Framebuffer objects

Ivan Gyurdiev ivg231 at gmail.com
Fri Sep 8 01:50:16 CDT 2006


Hi... I've been trying to get FBOs working, but I have extremely limited 
time to work on such things, so I thought I'd just post my current patch 
here, and see if people can help me figure out what's wrong with it :)

FBOs (framebuffer objects) are a newer extension, intended to replace 
pbuffers to accomplish offscreen rendering - so instead of drawing to 
the screen, you get to draw to other objects, more importantly textures. 
We currently support pbuffers, but the code is sketchy, and disabled for 
that reason.
SPEC: http://msi.unilim.fr/~porquet/glexts/GL_EXT_framebuffer_object.txt.htm

Known problems with this patch include:

(1) The D3D allows the user to setDepthStencilBuffer. I do no such thing 
- only  a default depth buffer is supported. Neither is sharing this 
depth buffer between offscreen and onscreen [ requires copying of pixels 
via lock/unlock ]. Resolution: next revision - we don't support that 
onscreen in the first place :)

(2) Attempting to bind a framebuffer using GL_RGB32F_ARB, and 
GL_RGBA32F_ARB formats will fail on my hardware (Nvidia GeForce 6800GS) 
with error GL_FRAMEBUFFER_UNSUPPORTED_EXT, which means the format 
combination was invalid for implementation-dependent reasons. However, 
this doesn't make sense, based on information online, which indicates 
this should work. See:
http://www.mathematik.uni-dortmund.de/~goeddeke/gpgpu/tutorial.htm : 
"Using textures as render targets".... or google.
This is a problem, since certain demos which make use of the R32F format 
won't work with FBOs - but oddly work with pbuffers.
See SoftShadowsII: http://www.humus.ca/index.php?page=3D&&start=8
On the other hand I know R16F -> GL_RGB16F works fine, based on 3Dc demo.

(3) Attempting to use GL_STENCIL_INDEX8_EXT in glRenderbufferStorageEXT 
will fail on my hardware with GL_INVALID_OPERATION. Why - this should 
work according to the GL spec. On the other hand this support list says 
otherwise: http://developer.nvidia.com/object/nv_ogl_texture_formats.html


=========
Note that bugs or no bugs, the patch fixes the following (demos from 
humus.ca):

3Dc demo runs correctly
TransparentShadowMapping demo runs correctly
Sketch demo runs correctly
Half-Life 2 startup screen runs correctly
----
Water demo offscreen content is moved  offscreen
SoftShadows2 - offscreen content moved offscreen, shows something a lot 
more correct
PhongLighting - offscreen content moved offscreen
----
...but doesn't quite match pbuffers, because:

SoftShadows2 - works completely in pbuffers (even if slow), has errors 
in FBOs
PhongLighting - has errors in FBOs
SelfShadowBump - no shadow artifacts on the wall, but now most of the 
demo's in shadow.


-------------- next part --------------
>From 98efb529e850dafb66c331afbc5168f90180650a Mon Sep 17 00:00:00 2001
From: Ivan Gyurdiev <ivg2 at cornell.edu>
Date: Thu, 7 Sep 2006 07:17:00 -0400
Subject: [PATCH] Add support for offscreen rendering via FBOs.

This uses:
GL_EXT_framebuffer_objects

A select_offscreen_mode() function was added,
where FBOs are given precedence over pbuffers - another way to do offscreen rendering,
which is older, not as nice, and currently disabled at compile time.

A shared depth buffer between offscreen and onscreen is not currently supported.
A custom depth buffer (SetDepthStencil) is not supported (but onscreen doesn't support it either).
---
 dlls/wined3d/device.c          |  201 +++++++++++++++++++++++++++++++++++-----
 dlls/wined3d/directx.c         |   17 +++
 dlls/wined3d/utils.c           |   38 +++++++-
 dlls/wined3d/wined3d_private.h |   70 +++++++++-----
 include/wine/wined3d_gl.h      |    1 
 5 files changed, 275 insertions(+), 52 deletions(-)

diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 463607f..aeed6b0 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -8,6 +8,7 @@
  * Copyright 2005 Oliver Stieber
  * Copyright 2006 Stefan Dösinger for CodeWeavers
  * Copyright 2006 Henri Verbeet
+ * Copyright 2006 Ivan Gyurdiev
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -82,6 +83,8 @@ static void WINAPI IWineD3DDeviceImpl_Ad
 
 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
 
+static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture);
+
 /* helper macros */
 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
 
@@ -239,6 +242,128 @@ static void setup_light(IWineD3DDevice *
 }
 
 /**********************************************************
+ * FBO helper functions follow
+ **********************************************************/
+
+static void device_fbo_attach_depthstencil(
+    IWineD3DDeviceImpl *This) {
+
+    TRACE("Attaching depth stencil to offscreen FBO.\n");
+
+    /* Attach a default Depth renderbuffer */
+    GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+        GL_RENDERBUFFER_EXT, This->offscreenRBO[OFFSCREEN_RBO_DEPTH]));
+    checkGLcall("glFramebufferRenderbufferEXT(OFFSCREEN_RBO_DEPTH)");
+
+    /* Attach a default Stencil renderbuffer */
+//    GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
+//        GL_RENDERBUFFER_EXT, This->offscreenRBO[OFFSCREEN_RBO_STENCIL]));
+//    checkGLcall("glFramebufferRenderbufferEXT(OFFSCREEN_RBO_STENCIL)");
+}
+
+static void device_fbo_attach_rendertarget(
+    IWineD3DDeviceImpl *This,
+    IWineD3DSurface* surface) {
+
+    glDescriptor* surface_desc;
+
+    TRACE("Attaching render surface %p to offscreen FBO.\n", surface);
+
+    /* Pre-load does some neessary prep., such as filling out the gl descriptor properly */
+    IWineD3DSurface_PreLoad(surface);
+    IWineD3DSurface_GetGlDesc(surface, &surface_desc);
+
+    /* Now attach surface to the FBO */
+    GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+        surface_desc->target, surface_desc->textureName, surface_desc->level));
+    checkGLcall("glFramebufferTexture2DEXT(0)");
+
+    checkGLfbstatus();
+
+    /* TODO: MRTs */
+}
+
+static void device_fbo_render_offscreen(
+    IWineD3DDeviceImpl *This,
+    IWineD3DSurface* initialRendertarget,
+    IWineD3DSurface* initialDepthStencil) {
+
+    UINT render_width, render_height;
+    WINED3DSURFACE_DESC render_desc;
+    memset(&render_desc, 0, sizeof(WINED3DSURFACE_DESC));
+    render_desc.Width = &render_width;
+    render_desc.Height = &render_height;
+
+    /* Grab the current rendertarget's width and height */
+    IWineD3DSurfaceImpl_GetDesc(initialRendertarget, &render_desc);
+ 
+    /* The first time offscreen rendering is requested,
+     * reserve one FBO, and two RBOs, and initialize storage for depth and stencil */
+
+    if (!This->offscreenFBO) {
+        GL_EXTCALL(glGenFramebuffersEXT(1, &This->offscreenFBO));
+        checkGLcall("glGenFramebuffersEXT");
+
+        GL_EXTCALL(glGenRenderbuffersEXT(2, This->offscreenRBO));
+        checkGLcall("glGenRenderbuffersEXT");
+
+        GL_EXTCALL(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, This->offscreenRBO[OFFSCREEN_RBO_DEPTH]));
+        checkGLcall("glBindRenderbufferEXT(OFFSCREEN_RBO_DEPTH)");
+        GL_EXTCALL(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24,
+            render_width, render_height));
+        checkGLcall("glRenderbufferStorageEXT(OFFSCREEN_RBO_DEPTH)");
+
+//        GL_EXTCALL(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, This->offscreenRBO[OFFSCREEN_RBO_STENCIL]));
+//        checkGLcall("glBindRenderbufferEXT(OFFSCREEN_RBO_STENCIL)");
+//        GL_EXTCALL(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX4_EXT,
+//            render_width, render_height));
+//        checkGLcall("glRenderbufferStorageEXT(OFFSCREEN_RBO_STENCIL)");
+    }
+
+    /* TODO: lock depthstencil */
+
+    /* Switch to offscreen FBO */
+    GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->offscreenFBO));
+    checkGLcall("glBindFramebufferEXT");
+
+    device_fbo_attach_rendertarget(This, initialRendertarget);
+    device_fbo_attach_depthstencil(This);
+
+    /* TODO: unlock depthstencil */
+}
+
+static void device_fbo_render_onscreen(
+    IWineD3DDeviceImpl *This) {
+
+    TRACE("Reverting to onscreen FBO.\n");
+
+    /* TODO: lock depthstencil */
+
+    /* Detach color */
+    GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
+        GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0));
+    checkGLcall("glFramebufferTexture2DEXT(0)");
+
+    /* Detach depth */
+    GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+        GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
+    checkGLcall("glFramebufferRenderbufferEXT(OFFSCREEN_DEPTH_RBO)");
+
+    /* Detach stencil */
+    GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+        GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
+    checkGLcall("glFramebufferRenderbufferEXT(OFFSCREEN_STENCIL_RBO)");
+
+    /* Switch to onscreen FBO */
+    GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
+    checkGLcall("glBindFramebufferEXT");
+
+    /* TODO: unlock depthstencil */
+
+    checkGLfbstatus();
+}
+
+/**********************************************************
  * GLSL helper functions follow
  **********************************************************/
 
@@ -2141,6 +2266,19 @@ static HRESULT WINAPI IWineD3DDeviceImpl
         This->cursorTexture = 0;
     }
 
+    /* Delete the offscreen FBO (if present), and switch back on-screen */
+    if (wined3d_settings.offscreen_selected_mode == OFFSCREEN_FBO && This->offscreenFBO) {
+        ENTER_GL();
+        device_fbo_render_onscreen(This);
+        device_render_to_texture(This, FALSE);
+        GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->offscreenFBO));
+        checkGLcall("glDeleteFramebuffersEXT");
+        GL_EXTCALL(glDeleteRenderbuffersEXT(2, This->offscreenRBO));
+        checkGLcall("glDeleteRenderbuffersEXT");
+        LEAVE_GL();
+        This->offscreenFBO = 0;
+    }
+
     for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
         IWineD3DDevice_SetTexture(iface, sampler, NULL);
     }
@@ -5984,8 +6122,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl
 
         /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
         IUnknown *targetContainer = NULL;
-        if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
-            || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
+        if (wined3d_settings.offscreen_selected_mode == OFFSCREEN_PBUFFER && 
+            (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
+          || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer))) {
+
             TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
             /** always dirtify for now. we must find a better way to see that surface have been modified
             (Modifications should will only occur via draw-primitive, but we do need better locking
@@ -7199,34 +7339,34 @@ static HRESULT WINAPI IWineD3DDeviceImpl
 
 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-    HRESULT  hr = WINED3D_OK;
     IWineD3DSurface *tmp;
 
     TRACE("(%p) Swapping z-buffer\n",This);
 
     if (pNewZStencil == This->stencilBufferTarget) {
         TRACE("Trying to do a NOP SetRenderTarget operation\n");
-    } else {
-        /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
-        * depending on the renter target implementation being used.
-        * A shared context implementation will share all buffers between all rendertargets (including swapchains),
-        * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
-        * stencil buffer and incure an extra memory overhead
-         ******************************************************/
-
-
-        tmp = This->stencilBufferTarget;
-        This->stencilBufferTarget = pNewZStencil;
-        /* should we be calling the parent or the wined3d surface? */
-        if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
-        if (NULL != tmp) IWineD3DSurface_Release(tmp);
-        hr = WINED3D_OK;
-        /** TODO: glEnable/glDisable on depth/stencil    depending on
-         *   pNewZStencil is NULL and the depth/stencil is enabled in d3d
-          **********************************************************/
+        return WINED3D_OK;
     }
 
-    return hr;
+    /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
+     * depending on the renter target implementation being used.
+     * A shared context implementation will share all buffers between all rendertargets (including swapchains),
+     * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
+     * stencil buffer and incure an extra memory overhead
+     ******************************************************/
+
+    tmp = This->stencilBufferTarget;
+    This->stencilBufferTarget = pNewZStencil;
+    /* should we be calling the parent or the wined3d surface? */
+    if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
+    if (NULL != tmp) IWineD3DSurface_Release(tmp);
+    /** TODO: glEnable/glDisable on depth/stencil    depending on
+     *   pNewZStencil is NULL and the depth/stencil is enabled in d3d
+      **********************************************************/
+
+    /* TODO: Unlock texture */
+
+    return WINED3D_OK; 
 }
 
 
@@ -7334,9 +7474,7 @@ static void device_reapply_stateblock(IW
     This->updateStateBlock = oldUpdateStateBlock;
 }
 
-/* Set the device to render to a texture, or not.
- * This involves changing renderUpsideDown */
-
+/* Set the device to render to a texture */
 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
 
     DWORD cullMode;
@@ -7352,6 +7490,7 @@ static void device_render_to_texture(IWi
     /* Set upside-down rendering, and update the cull mode */
     /* The surface must be rendered upside down to cancel the flip produced by glCopyTexImage */
     This->renderUpsideDown = isTexture;
+    This->offscreenRendering = isTexture;
     This->last_was_rhw = FALSE;
     This->proj_valid = FALSE;
     IWineD3DDevice_GetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, &cullMode);
@@ -7540,12 +7679,22 @@ #if defined(GL_VERSION_1_3)
 
             /* Reapply the stateblock, and set the device not to render to texture */
             device_reapply_stateblock(This);
+
+            /* If the offscreen FBO is being used, switch to the onscreen FBO */
+            if (wined3d_settings.offscreen_selected_mode == OFFSCREEN_FBO && This->offscreenRendering) 
+                device_fbo_render_onscreen(This);
             device_render_to_texture(This, FALSE);
         }
 
+    /* Offscreen rendering: FBOs */
+    } else if (wined3d_settings.offscreen_selected_mode == OFFSCREEN_FBO) {
+
+        device_fbo_render_offscreen(This, RenderSurface, This->depthStencilBuffer);
+        device_render_to_texture(This, TRUE);
+
     /* Offscreen rendering: PBuffers (currently disabled).
      * Also note that this path is never reached if FBOs are supported */
-    } else if (pbuffer_support &&
+    } else if (wined3d_settings.offscreen_selected_mode == OFFSCREEN_PBUFFER &&
                (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
 
         /** ********************************************************************
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index d4a0e97..ef9cdfb 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -26,7 +26,6 @@
 /* Uncomment this to force only a single display mode to be exposed: */
 /*#define DEBUG_SINGLE_MODE*/
 
-
 #include "config.h"
 #include "wined3d_private.h"
 
@@ -237,6 +236,20 @@ static void select_shader_mode(
     }
 }
 
+/* Select the offscreen mode, based on the given capabilities, and flags */ 
+
+static void select_offscreen_mode(
+    WineD3D_GL_Info *gl_info,
+    int* offscreen_selected) {
+
+    if (gl_info->supported[EXT_FRAMEBUFFER_OBJECT])
+        *offscreen_selected = OFFSCREEN_FBO;
+    else if (pbuffer_support)
+        *offscreen_selected = OFFSCREEN_PBUFFER;
+    else
+        *offscreen_selected = OFFSCREEN_NONE;
+}
+
 /** Select the number of report maximum shader constants based on the selected shader modes */
 void select_shader_max_constants(WineD3D_GL_Info *gl_info) {
 
@@ -1808,6 +1821,7 @@ static HRESULT WINAPI IWineD3DImpl_GetDe
     }
     select_shader_mode(&This->gl_info, DeviceType,
         &wined3d_settings.ps_selected_mode, &wined3d_settings.vs_selected_mode);
+    select_offscreen_mode(&This->gl_info, &wined3d_settings.offscreen_selected_mode);
     select_shader_max_constants(&This->gl_info);
 
     /* ------------------------------------------------
@@ -2398,6 +2412,7 @@ static HRESULT  WINAPI IWineD3DImpl_Crea
     LEAVE_GL();
     select_shader_mode(&This->gl_info, DeviceType,
         &wined3d_settings.ps_selected_mode, &wined3d_settings.vs_selected_mode);
+    select_offscreen_mode(&This->gl_info, &wined3d_settings.offscreen_selected_mode);
     select_shader_max_constants(&This->gl_info);
 
     temp_result = allocate_shader_constants(object->updateStateBlock);
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index e0778c0..40ae793 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -6,6 +6,7 @@
  * Copyright 2004 Christian Costa
  * Copyright 2005 Oliver Stieber
  * Copyright 2006 Henri Verbeet
+ * Copyright 2006 Ivan Gyurdiev
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -47,7 +48,7 @@ static const PixelFormatDesc formats[] =
     {WINED3DFMT_G8R8_G8B8   ,0x0        ,0x0        ,0x0        ,0x0        ,1/*?*/ ,TRUE       ,0                      ,0                  ,0                              },
     {WINED3DFMT_R8G8_B8G8   ,0x0        ,0x0        ,0x0        ,0x0        ,1/*?*/ ,TRUE       ,0                      ,0                  ,0                              },
     /* IEEE formats */
-    {WINED3DFMT_R32F        ,0x0        ,0x0        ,0x0        ,0x0        ,4      ,FALSE      ,GL_RGB32F_ARB         ,GL_RED             ,GL_FLOAT                       },
+    {WINED3DFMT_R32F        ,0x0        ,0x0        ,0x0        ,0x0        ,4      ,FALSE      ,GL_RGB32F_ARB         ,GL_RED             ,GL_FLOAT                        },
     {WINED3DFMT_G32R32F     ,0x0        ,0x0        ,0x0        ,0x0        ,8      ,FALSE      ,0                      ,0                  ,0                              },
     {WINED3DFMT_A32B32G32R32F,0x0       ,0x0        ,0x0        ,0x0        ,16     ,FALSE      ,GL_RGBA32F_ARB         ,GL_RGBA            ,GL_FLOAT                       },
     /* Hmm? */
@@ -646,6 +647,41 @@ #undef  POOL_TO_STR
   }
 }
 
+const char* debug_glerror(GLint err) {
+  switch (err) {
+#define GLERR_TO_STR(p) case p: return #p;
+    GLERR_TO_STR(GL_NO_ERROR);
+    GLERR_TO_STR(GL_INVALID_ENUM);
+    GLERR_TO_STR(GL_INVALID_VALUE);
+    GLERR_TO_STR(GL_INVALID_OPERATION);
+    GLERR_TO_STR(GL_STACK_OVERFLOW);
+    GLERR_TO_STR(GL_STACK_UNDERFLOW);
+    GLERR_TO_STR(GL_OUT_OF_MEMORY);
+    GLERR_TO_STR(GL_INVALID_FRAMEBUFFER_OPERATION_EXT);
+#undef GLERR_TO_STR
+  default:
+    FIXME("Unrecognized %u GL error!\n", err);
+    return "unrecognized";
+  }
+}
+
+const char* debug_fbstatus(GLenum status) {
+  switch (status) {
+#define FBSTATUS_TO_STR(p) case p: return #p;
+    FBSTATUS_TO_STR(GL_FRAMEBUFFER_COMPLETE_EXT);
+    FBSTATUS_TO_STR(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT);
+    FBSTATUS_TO_STR(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT);
+    FBSTATUS_TO_STR(GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT);
+    FBSTATUS_TO_STR(GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT);
+    FBSTATUS_TO_STR(GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT);
+    FBSTATUS_TO_STR(GL_FRAMEBUFFER_UNSUPPORTED_EXT);
+#undef FBSTATUS_TO_STR
+  default:
+    FIXME("Unrecognized %#x FB status!\n", status);
+    return "unrecognized";
+  }
+}
+
 /*****************************************************************************
  * Useful functions mapping GL <-> D3D values
  */
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index f103705..7d22c0f 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -5,6 +5,7 @@
  * Copyright 2002-2003 Raphael Junqueira
  * Copyright 2004 Jason Edmeades
  * Copyright 2005 Oliver Stieber
+ * Copyright 2006 Ivan Gyurdiev
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -127,6 +128,10 @@ #define VS_SW      2
 #define PS_NONE    0
 #define PS_HW      1
 
+#define OFFSCREEN_NONE    0
+#define OFFSCREEN_PBUFFER 1
+#define OFFSCREEN_FBO     2
+
 #define VBO_NONE   0
 #define VBO_HW     1
 
@@ -156,6 +161,7 @@ typedef struct wined3d_settings_s {
   BOOL glslRequested;
   int vs_selected_mode;
   int ps_selected_mode;
+  int offscreen_selected_mode;
 /* nonpower 2 function */
   int nonpower2_mode;
   int rendertargetlock_mode;
@@ -225,18 +231,28 @@ #define MAX_PALETTES      256
 
 /* Checking of API calls */
 /* --------------------- */
-#define checkGLcall(A)                                          \
-{                                                               \
-    GLint err = glGetError();                                   \
-    if (err == GL_NO_ERROR) {                                   \
-       TRACE("%s call ok %s / %d\n", A, __FILE__, __LINE__);    \
-                                                                \
-    } else do {                                                 \
-       FIXME(">>>>>>>>>>>>>>>>> %x from %s @ %s / %d\n",        \
-		err, A, __FILE__, __LINE__);                    \
-       err = glGetError();                                      \
-    } while (err != GL_NO_ERROR);                               \
-} 
+const char* debug_glerror(GLint err);
+#define checkGLcall(A)                                              \
+{                                                                   \
+    GLint err = glGetError();                                       \
+    if (err == GL_NO_ERROR) {                                       \
+       TRACE("%s call ok %s / %d\n", A, __FILE__, __LINE__);        \
+                                                                    \
+    } else do {                                                     \
+       FIXME(">>>>>>>>>>>>>>>>> %s returned from %s @ %s / %d\n",   \
+		debug_glerror(err), A, __FILE__, __LINE__);         \
+       err = glGetError();                                          \
+    } while (err != GL_NO_ERROR);                                   \
+}
+
+const char* debug_fbstatus(GLenum status);
+#define checkGLfbstatus()                                                       \
+{                                                                               \
+   GLenum status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)); \
+   if (status != GL_FRAMEBUFFER_COMPLETE_EXT)                                   \
+       FIXME(">>>>>>>>>>>>>>>> %s: incomplete framebuffer status\n",            \
+              debug_fbstatus(status));                                          \
+}
 
 /* Trace routines / diagnostics */
 /* ---------------------------- */
@@ -309,17 +325,17 @@ #endif
 
 /* Checking of per-vertex related GL calls */
 /* --------------------- */
-#define vcheckGLcall(A)                                         \
-{                                                               \
-    GLint err = glGetError();                                   \
-    if (err == GL_NO_ERROR) {                                   \
-       VTRACE(("%s call ok %s / %d\n", A, __FILE__, __LINE__)); \
-                                                                \
-    } else do {                                                 \
-       FIXME(">>>>>>>>>>>>>>>>> %x from %s @ %s / %d\n",        \
-                err, A, __FILE__, __LINE__);                    \
-       err = glGetError();                                      \
-    } while (err != GL_NO_ERROR);                               \
+#define vcheckGLcall(A)                                             \
+{                                                                   \
+    GLint err = glGetError();                                       \
+    if (err == GL_NO_ERROR) {                                       \
+       VTRACE(("%s call ok %s / %d\n", A, __FILE__, __LINE__));     \
+                                                                    \
+    } else do {                                                     \
+       FIXME(">>>>>>>>>>>>>>>>> %s returned from %s @ %s / %d\n",   \
+                debug_glerror(err), A, __FILE__, __LINE__);         \
+       err = glGetError();                                          \
+    } while (err != GL_NO_ERROR);                                   \
 }
 
 /* TODO: Confirm each of these works when wined3d move completed */
@@ -483,6 +499,7 @@ void dumpResources(ResourceList *resourc
 /*****************************************************************************
  * IWineD3DDevice implementation structure
  */
+
 typedef struct IWineD3DDeviceImpl
 {
     /* IUnknown fields      */
@@ -562,8 +579,13 @@ #define                         NEEDS_DI
     HRESULT                 state;
     BOOL                    d3d_initialized;
 
-    /* Screen buffer resources */
+    /* Screen buffer resources. */
     glContext contextCache[CONTEXT_CACHE];
+    GLuint offscreenFBO;
+    GLuint offscreenRBO[2]; 
+#define OFFSCREEN_RBO_DEPTH   0
+#define OFFSCREEN_RBO_STENCIL 1
+    BOOL offscreenRendering;
 
     /* A flag to check if endscene has been called before changing the render tartet */
     BOOL sceneEnded;
diff --git a/include/wine/wined3d_gl.h b/include/wine/wined3d_gl.h
index 1a589a5..d570d8c 100644
--- a/include/wine/wined3d_gl.h
+++ b/include/wine/wined3d_gl.h
@@ -1023,6 +1023,7 @@ #define GL_HILO8_NV                     
 #define GL_SIGNED_HILO8_NV                0x885F
 #define GL_FORCE_BLUE_TO_ONE_NV           0x8860
 #endif
+
 /* GL_ATI_texture_env_combine3 */
 #ifndef GL_ATI_texture_env_combine3
 #define GL_ATI_texture_env_combine3 1
-- 
1.4.1



More information about the wine-devel mailing list