diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index cd2ad97e26f..d59a5e7a4e3 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -5743,138 +5743,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice } } -static BOOL surface_is_full_rect(IWineD3DSurfaceImpl *surface, const RECT *r) -{ - if ((r->left && r->right) || abs(r->right - r->left) != surface->currentDesc.Width) - return FALSE; - if ((r->top && r->bottom) || abs(r->bottom - r->top) != surface->currentDesc.Height) - return FALSE; - return TRUE; -} - -void stretch_rect_fbo(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *src_surface, const RECT *src_rect_in, - IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect_in, const WINED3DTEXTUREFILTERTYPE filter) -{ - GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */ - const struct wined3d_gl_info *gl_info; - struct wined3d_context *context; - GLenum gl_filter; - RECT src_rect, dst_rect; - - TRACE("device %p, src_surface %p, src_rect_in %s, dst_surface %p, dst_rect_in %s, filter %s (0x%08x).\n", - device, src_surface, wine_dbgstr_rect(src_rect_in), dst_surface, - wine_dbgstr_rect(dst_rect_in), debug_d3dtexturefiltertype(filter), filter); - - src_rect = *src_rect_in; - dst_rect = *dst_rect_in; - - 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; - } - - /* Make sure the drawables are up-to-date. Loading the destination - * surface isn't required if the entire surface is overwritten. (And is - * in fact harmful if we're being called by surface_load_location() with - * the purpose of loading the destination surface.) */ - surface_load_location(src_surface, SFLAG_INDRAWABLE, NULL); - if (!surface_is_full_rect(dst_surface, &dst_rect)) - surface_load_location(dst_surface, SFLAG_INDRAWABLE, NULL); - - if (!surface_is_offscreen(src_surface)) context = context_acquire(device, src_surface); - else if (!surface_is_offscreen(dst_surface)) context = context_acquire(device, dst_surface); - else context = context_acquire(device, NULL); - - if (!context->valid) - { - context_release(context); - WARN("Invalid context, skipping blit.\n"); - return; - } - - gl_info = context->gl_info; - - if (!surface_is_offscreen(src_surface)) - { - GLenum buffer = surface_get_gl_buffer(src_surface); - - TRACE("Source surface %p is onscreen\n", src_surface); - - if (buffer == GL_FRONT) - surface_translate_frontbuffer_coords(src_surface, context->win_handle, &src_rect); - - src_rect.top = src_surface->currentDesc.Height - src_rect.top; - src_rect.bottom = src_surface->currentDesc.Height - src_rect.bottom; - - ENTER_GL(); - context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL); - glReadBuffer(buffer); - checkGLcall("glReadBuffer()"); - } else { - TRACE("Source surface %p is offscreen\n", src_surface); - ENTER_GL(); - context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, SFLAG_INTEXTURE); - glReadBuffer(GL_COLOR_ATTACHMENT0); - checkGLcall("glReadBuffer()"); - } - LEAVE_GL(); - - /* Attach dst surface to dst fbo */ - if (!surface_is_offscreen(dst_surface)) - { - GLenum buffer = surface_get_gl_buffer(dst_surface); - - TRACE("Destination surface %p is onscreen\n", dst_surface); - - if (buffer == GL_FRONT) - surface_translate_frontbuffer_coords(dst_surface, context->win_handle, &dst_rect); - - dst_rect.top = dst_surface->currentDesc.Height - dst_rect.top; - dst_rect.bottom = dst_surface->currentDesc.Height - dst_rect.bottom; - - ENTER_GL(); - context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL); - context_set_draw_buffer(context, buffer); - } - else - { - TRACE("Destination surface %p is offscreen\n", dst_surface); - - ENTER_GL(); - context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, SFLAG_INTEXTURE); - context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0); - } - - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE)); - IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1)); - IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2)); - IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3)); - - glDisable(GL_SCISSOR_TEST); - IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE)); - - gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, - dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, mask, gl_filter); - checkGLcall("glBlitFramebuffer()"); - - LEAVE_GL(); - - if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */ - - context_release(context); - - surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE); -} - static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget, BOOL set_viewport) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 995d00c6d54..662cdb89a54 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -3218,6 +3218,147 @@ void surface_translate_frontbuffer_coords(IWineD3DSurfaceImpl *surface, HWND win OffsetRect(rect, offset.x, offset.y); } +static BOOL surface_is_full_rect(IWineD3DSurfaceImpl *surface, const RECT *r) +{ + if ((r->left && r->right) || abs(r->right - r->left) != surface->currentDesc.Width) + return FALSE; + if ((r->top && r->bottom) || abs(r->bottom - r->top) != surface->currentDesc.Height) + return FALSE; + return TRUE; +} + +/* blit between surface locations. onscreen on different swapchains is not supported. + * depth / stencil is not supported. */ +static void surface_blt_fbo(IWineD3DDeviceImpl *device, const WINED3DTEXTUREFILTERTYPE filter, + IWineD3DSurfaceImpl *src_surface, DWORD src_location, const RECT *src_rect_in, + IWineD3DSurfaceImpl *dst_surface, DWORD dst_location, const RECT *dst_rect_in) +{ + const struct wined3d_gl_info *gl_info; + struct wined3d_context *context; + RECT src_rect, dst_rect; + GLenum gl_filter; + + TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter)); + TRACE("src_surface %p, src_location %s, src_rect %s,\n", + src_surface, debug_surflocation(src_location), wine_dbgstr_rect(src_rect_in)); + TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n", + dst_surface, debug_surflocation(dst_location), wine_dbgstr_rect(dst_rect_in)); + + src_rect = *src_rect_in; + dst_rect = *dst_rect_in; + + switch (filter) + { + case WINED3DTEXF_LINEAR: + gl_filter = GL_LINEAR; + break; + + default: + FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter); + case WINED3DTEXF_NONE: + case WINED3DTEXF_POINT: + gl_filter = GL_NEAREST; + break; + } + + if (src_location == SFLAG_INDRAWABLE && surface_is_offscreen(src_surface)) + src_location = SFLAG_INTEXTURE; + if (dst_location == SFLAG_INDRAWABLE && surface_is_offscreen(dst_surface)) + dst_location = SFLAG_INTEXTURE; + + /* Make sure the locations are up-to-date. Loading the destination + * surface isn't required if the entire surface is overwritten. (And is + * in fact harmful if we're being called by surface_load_location() with + * the purpose of loading the destination surface.) */ + surface_load_location(src_surface, src_location, NULL); + if (!surface_is_full_rect(dst_surface, &dst_rect)) + surface_load_location(dst_surface, dst_location, NULL); + + if (src_location == SFLAG_INDRAWABLE) context = context_acquire(device, src_surface); + else if (dst_location == SFLAG_INDRAWABLE) context = context_acquire(device, dst_surface); + else context = context_acquire(device, NULL); + + if (!context->valid) + { + context_release(context); + WARN("Invalid context, skipping blit.\n"); + return; + } + + gl_info = context->gl_info; + + if (src_location == SFLAG_INDRAWABLE) + { + GLenum buffer = surface_get_gl_buffer(src_surface); + + TRACE("Source surface %p is onscreen.\n", src_surface); + + if (buffer == GL_FRONT) + surface_translate_frontbuffer_coords(src_surface, context->win_handle, &src_rect); + + src_rect.top = src_surface->currentDesc.Height - src_rect.top; + src_rect.bottom = src_surface->currentDesc.Height - src_rect.bottom; + + ENTER_GL(); + context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL); + glReadBuffer(buffer); + checkGLcall("glReadBuffer()"); + } + else + { + TRACE("Source surface %p is offscreen.\n", src_surface); + ENTER_GL(); + context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location); + glReadBuffer(GL_COLOR_ATTACHMENT0); + checkGLcall("glReadBuffer()"); + } + LEAVE_GL(); + + if (dst_location == SFLAG_INDRAWABLE) + { + GLenum buffer = surface_get_gl_buffer(dst_surface); + + TRACE("Destination surface %p is onscreen.\n", dst_surface); + + if (buffer == GL_FRONT) + surface_translate_frontbuffer_coords(dst_surface, context->win_handle, &dst_rect); + + dst_rect.top = dst_surface->currentDesc.Height - dst_rect.top; + dst_rect.bottom = dst_surface->currentDesc.Height - dst_rect.bottom; + + ENTER_GL(); + context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL); + context_set_draw_buffer(context, buffer); + } + else + { + TRACE("Destination surface %p is offscreen.\n", dst_surface); + + ENTER_GL(); + context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location); + context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0); + } + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE)); + IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1)); + IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2)); + IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3)); + + glDisable(GL_SCISSOR_TEST); + IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE)); + + gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, + dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter); + checkGLcall("glBlitFramebuffer()"); + + LEAVE_GL(); + + if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */ + + context_release(context); +} + /* Not called from the VTable */ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *dst_surface, const RECT *DestRect, IWineD3DSurfaceImpl *src_surface, const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, @@ -3429,7 +3570,10 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *dst_surface, &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format_desc, &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format_desc)) { - stretch_rect_fbo(device, src_surface, &src_rect, dst_surface, &dst_rect, Filter); + surface_blt_fbo(device, Filter, + src_surface, SFLAG_INDRAWABLE, &src_rect, + dst_surface, SFLAG_INDRAWABLE, &dst_rect); + surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE); } else if (!stretchx || dst_rect.right - dst_rect.left > src_surface->currentDesc.Width || dst_rect.bottom - dst_rect.top > src_surface->currentDesc.Height) @@ -3470,10 +3614,13 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *dst_surface, &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format_desc)) { - TRACE("Using stretch_rect_fbo\n"); + TRACE("Using surface_blt_fbo.\n"); /* The source is always a texture, but never the currently active render target, and the texture * contents are never upside down. */ - stretch_rect_fbo(device, src_surface, &src_rect, dst_surface, &dst_rect, Filter); + surface_blt_fbo(device, Filter, + src_surface, SFLAG_INDRAWABLE, &src_rect, + dst_surface, SFLAG_INDRAWABLE, &dst_rect); + surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE); return WINED3D_OK; } @@ -4206,43 +4353,6 @@ static inline void surface_blt_to_drawable(IWineD3DSurfaceImpl *This, const RECT context_release(context); } -static void surface_load_srgb_fbo(IWineD3DSurfaceImpl *surface, DWORD location) -{ - IWineD3DDeviceImpl *device = surface->resource.device; - const struct wined3d_gl_info *gl_info; - struct wined3d_context *context; - - context = context_acquire(device, NULL); - gl_info = context->gl_info; - - ENTER_GL(); - - context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, surface, NULL, - location == SFLAG_INSRGBTEX ? SFLAG_INTEXTURE : SFLAG_INSRGBTEX); - glReadBuffer(GL_COLOR_ATTACHMENT0); - checkGLcall("glReadBuffer()"); - - context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, surface, NULL, location); - context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0); - - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE)); - IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1)); - IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2)); - IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3)); - - glDisable(GL_SCISSOR_TEST); - IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE)); - - gl_info->fbo_ops.glBlitFramebuffer(0, 0, surface->currentDesc.Width, surface->currentDesc.Height, - 0, 0, surface->currentDesc.Width, surface->currentDesc.Height, GL_COLOR_BUFFER_BIT, GL_NEAREST); - checkGLcall("glBlitFramebuffer()"); - - LEAVE_GL(); - - context_release(context); -} - HRESULT surface_load_location(IWineD3DSurfaceImpl *surface, DWORD flag, const RECT *rect) { IWineD3DDeviceImpl *device = surface->resource.device; @@ -4409,7 +4519,11 @@ HRESULT surface_load_location(IWineD3DSurfaceImpl *surface, DWORD flag, const RE NULL, surface->resource.usage, surface->resource.pool, surface->resource.format_desc, NULL, surface->resource.usage, surface->resource.pool, surface->resource.format_desc)) { - surface_load_srgb_fbo(surface, flag); + DWORD src_location = flag == SFLAG_INSRGBTEX ? SFLAG_INTEXTURE : SFLAG_INSRGBTEX; + RECT rect = {0, 0, surface->currentDesc.Width, surface->currentDesc.Height}; + + surface_blt_fbo(surface->resource.device, WINED3DTEXF_POINT, + surface, src_location, &rect, surface, flag, &rect); } else { diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index fe44eae7f27..77ef661832b 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2993,10 +2993,6 @@ static inline BOOL use_ps(IWineD3DStateBlockImpl *stateblock) return (stateblock->pixelShader && stateblock->device->ps_selected_mode != SHADER_NONE); } -void stretch_rect_fbo(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *src_surface, - const RECT *src_rect, IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect, - const WINED3DTEXTUREFILTERTYPE filter) DECLSPEC_HIDDEN; - /* The WNDCLASS-Name for the fake window which we use to retrieve the GL capabilities */ #define WINED3D_OPENGL_WINDOW_CLASS_NAME "WineD3D_OpenGL"