summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gallium/drivers/svga/svga_context.c5
-rw-r--r--src/gallium/drivers/svga/svga_context.h1
-rw-r--r--src/gallium/drivers/svga/svga_resource_buffer_upload.c8
-rw-r--r--src/gallium/drivers/svga/svga_resource_texture.c258
-rw-r--r--src/gallium/drivers/svga/svga_resource_texture.h32
-rw-r--r--src/gallium/drivers/svga/svga_winsys.h1
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;
};