diff options
-rw-r--r-- | src/gallium/drivers/svga/svga_resource_buffer.c | 13 | ||||
-rw-r--r-- | src/gallium/drivers/svga/svga_resource_buffer.h | 18 | ||||
-rw-r--r-- | src/gallium/drivers/svga/svga_resource_buffer_upload.c | 197 | ||||
-rw-r--r-- | src/gallium/drivers/svga/svga_resource_buffer_upload.h | 16 |
4 files changed, 217 insertions, 27 deletions
diff --git a/src/gallium/drivers/svga/svga_resource_buffer.c b/src/gallium/drivers/svga/svga_resource_buffer.c index 39aa530a672..e9d31de6166 100644 --- a/src/gallium/drivers/svga/svga_resource_buffer.c +++ b/src/gallium/drivers/svga/svga_resource_buffer.c @@ -413,21 +413,26 @@ svga_buffer_create(struct pipe_screen *screen, sbuf->b.b.screen = screen; bind_flags = template->bind; + LIST_INITHEAD(&sbuf->surfaces); + if (bind_flags & PIPE_BIND_CONSTANT_BUFFER) { /* Constant buffers can only have the PIPE_BIND_CONSTANT_BUFFER * flag set. */ if (ss->sws->have_vgpu10) { bind_flags = PIPE_BIND_CONSTANT_BUFFER; - - /* Constant buffer size needs to be in multiples of 16. */ - sbuf->b.b.width0 = align(sbuf->b.b.width0, 16); } } + /* Although svga device only requires constant buffer size to be + * in multiples of 16, in order to allow bind_flags promotion, + * we are mandating all buffer size to be in multiples of 16. + */ + sbuf->b.b.width0 = align(sbuf->b.b.width0, 16); + if (svga_buffer_needs_hw_storage(bind_flags)) { - /* If the buffer will be used for vertex/index/stream data, set + /* If the buffer is not used for constant buffer, set * the vertex/index bind flags as well so that the buffer will be * accepted for those uses. * Note that the PIPE_BIND_ flags we get from the state tracker are diff --git a/src/gallium/drivers/svga/svga_resource_buffer.h b/src/gallium/drivers/svga/svga_resource_buffer.h index 2096a9821cc..db533416ec4 100644 --- a/src/gallium/drivers/svga/svga_resource_buffer.h +++ b/src/gallium/drivers/svga/svga_resource_buffer.h @@ -59,6 +59,18 @@ struct svga_buffer_range struct svga_3d_update_gb_image; /** + * This structure describes the bind flags and cache key associated + * with the host surface. + */ +struct svga_buffer_surface +{ + struct list_head list; + unsigned bind_flags; + struct svga_host_surface_cache_key key; + struct svga_winsys_surface *handle; +}; + +/** * SVGA pipe buffer. */ struct svga_buffer @@ -101,6 +113,12 @@ struct svga_buffer struct svga_winsys_surface *handle; /** + * List of surfaces created for this buffer resource to support + * incompatible bind flags. + */ + struct list_head surfaces; + + /** * Information about ongoing and past map operations. */ struct { diff --git a/src/gallium/drivers/svga/svga_resource_buffer_upload.c b/src/gallium/drivers/svga/svga_resource_buffer_upload.c index d18d026bfa1..d467182f1ca 100644 --- a/src/gallium/drivers/svga/svga_resource_buffer_upload.c +++ b/src/gallium/drivers/svga/svga_resource_buffer_upload.c @@ -148,6 +148,8 @@ svga_buffer_create_host_surface(struct svga_screen *ss, struct svga_buffer *sbuf, unsigned bind_flags) { + enum pipe_error ret = PIPE_OK; + assert(!sbuf->user); if (!sbuf->handle) { @@ -207,9 +209,13 @@ svga_buffer_create_host_surface(struct svga_screen *ss, SVGA_DBG(DEBUG_DMA, " --> got sid %p sz %d (buffer)\n", sbuf->handle, sbuf->b.b.width0); + + /* Add the new surface to the buffer surface list */ + ret = svga_buffer_add_host_surface(sbuf, sbuf->handle, &sbuf->key, + bind_flags); } - return PIPE_OK; + return ret; } @@ -221,23 +227,17 @@ svga_buffer_recreate_host_surface(struct svga_context *svga, struct svga_buffer *sbuf, unsigned bind_flags) { - struct svga_screen *ss = svga_screen(sbuf->b.b.screen); - struct svga_winsys_surface *old_handle; - struct svga_host_surface_cache_key old_key; enum pipe_error ret = PIPE_OK; + struct svga_winsys_surface *old_handle = sbuf->handle; assert(sbuf->bind_flags != bind_flags); + assert(old_handle); - /* Flush any pending upload first */ - svga_buffer_upload_flush(svga, sbuf); - - /* Save the old resource handle and key */ - old_handle = sbuf->handle; - old_key = sbuf->key; sbuf->handle = NULL; - /* Create a new resource with the required bind_flags */ - ret = svga_buffer_create_host_surface(ss, sbuf, bind_flags); + /* Create a new resource with the requested bind_flags */ + ret = svga_buffer_create_host_surface(svga_screen(svga->pipe.screen), + sbuf, bind_flags); if (ret == PIPE_OK) { /* Copy the surface data */ assert(sbuf->handle); @@ -254,20 +254,175 @@ svga_buffer_recreate_host_surface(struct svga_context *svga, /* Set the new bind flags for this buffer resource */ sbuf->bind_flags = bind_flags; - /* Destroy the old resource handle */ - svga_screen_surface_destroy(ss, &old_key, &old_handle); + return ret; +} + + +/** + * Returns TRUE if the surface bind flags is compatible with the new bind flags. + */ +static boolean +compatible_bind_flags(unsigned bind_flags, + unsigned tobind_flags) +{ + if ((bind_flags & tobind_flags) == tobind_flags) + return TRUE; + else if ((bind_flags|tobind_flags) & PIPE_BIND_CONSTANT_BUFFER) + return FALSE; + else + return TRUE; +} + + +/** + * Returns a buffer surface from the surface list + * that has the requested bind flags or its existing bind flags + * can be promoted to include the new bind flags. + */ +static struct svga_buffer_surface * +svga_buffer_get_host_surface(struct svga_buffer *sbuf, + unsigned bind_flags) +{ + struct svga_buffer_surface *bufsurf; + + LIST_FOR_EACH_ENTRY(bufsurf, &sbuf->surfaces, list) { + if (compatible_bind_flags(bufsurf->bind_flags, bind_flags)) + return bufsurf; + } + return NULL; +} + + +/** + * Adds the host surface to the buffer surface list. + */ +enum pipe_error +svga_buffer_add_host_surface(struct svga_buffer *sbuf, + struct svga_winsys_surface *handle, + struct svga_host_surface_cache_key *key, + unsigned bind_flags) +{ + struct svga_buffer_surface *bufsurf; + + bufsurf = CALLOC_STRUCT(svga_buffer_surface); + if (!bufsurf) + return PIPE_ERROR_OUT_OF_MEMORY; + + bufsurf->bind_flags = bind_flags; + bufsurf->handle = handle; + bufsurf->key = *key; + + /* add the surface to the surface list */ + LIST_ADD(&bufsurf->list, &sbuf->surfaces); + + return PIPE_OK; +} + + +/** + * Start using the specified surface for this buffer resource. + */ +void +svga_buffer_bind_host_surface(struct svga_context *svga, + struct svga_buffer *sbuf, + struct svga_buffer_surface *bufsurf) +{ + enum pipe_error ret; + + /* Update the to-bind surface */ + assert(bufsurf->handle); + assert(sbuf->handle); + /* If we are switching from stream output to other buffer, + * make sure to copy the buffer content. + */ + if (sbuf->bind_flags & PIPE_BIND_STREAM_OUTPUT) { + ret = SVGA3D_vgpu10_BufferCopy(svga->swc, sbuf->handle, bufsurf->handle, + 0, 0, sbuf->b.b.width0); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_BufferCopy(svga->swc, sbuf->handle, bufsurf->handle, + 0, 0, sbuf->b.b.width0); + assert(ret == PIPE_OK); + } + } + + /* Set this surface as the current one */ + sbuf->handle = bufsurf->handle; + sbuf->key = bufsurf->key; + sbuf->bind_flags = bufsurf->bind_flags; +} + + +/** + * Prepare a host surface that can be used as indicated in the + * tobind_flags. If the existing host surface is not created + * with the necessary binding flags and if the new bind flags can be + * combined with the existing bind flags, then we will recreate a + * new surface with the combined bind flags. Otherwise, we will create + * a surface for that incompatible bind flags. + * For example, if a stream output buffer is reused as a constant buffer, + * since constant buffer surface cannot be bound as a stream output surface, + * two surfaces will be created, one for stream output, + * and another one for constant buffer. + */ +enum pipe_error +svga_buffer_validate_host_surface(struct svga_context *svga, + struct svga_buffer *sbuf, + unsigned tobind_flags) +{ + struct svga_buffer_surface *bufsurf; + enum pipe_error ret = PIPE_OK; + + /* Flush any pending upload first */ + svga_buffer_upload_flush(svga, sbuf); + + /* First check from the cached buffer surface list to see if there is + * already a buffer surface that has the requested bind flags, or + * surface with compatible bind flags that can be promoted. + */ + bufsurf = svga_buffer_get_host_surface(sbuf, tobind_flags); + + if (bufsurf) { + if ((bufsurf->bind_flags & tobind_flags) == tobind_flags) { + /* there is a surface with the requested bind flags */ + svga_buffer_bind_host_surface(svga, sbuf, bufsurf); + } else { + + /* Recreate a host surface with the combined bind flags */ + ret = svga_buffer_recreate_host_surface(svga, sbuf, + bufsurf->bind_flags | + tobind_flags); + + /* Destroy the old surface */ + svga_screen_surface_destroy(svga_screen(sbuf->b.b.screen), + &bufsurf->key, &bufsurf->handle); + + LIST_DEL(&bufsurf->list); + FREE(bufsurf); + } + } else { + /* Need to create a new surface if the bind flags are incompatible, + * such as constant buffer surface & stream output surface. + */ + ret = svga_buffer_recreate_host_surface(svga, sbuf, + tobind_flags); + } return ret; } + void svga_buffer_destroy_host_surface(struct svga_screen *ss, struct svga_buffer *sbuf) { - if (sbuf->handle) { + struct svga_buffer_surface *bufsurf, *next; + + LIST_FOR_EACH_ENTRY_SAFE(bufsurf, next, &sbuf->surfaces, list) { SVGA_DBG(DEBUG_DMA, " ungrab sid %p sz %d\n", - sbuf->handle, sbuf->b.b.width0); - svga_screen_surface_destroy(ss, &sbuf->key, &sbuf->handle); + bufsurf->handle, sbuf->b.b.width0); + svga_screen_surface_destroy(ss, &bufsurf->key, &bufsurf->handle); + FREE(bufsurf); } } @@ -841,13 +996,9 @@ svga_buffer_handle(struct svga_context *svga, struct pipe_resource *buf, if (sbuf->handle) { if ((sbuf->bind_flags & tobind_flags) != tobind_flags) { /* If the allocated resource's bind flags do not include the - * requested bind flags, create a new resource to include the - * new bind flags, and do a BufferCopy from the old resource to - * the new one. + * requested bind flags, validate the host surface. */ - assert(svga_have_vgpu10(svga)); - ret = svga_buffer_recreate_host_surface(svga, sbuf, - sbuf->bind_flags|tobind_flags); + ret = svga_buffer_validate_host_surface(svga, sbuf, tobind_flags); if (ret != PIPE_OK) return NULL; } diff --git a/src/gallium/drivers/svga/svga_resource_buffer_upload.h b/src/gallium/drivers/svga/svga_resource_buffer_upload.h index 877ae5499a1..c2d749b2091 100644 --- a/src/gallium/drivers/svga/svga_resource_buffer_upload.h +++ b/src/gallium/drivers/svga/svga_resource_buffer_upload.h @@ -55,6 +55,22 @@ svga_buffer_recreate_host_surface(struct svga_context *svga, struct svga_buffer *sbuf, unsigned bind_flags); +enum pipe_error +svga_buffer_add_host_surface(struct svga_buffer *sbuf, + struct svga_winsys_surface *handle, + struct svga_host_surface_cache_key *key, + unsigned bind_flags); + +void +svga_buffer_bind_host_surface(struct svga_context *svga, + struct svga_buffer *sbuf, + struct svga_buffer_surface *bufsurf); + +enum pipe_error +svga_buffer_validate_host_surface(struct svga_context *svga, + struct svga_buffer *sbuf, + unsigned bind_flags); + void svga_buffer_destroy_host_surface(struct svga_screen *ss, struct svga_buffer *sbuf); |