1b8e80941Smrg/*
2b8e80941Smrg * Copyright 2014, 2015 Red Hat.
3b8e80941Smrg *
4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
6b8e80941Smrg * to deal in the Software without restriction, including without limitation
7b8e80941Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub
8b8e80941Smrg * license, and/or sell copies of the Software, and to permit persons to whom
9b8e80941Smrg * the Software is furnished to do so, subject to the following conditions:
10b8e80941Smrg *
11b8e80941Smrg * The above copyright notice and this permission notice (including the next
12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
13b8e80941Smrg * Software.
14b8e80941Smrg *
15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18b8e80941Smrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19b8e80941Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20b8e80941Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21b8e80941Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE.
22b8e80941Smrg */
23b8e80941Smrg#include "util/u_format.h"
24b8e80941Smrg#include "util/u_inlines.h"
25b8e80941Smrg#include "util/u_memory.h"
26b8e80941Smrg
27b8e80941Smrg#include "virgl_context.h"
28b8e80941Smrg#include "virgl_resource.h"
29b8e80941Smrg#include "virgl_screen.h"
30b8e80941Smrg
31b8e80941Smrgstatic void virgl_copy_region_with_blit(struct pipe_context *pipe,
32b8e80941Smrg                                        struct pipe_resource *dst,
33b8e80941Smrg                                        unsigned dst_level,
34b8e80941Smrg                                        const struct pipe_box *dst_box,
35b8e80941Smrg                                        struct pipe_resource *src,
36b8e80941Smrg                                        unsigned src_level,
37b8e80941Smrg                                        const struct pipe_box *src_box)
38b8e80941Smrg{
39b8e80941Smrg   struct pipe_blit_info blit;
40b8e80941Smrg
41b8e80941Smrg   assert(src_box->width == dst_box->width);
42b8e80941Smrg   assert(src_box->height == dst_box->height);
43b8e80941Smrg   assert(src_box->depth == dst_box->depth);
44b8e80941Smrg
45b8e80941Smrg   memset(&blit, 0, sizeof(blit));
46b8e80941Smrg   blit.src.resource = src;
47b8e80941Smrg   blit.src.format = src->format;
48b8e80941Smrg   blit.src.level = src_level;
49b8e80941Smrg   blit.src.box = *src_box;
50b8e80941Smrg   blit.dst.resource = dst;
51b8e80941Smrg   blit.dst.format = dst->format;
52b8e80941Smrg   blit.dst.level = dst_level;
53b8e80941Smrg   blit.dst.box.x = dst_box->x;
54b8e80941Smrg   blit.dst.box.y = dst_box->y;
55b8e80941Smrg   blit.dst.box.z = dst_box->z;
56b8e80941Smrg   blit.dst.box.width = src_box->width;
57b8e80941Smrg   blit.dst.box.height = src_box->height;
58b8e80941Smrg   blit.dst.box.depth = src_box->depth;
59b8e80941Smrg   blit.mask = util_format_get_mask(src->format) &
60b8e80941Smrg      util_format_get_mask(dst->format);
61b8e80941Smrg   blit.filter = PIPE_TEX_FILTER_NEAREST;
62b8e80941Smrg
63b8e80941Smrg   if (blit.mask) {
64b8e80941Smrg      pipe->blit(pipe, &blit);
65b8e80941Smrg   }
66b8e80941Smrg}
67b8e80941Smrg
68b8e80941Smrgstatic unsigned temp_bind(unsigned orig)
69b8e80941Smrg{
70b8e80941Smrg   unsigned warn = ~(PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL |
71b8e80941Smrg                     PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_DISPLAY_TARGET);
72b8e80941Smrg   if (orig & warn)
73b8e80941Smrg      debug_printf("VIRGL: Warning, possibly unhandled bind: %x\n",
74b8e80941Smrg                   orig & warn);
75b8e80941Smrg
76b8e80941Smrg   return orig & (PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_RENDER_TARGET);
77b8e80941Smrg}
78b8e80941Smrg
79b8e80941Smrgstatic void virgl_init_temp_resource_from_box(struct pipe_resource *res,
80b8e80941Smrg                                              struct pipe_resource *orig,
81b8e80941Smrg                                              const struct pipe_box *box,
82b8e80941Smrg                                              unsigned level, unsigned flags,
83b8e80941Smrg                                              enum pipe_format fmt)
84b8e80941Smrg{
85b8e80941Smrg   memset(res, 0, sizeof(*res));
86b8e80941Smrg   res->bind = temp_bind(orig->bind);
87b8e80941Smrg   res->format = fmt;
88b8e80941Smrg   res->width0 = box->width;
89b8e80941Smrg   res->height0 = box->height;
90b8e80941Smrg   res->depth0 = 1;
91b8e80941Smrg   res->array_size = 1;
92b8e80941Smrg   res->usage = PIPE_USAGE_STAGING;
93b8e80941Smrg   res->flags = flags;
94b8e80941Smrg
95b8e80941Smrg   /* We must set the correct texture target and dimensions for a 3D box. */
96b8e80941Smrg   if (box->depth > 1 && util_max_layer(orig, level) > 0)
97b8e80941Smrg      res->target = orig->target;
98b8e80941Smrg   else
99b8e80941Smrg      res->target = PIPE_TEXTURE_2D;
100b8e80941Smrg
101b8e80941Smrg   if (res->target != PIPE_BUFFER)
102b8e80941Smrg      res->bind = PIPE_BIND_RENDER_TARGET;
103b8e80941Smrg
104b8e80941Smrg   switch (res->target) {
105b8e80941Smrg   case PIPE_TEXTURE_1D_ARRAY:
106b8e80941Smrg   case PIPE_TEXTURE_2D_ARRAY:
107b8e80941Smrg   case PIPE_TEXTURE_CUBE_ARRAY:
108b8e80941Smrg      res->array_size = box->depth;
109b8e80941Smrg      break;
110b8e80941Smrg   case PIPE_TEXTURE_3D:
111b8e80941Smrg      res->depth0 = box->depth;
112b8e80941Smrg      break;
113b8e80941Smrg   default:
114b8e80941Smrg      break;
115b8e80941Smrg   }
116b8e80941Smrg}
117b8e80941Smrg
118b8e80941Smrgstatic void *texture_transfer_map_plain(struct pipe_context *ctx,
119b8e80941Smrg                                        struct pipe_resource *resource,
120b8e80941Smrg                                        unsigned level,
121b8e80941Smrg                                        unsigned usage,
122b8e80941Smrg                                        const struct pipe_box *box,
123b8e80941Smrg                                        struct pipe_transfer **transfer)
124b8e80941Smrg{
125b8e80941Smrg   struct virgl_context *vctx = virgl_context(ctx);
126b8e80941Smrg   struct virgl_winsys *vws = virgl_screen(ctx->screen)->vws;
127b8e80941Smrg   struct virgl_resource *vtex = virgl_resource(resource);
128b8e80941Smrg   struct virgl_transfer *trans;
129b8e80941Smrg   bool flush, readback;
130b8e80941Smrg
131b8e80941Smrg   trans = virgl_resource_create_transfer(&vctx->transfer_pool, resource,
132b8e80941Smrg                                          &vtex->metadata, level, usage, box);
133b8e80941Smrg   trans->resolve_transfer = NULL;
134b8e80941Smrg
135b8e80941Smrg   assert(resource->nr_samples <= 1);
136b8e80941Smrg
137b8e80941Smrg   flush = virgl_res_needs_flush(vctx, trans);
138b8e80941Smrg   if (flush)
139b8e80941Smrg      ctx->flush(ctx, NULL, 0);
140b8e80941Smrg
141b8e80941Smrg   readback = virgl_res_needs_readback(vctx, vtex, usage, level);
142b8e80941Smrg   if (readback)
143b8e80941Smrg      vws->transfer_get(vws, vtex->hw_res, box, trans->base.stride,
144b8e80941Smrg                        trans->l_stride, trans->offset, level);
145b8e80941Smrg
146b8e80941Smrg   if (readback || flush)
147b8e80941Smrg      vws->resource_wait(vws, vtex->hw_res);
148b8e80941Smrg
149b8e80941Smrg   trans->hw_res_map = vws->resource_map(vws, vtex->hw_res);
150b8e80941Smrg   if (!trans->hw_res_map) {
151b8e80941Smrg      virgl_resource_destroy_transfer(&vctx->transfer_pool, trans);
152b8e80941Smrg      return NULL;
153b8e80941Smrg   }
154b8e80941Smrg
155b8e80941Smrg   *transfer = &trans->base;
156b8e80941Smrg   return trans->hw_res_map + trans->offset;
157b8e80941Smrg}
158b8e80941Smrg
159b8e80941Smrgstatic void *texture_transfer_map_resolve(struct pipe_context *ctx,
160b8e80941Smrg                                          struct pipe_resource *resource,
161b8e80941Smrg                                          unsigned level,
162b8e80941Smrg                                          unsigned usage,
163b8e80941Smrg                                          const struct pipe_box *box,
164b8e80941Smrg                                          struct pipe_transfer **transfer)
165b8e80941Smrg{
166b8e80941Smrg   struct virgl_context *vctx = virgl_context(ctx);
167b8e80941Smrg   struct virgl_resource *vtex = virgl_resource(resource);
168b8e80941Smrg   struct pipe_resource templ, *resolve_tmp;
169b8e80941Smrg   struct virgl_transfer *trans;
170b8e80941Smrg
171b8e80941Smrg   trans = virgl_resource_create_transfer(&vctx->transfer_pool, resource,
172b8e80941Smrg                                          &vtex->metadata, level, usage, box);
173b8e80941Smrg   if (!trans)
174b8e80941Smrg      return NULL;
175b8e80941Smrg
176b8e80941Smrg   enum pipe_format fmt = resource->format;
177b8e80941Smrg   if (!virgl_has_readback_format(ctx->screen, fmt)) {
178b8e80941Smrg      if (util_format_fits_8unorm(util_format_description(fmt)))
179b8e80941Smrg         fmt = PIPE_FORMAT_R8G8B8A8_UNORM;
180b8e80941Smrg      else if (util_format_is_pure_sint(fmt))
181b8e80941Smrg         fmt = PIPE_FORMAT_R32G32B32A32_SINT;
182b8e80941Smrg      else if (util_format_is_pure_uint(fmt))
183b8e80941Smrg         fmt = PIPE_FORMAT_R32G32B32A32_UINT;
184b8e80941Smrg      else
185b8e80941Smrg         fmt = PIPE_FORMAT_R32G32B32A32_FLOAT;
186b8e80941Smrg      assert(virgl_has_readback_format(ctx->screen, fmt));
187b8e80941Smrg   }
188b8e80941Smrg
189b8e80941Smrg   virgl_init_temp_resource_from_box(&templ, resource, box, level, 0, fmt);
190b8e80941Smrg
191b8e80941Smrg   resolve_tmp = ctx->screen->resource_create(ctx->screen, &templ);
192b8e80941Smrg   if (!resolve_tmp)
193b8e80941Smrg      return NULL;
194b8e80941Smrg
195b8e80941Smrg   struct pipe_box dst_box = *box;
196b8e80941Smrg   dst_box.x = dst_box.y = dst_box.z = 0;
197b8e80941Smrg
198b8e80941Smrg   if (usage & PIPE_TRANSFER_READ) {
199b8e80941Smrg      virgl_copy_region_with_blit(ctx, resolve_tmp, 0, &dst_box, resource,
200b8e80941Smrg                                  level, box);
201b8e80941Smrg      ctx->flush(ctx, NULL, 0);
202b8e80941Smrg   }
203b8e80941Smrg
204b8e80941Smrg   void *ptr = texture_transfer_map_plain(ctx, resolve_tmp, 0, usage, &dst_box,
205b8e80941Smrg                                          &trans->resolve_transfer);
206b8e80941Smrg   if (!ptr)
207b8e80941Smrg      goto fail;
208b8e80941Smrg
209b8e80941Smrg   *transfer = &trans->base;
210b8e80941Smrg   if (fmt == resource->format) {
211b8e80941Smrg      trans->base.stride = trans->resolve_transfer->stride;
212b8e80941Smrg      trans->base.layer_stride = trans->resolve_transfer->layer_stride;
213b8e80941Smrg      return ptr;
214b8e80941Smrg   } else {
215b8e80941Smrg      if (usage & PIPE_TRANSFER_READ) {
216b8e80941Smrg         struct virgl_winsys *vws = virgl_screen(ctx->screen)->vws;
217b8e80941Smrg         void *src = ptr;
218b8e80941Smrg         ptr = vws->resource_map(vws, vtex->hw_res);
219b8e80941Smrg         if (!ptr)
220b8e80941Smrg            goto fail;
221b8e80941Smrg
222b8e80941Smrg          if (!util_format_translate_3d(resource->format,
223b8e80941Smrg                                       ptr,
224b8e80941Smrg                                       trans->base.stride,
225b8e80941Smrg                                       trans->base.layer_stride,
226b8e80941Smrg                                       box->x, box->y, box->z,
227b8e80941Smrg                                       fmt,
228b8e80941Smrg                                       src,
229b8e80941Smrg                                       trans->resolve_transfer->stride,
230b8e80941Smrg                                       trans->resolve_transfer->layer_stride,
231b8e80941Smrg                                       0, 0, 0,
232b8e80941Smrg                                       box->width, box->height, box->depth)) {
233b8e80941Smrg            debug_printf("failed to translate format %s to %s\n",
234b8e80941Smrg                         util_format_short_name(fmt),
235b8e80941Smrg                         util_format_short_name(resource->format));
236b8e80941Smrg            goto fail;
237b8e80941Smrg         }
238b8e80941Smrg      }
239b8e80941Smrg
240b8e80941Smrg      if ((usage & PIPE_TRANSFER_WRITE) == 0)
241b8e80941Smrg         pipe_resource_reference(&trans->resolve_transfer->resource, NULL);
242b8e80941Smrg
243b8e80941Smrg      return ptr + trans->offset;
244b8e80941Smrg   }
245b8e80941Smrg
246b8e80941Smrgfail:
247b8e80941Smrg   pipe_resource_reference(&resolve_tmp, NULL);
248b8e80941Smrg   virgl_resource_destroy_transfer(&vctx->transfer_pool, trans);
249b8e80941Smrg   return NULL;
250b8e80941Smrg}
251b8e80941Smrg
252b8e80941Smrgstatic bool needs_resolve(struct pipe_screen *screen,
253b8e80941Smrg                          struct pipe_resource *resource, unsigned usage)
254b8e80941Smrg{
255b8e80941Smrg   if (resource->nr_samples > 1)
256b8e80941Smrg      return true;
257b8e80941Smrg
258b8e80941Smrg   if (usage & PIPE_TRANSFER_READ)
259b8e80941Smrg      return !util_format_is_depth_or_stencil(resource->format) &&
260b8e80941Smrg             !virgl_has_readback_format(screen, resource->format);
261b8e80941Smrg
262b8e80941Smrg   return false;
263b8e80941Smrg}
264b8e80941Smrg
265b8e80941Smrgstatic void *virgl_texture_transfer_map(struct pipe_context *ctx,
266b8e80941Smrg                                        struct pipe_resource *resource,
267b8e80941Smrg                                        unsigned level,
268b8e80941Smrg                                        unsigned usage,
269b8e80941Smrg                                        const struct pipe_box *box,
270b8e80941Smrg                                        struct pipe_transfer **transfer)
271b8e80941Smrg{
272b8e80941Smrg   if (needs_resolve(ctx->screen, resource, usage))
273b8e80941Smrg      return texture_transfer_map_resolve(ctx, resource, level, usage, box,
274b8e80941Smrg                                          transfer);
275b8e80941Smrg
276b8e80941Smrg   return texture_transfer_map_plain(ctx, resource, level, usage, box, transfer);
277b8e80941Smrg}
278b8e80941Smrg
279b8e80941Smrgstatic void flush_data(struct pipe_context *ctx,
280b8e80941Smrg                       struct virgl_transfer *trans,
281b8e80941Smrg                       const struct pipe_box *box)
282b8e80941Smrg{
283b8e80941Smrg   struct virgl_winsys *vws = virgl_screen(ctx->screen)->vws;
284b8e80941Smrg   vws->transfer_put(vws, virgl_resource(trans->base.resource)->hw_res, box,
285b8e80941Smrg                     trans->base.stride, trans->l_stride, trans->offset,
286b8e80941Smrg                     trans->base.level);
287b8e80941Smrg}
288b8e80941Smrg
289b8e80941Smrgstatic void virgl_texture_transfer_unmap(struct pipe_context *ctx,
290b8e80941Smrg                                         struct pipe_transfer *transfer)
291b8e80941Smrg{
292b8e80941Smrg   struct virgl_context *vctx = virgl_context(ctx);
293b8e80941Smrg   struct virgl_transfer *trans = virgl_transfer(transfer);
294b8e80941Smrg   bool queue_unmap = false;
295b8e80941Smrg
296b8e80941Smrg   if (transfer->usage & PIPE_TRANSFER_WRITE &&
297b8e80941Smrg       (transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT) == 0) {
298b8e80941Smrg
299b8e80941Smrg      if (trans->resolve_transfer && (trans->base.resource->format ==
300b8e80941Smrg          trans->resolve_transfer->resource->format)) {
301b8e80941Smrg         flush_data(ctx, virgl_transfer(trans->resolve_transfer),
302b8e80941Smrg                    &trans->resolve_transfer->box);
303b8e80941Smrg
304b8e80941Smrg         /* FINISHME: In case the destination format isn't renderable here, the
305b8e80941Smrg          * blit here will currently fail. This could for instance happen if the
306b8e80941Smrg          * mapped resource is of a compressed format, and it's mapped with both
307b8e80941Smrg          * read and write usage.
308b8e80941Smrg          */
309b8e80941Smrg
310b8e80941Smrg         virgl_copy_region_with_blit(ctx,
311b8e80941Smrg                                     trans->base.resource, trans->base.level,
312b8e80941Smrg                                     &transfer->box,
313b8e80941Smrg                                     trans->resolve_transfer->resource, 0,
314b8e80941Smrg                                     &trans->resolve_transfer->box);
315b8e80941Smrg         ctx->flush(ctx, NULL, 0);
316b8e80941Smrg      } else
317b8e80941Smrg         queue_unmap = true;
318b8e80941Smrg   }
319b8e80941Smrg
320b8e80941Smrg   if (trans->resolve_transfer) {
321b8e80941Smrg      pipe_resource_reference(&trans->resolve_transfer->resource, NULL);
322b8e80941Smrg      virgl_resource_destroy_transfer(&vctx->transfer_pool,
323b8e80941Smrg                                      virgl_transfer(trans->resolve_transfer));
324b8e80941Smrg   }
325b8e80941Smrg
326b8e80941Smrg   if (queue_unmap)
327b8e80941Smrg      virgl_transfer_queue_unmap(&vctx->queue, trans);
328b8e80941Smrg   else
329b8e80941Smrg      virgl_resource_destroy_transfer(&vctx->transfer_pool, trans);
330b8e80941Smrg}
331b8e80941Smrg
332b8e80941Smrgstatic const struct u_resource_vtbl virgl_texture_vtbl =
333b8e80941Smrg{
334b8e80941Smrg   virgl_resource_get_handle,           /* get_handle */
335b8e80941Smrg   virgl_resource_destroy,              /* resource_destroy */
336b8e80941Smrg   virgl_texture_transfer_map,          /* transfer_map */
337b8e80941Smrg   NULL,                                /* transfer_flush_region */
338b8e80941Smrg   virgl_texture_transfer_unmap,        /* transfer_unmap */
339b8e80941Smrg};
340b8e80941Smrg
341b8e80941Smrgvoid virgl_texture_init(struct virgl_resource *res)
342b8e80941Smrg{
343b8e80941Smrg   res->u.vtbl = &virgl_texture_vtbl;
344b8e80941Smrg}
345