wined3d: Infrastructure to render swapchains to a FBO.

This commit is contained in:
Stefan Dösinger 2009-12-06 17:39:47 +01:00 committed by Alexandre Julliard
parent 2b0271b185
commit 817714912b
5 changed files with 149 additions and 5 deletions

View File

@ -1893,7 +1893,7 @@ static inline struct wined3d_context *FindContext(IWineD3DDeviceImpl *This, IWin
context = findThreadContextForSwapChain(swapchain, tid); context = findThreadContextForSwapChain(swapchain, tid);
old_render_offscreen = context->render_offscreen; 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 /* 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 * 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 * rendering. No context change is needed in that case

View File

@ -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->context[0] = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
swapchain->num_contexts = 1; swapchain->num_contexts = 1;
swapchain->context[0]->render_offscreen = swapchain->render_to_fbo;
create_dummy_textures(This); create_dummy_textures(This);

View File

@ -668,6 +668,10 @@ GLenum surface_get_gl_buffer(IWineD3DSurface *iface, IWineD3DSwapChain *swapchai
TRACE("(%p) : swapchain %p\n", This, swapchain); TRACE("(%p) : swapchain %p\n", This, swapchain);
if (swapchain_impl->backBuffer && swapchain_impl->backBuffer[0] == iface) { 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"); TRACE("Returning GL_BACK\n");
return GL_BACK; return GL_BACK;
} else if (swapchain_impl->frontBuffer == iface) { } else if (swapchain_impl->frontBuffer == iface) {
@ -5129,8 +5133,17 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_DrawOverlay(IWineD3DSurface *iface) {
BOOL surface_is_offscreen(IWineD3DSurface *iface) BOOL surface_is_offscreen(IWineD3DSurface *iface)
{ {
IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) This->container;
return !(This->Flags & SFLAG_SWAPCHAIN); /* 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;
/* If the swapchain is rendered to an FBO, the backbuffer is
* offscreen, otherwise onscreen */
return swapchain->render_to_fbo;
} }
const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl = const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =

View File

@ -95,6 +95,116 @@ static void WINAPI IWineD3DSwapChainImpl_Destroy(IWineD3DSwapChain *iface)
HeapFree(GetProcessHeap(), 0, This); 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) { static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion, DWORD dwFlags) {
IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
struct wined3d_context *context; struct wined3d_context *context;
@ -160,6 +270,22 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CO
IWineD3DSwapChain_SetDestWindowOverride(iface, hDestWindowOverride); 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 */ SwapBuffers(This->context[0]->hdc); /* TODO: cycle through the swapchain buffers */
TRACE("SwapBuffers called, Starting new frame\n"); 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); WINED3DCLEAR_TARGET, 0xff00ffff, 1.0f, 0);
} }
if(((IWineD3DSurfaceImpl *) This->frontBuffer)->Flags & SFLAG_INSYSMEM || if(!This->render_to_fbo &&
((IWineD3DSurfaceImpl *) This->backBuffer[0])->Flags & SFLAG_INSYSMEM ) { ( ((IWineD3DSurfaceImpl *) This->frontBuffer)->Flags & SFLAG_INSYSMEM ||
/* Both memory copies of the surfaces are ok, flip them around too instead of dirtifying */ ((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 *front = (IWineD3DSurfaceImpl *) This->frontBuffer;
IWineD3DSurfaceImpl *back = (IWineD3DSurfaceImpl *) This->backBuffer[0]; IWineD3DSurfaceImpl *back = (IWineD3DSurfaceImpl *) This->backBuffer[0];

View File

@ -2413,6 +2413,7 @@ typedef struct IWineD3DSwapChainImpl
DWORD orig_width, orig_height; DWORD orig_width, orig_height;
WINED3DFORMAT orig_fmt; WINED3DFORMAT orig_fmt;
WINED3DGAMMARAMP orig_gamma; WINED3DGAMMARAMP orig_gamma;
BOOL render_to_fbo;
long prev_time, frames; /* Performance tracking */ long prev_time, frames; /* Performance tracking */
unsigned int vSyncCounter; unsigned int vSyncCounter;