wined3d: Infrastructure to render swapchains to a FBO.
This commit is contained in:
parent
2b0271b185
commit
817714912b
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
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 =
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue