From acfe7545a9425483875412e89f9824f90e4542a3 Mon Sep 17 00:00:00 2001 From: Allan Tong Date: Sat, 15 Dec 2007 12:55:11 -0500 Subject: wined3d: Make FBO draw buffer selection in ActivateContext. --- dlls/wined3d/context.c | 69 ++++++++++++++++++++++++++++++++++++--- dlls/wined3d/device.c | 8 +--- dlls/wined3d/drawprim.c | 6 --- dlls/wined3d/wined3d_private.h | 3 ++ 4 files changed, 68 insertions(+), 18 deletions(-) diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c index 140ae6f..1a47513 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -893,15 +893,72 @@ void ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, ContextU /* We only need ENTER_GL for the gl calls made below and for the helper functions which make GL calls */ ENTER_GL(); - /* Select the right draw buffer. It is selected in FindContext. */ - if(drawBuffer && context->last_draw_buffer != drawBuffer) { - TRACE("Drawing to buffer: %#x\n", drawBuffer); - context->last_draw_buffer = drawBuffer; - glDrawBuffer(drawBuffer); - checkGLcall("glDrawBuffer"); + if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) { + /* Select the right draw buffer. It is selected in FindContext. */ + if(drawBuffer && context->last_draw_buffer != drawBuffer) { + TRACE("Drawing to buffer: %#x\n", drawBuffer); + context->last_draw_buffer = drawBuffer; + + glDrawBuffer(drawBuffer); + checkGLcall("glDrawBuffer"); + } + } else { + if (!This->render_offscreen) { + /* Onscreen rendering with ORM_FBO */ + + if(drawBuffer && context->last_draw_buffer != drawBuffer) { + TRACE("Drawing to buffer: %#x\n", drawBuffer); + context->last_draw_buffer = drawBuffer; + + GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); + glDrawBuffer(drawBuffer); + checkGLcall("glDrawBuffer"); + } + } else { + /* Offscreen FBO rendering */ + + BOOL oldInDraw = This->isInDraw; + + /* Prevent ActivateContext from being called recursively. */ + This->isInDraw = TRUE; + + /* Drawable selection differs depending on the specified context usage. For primitive rendering and + * framebuffer clears, all the device's render targets are selected. Otherwise the draw buffer is + * set to the target surface. The context's last_draw_buffer is used to indicate which path was last + * taken. + */ + switch (usage) { + case CTXUSAGE_RESOURCELOAD: + case CTXUSAGE_BLIT: + if (context->last_target_surface != target || context->last_draw_buffer != GL_COLOR_ATTACHMENT0_EXT) + { + context->last_draw_buffer = GL_COLOR_ATTACHMENT0_EXT; + + bind_fbo((IWineD3DDevice*)This, GL_FRAMEBUFFER_EXT, &This->dst_fbo); + attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, target); + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + checkGLcall("glDrawBuffer()"); + } + break; + + case CTXUSAGE_CLEAR: + case CTXUSAGE_DRAWPRIM: + context->last_draw_buffer = GL_COLOR_ATTACHMENT1_EXT; + + apply_fbo_state((IWineD3DDevice*)This); + break; + + default: + FIXME("Unexpected context usage requested\n"); + } + + This->isInDraw = oldInDraw; + } } + context->last_target_surface = target; + switch(usage) { case CTXUSAGE_RESOURCELOAD: /* This does not require any special states to be set up */ diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index db4c5b4..10125c8 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -4820,10 +4820,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR); ENTER_GL(); - if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) { - apply_fbo_state(iface); - } - /* Only set the values up once, as they are not changing */ if (Flags & WINED3DCLEAR_STENCIL) { glClearStencil(Stencil); @@ -5755,7 +5751,7 @@ static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) { return NULL; } -static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) { +void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; if (!*fbo) { @@ -5766,7 +5762,7 @@ static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) { checkGLcall("glBindFramebuffer()"); } -static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) { +void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) { const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface; IWineD3DBaseTextureImpl *texture_impl; GLenum texttarget, target; diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c index 5b3a2e5..8c78b7d 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -983,12 +983,6 @@ void drawPrimitive(IWineD3DDevice *iface, /* Ok, we will be updating the screen from here onwards so grab the lock */ - if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) { - ENTER_GL(); - apply_fbo_state(iface); - LEAVE_GL(); - } - ActivateContext(This, This->render_targets[0], CTXUSAGE_DRAWPRIM); ENTER_GL(); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 6207162..b09bb41 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -495,6 +495,7 @@ struct WineD3DContext { /* Stores some inforation about the context state for optimization */ GLint last_draw_buffer; + IWineD3DSurface *last_target_surface; BOOL last_was_rhw; /* true iff last draw_primitive was in xyzrhw mode */ BOOL last_was_pshader; BOOL last_was_vshader; @@ -2222,6 +2223,8 @@ static inline BOOL use_ps(IWineD3DDeviceImpl *device) { && ((IWineD3DPixelShaderImpl *)device->stateBlock->pixelShader)->baseShader.function); } +void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo); +void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface); void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect, IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip); -- 1.5.2.5