Stefan Dösinger : wined3d: Infrastructure to render swapchains to a FBO.

Alexandre Julliard julliard at winehq.org
Mon Dec 7 10:26:18 CST 2009


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

Author: Stefan Dösinger <stefan at codeweavers.com>
Date:   Sun Dec  6 17:39:47 2009 +0100

wined3d: Infrastructure to render swapchains to a FBO.

---

 dlls/wined3d/context.c         |    2 +-
 dlls/wined3d/device.c          |    1 +
 dlls/wined3d/surface.c         |   15 ++++-
 dlls/wined3d/swapchain.c       |  135 +++++++++++++++++++++++++++++++++++++++-
 dlls/wined3d/wined3d_private.h |    1 +
 5 files changed, 149 insertions(+), 5 deletions(-)

diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 5bd06be..b56890e 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -1893,7 +1893,7 @@ static inline struct wined3d_context *FindContext(IWineD3DDeviceImpl *This, IWin
         context = findThreadContextForSwapChain(swapchain, tid);
 
         old_render_offscreen = context->render_offscreen;
-        context->render_offscreen = FALSE;
+        context->render_offscreen = ((IWineD3DSwapChainImpl *)swapchain)->render_to_fbo;
         /* The context != This->activeContext will catch a NOP context change. This can occur
          * if we are switching back to swapchain rendering in case of FBO or Back Buffer offscreen
          * rendering. No context change is needed in that case
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 5c5f6ed..1f2cdac 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -6683,6 +6683,7 @@ HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *
     }
     swapchain->context[0] = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
     swapchain->num_contexts = 1;
+    swapchain->context[0]->render_offscreen = swapchain->render_to_fbo;
 
     create_dummy_textures(This);
 
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 7c4551b..bd283af 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -668,6 +668,10 @@ GLenum surface_get_gl_buffer(IWineD3DSurface *iface, IWineD3DSwapChain *swapchai
     TRACE("(%p) : swapchain %p\n", This, swapchain);
 
     if (swapchain_impl->backBuffer && swapchain_impl->backBuffer[0] == iface) {
+        if(swapchain_impl->render_to_fbo) {
+            TRACE("Returning GL_COLOR_ATTACHMENT0\n");
+            return GL_COLOR_ATTACHMENT0;
+        }
         TRACE("Returning GL_BACK\n");
         return GL_BACK;
     } else if (swapchain_impl->frontBuffer == iface) {
@@ -5129,8 +5133,17 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_DrawOverlay(IWineD3DSurface *iface) {
 BOOL surface_is_offscreen(IWineD3DSurface *iface)
 {
     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
+    IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) This->container;
+
+    /* Not on a swapchain - must be offscreen */
+    if (!(This->Flags & SFLAG_SWAPCHAIN)) return TRUE;
+
+    /* The front buffer is always onscreen */
+    if(iface == swapchain->frontBuffer) return FALSE;
 
-    return !(This->Flags & SFLAG_SWAPCHAIN);
+    /* If the swapchain is rendered to an FBO, the backbuffer is
+     * offscreen, otherwise onscreen */
+    return swapchain->render_to_fbo;
 }
 
 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c
index a23166a..5b4075d 100644
--- a/dlls/wined3d/swapchain.c
+++ b/dlls/wined3d/swapchain.c
@@ -95,6 +95,116 @@ static void WINAPI IWineD3DSwapChainImpl_Destroy(IWineD3DSwapChain *iface)
     HeapFree(GetProcessHeap(), 0, This);
 }
 
