map_addr = NULL;
break;
case VIRGL_TRANSFER_MAP_STAGING:
- map_addr = virgl_transfer_uploader_map(vctx, trans);
+ map_addr = virgl_staging_map(vctx, trans);
/* Copy transfers don't make use of hw_res_map at the moment. */
trans->hw_res_map = NULL;
break;
struct virgl_screen *vs = virgl_screen(ctx->screen);
struct pipe_resource *res = transfer->resource;
- /* We don't need to transfer the contents of staging buffers, since they
- * don't have any host-side storage. */
- if (pipe_to_virgl_bind(vs, res->bind, res->flags) == VIRGL_BIND_STAGING) {
- virgl_resource_destroy_transfer(vctx, trans);
- return;
- }
+ /* We don't transfer the contents of staging resources, since they don't
+ * have any host-side storage. */
+ assert(pipe_to_virgl_bind(vs, res->bind, res->flags) != VIRGL_BIND_STAGING);
if (trans->base.usage & PIPE_TRANSFER_WRITE) {
if (transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT) {
if (trans->copy_src_hw_res) {
virgl_encode_copy_transfer(vctx, trans);
- /* It's now safe for other mappings to use the transfer_uploader. */
- vctx->transfer_uploader_in_use = false;
virgl_resource_destroy_transfer(vctx, trans);
} else {
virgl_transfer_queue_unmap(&vctx->queue, trans);
#include "virgl_protocol.h"
#include "virgl_resource.h"
#include "virgl_screen.h"
+#include "virgl_staging_mgr.h"
struct virgl_vertex_elements_state {
uint32_t handle;
rs->vws->cmd_buf_destroy(vctx->cbuf);
if (vctx->uploader)
u_upload_destroy(vctx->uploader);
- if (vctx->transfer_uploader)
- u_upload_destroy(vctx->transfer_uploader);
+ if (vctx->supports_staging)
+ virgl_staging_destroy(&vctx->staging);
util_primconvert_destroy(vctx->primconvert);
virgl_transfer_queue_fini(&vctx->queue);
goto fail;
vctx->base.stream_uploader = vctx->uploader;
vctx->base.const_uploader = vctx->uploader;
- /* Use a custom/staging buffer for the transfer uploader, since we are
- * using it only for copies to other resources.
- */
+
+ /* We use a special staging buffer as the source of copy transfers. */
if ((rs->caps.caps.v2.capability_bits & VIRGL_CAP_COPY_TRANSFER) &&
vctx->encoded_transfers) {
- vctx->transfer_uploader = u_upload_create(&vctx->base, 1024 * 1024,
- PIPE_BIND_CUSTOM,
- PIPE_USAGE_STAGING,
- VIRGL_RESOURCE_FLAG_STAGING);
- if (!vctx->transfer_uploader)
- goto fail;
+ virgl_staging_init(&vctx->staging, &vctx->base, 1024 * 1024);
+ vctx->supports_staging = true;
}
vctx->hw_sub_ctx_id = rs->sub_ctx_id++;
#include "util/slab.h"
#include "util/list.h"
+#include "virgl_staging_mgr.h"
#include "virgl_transfer_queue.h"
struct pipe_screen;
struct slab_child_pool transfer_pool;
struct virgl_transfer_queue queue;
struct u_upload_mgr *uploader;
- struct u_upload_mgr *transfer_uploader;
- bool transfer_uploader_in_use;
+ struct virgl_staging_mgr staging;
bool encoded_transfers;
+ bool supports_staging;
struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS];
unsigned num_vertex_buffers;
#include "virgl_context.h"
#include "virgl_resource.h"
#include "virgl_screen.h"
+#include "virgl_staging_mgr.h"
/* A (soft) limit for the amount of memory we want to allow for queued staging
* resources. This is used to decide when we should force a flush, in order to
if (xfer->base.usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
can_realloc = virgl_can_rebind_resource(vctx, &res->u.b);
} else {
- can_staging = vctx->transfer_uploader &&
- !vctx->transfer_uploader_in_use;
+ can_staging = vctx->supports_staging;
}
/* discard implies no readback */
return size;
}
-/* Maps a region from the transfer uploader to service the transfer. */
-void *virgl_transfer_uploader_map(struct virgl_context *vctx,
- struct virgl_transfer *vtransfer)
+/* Maps a region from staging to service the transfer. */
+void *virgl_staging_map(struct virgl_context *vctx,
+ struct virgl_transfer *vtransfer)
{
struct virgl_resource *vres = virgl_resource(vtransfer->base.resource);
- struct pipe_resource *copy_src_res = NULL;
unsigned size;
unsigned align_offset;
unsigned stride;
unsigned layer_stride;
void *map_addr;
+ bool alloc_succeeded;
- assert(vctx->transfer_uploader);
- assert(!vctx->transfer_uploader_in_use);
+ assert(vctx->supports_staging);
size = virgl_transfer_map_size(vtransfer, &stride, &layer_stride);
vtransfer->base.box.x % VIRGL_MAP_BUFFER_ALIGNMENT :
0;
- u_upload_alloc(vctx->transfer_uploader, 0, size + align_offset,
- VIRGL_MAP_BUFFER_ALIGNMENT,
- &vtransfer->copy_src_offset,
- ©_src_res, &map_addr);
- if (map_addr) {
- struct virgl_winsys *vws = virgl_screen(vctx->base.screen)->vws;
-
- /* Extract and reference the hw_res backing the pipe_resource. */
- vws->resource_reference(vws, &vtransfer->copy_src_hw_res,
- virgl_resource(copy_src_res)->hw_res);
- pipe_resource_reference(©_src_res, NULL);
-
+ alloc_succeeded =
+ virgl_staging_alloc(&vctx->staging, size + align_offset,
+ VIRGL_MAP_BUFFER_ALIGNMENT,
+ &vtransfer->copy_src_offset,
+ &vtransfer->copy_src_hw_res,
+ &map_addr);
+ if (alloc_succeeded) {
/* Update source offset and address to point to the requested x coordinate
* if we have an align_offset (see above for more information). */
vtransfer->copy_src_offset += align_offset;
*/
virgl_resource_dirty(vres, vtransfer->base.level);
- /* The pointer returned by u_upload_alloc already has +offset
- * applied. */
- vctx->transfer_uploader_in_use = true;
-
/* We are using the minimum required size to hold the contents,
* possibly using a layout different from the layout of the resource,
* so update the transfer strides accordingly.
void virgl_resource_dirty(struct virgl_resource *res, uint32_t level);
-void *virgl_transfer_uploader_map(struct virgl_context *vctx,
- struct virgl_transfer *vtransfer);
+void *virgl_staging_map(struct virgl_context *vctx,
+ struct virgl_transfer *vtransfer);
bool
virgl_resource_realloc(struct virgl_context *vctx,
map_addr = NULL;
break;
case VIRGL_TRANSFER_MAP_STAGING:
- map_addr = virgl_transfer_uploader_map(vctx, trans);
+ map_addr = virgl_staging_map(vctx, trans);
/* Copy transfers don't make use of hw_res_map at the moment. */
trans->hw_res_map = NULL;
break;
struct pipe_resource *res = transfer->resource;
bool queue_unmap = false;
- /* We don't need to transfer the contents of staging buffers, since they
- * don't have any host-side storage. */
- if (pipe_to_virgl_bind(vs, res->bind, res->flags) == VIRGL_BIND_STAGING) {
- virgl_resource_destroy_transfer(vctx, trans);
- return;
- }
+ /* We don't transfer the contents of staging resources, since they don't
+ * have any host-side storage. */
+ assert(pipe_to_virgl_bind(vs, res->bind, res->flags) != VIRGL_BIND_STAGING);
if (transfer->usage & PIPE_TRANSFER_WRITE &&
(transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT) == 0) {
if (queue_unmap) {
if (trans->copy_src_hw_res) {
virgl_encode_copy_transfer(vctx, trans);
- /* It's now safe for other mappings to use the transfer_uploader. */
- vctx->transfer_uploader_in_use = false;
virgl_resource_destroy_transfer(vctx, trans);
} else {
virgl_transfer_queue_unmap(&vctx->queue, trans);