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