H. Verbeet : wined3d: Use the framebuffer blit extension to implement StretchRect.

Alexandre Julliard julliard at wine.codeweavers.com
Mon Apr 9 07:36:07 CDT 2007


Module: wine
Branch: master
Commit: 75e91fa4098c80fa390e3c3f8231e2ef69a659d0
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=75e91fa4098c80fa390e3c3f8231e2ef69a659d0

Author: H. Verbeet <hverbeet at gmail.com>
Date:   Mon Apr  9 01:54:07 2007 +0200

wined3d: Use the framebuffer blit extension to implement StretchRect.

---

 dlls/wined3d/device.c          |   77 ++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/surface.c         |   12 ++++--
 dlls/wined3d/wined3d_private.h |    5 +++
 3 files changed, 90 insertions(+), 4 deletions(-)

diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 506b61c..580fcd0 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -181,6 +181,12 @@ static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
         if (This->fbo) {
             GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
         }
+        if (This->src_fbo) {
+            GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
+        }
+        if (This->dst_fbo) {
+            GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
+        }
 
         HeapFree(GetProcessHeap(), 0, This->render_targets);
         HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
@@ -5242,6 +5248,77 @@ void apply_fbo_state(IWineD3DDevice *iface) {
     check_fbo_status(iface);
 }
 
+static BOOL is_onscreen(IWineD3DSurface *target) {
+    HRESULT hr;
+    void *tmp;
+
+    hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, &tmp);
+    if (SUCCEEDED(hr)) {
+        IWineD3DSwapChain_Release((IUnknown *)tmp);
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, const WINED3DRECT *src_rect,
+        IWineD3DSurface *dst_surface, const WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
+    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+    GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
+    GLenum gl_filter;
+
+    TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x)\n",
+            This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter);
+
+    switch (filter) {
+        case WINED3DTEXF_LINEAR:
+            gl_filter = GL_LINEAR;
+            break;
+
+        default:
+            FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
+        case WINED3DTEXF_NONE:
+        case WINED3DTEXF_POINT:
+            gl_filter = GL_NEAREST;
+            break;
+    }
+
+    /* Attach src surface to src fbo */
+    if (is_onscreen(src_surface)) {
+        GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
+        flip = !flip;
+    } else {
+        IWineD3DSurface_PreLoad(src_surface);
+        bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
+        attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
+    }
+
+    /* Attach dst surface to dst fbo */
+    if (is_onscreen(dst_surface)) {
+        GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
+        flip = !flip;
+    } else {
+        IWineD3DSurface_PreLoad(dst_surface);
+        bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
+        attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
+    }
+
+    if (flip) {
+        GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
+                dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
+    } else {
+        GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
+                dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
+    }
+
+    if (This->render_offscreen) {
+        bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
+    } else {
+        GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
+        checkGLcall("glBindFramebuffer()");
+    }
+}
+
 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
     WINED3DVIEWPORT viewport;
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 34b8e5b..e846b18 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -2759,8 +2759,7 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *
         }
 
         /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
-         * flip the image nor scale it. If GL_EXT_framebuffer_blit is available it can be used(hopefully,
-         * not implemented by now). Otherwise:
+         * flip the image nor scale it.
          *
          * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
          * -> If the app wants a image width an unscaled width, copy it line per line
@@ -2769,9 +2768,14 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *
          *    back buffer. This is slower than reading line per line, thus not used for flipping
          * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
          *    pixel by pixel
+         *
+         * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies
+         * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering
+         * backends.
          */
-        if(FALSE /* GL_SUPPORT(EXT_FRAMEBUFFER_BLIT) */) {
-            TRACE("Using GL_EXT_framebuffer_blit for copying\n");
+        if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && GL_SUPPORT(EXT_FRAMEBUFFER_BLIT)) {
+            stretch_rect_fbo((IWineD3DDevice *)myDevice, SrcSurface, &srect,
+                    (IWineD3DSurface *)This, &rect, Filter, upsideDown);
         } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width ||
                                     rect.y2 - rect.y1 > Src->currentDesc.Height) {
             TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 65cd345..d0da532 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -674,6 +674,8 @@ struct IWineD3DDeviceImpl
     BOOL                    render_offscreen;
     WINED3D_DEPTHCOPYSTATE  depth_copy_state;
     GLuint                  fbo;
+    GLuint                  src_fbo;
+    GLuint                  dst_fbo;
     GLenum                  *draw_buffers;
 
     /* Cursor management */
@@ -1969,4 +1971,7 @@ static inline BOOL use_ps(IWineD3DDeviceImpl *device) {
             && ((IWineD3DPixelShaderImpl *)device->stateBlock->pixelShader)->baseShader.function);
 }
 
+void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, const WINED3DRECT *src_rect,
+        IWineD3DSurface *dst_surface, const WINED3DRECT *dst_rect, WINED3DTEXTUREFILTERTYPE filter, BOOL flip);
+
 #endif




More information about the wine-cvs mailing list