1/**************************************************************************
2 *
3 * Copyright 2010 Luca Barbieri
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 **************************************************************************/
26
27#include "util/u_staging.h"
28#include "pipe/p_context.h"
29#include "util/u_memory.h"
30#include "util/u_inlines.h"
31
32static void
33util_staging_resource_template(struct pipe_resource *pt, unsigned width, unsigned height, unsigned depth, struct pipe_resource *template)
34{
35   memset(template, 0, sizeof(struct pipe_resource));
36   if(pt->target != PIPE_BUFFER && depth <= 1)
37      template->target = PIPE_TEXTURE_RECT;
38   else
39      template->target = pt->target;
40   template->format = pt->format;
41   template->width0 = width;
42   template->height0 = height;
43   template->depth0 = depth;
44   template->array_size = 1;
45   template->last_level = 0;
46   template->nr_samples = pt->nr_samples;
47   template->bind = 0;
48   template->usage = PIPE_USAGE_STAGING;
49   template->flags = 0;
50}
51
52struct util_staging_transfer *
53util_staging_transfer_init(struct pipe_context *pipe,
54           struct pipe_resource *pt,
55           unsigned level,
56           unsigned usage,
57           const struct pipe_box *box,
58           boolean direct, struct util_staging_transfer *tx)
59{
60   struct pipe_screen *pscreen = pipe->screen;
61
62   struct pipe_resource staging_resource_template;
63
64   pipe_resource_reference(&tx->base.resource, pt);
65   tx->base.level = level;
66   tx->base.usage = usage;
67   tx->base.box = *box;
68
69   if (direct)
70   {
71      tx->staging_resource = pt;
72      return tx;
73   }
74
75   util_staging_resource_template(pt, box->width, box->height, box->depth, &staging_resource_template);
76   tx->staging_resource = pscreen->resource_create(pscreen, &staging_resource_template);
77   if (!tx->staging_resource)
78   {
79      pipe_resource_reference(&tx->base.resource, NULL);
80      FREE(tx);
81      return NULL;
82   }
83
84   if (usage & PIPE_TRANSFER_READ)
85   {
86      /* XXX this looks wrong dst is always the same but looping over src z? */
87      unsigned zi;
88      struct pipe_box sbox;
89      sbox.x = box->x;
90      sbox.y = box->y;
91      sbox.z = box->z;
92      sbox.width = box->width;
93      sbox.height = box->height;
94      sbox.depth = 1;
95      for(zi = 0; zi < box->depth; ++zi) {
96         sbox.z = sbox.z + zi;
97         pipe->resource_copy_region(pipe, tx->staging_resource, 0, 0, 0, 0,
98                                    tx->base.resource, level, &sbox);
99      }
100   }
101
102   return tx;
103}
104
105void
106util_staging_transfer_destroy(struct pipe_context *pipe, struct pipe_transfer *ptx)
107{
108   struct util_staging_transfer *tx = (struct util_staging_transfer *)ptx;
109
110   if (tx->staging_resource != tx->base.resource)
111   {
112      if(tx->base.usage & PIPE_TRANSFER_WRITE) {
113         /* XXX this looks wrong src is always the same but looping over dst z? */
114         unsigned zi;
115         struct pipe_box sbox;
116         sbox.x = 0;
117         sbox.y = 0;
118         sbox.z = 0;
119         sbox.width = tx->base.box.width;
120         sbox.height = tx->base.box.height;
121         sbox.depth = 1;
122         for(zi = 0; zi < tx->base.box.depth; ++zi)
123            pipe->resource_copy_region(pipe, tx->base.resource, tx->base.level, tx->base.box.x, tx->base.box.y, tx->base.box.z + zi,
124                                       tx->staging_resource, 0, &sbox);
125      }
126
127      pipe_resource_reference(&tx->staging_resource, NULL);
128   }
129
130   pipe_resource_reference(&ptx->resource, NULL);
131   FREE(ptx);
132}
133