From 2b8e900ac4f1cfce6b3234967b4931a524114ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Wed, 15 Jan 2014 14:54:12 +0100 Subject: [PATCH] wined3d: Give buffers their own location. --- dlls/wined3d/surface.c | 196 +++++++++++++-------------------- dlls/wined3d/utils.c | 3 +- dlls/wined3d/wined3d_private.h | 15 +-- 3 files changed, 89 insertions(+), 125 deletions(-) diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index ab7bbd6a2d7..3a0d3279a98 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -37,7 +37,7 @@ WINE_DECLARE_DEBUG_CHANNEL(d3d); #define MAXLOCKCOUNT 50 /* After this amount of locks do not free the sysmem copy. */ static const DWORD surface_simple_locations = - SFLAG_INDIB | SFLAG_INUSERMEM | SFLAG_INSYSMEM; + SFLAG_INDIB | SFLAG_INUSERMEM | SFLAG_INSYSMEM | SFLAG_INBUFFER; static void surface_cleanup(struct wined3d_surface *surface) { @@ -508,6 +508,12 @@ static HRESULT surface_create_dib_section(struct wined3d_surface *surface) static void surface_get_memory(const struct wined3d_surface *surface, struct wined3d_bo_address *data, DWORD location) { + if (location & SFLAG_INBUFFER) + { + data->addr = NULL; + data->buffer_object = surface->pbo; + return; + } if (location & SFLAG_INUSERMEM) { data->addr = surface->user_memory; @@ -522,12 +528,6 @@ static void surface_get_memory(const struct wined3d_surface *surface, struct win } if (location & SFLAG_INSYSMEM) { - if (surface->pbo) - { - data->addr = NULL; - data->buffer_object = surface->pbo; - return; - } data->addr = surface->resource.heap_memory; data->buffer_object = 0; return; @@ -538,14 +538,17 @@ static void surface_get_memory(const struct wined3d_surface *surface, struct win data->buffer_object = 0; } -static void surface_create_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info) +static void surface_prepare_buffer(struct wined3d_surface *surface) { struct wined3d_context *context; GLenum error; - struct wined3d_bo_address data; - surface_get_memory(surface, &data, SFLAG_INSYSMEM); + const struct wined3d_gl_info *gl_info; + + if (surface->pbo) + return; context = context_acquire(surface->resource.device, NULL); + gl_info = context->gl_info; GL_EXTCALL(glGenBuffersARB(1, &surface->pbo)); error = gl_info->gl_ops.gl.p_glGetError(); @@ -558,37 +561,29 @@ static void surface_create_pbo(struct wined3d_surface *surface, const struct win checkGLcall("glBindBufferARB"); GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->resource.size + 4, - data.addr, GL_STREAM_DRAW_ARB)); + NULL, GL_STREAM_DRAW_ARB)); checkGLcall("glBufferDataARB"); GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); checkGLcall("glBindBufferARB"); - /* We don't need the system memory anymore and we can't even use it for PBOs. */ - if (!(surface->flags & SFLAG_CLIENT)) - wined3d_resource_free_sysmem(&surface->resource); - surface->map_binding = SFLAG_INSYSMEM; context_release(context); } static void surface_prepare_system_memory(struct wined3d_surface *surface) { - const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info; - TRACE("surface %p.\n", surface); - if (!surface->pbo && surface->flags & SFLAG_PBO) - surface_create_pbo(surface, gl_info); - else if (!(surface->resource.heap_memory || surface->pbo)) - { - /* Whatever surface we have, make sure that there is memory allocated - * for the downloaded copy, or a PBO to map. */ - if (!wined3d_resource_allocate_sysmem(&surface->resource)) - ERR("Failed to allocate system memory.\n"); + if (surface->resource.heap_memory) + return; - if (surface->flags & SFLAG_INSYSMEM) - ERR("Surface without memory or PBO has SFLAG_INSYSMEM set.\n"); - } + /* Whatever surface we have, make sure that there is memory allocated + * for the downloaded copy, or a PBO to map. */ + if (!wined3d_resource_allocate_sysmem(&surface->resource)) + ERR("Failed to allocate system memory.\n"); + + if (surface->flags & SFLAG_INSYSMEM) + ERR("Surface without system memory has SFLAG_INSYSMEM set.\n"); } void surface_prepare_map_memory(struct wined3d_surface *surface) @@ -608,6 +603,10 @@ void surface_prepare_map_memory(struct wined3d_surface *surface) surface_prepare_system_memory(surface); break; + case SFLAG_INBUFFER: + surface_prepare_buffer(surface); + break; + default: ERR("Unexpected map binding %s.\n", debug_surflocation(surface->map_binding)); } @@ -616,7 +615,7 @@ void surface_prepare_map_memory(struct wined3d_surface *surface) static void surface_evict_sysmem(struct wined3d_surface *surface) { if (surface->resource.map_count || (surface->flags & SFLAG_DONOTFREE) - || surface->user_memory || surface->pbo) + || surface->user_memory) return; wined3d_resource_free_sysmem(&surface->resource); @@ -751,7 +750,7 @@ static HRESULT surface_private_setup(struct wined3d_surface *surface) surface->flags |= SFLAG_DISCARDED; if (surface_use_pbo(surface)) - surface->flags |= SFLAG_PBO; + surface->map_binding = SFLAG_INBUFFER; return WINED3D_OK; } @@ -814,6 +813,9 @@ static void surface_realize_palette(struct wined3d_surface *surface) static BYTE *surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD flags) { struct wined3d_device *device = surface->resource.device; + BYTE *ret; + const struct wined3d_gl_info *gl_info; + struct wined3d_context *context; TRACE("surface %p, rect %s, flags %#x.\n", surface, wine_dbgstr_rect(rect), flags); @@ -826,31 +828,19 @@ static BYTE *surface_map(struct wined3d_surface *surface, const RECT *rect, DWOR case SFLAG_INDIB: return surface->dib.bitmap_data; + case SFLAG_INBUFFER: + context = context_acquire(device, NULL); + gl_info = context->gl_info; + + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo)); + ret = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB)); + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); + checkGLcall("map PBO"); + + context_release(context); + return ret; + case SFLAG_INSYSMEM: - if (surface->pbo) - { - BYTE *ret; - const struct wined3d_gl_info *gl_info; - struct wined3d_context *context; - - context = context_acquire(device, NULL); - gl_info = context->gl_info; - - GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo)); - checkGLcall("glBindBufferARB"); - - ret = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB)); - checkGLcall("glMapBufferARB"); - - /* Make sure the PBO isn't set anymore in order not to break non-PBO - * calls. */ - GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); - checkGLcall("glBindBufferARB"); - - context_release(context); - return ret; - } - return surface->resource.heap_memory; default: @@ -862,6 +852,8 @@ static BYTE *surface_map(struct wined3d_surface *surface, const RECT *rect, DWOR static void surface_unmap(struct wined3d_surface *surface) { struct wined3d_device *device = surface->resource.device; + const struct wined3d_gl_info *gl_info; + struct wined3d_context *context; TRACE("surface %p.\n", surface); @@ -870,28 +862,19 @@ static void surface_unmap(struct wined3d_surface *surface) switch (surface->map_binding) { case SFLAG_INUSERMEM: - break; - case SFLAG_INDIB: + case SFLAG_INSYSMEM: break; - case SFLAG_INSYSMEM: - if (surface->pbo) - { - const struct wined3d_gl_info *gl_info; - struct wined3d_context *context; + case SFLAG_INBUFFER: + context = context_acquire(device, NULL); + gl_info = context->gl_info; - TRACE("Freeing PBO memory.\n"); - - context = context_acquire(device, NULL); - gl_info = context->gl_info; - - GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo)); - GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB)); - GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); - checkGLcall("glUnmapBufferARB"); - context_release(context); - } + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo)); + GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB)); + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); + checkGLcall("glUnmapBufferARB"); + context_release(context); break; default: @@ -1306,38 +1289,11 @@ HRESULT CDECL wined3d_surface_get_render_target_data(struct wined3d_surface *sur /* Context activation is done by the caller. */ static void surface_remove_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info) { - void *dst; - - if (surface->flags & SFLAG_DIBSECTION) - { - surface->map_binding = SFLAG_INDIB; - dst = surface->dib.bitmap_data; - if (surface->flags & SFLAG_INSYSMEM) - { - surface_invalidate_location(surface, SFLAG_INSYSMEM); - surface_validate_location(surface, SFLAG_INDIB); - } - } - else - { - if (!surface->resource.heap_memory) - wined3d_resource_allocate_sysmem(&surface->resource); - else if (!(surface->flags & SFLAG_CLIENT)) - ERR("Surface %p has heap_memory %p and flags %#x.\n", - surface, surface->resource.heap_memory, surface->flags); - - dst = surface->resource.heap_memory; - } - - GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo)); - checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)"); - GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0, - surface->resource.size, dst)); - checkGLcall("glGetBufferSubDataARB"); GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo)); - checkGLcall("glDeleteBuffersARB"); + checkGLcall("glDeleteBuffersARB(1, &surface->pbo)"); surface->pbo = 0; + surface_invalidate_location(surface, SFLAG_INBUFFER); } static BOOL surface_init_sysmem(struct wined3d_surface *surface) @@ -1378,13 +1334,11 @@ static void surface_unload(struct wined3d_resource *resource) * Put the surfaces into sysmem, and reset the content. The D3D content is undefined, * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain * or the depth stencil into an FBO the texture or render buffer will be removed - * and all flags get lost - */ - if (!surface->pbo) - { - surface_init_sysmem(surface); - surface_validate_location(surface, surface->map_binding); - } + * and all flags get lost */ + surface_init_sysmem(surface); + surface_validate_location(surface, SFLAG_INSYSMEM); + surface_invalidate_location(surface, ~SFLAG_INSYSMEM); + /* We also get here when the ddraw swapchain is destroyed, for example * for a mode switch. In this case this surface won't necessarily be * an implicit surface. We have to mark it lost so that the @@ -1395,8 +1349,8 @@ static void surface_unload(struct wined3d_resource *resource) { surface_prepare_map_memory(surface); surface_load_location(surface, surface->map_binding); + surface_invalidate_location(surface, ~surface->map_binding); } - surface_invalidate_location(surface, ~surface->map_binding); surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED); context = context_acquire(device, NULL); @@ -2795,8 +2749,8 @@ HRESULT CDECL wined3d_surface_update_desc(struct wined3d_surface *surface, * If the surface didn't use PBOs previously but could now, don't * change it - whatever made us not use PBOs might come back, e.g. * color keys. */ - if (!surface_use_pbo(surface)) - surface->flags &= ~SFLAG_PBO; + if (surface->map_binding == SFLAG_INBUFFER && !surface_use_pbo(surface)) + surface->map_binding = create_dib ? SFLAG_INDIB : SFLAG_INSYSMEM; if (create_dib) { @@ -2809,7 +2763,10 @@ HRESULT CDECL wined3d_surface_update_desc(struct wined3d_surface *surface, if (!surface_init_sysmem(surface)) return E_OUTOFMEMORY; - surface_validate_location(surface, surface->map_binding); + if (surface->map_binding == SFLAG_INBUFFER) + surface_validate_location(surface, SFLAG_INSYSMEM); + else + surface_validate_location(surface, surface->map_binding); return WINED3D_OK; } @@ -4896,6 +4853,7 @@ static DWORD resource_access_from_location(DWORD location) case SFLAG_INSYSMEM: case SFLAG_INUSERMEM: case SFLAG_INDIB: + case SFLAG_INBUFFER: return WINED3D_RESOURCE_ACCESS_CPU; case SFLAG_INDRAWABLE: @@ -5115,8 +5073,15 @@ static HRESULT surface_load_texture(struct wined3d_surface *surface, if ((convert != WINED3D_CT_NONE || format.convert) && surface->pbo) { TRACE("Removing the pbo attached to surface %p.\n", surface); + + if (surface->flags & SFLAG_DIBSECTION) + surface->map_binding = SFLAG_INDIB; + else + surface->map_binding = SFLAG_INSYSMEM; + + surface_prepare_map_memory(surface); + surface_load_location(surface, surface->map_binding); surface_remove_pbo(surface, gl_info); - surface->flags &= ~SFLAG_PBO; } surface_get_memory(surface, &data, surface->flags); @@ -5216,10 +5181,6 @@ HRESULT surface_load_location(struct wined3d_surface *surface, DWORD location) if (surface->flags & location) { TRACE("Location already up to date.\n"); - - if (location == SFLAG_INSYSMEM && !surface->pbo && surface->flags & SFLAG_PBO) - surface_create_pbo(surface, gl_info); - return WINED3D_OK; } @@ -5243,6 +5204,7 @@ HRESULT surface_load_location(struct wined3d_surface *surface, DWORD location) case SFLAG_INDIB: case SFLAG_INUSERMEM: case SFLAG_INSYSMEM: + case SFLAG_INBUFFER: surface_load_sysmem(surface, gl_info, location); break; diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index eb62455db47..986f0c6a21c 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -2795,7 +2795,7 @@ void dump_color_fixup_desc(struct color_fixup_desc fixup) } const char *debug_surflocation(DWORD flag) { - char buf[152]; + char buf[172]; buf[0] = 0; if (flag & SFLAG_INSYSMEM) strcat(buf, " | SFLAG_INSYSMEM"); /* 17 */ @@ -2806,6 +2806,7 @@ const char *debug_surflocation(DWORD flag) { if (flag & SFLAG_INRB_RESOLVED) strcat(buf, " | SFLAG_INRB_RESOLVED"); /* 22 */ if (flag & SFLAG_INUSERMEM) strcat(buf, " | SFLAG_INUSERMEM"); /* 18 */ if (flag & SFLAG_INDIB) strcat(buf, " | SFLAG_INDIB"); /* 14 */ + if (flag & SFLAG_INBUFFER) strcat(buf, " | SFLAG_INBUFFER"); /* 17 */ return wine_dbg_sprintf("%s", buf[0] ? buf + 3 : "0"); } diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 9d4c39cb689..a206a53147c 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2299,13 +2299,13 @@ void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back) D #define SFLAG_INSYSMEM 0x00002000 /* The system memory copy is current. */ #define SFLAG_INUSERMEM 0x00004000 /* The user memory copy is current. */ #define SFLAG_INDIB 0x00008000 /* The DIB copy is current. */ -#define SFLAG_INTEXTURE 0x00010000 /* The GL texture is current. */ -#define SFLAG_INSRGBTEX 0x00020000 /* The GL sRGB texture is current. */ -#define SFLAG_INDRAWABLE 0x00040000 /* The GL drawable is current. */ -#define SFLAG_INRB_MULTISAMPLE 0x00080000 /* The multisample renderbuffer is current. */ -#define SFLAG_INRB_RESOLVED 0x00100000 /* The resolved renderbuffer is current. */ -#define SFLAG_DISCARDED 0x00200000 /* Surface was discarded, allocating new location is enough. */ -#define SFLAG_PBO 0x00400000 /* Use a PBO for mapping. */ +#define SFLAG_INBUFFER 0x00010000 /* The PBO copy is current. */ +#define SFLAG_INTEXTURE 0x00020000 /* The GL texture is current. */ +#define SFLAG_INSRGBTEX 0x00040000 /* The GL sRGB texture is current. */ +#define SFLAG_INDRAWABLE 0x00080000 /* The GL drawable is current. */ +#define SFLAG_INRB_MULTISAMPLE 0x00100000 /* The multisample renderbuffer is current. */ +#define SFLAG_INRB_RESOLVED 0x00200000 /* The resolved renderbuffer is current. */ +#define SFLAG_DISCARDED 0x00400000 /* Surface was discarded, allocating new location is enough. */ /* In some conditions the surface memory must not be freed: * SFLAG_CONVERTED: Converting the data back would take too long @@ -2320,6 +2320,7 @@ void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back) D #define SFLAG_LOCATIONS (SFLAG_INSYSMEM | \ SFLAG_INUSERMEM | \ SFLAG_INDIB | \ + SFLAG_INBUFFER | \ SFLAG_INTEXTURE | \ SFLAG_INSRGBTEX | \ SFLAG_INDRAWABLE | \