[4/5] wined3d: Add FBO support for offscreen rendering

H. Verbeet hverbeet at gmail.com
Fri Nov 17 06:24:00 CST 2006


For now this is still a registry setting, but eventually this should
become the default mode.

Changelog:
  - Add FBO support for offscreen rendering
-------------- next part --------------
---

 dlls/wined3d/device.c          |   69 +++++++++++++++++++++++++++++++++++++++-
 dlls/wined3d/directx.c         |    6 +++
 dlls/wined3d/drawprim.c        |   14 ++++++++
 dlls/wined3d/wined3d_main.c    |    5 +++
 dlls/wined3d/wined3d_private.h |    2 +
 5 files changed, 95 insertions(+), 1 deletions(-)

diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 239d15d..ef0e046 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -5985,7 +5985,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     checkGLcall("glFlush");
 
     TRACE("End Scene\n");
-    if(This->renderTarget != NULL) {
+    /* If we're using FBOs this isn't needed */
+    if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->renderTarget != NULL) {
 
         /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
         IUnknown *targetContainer = NULL;
@@ -6989,6 +6990,66 @@ static HRESULT  WINAPI  IWineD3DDeviceIm
     return WINED3D_OK;
 }
 
+static void bind_fbo(IWineD3DDevice *iface) {
+    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+
+    if (!This->fbo) {
+        GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
+        checkGLcall("glGenFramebuffersEXT()");
+    }
+    GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
+    checkGLcall("glBindFramebuffer()");
+}
+
+/* TODO: Handle stencil attachments */
+static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
+    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+    IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
+
+    bind_fbo(iface);
+
+    if (depth_stencil_impl) {
+        IWineD3DSurface_PreLoad(depth_stencil);
+        glBindTexture (GL_TEXTURE_2D, depth_stencil_impl->glDescription.textureName);
+
+        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(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 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()");
+    }
+
+    if (!This->render_offscreen) {
+        GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
+        checkGLcall("glBindFramebuffer()");
+    }
+}
+
+static void set_render_target_fbo(IWineD3DDevice *iface, IWineD3DSurface *render_target) {
+    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+    IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
+
+    if (This->render_offscreen) {
+        bind_fbo(iface);
+
+        IWineD3DSurface_PreLoad(render_target);
+
+        glBindTexture (GL_TEXTURE_2D, rtimpl->glDescription.textureName);
+        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+        GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, rtimpl->glDescription.textureName, 0));
+        checkGLcall("glFramebufferTexture2DEXT()");
+    } else {
+        GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
+        checkGLcall("glBindFramebuffer()");
+    }
+}
+
 /* internal static helper functions */
 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
                                                 IWineD3DSurface *RenderSurface);
@@ -7040,6 +7101,9 @@ static HRESULT WINAPI IWineD3DDeviceImpl
         implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
         stencil buffer and incure an extra memory overhead */
         hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
+        if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
+            set_render_target_fbo(iface, pRenderTarget);
+        }
     }
 
     if (SUCCEEDED(hr)) {
@@ -7086,6 +7150,9 @@ static HRESULT WINAPI IWineD3DDeviceImpl
         /** TODO: glEnable/glDisable on depth/stencil    depending on
          *   pNewZStencil is NULL and the depth/stencil is enabled in d3d
           **********************************************************/
+        if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
+            set_depth_stencil_fbo(iface, pNewZStencil);
+        }
     }
 
     return hr;
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 00c95cd..368f384 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -791,6 +791,12 @@ #undef USE_GL_FUNC
         wined3d_settings.nonpower2_mode = NP2_NONE;
     }
 
+    /* We can only use ORM_FBO when the hardware supports it. */
+    if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && !gl_info->supported[EXT_FRAMEBUFFER_OBJECT]) {
+        WARN_(d3d_caps)("GL_EXT_framebuffer_object not supported, falling back to PBuffer offscreen rendering mode.\n");
+        wined3d_settings.offscreen_rendering_mode = ORM_PBUFFER;
+    }
+
     /* Below is a list of Nvidia and ATI GPUs. Both vendors have dozens of different GPUs with roughly the same
      * features. In most cases GPUs from a certain family differ in clockspeeds, the amount of video memory and
      * in case of the latest videocards in the number of pixel/vertex pipelines.
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index 0bea61f..4a1bd8e 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -2078,6 +2078,16 @@ static void drawPrimitiveUploadTextures(
     }
 }
 
+static void check_fbo_status(IWineD3DDevice *iface) {
+    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+
+    GLenum status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
+    switch(status) {
+        case GL_FRAMEBUFFER_COMPLETE_EXT: TRACE("FBO complete.\n"); break;
+        default: TRACE("FBO status %#x.\n", status); break;
+    }
+}
+
 /* Routine common to the draw primitive and draw indexed primitive routines */
 void drawPrimitive(IWineD3DDevice *iface,
                    int PrimitiveType,
@@ -2101,6 +2111,10 @@ void drawPrimitive(IWineD3DDevice *iface
 
     BOOL lighting_changed, lighting_original = FALSE;
 
+    if (TRACE_ON(d3d_draw) && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
+        check_fbo_status(iface);
+    }
+
     /* 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 && 
diff --git a/dlls/wined3d/wined3d_main.c b/dlls/wined3d/wined3d_main.c
index e339815..a3fc80b 100644
--- a/dlls/wined3d/wined3d_main.c
+++ b/dlls/wined3d/wined3d_main.c
@@ -215,6 +215,11 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, 
                     TRACE("Using PBuffers for offscreen rendering\n");
                     wined3d_settings.offscreen_rendering_mode = ORM_PBUFFER;
                 }
+                else if (!strcmp(buffer,"fbo"))
+                {
+                    TRACE("Using FBOs for offscreen rendering\n");
+                    wined3d_settings.offscreen_rendering_mode = ORM_FBO;
+                }
             }
             if ( !get_config_key( hkey, appkey, "RenderTargetLockMode", buffer, size) )
             {
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index b3465a8..6a4894c 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -137,6 +137,7 @@ #define NP2_NATIVE 2
 
 #define ORM_BACKBUFFER  0
 #define ORM_PBUFFER     1
+#define ORM_FBO         2
 
 #define SHADER_SW   0
 #define SHADER_ARB  1
@@ -550,6 +551,7 @@ #define                         NEEDS_DI
 
     /* For rendering to a texture using glCopyTexImage */
     BOOL                    render_offscreen;
+    GLuint                  fbo;
 
     /* Cursor management */
     BOOL                    bCursorVisible;


More information about the wine-patches mailing list