virgl: also destroy all read-transfers
[mesa.git] / src / gallium / drivers / virgl / virgl_texture.c
index 64b6744462d98764f60e70374273faeefff37b0c..1832309aa49dfeab9b9f6bca2ab573517e26dc06 100644 (file)
@@ -94,31 +94,6 @@ static void virgl_init_temp_resource_from_box(struct pipe_resource *res,
    }
 }
 
-static unsigned
-vrend_get_tex_image_offset(const struct virgl_texture *res,
-                           unsigned level, unsigned layer)
-{
-   const struct pipe_resource *pres = &res->base.u.b;
-   const unsigned hgt = u_minify(pres->height0, level);
-   const unsigned nblocksy = util_format_get_nblocksy(pres->format, hgt);
-   unsigned offset = res->level_offset[level];
-
-   if (pres->target == PIPE_TEXTURE_CUBE ||
-       pres->target == PIPE_TEXTURE_CUBE_ARRAY ||
-       pres->target == PIPE_TEXTURE_3D ||
-       pres->target == PIPE_TEXTURE_2D_ARRAY) {
-      offset += layer * nblocksy * res->stride[level];
-   }
-   else if (pres->target == PIPE_TEXTURE_1D_ARRAY) {
-      offset += layer * res->stride[level];
-   }
-   else {
-      assert(layer == 0);
-   }
-
-   return offset;
-}
-
 static void *virgl_texture_transfer_map(struct pipe_context *ctx,
                                         struct pipe_resource *resource,
                                         unsigned level,
@@ -128,44 +103,21 @@ static void *virgl_texture_transfer_map(struct pipe_context *ctx,
 {
    struct virgl_context *vctx = virgl_context(ctx);
    struct virgl_screen *vs = virgl_screen(ctx->screen);
-   struct virgl_texture *vtex = virgl_texture(resource);
-   enum pipe_format format = resource->format;
+   struct virgl_resource *vtex = virgl_resource(resource);
    struct virgl_transfer *trans;
    void *ptr;
    boolean readback = TRUE;
-   uint32_t offset;
    struct virgl_hw_res *hw_res;
-   const unsigned h = u_minify(vtex->base.u.b.height0, level);
-   const unsigned nblocksy = util_format_get_nblocksy(format, h);
-   bool is_depth = util_format_has_depth(util_format_description(resource->format));
-   uint32_t l_stride;
-   bool doflushwait;
-
-   doflushwait = virgl_res_needs_flush_wait(vctx, &vtex->base, usage);
-   if (doflushwait)
-      ctx->flush(ctx, NULL, 0);
-
-   trans = util_slab_alloc(&vctx->texture_transfer_pool);
-   if (!trans)
-      return NULL;
+   bool flush;
 
-   trans->base.resource = resource;
-   trans->base.level = level;
-   trans->base.usage = usage;
-   trans->base.box = *box;
-   trans->base.stride = vtex->stride[level];
-   trans->base.layer_stride = trans->base.stride * nblocksy;
+   trans = virgl_resource_create_transfer(&vctx->transfer_pool, resource,
+                                          &vtex->metadata, level, usage, box);
 
-   if (resource->target != PIPE_TEXTURE_3D &&
-       resource->target != PIPE_TEXTURE_CUBE &&
-       resource->target != PIPE_TEXTURE_1D_ARRAY &&
-       resource->target != PIPE_TEXTURE_2D_ARRAY &&
-       resource->target != PIPE_TEXTURE_CUBE_ARRAY)
-      l_stride = 0;
-   else
-      l_stride = trans->base.layer_stride;
+   flush = virgl_res_needs_flush(vctx, trans);
+   if (flush)
+      ctx->flush(ctx, NULL, 0);
 
-   if (is_depth && resource->nr_samples > 1) {
+   if (resource->nr_samples > 1) {
       struct pipe_resource tmp_resource;
       virgl_init_temp_resource_from_box(&tmp_resource, resource, box,
                                         level, 0);
@@ -176,31 +128,30 @@ static void *virgl_texture_transfer_map(struct pipe_context *ctx,
       ctx->flush(ctx, NULL, 0);
       /* we want to do a resolve blit into the temporary */
       hw_res = trans->resolve_tmp->hw_res;
-      offset = 0;
+      struct virgl_resource_metadata *data = &trans->resolve_tmp->metadata;
+      trans->base.stride = data->stride[level];
+      trans->base.layer_stride = data->layer_stride[level];
+      trans->offset = 0;
    } else {
-      offset = vrend_get_tex_image_offset(vtex, level, box->z);
-
-      offset += box->y / util_format_get_blockheight(format) * trans->base.stride +
-      box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
-      hw_res = vtex->base.hw_res;
+      hw_res = vtex->hw_res;
       trans->resolve_tmp = NULL;
    }
 
-   readback = virgl_res_needs_readback(vctx, &vtex->base, usage);
-   if (readback)
-      vs->vws->transfer_get(vs->vws, hw_res, box, trans->base.stride, l_stride, offset, level);
+   readback = virgl_res_needs_readback(vctx, vtex, usage, level);
+   if (readback) {
+      vs->vws->transfer_get(vs->vws, hw_res, box, trans->base.stride,
+                            trans->l_stride, trans->offset, level);
 
-   if (doflushwait || readback)
-      vs->vws->resource_wait(vs->vws, vtex->base.hw_res);
+      vs->vws->resource_wait(vs->vws, vtex->hw_res);
+   }
 
    ptr = vs->vws->resource_map(vs->vws, hw_res);
    if (!ptr) {
+      virgl_resource_destroy_transfer(&vctx->transfer_pool, trans);
       return NULL;
    }
 
-   trans->offset = offset;
    *transfer = &trans->base;
-
    return ptr + trans->offset;
 }
 
@@ -209,142 +160,41 @@ static void virgl_texture_transfer_unmap(struct pipe_context *ctx,
 {
    struct virgl_context *vctx = virgl_context(ctx);
    struct virgl_transfer *trans = virgl_transfer(transfer);
-   struct virgl_texture *vtex = virgl_texture(transfer->resource);
-   uint32_t l_stride;
-
-   if (transfer->resource->target != PIPE_TEXTURE_3D &&
-       transfer->resource->target != PIPE_TEXTURE_CUBE &&
-       transfer->resource->target != PIPE_TEXTURE_1D_ARRAY &&
-       transfer->resource->target != PIPE_TEXTURE_2D_ARRAY &&
-       transfer->resource->target != PIPE_TEXTURE_CUBE_ARRAY)
-      l_stride = 0;
-   else
-      l_stride = trans->base.layer_stride;
+   struct virgl_resource *vtex = virgl_resource(transfer->resource);
 
    if (trans->base.usage & PIPE_TRANSFER_WRITE) {
       if (!(transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT)) {
          struct virgl_screen *vs = virgl_screen(ctx->screen);
-         vtex->base.clean = FALSE;
          vctx->num_transfers++;
-         vs->vws->transfer_put(vs->vws, vtex->base.hw_res,
-                               &transfer->box, trans->base.stride, l_stride, trans->offset, transfer->level);
 
+         if (trans->resolve_tmp) {
+            vs->vws->transfer_put(vs->vws, vtex->hw_res,
+                                  &transfer->box, trans->base.stride,
+                                  trans->l_stride, trans->offset,
+                                  transfer->level);
+         } else {
+            virgl_transfer_queue_unmap(&vctx->queue, trans);
+         }
       }
    }
 
-   if (trans->resolve_tmp)
+   if (trans->resolve_tmp) {
       pipe_resource_reference((struct pipe_resource **)&trans->resolve_tmp, NULL);
-
-   util_slab_free(&vctx->texture_transfer_pool, trans);
-}
-
-
-static boolean
-vrend_resource_layout(struct virgl_texture *res,
-                      uint32_t *total_size)
-{
-   struct pipe_resource *pt = &res->base.u.b;
-   unsigned level;
-   unsigned width = pt->width0;
-   unsigned height = pt->height0;
-   unsigned depth = pt->depth0;
-   unsigned buffer_size = 0;
-
-   for (level = 0; level <= pt->last_level; level++) {
-      unsigned slices;
-
-      if (pt->target == PIPE_TEXTURE_CUBE)
-         slices = 6;
-      else if (pt->target == PIPE_TEXTURE_3D)
-         slices = depth;
-      else
-         slices = pt->array_size;
-
-      res->stride[level] = util_format_get_stride(pt->format, width);
-      res->level_offset[level] = buffer_size;
-
-      buffer_size += (util_format_get_nblocksy(pt->format, height) *
-                      slices * res->stride[level]);
-
-      width = u_minify(width, 1);
-      height = u_minify(height, 1);
-      depth = u_minify(depth, 1);
-   }
-
-   if (pt->nr_samples <= 1)
-      *total_size = buffer_size;
-   else /* don't create guest backing store for MSAA */
-      *total_size = 0;
-   return TRUE;
-}
-
-static boolean virgl_texture_get_handle(struct pipe_screen *screen,
-                                         struct pipe_resource *ptex,
-                                         struct winsys_handle *whandle)
-{
-   struct virgl_screen *vs = virgl_screen(screen);
-   struct virgl_texture *vtex = virgl_texture(ptex);
-
-   return vs->vws->resource_get_handle(vs->vws, vtex->base.hw_res, vtex->stride[0], whandle);
-}
-
-static void virgl_texture_destroy(struct pipe_screen *screen,
-                                  struct pipe_resource *res)
-{
-   struct virgl_screen *vs = virgl_screen(screen);
-   struct virgl_texture *vtex = virgl_texture(res);
-   vs->vws->resource_unref(vs->vws, vtex->base.hw_res);
-   FREE(vtex);
+      virgl_resource_destroy_transfer(&vctx->transfer_pool, trans);
+   } else if (!(trans->base.usage & PIPE_TRANSFER_WRITE))
+      virgl_resource_destroy_transfer(&vctx->transfer_pool, trans);
 }
 
 static const struct u_resource_vtbl virgl_texture_vtbl =
 {
-   virgl_texture_get_handle,            /* get_handle */
-   virgl_texture_destroy,               /* resource_destroy */
+   virgl_resource_get_handle,           /* get_handle */
+   virgl_resource_destroy,              /* resource_destroy */
    virgl_texture_transfer_map,          /* transfer_map */
    NULL,                                /* transfer_flush_region */
    virgl_texture_transfer_unmap,        /* transfer_unmap */
 };
 
-struct pipe_resource *
-virgl_texture_from_handle(struct virgl_screen *vs,
-                          const struct pipe_resource *template,
-                          struct winsys_handle *whandle)
+void virgl_texture_init(struct virgl_resource *res)
 {
-   struct virgl_texture *tex;
-   uint32_t size;
-
-   tex = CALLOC_STRUCT(virgl_texture);
-   tex->base.u.b = *template;
-   tex->base.u.b.screen = &vs->base;
-   pipe_reference_init(&tex->base.u.b.reference, 1);
-   tex->base.u.vtbl = &virgl_texture_vtbl;
-   vrend_resource_layout(tex, &size);
-
-   tex->base.hw_res = vs->vws->resource_create_from_handle(vs->vws, whandle);
-   return &tex->base.u.b;
-}
-
-struct pipe_resource *virgl_texture_create(struct virgl_screen *vs,
-                                           const struct pipe_resource *template)
-{
-   struct virgl_texture *tex;
-   uint32_t size;
-   unsigned vbind;
-
-   tex = CALLOC_STRUCT(virgl_texture);
-   tex->base.clean = TRUE;
-   tex->base.u.b = *template;
-   tex->base.u.b.screen = &vs->base;
-   pipe_reference_init(&tex->base.u.b.reference, 1);
-   tex->base.u.vtbl = &virgl_texture_vtbl;
-   vrend_resource_layout(tex, &size);
-
-   vbind = pipe_to_virgl_bind(template->bind);
-   tex->base.hw_res = vs->vws->resource_create(vs->vws, template->target, template->format, vbind, template->width0, template->height0, template->depth0, template->array_size, template->last_level, template->nr_samples, size);
-   if (!tex->base.hw_res) {
-      FREE(tex);
-      return NULL;
-   }
-   return &tex->base.u.b;
+   res->u.vtbl = &virgl_texture_vtbl;
 }