On Wed, Mar 24, 2010 at 1:19 PM, Henri Verbeet <hverb...@gmail.com> wrote: > On 24 March 2010 12:53, Roderick Colenbrander <thunderbir...@gmail.com> wrote: >> Now back to the blitter design. Henri's proposal is to have several >> blitters for this discussion reduce it to shader_blit and cpu_blit. >> The cpu_blit would be the software fall back for a blit, colorfill or >> whatever operation. > It's not necessarily a fallback, it's certainly possible that if e.g. > both surfaces are in sysmem doing the blit on the CPU is going to be > faster than doing a upload/blit/download sequence. (Which is only > allowed because we're sloppy about resource pools in the first place.) > A sysmem->GPU blit is essentially just an upload with an appropriate > buffer, format flags, etc. There's also the possibility for e.g. an > SSE based implementation, behind proper capability checking. > >> A potential (but perhaps ugly) design of a cpu >> fallback, could be to just call IWineD3DBaseSurface. A more drastic >> approach would basically be to kill the IWineD3DBaseSurface fallbacks >> and have ONE Blt and BltFast in surface.c which would just fall back >> to software when OpenGL isn't around. What do you think? >> > Calling IWineD3DBaseSurface is probably good enough for a start. I'd > probably start with identifying the different blit functions inside > BltOverride() and the logic for selecting them. Then you can separate > those into functions, after which you can create separate blitter > implementations. Once we have those we can work on cleaning up > individual implementations, selection logic, etc. >
I have experimented a bit with the design (intially only color fill since that's quite independent). Note this is just a proof of concept (some of the helper functions would become separate patches). This patch is the current code in the new form. In a later stage an FBO blit_shader can be added which can call the FBO based color fill but that's quite easy to extend later on. At this point no context setup is needed since the helpers already do that but after this is all over, they could be moved over to this framework to make it a bit nicer. Roderick
diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index da8072c..f215cf7 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -6848,12 +6848,24 @@ static BOOL arbfp_blit_color_fixup_supported(const struct wined3d_gl_info *gl_in } } +static BOOL arbfp_blit_can_blit(blit_operation op, IWineD3DSurfaceImpl *src_surface, IWineD3DSurfaceImpl *dst_surface) +{ + ERR("op=%d\n", op); + switch(op) + { + default: + return FALSE; + } +} + const struct blit_shader arbfp_blit = { arbfp_blit_alloc, arbfp_blit_free, arbfp_blit_set, arbfp_blit_unset, arbfp_blit_color_fixup_supported, + arbfp_blit_can_blit, + NULL }; #undef GLINFO_LOCATION diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 5355f51..3647617 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -5495,114 +5495,6 @@ static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, context_release(context); } -static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) { - unsigned int r, g, b, a; - DWORD ret; - - if (destfmt == WINED3DFMT_B8G8R8A8_UNORM - || destfmt == WINED3DFMT_B8G8R8X8_UNORM - || destfmt == WINED3DFMT_B8G8R8_UNORM) - return color; - - TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt)); - - a = (color & 0xff000000) >> 24; - r = (color & 0x00ff0000) >> 16; - g = (color & 0x0000ff00) >> 8; - b = (color & 0x000000ff) >> 0; - - switch(destfmt) - { - case WINED3DFMT_B5G6R5_UNORM: - if(r == 0xff && g == 0xff && b == 0xff) return 0xffff; - r = (r * 32) / 256; - g = (g * 64) / 256; - b = (b * 32) / 256; - ret = r << 11; - ret |= g << 5; - ret |= b; - TRACE("Returning %08x\n", ret); - return ret; - - case WINED3DFMT_B5G5R5X1_UNORM: - case WINED3DFMT_B5G5R5A1_UNORM: - a = (a * 2) / 256; - r = (r * 32) / 256; - g = (g * 32) / 256; - b = (b * 32) / 256; - ret = a << 15; - ret |= r << 10; - ret |= g << 5; - ret |= b << 0; - TRACE("Returning %08x\n", ret); - return ret; - - case WINED3DFMT_A8_UNORM: - TRACE("Returning %08x\n", a); - return a; - - case WINED3DFMT_B4G4R4X4_UNORM: - case WINED3DFMT_B4G4R4A4_UNORM: - a = (a * 16) / 256; - r = (r * 16) / 256; - g = (g * 16) / 256; - b = (b * 16) / 256; - ret = a << 12; - ret |= r << 8; - ret |= g << 4; - ret |= b << 0; - TRACE("Returning %08x\n", ret); - return ret; - - case WINED3DFMT_B2G3R3_UNORM: - r = (r * 8) / 256; - g = (g * 8) / 256; - b = (b * 4) / 256; - ret = r << 5; - ret |= g << 2; - ret |= b << 0; - TRACE("Returning %08x\n", ret); - return ret; - - case WINED3DFMT_R8G8B8X8_UNORM: - case WINED3DFMT_R8G8B8A8_UNORM: - ret = a << 24; - ret |= b << 16; - ret |= g << 8; - ret |= r << 0; - TRACE("Returning %08x\n", ret); - return ret; - - case WINED3DFMT_B10G10R10A2_UNORM: - a = (a * 4) / 256; - r = (r * 1024) / 256; - g = (g * 1024) / 256; - b = (b * 1024) / 256; - ret = a << 30; - ret |= r << 20; - ret |= g << 10; - ret |= b << 0; - TRACE("Returning %08x\n", ret); - return ret; - - case WINED3DFMT_R10G10B10A2_UNORM: - a = (a * 4) / 256; - r = (r * 1024) / 256; - g = (g * 1024) / 256; - b = (b * 1024) / 256; - ret = a << 30; - ret |= b << 20; - ret |= g << 10; - ret |= r << 0; - TRACE("Returning %08x\n", ret); - return ret; - - default: - FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt)); - return 0; - } -} - static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color) { @@ -5624,7 +5516,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, /* Just forward this to the DirectDraw blitting engine */ memset(&BltFx, 0, sizeof(BltFx)); BltFx.dwSize = sizeof(BltFx); - BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format); + BltFx.u5.dwFillColor = color_convert_argb_to_fmt(color, surface->resource.format_desc->format); return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT); } @@ -5672,7 +5564,7 @@ static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *ifac /* Just forward this to the DirectDraw blitting engine */ memset(&BltFx, 0, sizeof(BltFx)); BltFx.dwSize = sizeof(BltFx); - BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format); + BltFx.u5.dwFillColor = color_convert_argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format); hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT); if (FAILED(hr)) { diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 9850731..3d1f3e2 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -3692,6 +3692,24 @@ static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWine IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INTEXTURE, TRUE); } +static const struct blit_shader *blitters[] = +{ + &arbfp_blit, + &ffp_blit, + &cpu_blit +}; + +const struct blit_shader *surface_select_blitter(const struct wined3d_gl_info *gl_info, IWineD3DSurfaceImpl *src, IWineD3DSurfaceImpl *dst, enum blit_operation op) +{ + int i; + for(i=0; i < (sizeof(blitters) / sizeof(blitters[0])); i++) + { + if(blitters[i]->can_blit(op, src, dst)) + return blitters[i]; + } + return NULL; +} + /* Not called from the VTable */ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, const RECT *DestRect, IWineD3DSurface *SrcSurface, const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, @@ -4126,6 +4144,8 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, const return WINED3D_OK; } else { + + /* Source-Less Blit to render target */ if (Flags & WINEDDBLT_COLORFILL) { /* This is easy to handle for the D3D Device... */ @@ -4133,15 +4153,8 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, const TRACE("Colorfill\n"); - /* This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0] || dstSwapchain - must be true if we are here */ - if (This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0] && - !(This == (IWineD3DSurfaceImpl*) dstSwapchain->frontBuffer || - (dstSwapchain->backBuffer && This == (IWineD3DSurfaceImpl*) dstSwapchain->backBuffer[0]))) { - TRACE("Surface is higher back buffer, falling back to software\n"); - return WINED3DERR_INVALIDCALL; - } - +//this should become a helper function; I'm not that happy it relies on a surface which is mostly because of 8-bit else it could be the inverse of utils.c color_convert_argb_to_fmt +//<surface_convert_color_to_argb> /* The color as given in the Blt function is in the format of the frame-buffer... * 'clear' expect it in ARGB format => we need to do some conversion :-) */ @@ -4185,11 +4198,12 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, const ERR("Wrong surface type for BLT override(Format doesn't match) !\n"); return WINED3DERR_INVALIDCALL; } +//</surface_convert_color_to_argb> - TRACE("(%p) executing Render Target override, color = %x\n", This, color); - IWineD3DDeviceImpl_ClearSurface(myDevice, This, 1 /* Number of rectangles */, - &rect, WINED3DCLEAR_TARGET, color, 0.0f /* Z */, 0 /* Stencil */); - return WINED3D_OK; + const struct blit_shader *blitter = surface_select_blitter(&myDevice->adapter->gl_info, NULL, This, BLIT_OP_COLOR_FILL); + + //again RECT or WINED3DRECT? + return blitter->color_fill(myDevice, This, (RECT*)&rect, color); } } @@ -5225,10 +5239,81 @@ static BOOL ffp_blit_color_fixup_supported(const struct wined3d_gl_info *gl_info return FALSE; } +static BOOL ffp_blit_can_blit(blit_operation op, IWineD3DSurfaceImpl *src_surface, IWineD3DSurfaceImpl *dst_surface) +{ + IWineD3DDeviceImpl *device = dst_surface->resource.device; + IWineD3DSwapChainImpl *dst_swapchain; + + TRACE("op=%d\n", op); + + IWineD3DSurface_GetContainer((IWineD3DSurface*)dst_surface, &IID_IWineD3DSwapChain, (void **)&dst_swapchain); + if(dst_swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dst_swapchain); + + switch(op) + { + case BLIT_OP_COLOR_FILL: + { + /* We can only handle the case where the surface is the primary render target OR + * if it is the front or back buffer on the swapchain. + */ + if ((IWineD3DSurface*)dst_surface != device->render_targets[0] && + !((IWineD3DSurface*)dst_surface == dst_swapchain->frontBuffer || + (dst_swapchain->backBuffer && (IWineD3DSurface*)dst_surface == dst_swapchain->backBuffer[0]))) + return FALSE; + else + return TRUE; + } + break; + + default: + return FALSE; + } +} + +static HRESULT ffp_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect, DWORD fill_color) +{ +//what to do regarding RECT / WINED3DRECT? cast or a helper function? + return IWineD3DDeviceImpl_ClearSurface(device, dst_surface, 1 /* Number of rectangles */, + dst_rect, WINED3DCLEAR_TARGET, fill_color, 0.0f /* Z */, 0 /* Stencil */); +} + const struct blit_shader ffp_blit = { ffp_blit_alloc, ffp_blit_free, ffp_blit_set, ffp_blit_unset, - ffp_blit_color_fixup_supported + ffp_blit_color_fixup_supported, + ffp_blit_can_blit, + ffp_blit_color_fill }; + +static BOOL cpu_blit_can_blit(blit_operation op, IWineD3DSurfaceImpl *src_surface, IWineD3DSurfaceImpl *dst_surface) +{ + TRACE("op=%d\n", op); + /* In the future we should be able to do everything for now only color filling */ + switch(op) + { + case BLIT_OP_COLOR_FILL: + return TRUE; + default: + return FALSE; + } +} + +static HRESULT cpu_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect, DWORD fill_color) +{ + WINEDDBLTFX BltFx; + memset(&BltFx, 0, sizeof(BltFx)); + BltFx.dwSize = sizeof(BltFx); + BltFx.u5.dwFillColor = color_convert_argb_to_fmt(fill_color, dst_surface->resource.format_desc->format); + return IWineD3DBaseSurfaceImpl_Blt((IWineD3DSurface*)dst_surface, dst_rect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT); +} + +const struct blit_shader cpu_blit = { + NULL, /* alloc_private */ + NULL, /* free_private */ + NULL, /* set_shader */ + NULL, /* unset_shader */ + NULL, /* color_fixup_supported */ + cpu_blit_can_blit, + cpu_blit_color_fill +}; \ No newline at end of file diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 5c8747b..f0fc46f 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -2193,6 +2193,115 @@ BOOL getDepthStencilBits(const struct wined3d_format_desc *format_desc, short *d return TRUE; } +DWORD color_convert_argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) +{ + unsigned int r, g, b, a; + DWORD ret; + + if (destfmt == WINED3DFMT_B8G8R8A8_UNORM + || destfmt == WINED3DFMT_B8G8R8X8_UNORM + || destfmt == WINED3DFMT_B8G8R8_UNORM) + return color; + + TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt)); + + a = (color & 0xff000000) >> 24; + r = (color & 0x00ff0000) >> 16; + g = (color & 0x0000ff00) >> 8; + b = (color & 0x000000ff) >> 0; + + switch(destfmt) + { + case WINED3DFMT_B5G6R5_UNORM: + if(r == 0xff && g == 0xff && b == 0xff) return 0xffff; + r = (r * 32) / 256; + g = (g * 64) / 256; + b = (b * 32) / 256; + ret = r << 11; + ret |= g << 5; + ret |= b; + TRACE("Returning %08x\n", ret); + return ret; + + case WINED3DFMT_B5G5R5X1_UNORM: + case WINED3DFMT_B5G5R5A1_UNORM: + a = (a * 2) / 256; + r = (r * 32) / 256; + g = (g * 32) / 256; + b = (b * 32) / 256; + ret = a << 15; + ret |= r << 10; + ret |= g << 5; + ret |= b << 0; + TRACE("Returning %08x\n", ret); + return ret; + + case WINED3DFMT_A8_UNORM: + TRACE("Returning %08x\n", a); + return a; + + case WINED3DFMT_B4G4R4X4_UNORM: + case WINED3DFMT_B4G4R4A4_UNORM: + a = (a * 16) / 256; + r = (r * 16) / 256; + g = (g * 16) / 256; + b = (b * 16) / 256; + ret = a << 12; + ret |= r << 8; + ret |= g << 4; + ret |= b << 0; + TRACE("Returning %08x\n", ret); + return ret; + + case WINED3DFMT_B2G3R3_UNORM: + r = (r * 8) / 256; + g = (g * 8) / 256; + b = (b * 4) / 256; + ret = r << 5; + ret |= g << 2; + ret |= b << 0; + TRACE("Returning %08x\n", ret); + return ret; + + case WINED3DFMT_R8G8B8X8_UNORM: + case WINED3DFMT_R8G8B8A8_UNORM: + ret = a << 24; + ret |= b << 16; + ret |= g << 8; + ret |= r << 0; + TRACE("Returning %08x\n", ret); + return ret; + + case WINED3DFMT_B10G10R10A2_UNORM: + a = (a * 4) / 256; + r = (r * 1024) / 256; + g = (g * 1024) / 256; + b = (b * 1024) / 256; + ret = a << 30; + ret |= r << 20; + ret |= g << 10; + ret |= b << 0; + TRACE("Returning %08x\n", ret); + return ret; + + case WINED3DFMT_R10G10B10A2_UNORM: + a = (a * 4) / 256; + r = (r * 1024) / 256; + g = (g * 1024) / 256; + b = (b * 1024) / 256; + ret = a << 30; + ret |= b << 20; + ret |= g << 10; + ret |= r << 0; + TRACE("Returning %08x\n", ret); + return ret; + + default: + FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt)); + return 0; + } +} + /* DirectDraw stuff */ WINED3DFORMAT pixelformat_for_depth(DWORD depth) { switch(depth) { diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index db063dc..c80eadf 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1162,6 +1162,13 @@ HRESULT compile_state_table(struct StateEntry *StateTable, APPLYSTATEFUNC **dev_ const struct wined3d_gl_info *gl_info, const struct StateEntryTemplate *vertex, const struct fragment_pipeline *fragment, const struct StateEntryTemplate *misc) DECLSPEC_HIDDEN; +typedef enum blit_operation +{ + BLIT_OP_COLOR_FILL=1, + BLIT_OP_BLIT_SYSMEM_TO_DRAWABLE=2, + BLIT_OP_BLIT_DRAWABLE_TO_TEXTURE=3 +} blit_operation; + /* Shaders for color conversions in blits */ struct blit_shader { @@ -1171,10 +1178,13 @@ struct blit_shader GLenum textype, UINT width, UINT height); void (*unset_shader)(IWineD3DDevice *iface); BOOL (*color_fixup_supported)(const struct wined3d_gl_info *gl_info, struct color_fixup_desc fixup); + BOOL (*can_blit)(blit_operation op, IWineD3DSurfaceImpl *src_surface, IWineD3DSurfaceImpl *dst_surface); + HRESULT (*color_fill)(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect, DWORD fill_color); }; extern const struct blit_shader ffp_blit DECLSPEC_HIDDEN; extern const struct blit_shader arbfp_blit DECLSPEC_HIDDEN; +extern const struct blit_shader cpu_blit DECLSPEC_HIDDEN; typedef enum ContextUsage { CTXUSAGE_RESOURCELOAD = 1, /* Only loads textures: No State is applied */ @@ -2616,6 +2626,9 @@ const char *debug_d3dtop(WINED3DTEXTUREOP d3dtop) DECLSPEC_HIDDEN; void dump_color_fixup_desc(struct color_fixup_desc fixup) DECLSPEC_HIDDEN; const char *debug_surflocation(DWORD flag) DECLSPEC_HIDDEN; +/* Color conversion routines */ +DWORD color_convert_argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) DECLSPEC_HIDDEN; + /* Routines for GL <-> D3D values */ GLenum StencilOp(DWORD op) DECLSPEC_HIDDEN; GLenum CompareFunc(DWORD func) DECLSPEC_HIDDEN;