+/* A GL context is provided by the caller */
+static inline void swapchain_blit(IWineD3DSwapChainImpl *This, struct wined3d_context *context)
+{
+    RECT window;
+    IWineD3DDeviceImpl *device = This->wineD3DDevice;
+    IWineD3DSurfaceImpl *backbuffer = ((IWineD3DSurfaceImpl *) This->backBuffer[0]);
+    UINT w = backbuffer->currentDesc.Width;
+    UINT h = backbuffer->currentDesc.Height;
+    GLenum gl_filter;
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+
+    GetClientRect(This->win_handle, &window);
+    if(w == window.right && h == window.bottom) gl_filter = GL_NEAREST;
+    else gl_filter = GL_LINEAR;
+
+    if(gl_info->supported[EXT_FRAMEBUFFER_BLIT])
+    {
+        ENTER_GL();
+        context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
+        context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, This->backBuffer[0]);
+        context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
+
+        context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
+        glDrawBuffer(GL_BACK);
+
+        glDisable(GL_SCISSOR_TEST);
+        IWineD3DDeviceImpl_MarkStateDirty(This->wineD3DDevice, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
+
+        /* Note that the texture is upside down */
+        gl_info->fbo_ops.glBlitFramebuffer(0, 0, w, h,
+                                           window.left, window.bottom, window.right, window.top,
+                                           GL_COLOR_BUFFER_BIT, gl_filter);
+        checkGLcall("Swapchain present blit(EXT_framebuffer_blit)\n");
+        LEAVE_GL();
+    }
+    else
+    {
+        struct wined3d_context *context2;
+        float tex_left = 0;
+        float tex_top = 0;
+        float tex_right = w;
+        float tex_bottom = h;
+
+        context2 = context_acquire(This->wineD3DDevice, This->backBuffer[0], CTXUSAGE_BLIT);
+
+        if(backbuffer->Flags & SFLAG_NORMCOORD)
+        {
+            tex_left /= w;
+            tex_right /= w;
+            tex_top /= h;
+            tex_bottom /= h;
+        }
+
+        ENTER_GL();
+        context_bind_fbo(context2, GL_DRAW_FRAMEBUFFER, NULL);
+
+        /* Set up the texture. The surface is not in a IWineD3D*Texture container,
+         * so there are no d3d texture settings to dirtify
+         */
+        device->blitter->set_shader((IWineD3DDevice *) device, backbuffer->resource.format_desc,
+                                    backbuffer->texture_target, backbuffer->pow2Width,
+                                    backbuffer->pow2Height);
+        glTexParameteri(backbuffer->texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(backbuffer->texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+        glDrawBuffer(GL_BACK);
+
+        /* Set the viewport to the destination rectandle, disable any projection
+         * transformation set up by CTXUSAGE_BLIT, and draw a (-1,-1)-(1,1) quad.
+         *
+         * Back up viewport and matrix to avoid breaking last_was_blit
+         *
+         * Note that CTXUSAGE_BLIT set up viewport and ortho to match the surface
+         * size - we want the GL drawable(=window) size.
+         */
+        glPushAttrib(GL_VIEWPORT_BIT);
+        glViewport(window.left, window.top, window.right, window.bottom);
+        glMatrixMode(GL_PROJECTION);
+        glPushMatrix();
+        glLoadIdentity();
+
+        glBegin(GL_QUADS);
+            /* bottom left */
+            glTexCoord2f(tex_left, tex_bottom);
+            glVertex2i(-1, -1);
+
+            /* top left */
+            glTexCoord2f(tex_left, tex_top);
+            glVertex2i(-1, 1);
+
+            /* top right */
+            glTexCoord2f(tex_right, tex_top);
+            glVertex2i(1, 1);
+
+            /* bottom right */
+            glTexCoord2f(tex_right, tex_bottom);
+            glVertex2i(1, -1);
+        glEnd();
+
+        glPopMatrix();
+        glPopAttrib();
+
+        device->blitter->unset_shader((IWineD3DDevice *) device);
+        checkGLcall("Swapchain present blit(manual)\n");
+        LEAVE_GL();
+
+        context_release(context2);
+    }
+}
+
 static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion, DWORD dwFlags) {
     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
     struct wined3d_context *context;
@@ -160,6 +270,22 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CO
         IWineD3DSwapChain_SetDestWindowOverride(iface, hDestWindowOverride);
     }
 
+    if(This->render_to_fbo)
+    {
+        /* This codepath should only be hit with the COPY swapeffect. Otherwise a backbuffer-
+         * window size mismatch is impossible(fullscreen) and src and dst rectangles are
+         * not allowed(they need the COPY swapeffect)
+         *
+         * The DISCARD swap effect is ok as well since any backbuffer content is allowed after
+         * the swap
+         */
+        if(This->presentParms.SwapEffect == WINED3DSWAPEFFECT_FLIP )
+        {
+            FIXME("Render-to-fbo with WINED3DSWAPEFFECT_FLIP\n");
+        }
+        swapchain_blit(This, context);
+    }
+
     SwapBuffers(This->context[0]->hdc); /* TODO: cycle through the swapchain buffers */
 
     TRACE("SwapBuffers called, Starting new frame\n");
@@ -239,9 +365,12 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CO
                 WINED3DCLEAR_TARGET, 0xff00ffff, 1.0f, 0);
     }
 
-    if(((IWineD3DSurfaceImpl *) This->frontBuffer)->Flags   & SFLAG_INSYSMEM ||
-       ((IWineD3DSurfaceImpl *) This->backBuffer[0])->Flags & SFLAG_INSYSMEM ) {
-        /* Both memory copies of the surfaces are ok, flip them around too instead of dirtifying */
+    if(!This->render_to_fbo &&
+       ( ((IWineD3DSurfaceImpl *) This->frontBuffer)->Flags   & SFLAG_INSYSMEM ||
+         ((IWineD3DSurfaceImpl *) This->backBuffer[0])->Flags & SFLAG_INSYSMEM ) ) {
+        /* Both memory copies of the surfaces are ok, flip them around too instead of dirtifying
+         * Doesn't work with render_to_fbo because we're not flipping
+         */
         IWineD3DSurfaceImpl *front = (IWineD3DSurfaceImpl *) This->frontBuffer;
         IWineD3DSurfaceImpl *back = (IWineD3DSurfaceImpl *) This->backBuffer[0];
 
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 4fb556c..3173d12 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2413,6 +2413,7 @@ typedef struct IWineD3DSwapChainImpl
     DWORD                     orig_width, orig_height;
     WINED3DFORMAT             orig_fmt;
     WINED3DGAMMARAMP          orig_gamma;
+    BOOL                      render_to_fbo;
 
     long prev_time, frames;   /* Performance tracking */
     unsigned int vSyncCounter;




More information about the wine-cvs mailing list