diff options
-rw-r--r-- | src/gallium/drivers/svga/svga_context.c | 5 | ||||
-rw-r--r-- | src/gallium/drivers/svga/svga_context.h | 1 | ||||
-rw-r--r-- | src/gallium/drivers/svga/svga_resource_buffer_upload.c | 8 | ||||
-rw-r--r-- | src/gallium/drivers/svga/svga_resource_texture.c | 258 | ||||
-rw-r--r-- | src/gallium/drivers/svga/svga_resource_texture.h | 32 | ||||
-rw-r--r-- | src/gallium/drivers/svga/svga_winsys.h | 1 |
6 files changed, 279 insertions, 26 deletions
diff --git a/src/gallium/drivers/svga/svga_context.c b/src/gallium/drivers/svga/svga_context.c index 1ed0f3d1b78..10085102110 100644 --- a/src/gallium/drivers/svga/svga_context.c +++ b/src/gallium/drivers/svga/svga_context.c @@ -102,6 +102,7 @@ static void svga_destroy( struct pipe_context *pipe ) util_bitmask_destroy(svga->stream_output_id_bm); util_bitmask_destroy(svga->query_id_bm); u_upload_destroy(svga->const0_upload); + svga_texture_transfer_map_upload_destroy(svga); /* free user's constant buffers */ for (shader = 0; shader < PIPE_SHADER_TYPES; ++shader) { @@ -214,6 +215,9 @@ struct pipe_context *svga_context_create(struct pipe_screen *screen, if (!svga->const0_upload) goto cleanup; + if (!svga_texture_transfer_map_upload_create(svga)) + goto cleanup; + /* Avoid shortcircuiting state with initial value of zero. */ memset(&svga->state.hw_clear, 0xcd, sizeof(svga->state.hw_clear)); @@ -279,6 +283,7 @@ cleanup: if (svga->const0_upload) u_upload_destroy(svga->const0_upload); + svga_texture_transfer_map_upload_destroy(svga); if (svga->hwtnl) svga_hwtnl_destroy(svga->hwtnl); if (svga->swc) diff --git a/src/gallium/drivers/svga/svga_context.h b/src/gallium/drivers/svga/svga_context.h index afb04120ef5..cbc4a9c86e9 100644 --- a/src/gallium/drivers/svga/svga_context.h +++ b/src/gallium/drivers/svga/svga_context.h @@ -431,6 +431,7 @@ struct svga_context struct svga_winsys_context *swc; struct blitter_context *blitter; struct u_upload_mgr *const0_upload; + struct u_upload_mgr *tex_upload; struct { boolean no_swtnl; diff --git a/src/gallium/drivers/svga/svga_resource_buffer_upload.c b/src/gallium/drivers/svga/svga_resource_buffer_upload.c index 7ecf95c1af7..ac8cedfd3b7 100644 --- a/src/gallium/drivers/svga/svga_resource_buffer_upload.c +++ b/src/gallium/drivers/svga/svga_resource_buffer_upload.c @@ -166,6 +166,14 @@ svga_buffer_create_host_surface(struct svga_screen *ss, if (sbuf->bind_flags & PIPE_BIND_SAMPLER_VIEW) sbuf->key.flags |= SVGA3D_SURFACE_BIND_SHADER_RESOURCE; + if (!sbuf->bind_flags && sbuf->b.b.usage == PIPE_USAGE_STAGING) { + /* This surface is to be used with the + * SVGA3D_CMD_DX_TRANSFER_FROM_BUFFER command, and no other + * bind flags are allowed to be set for this surface. + */ + sbuf->key.flags = SVGA3D_SURFACE_TRANSFER_FROM_BUFFER; + } + sbuf->key.size.width = sbuf->b.b.width0; sbuf->key.size.height = 1; sbuf->key.size.depth = 1; diff --git a/src/gallium/drivers/svga/svga_resource_texture.c b/src/gallium/drivers/svga/svga_resource_texture.c index 85e1805c546..a79f43d9fe8 100644 --- a/src/gallium/drivers/svga/svga_resource_texture.c +++ b/src/gallium/drivers/svga/svga_resource_texture.c @@ -34,6 +34,7 @@ #include "util/u_math.h" #include "util/u_memory.h" #include "util/u_resource.h" +#include "util/u_upload_mgr.h" #include "svga_cmd.h" #include "svga_format.h" @@ -403,11 +404,6 @@ svga_texture_transfer_map_direct(struct svga_context *svga, unsigned w, h, nblocksx, nblocksy; unsigned usage = st->base.usage; - if (!surf) { - FREE(st); - return NULL; - } - /* we'll directly access the guest-backed surface */ w = u_minify(texture->width0, level); h = u_minify(texture->height0, level); @@ -417,13 +413,6 @@ svga_texture_transfer_map_direct(struct svga_context *svga, st->base.stride = nblocksx*util_format_get_blocksize(texture->format); st->base.layer_stride = st->base.stride * nblocksy; - /* If this is the first time mapping to the surface in this - * command buffer, clear the dirty masks of this surface. - */ - if (sws->surface_is_flushed(sws, surf)) { - svga_clear_texture_dirty(tex); - } - if (need_tex_readback(transfer)) { enum pipe_error ret; @@ -525,11 +514,6 @@ svga_texture_transfer_map_direct(struct svga_context *svga, st->base.box.y, st->base.box.z); - if (usage & PIPE_TRANSFER_WRITE) { - /* mark this texture level as dirty */ - svga_set_texture_dirty(tex, st->slice, level); - } - return (void *) (map + offset); } } @@ -550,13 +534,17 @@ svga_texture_transfer_map(struct pipe_context *pipe, struct svga_winsys_screen *sws = svga_screen(pipe->screen)->sws; struct svga_texture *tex = svga_texture(texture); struct svga_transfer *st; + struct svga_winsys_surface *surf = tex->handle; boolean use_direct_map = svga_have_gb_objects(svga) && !svga_have_gb_dma(svga); - void *returnVal = NULL; + void *map = NULL; int64_t begin = svga_get_time(svga); SVGA_STATS_TIME_PUSH(sws, SVGA_STATS_TIME_TEXTRANSFERMAP); + if (!surf) + goto done; + /* We can't map texture storage directly unless we have GB objects */ if (usage & PIPE_TRANSFER_MAP_DIRECTLY) { if (svga_have_gb_objects(svga)) @@ -596,14 +584,30 @@ svga_texture_transfer_map(struct pipe_context *pipe, st->use_direct_map = use_direct_map; pipe_resource_reference(&st->base.resource, texture); - if (use_direct_map) { - returnVal = svga_texture_transfer_map_direct(svga, st); + /* If this is the first time mapping to the surface in this + * command buffer, clear the dirty masks of this surface. + */ + if (sws->surface_is_flushed(sws, surf)) { + svga_clear_texture_dirty(tex); + } + + if (!use_direct_map) { + /* upload to the DMA buffer */ + map = svga_texture_transfer_map_dma(svga, st); } else { - returnVal = svga_texture_transfer_map_dma(svga, st); + if (svga_texture_transfer_map_can_upload(svga, st)) { + /* upload to the texture upload buffer */ + map = svga_texture_transfer_map_upload(svga, st); + } + + if (!map) { + /* map directly to the GBS surface */ + map = svga_texture_transfer_map_direct(svga, st); + } } - if (!returnVal) { + if (!map) { FREE(st); } else { @@ -613,13 +617,18 @@ svga_texture_transfer_map(struct pipe_context *pipe, /* record texture upload for HUD */ svga->hud.num_bytes_uploaded += st->base.layer_stride * st->base.box.depth; + + /* mark this texture level as dirty */ + svga_set_texture_dirty(tex, st->slice, level); } } done: svga->hud.map_buffer_time += (svga_get_time(svga) - begin); SVGA_STATS_TIME_POP(sws); - return returnVal; + (void) sws; + + return map; } /** @@ -732,6 +741,7 @@ svga_texture_transfer_unmap_direct(struct svga_context *svga, svga_texture_surface_unmap(svga, transfer); + /* Now send an update command to update the content in the backend. */ if (st->base.usage & PIPE_TRANSFER_WRITE) { struct svga_winsys_surface *surf = tex->handle; SVGA3dBox box; @@ -785,6 +795,7 @@ svga_texture_transfer_unmap_direct(struct svga_context *svga, ret = update_image_vgpu9(svga, surf, &box, st->slice, transfer->level); assert(ret == PIPE_OK); } + (void) ret; } } @@ -800,16 +811,20 @@ svga_texture_transfer_unmap(struct pipe_context *pipe, SVGA_STATS_TIME_PUSH(sws, SVGA_STATS_TIME_TEXTRANSFERUNMAP); - if (st->use_direct_map) { - svga_texture_transfer_unmap_direct(svga, st); + if (!st->use_direct_map) { + svga_texture_transfer_unmap_dma(svga, st); + } + else if (st->upload.buf) { + svga_texture_transfer_unmap_upload(svga, st); } else { - svga_texture_transfer_unmap_dma(svga, st); + svga_texture_transfer_unmap_direct(svga, st); } if (st->base.usage & PIPE_TRANSFER_WRITE) { svga->hud.num_resource_updates++; + /* Mark the texture level as dirty */ ss->texture_timestamp++; svga_age_texture_view(tex, transfer->level); if (transfer->resource->target == PIPE_TEXTURE_CUBE) @@ -821,6 +836,7 @@ svga_texture_transfer_unmap(struct pipe_context *pipe, pipe_resource_reference(&st->base.resource, NULL); FREE(st); SVGA_STATS_TIME_POP(sws); + (void) sws; } @@ -1237,3 +1253,193 @@ svga_texture_generate_mipmap(struct pipe_context *pipe, return TRUE; } + + +/* texture upload buffer default size in bytes */ +#define TEX_UPLOAD_DEFAULT_SIZE (1024 * 1024) + +/** + * Create a texture upload buffer + */ +boolean +svga_texture_transfer_map_upload_create(struct svga_context *svga) +{ + svga->tex_upload = u_upload_create(&svga->pipe, TEX_UPLOAD_DEFAULT_SIZE, + 0, PIPE_USAGE_STAGING); + return svga->tex_upload != NULL; +} + + +/** + * Destroy the texture upload buffer + */ +void +svga_texture_transfer_map_upload_destroy(struct svga_context *svga) +{ + u_upload_destroy(svga->tex_upload); +} + + +/** + * Returns true if this transfer map request can use the upload buffer. + */ +boolean +svga_texture_transfer_map_can_upload(struct svga_context *svga, + struct svga_transfer *st) +{ + struct pipe_resource *texture = st->base.resource; + + if (!svga_have_vgpu10(svga)) + return FALSE; + + if (svga_sws(svga)->have_transfer_from_buffer_cmd == FALSE) + return FALSE; + + if (st->base.usage & PIPE_TRANSFER_READ) + return FALSE; + + /* TransferFromBuffer command is not well supported with multi-samples surface */ + if (texture->nr_samples > 1) + return FALSE; + + /* Do not use the upload path with compressed format or rgb9_e5 */ + if (util_format_is_compressed(texture->format) || + texture->format == PIPE_FORMAT_R9G9B9E5_FLOAT) + return FALSE; + + return TRUE; +} + + +/** + * Use upload buffer for the transfer map request. + */ +void * +svga_texture_transfer_map_upload(struct svga_context *svga, + struct svga_transfer *st) +{ + struct pipe_resource *texture = st->base.resource; + struct pipe_resource *tex_buffer = NULL; + void *tex_map; + unsigned nblocksx, nblocksy; + unsigned offset; + unsigned upload_size; + + assert(svga->tex_upload); + + st->upload.box.x = st->base.box.x; + st->upload.box.y = st->base.box.y; + st->upload.box.z = st->base.box.z; + st->upload.box.w = st->base.box.width; + st->upload.box.h = st->base.box.height; + st->upload.box.d = st->base.box.depth; + st->upload.nlayers = 1; + + switch (texture->target) { + case PIPE_TEXTURE_CUBE: + st->upload.box.z = 0; + break; + case PIPE_TEXTURE_2D_ARRAY: + st->upload.nlayers = st->base.box.depth; + st->upload.box.z = 0; + st->upload.box.d = 1; + break; + case PIPE_TEXTURE_1D_ARRAY: + st->upload.nlayers = st->base.box.depth; + st->upload.box.y = st->upload.box.z = 0; + st->upload.box.d = 1; + break; + default: + break; + } + + nblocksx = util_format_get_nblocksx(texture->format, st->base.box.width); + nblocksy = util_format_get_nblocksy(texture->format, st->base.box.height); + + st->base.stride = nblocksx * util_format_get_blocksize(texture->format); + st->base.layer_stride = st->base.stride * nblocksy; + + /* In order to use the TransferFromBuffer command to update the + * texture content from the buffer, the layer stride for a multi-layers + * surface needs to be in multiples of 16 bytes. + */ + if (st->upload.nlayers > 1 && st->base.layer_stride & 15) + return NULL; + + upload_size = st->base.layer_stride * st->base.box.depth; + upload_size = align(upload_size, 16); + + /* If the upload size exceeds the default buffer size, the + * upload buffer manager code will try to allocate a new buffer + * with the new buffer size. + */ + u_upload_alloc(svga->tex_upload, 0, upload_size, 16, + &offset, &tex_buffer, &tex_map); + + if (!tex_map) { + return NULL; + } + + st->upload.buf = tex_buffer; + st->upload.map = tex_map; + st->upload.offset = offset; + + return tex_map; +} + + +/** + * Unmap upload map transfer request + */ +void +svga_texture_transfer_unmap_upload(struct svga_context *svga, + struct svga_transfer *st) +{ + struct svga_winsys_surface *srcsurf; + struct svga_winsys_surface *dstsurf; + struct pipe_resource *texture = st->base.resource; + enum pipe_error ret; + unsigned subResource; + unsigned numMipLevels; + unsigned i, layer; + unsigned offset = st->upload.offset; + + assert(svga->tex_upload); + assert(st->upload.buf); + + /* unmap the texture upload buffer */ + u_upload_unmap(svga->tex_upload); + + srcsurf = svga_buffer_handle(svga, st->upload.buf); + dstsurf = svga_texture(texture)->handle; + assert(dstsurf); + + numMipLevels = texture->last_level + 1; + + for (i = 0, layer = st->slice; i < st->upload.nlayers; i++, layer++) { + subResource = layer * numMipLevels + st->base.level; + + /* send a transferFromBuffer command to update the host texture surface */ + assert((offset & 15) == 0); + + ret = SVGA3D_vgpu10_TransferFromBuffer(svga->swc, srcsurf, + offset, + st->base.stride, + st->base.layer_stride, + dstsurf, subResource, + &st->upload.box); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_TransferFromBuffer(svga->swc, srcsurf, + offset, + st->base.stride, + st->base.layer_stride, + dstsurf, subResource, + &st->upload.box); + assert(ret == PIPE_OK); + } + offset += st->base.layer_stride; + } + + pipe_resource_reference(&st->upload.buf, NULL); +} diff --git a/src/gallium/drivers/svga/svga_resource_texture.h b/src/gallium/drivers/svga/svga_resource_texture.h index ffd5feac9a3..ff46ed55f03 100644 --- a/src/gallium/drivers/svga/svga_resource_texture.h +++ b/src/gallium/drivers/svga/svga_resource_texture.h @@ -113,7 +113,22 @@ struct svga_transfer * big enough */ void *swbuf; + /* True if guest backed surface is supported and we can directly map + * to the surface for this transfer. + */ boolean use_direct_map; + + struct { + struct pipe_resource *buf; /* points to the upload buffer if this + * transfer is done via the upload buffer + * instead of directly mapping to the + * resource's surface. + */ + void *map; + unsigned offset; + SVGA3dBox box; + unsigned nlayers; + } upload; }; @@ -256,5 +271,22 @@ svga_texture_generate_mipmap(struct pipe_context *pipe, unsigned first_layer, unsigned last_layer); +boolean +svga_texture_transfer_map_upload_create(struct svga_context *svga); + +void +svga_texture_transfer_map_upload_destroy(struct svga_context *svga); + +boolean +svga_texture_transfer_map_can_upload(struct svga_context *svga, + struct svga_transfer *st); + +void * +svga_texture_transfer_map_upload(struct svga_context *svga, + struct svga_transfer *st); + +void +svga_texture_transfer_unmap_upload(struct svga_context *svga, + struct svga_transfer *st); #endif /* SVGA_TEXTURE_H */ diff --git a/src/gallium/drivers/svga/svga_winsys.h b/src/gallium/drivers/svga/svga_winsys.h index 901a73eba0a..f226581774e 100644 --- a/src/gallium/drivers/svga/svga_winsys.h +++ b/src/gallium/drivers/svga/svga_winsys.h @@ -711,6 +711,7 @@ struct svga_winsys_screen boolean have_generate_mipmap_cmd; boolean have_set_predication_cmd; + boolean have_transfer_from_buffer_cmd; }; |