From 75e91fa4098c80fa390e3c3f8231e2ef69a659d0 Mon Sep 17 00:00:00 2001 From: "H. Verbeet" Date: Mon, 9 Apr 2007 01:54:07 +0200 Subject: [PATCH] wined3d: Use the framebuffer blit extension to implement StretchRect. --- dlls/wined3d/device.c | 77 ++++++++++++++++++++++++++++++++++ dlls/wined3d/surface.c | 12 ++++-- dlls/wined3d/wined3d_private.h | 5 +++ 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 506b61c424..580fcd0d31 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -181,6 +181,12 @@ static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) { if (This->fbo) { GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo)); } + if (This->src_fbo) { + GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo)); + } + if (This->dst_fbo) { + GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo)); + } HeapFree(GetProcessHeap(), 0, This->render_targets); HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments); @@ -5242,6 +5248,77 @@ void apply_fbo_state(IWineD3DDevice *iface) { check_fbo_status(iface); } +static BOOL is_onscreen(IWineD3DSurface *target) { + HRESULT hr; + void *tmp; + + hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, &tmp); + if (SUCCEEDED(hr)) { + IWineD3DSwapChain_Release((IUnknown *)tmp); + return TRUE; + } + + return FALSE; +} + +void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, const WINED3DRECT *src_rect, + IWineD3DSurface *dst_surface, const WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */ + GLenum gl_filter; + + TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x)\n", + This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter); + + switch (filter) { + case WINED3DTEXF_LINEAR: + gl_filter = GL_LINEAR; + break; + + default: + FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter); + case WINED3DTEXF_NONE: + case WINED3DTEXF_POINT: + gl_filter = GL_NEAREST; + break; + } + + /* Attach src surface to src fbo */ + if (is_onscreen(src_surface)) { + GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0)); + flip = !flip; + } else { + IWineD3DSurface_PreLoad(src_surface); + bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo); + attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface); + } + + /* Attach dst surface to dst fbo */ + if (is_onscreen(dst_surface)) { + GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0)); + flip = !flip; + } else { + IWineD3DSurface_PreLoad(dst_surface); + bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo); + attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface); + } + + if (flip) { + GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2, + dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter)); + } else { + GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2, + dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter)); + } + + if (This->render_offscreen) { + bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo); + } else { + GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); + checkGLcall("glBindFramebuffer()"); + } +} + static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; WINED3DVIEWPORT viewport; diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 34b8e5b8d9..e846b18e97 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -2759,8 +2759,7 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT * } /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot - * flip the image nor scale it. If GL_EXT_framebuffer_blit is available it can be used(hopefully, - * not implemented by now). Otherwise: + * flip the image nor scale it. * * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call * -> If the app wants a image width an unscaled width, copy it line per line @@ -2769,9 +2768,14 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT * * back buffer. This is slower than reading line per line, thus not used for flipping * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied * pixel by pixel + * + * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies + * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering + * backends. */ - if(FALSE /* GL_SUPPORT(EXT_FRAMEBUFFER_BLIT) */) { - TRACE("Using GL_EXT_framebuffer_blit for copying\n"); + if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && GL_SUPPORT(EXT_FRAMEBUFFER_BLIT)) { + stretch_rect_fbo((IWineD3DDevice *)myDevice, SrcSurface, &srect, + (IWineD3DSurface *)This, &rect, Filter, upsideDown); } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width || rect.y2 - rect.y1 > Src->currentDesc.Height) { TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n"); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 65cd3458e6..d0da532559 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -674,6 +674,8 @@ struct IWineD3DDeviceImpl BOOL render_offscreen; WINED3D_DEPTHCOPYSTATE depth_copy_state; GLuint fbo; + GLuint src_fbo; + GLuint dst_fbo; GLenum *draw_buffers; /* Cursor management */ @@ -1969,4 +1971,7 @@ static inline BOOL use_ps(IWineD3DDeviceImpl *device) { && ((IWineD3DPixelShaderImpl *)device->stateBlock->pixelShader)->baseShader.function); } +void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, const WINED3DRECT *src_rect, + IWineD3DSurface *dst_surface, const WINED3DRECT *dst_rect, WINED3DTEXTUREFILTERTYPE filter, BOOL flip); + #endif