1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2006 VMware, Inc.
4bf215546Sopenharmony_ci * All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the
8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
12bf215546Sopenharmony_ci * the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
16bf215546Sopenharmony_ci * of the Software.
17bf215546Sopenharmony_ci *
18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci **************************************************************************/
27bf215546Sopenharmony_ci /*
28bf215546Sopenharmony_ci  * Authors:
29bf215546Sopenharmony_ci  *   Keith Whitwell <keithw@vmware.com>
30bf215546Sopenharmony_ci  *   Michel Dänzer <daenzer@vmware.com>
31bf215546Sopenharmony_ci  */
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#include "pipe/p_defines.h"
34bf215546Sopenharmony_ci#include "util/u_inlines.h"
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_ci#include "util/format/u_format.h"
37bf215546Sopenharmony_ci#include "util/u_math.h"
38bf215546Sopenharmony_ci#include "util/u_memory.h"
39bf215546Sopenharmony_ci#include "util/u_transfer.h"
40bf215546Sopenharmony_ci#include "util/u_surface.h"
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_ci#include "sp_context.h"
43bf215546Sopenharmony_ci#include "sp_flush.h"
44bf215546Sopenharmony_ci#include "sp_texture.h"
45bf215546Sopenharmony_ci#include "sp_screen.h"
46bf215546Sopenharmony_ci
47bf215546Sopenharmony_ci#include "frontend/sw_winsys.h"
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci/**
51bf215546Sopenharmony_ci * Conventional allocation path for non-display textures:
52bf215546Sopenharmony_ci * Use a simple, maximally packed layout.
53bf215546Sopenharmony_ci */
54bf215546Sopenharmony_cistatic boolean
55bf215546Sopenharmony_cisoftpipe_resource_layout(struct pipe_screen *screen,
56bf215546Sopenharmony_ci                         struct softpipe_resource *spr,
57bf215546Sopenharmony_ci                         boolean allocate)
58bf215546Sopenharmony_ci{
59bf215546Sopenharmony_ci   struct pipe_resource *pt = &spr->base;
60bf215546Sopenharmony_ci   unsigned level;
61bf215546Sopenharmony_ci   unsigned width = pt->width0;
62bf215546Sopenharmony_ci   unsigned height = pt->height0;
63bf215546Sopenharmony_ci   unsigned depth = pt->depth0;
64bf215546Sopenharmony_ci   uint64_t buffer_size = 0;
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci   for (level = 0; level <= pt->last_level; level++) {
67bf215546Sopenharmony_ci      unsigned slices, nblocksy;
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_ci      nblocksy = util_format_get_nblocksy(pt->format, height);
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci      if (pt->target == PIPE_TEXTURE_CUBE)
72bf215546Sopenharmony_ci         assert(pt->array_size == 6);
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_ci      if (pt->target == PIPE_TEXTURE_3D)
75bf215546Sopenharmony_ci         slices = depth;
76bf215546Sopenharmony_ci      else
77bf215546Sopenharmony_ci         slices = pt->array_size;
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci      spr->stride[level] = util_format_get_stride(pt->format, width);
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_ci      spr->level_offset[level] = buffer_size;
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_ci      /* if row_stride * height > SP_MAX_TEXTURE_SIZE */
84bf215546Sopenharmony_ci      if ((uint64_t)spr->stride[level] * nblocksy > SP_MAX_TEXTURE_SIZE) {
85bf215546Sopenharmony_ci         /* image too large */
86bf215546Sopenharmony_ci         return FALSE;
87bf215546Sopenharmony_ci      }
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci      spr->img_stride[level] = spr->stride[level] * nblocksy;
90bf215546Sopenharmony_ci
91bf215546Sopenharmony_ci      buffer_size += (uint64_t) spr->img_stride[level] * slices;
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci      width  = u_minify(width, 1);
94bf215546Sopenharmony_ci      height = u_minify(height, 1);
95bf215546Sopenharmony_ci      depth = u_minify(depth, 1);
96bf215546Sopenharmony_ci   }
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_ci   if (buffer_size > SP_MAX_TEXTURE_SIZE)
99bf215546Sopenharmony_ci      return FALSE;
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_ci   if (allocate) {
102bf215546Sopenharmony_ci      spr->data = align_malloc(buffer_size, 64);
103bf215546Sopenharmony_ci      return spr->data != NULL;
104bf215546Sopenharmony_ci   }
105bf215546Sopenharmony_ci   else {
106bf215546Sopenharmony_ci      return TRUE;
107bf215546Sopenharmony_ci   }
108bf215546Sopenharmony_ci}
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_ci/**
112bf215546Sopenharmony_ci * Check the size of the texture specified by 'res'.
113bf215546Sopenharmony_ci * \return TRUE if OK, FALSE if too large.
114bf215546Sopenharmony_ci */
115bf215546Sopenharmony_cistatic bool
116bf215546Sopenharmony_cisoftpipe_can_create_resource(struct pipe_screen *screen,
117bf215546Sopenharmony_ci                             const struct pipe_resource *res)
118bf215546Sopenharmony_ci{
119bf215546Sopenharmony_ci   struct softpipe_resource spr;
120bf215546Sopenharmony_ci   memset(&spr, 0, sizeof(spr));
121bf215546Sopenharmony_ci   spr.base = *res;
122bf215546Sopenharmony_ci   return softpipe_resource_layout(screen, &spr, FALSE);
123bf215546Sopenharmony_ci}
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci
126bf215546Sopenharmony_ci/**
127bf215546Sopenharmony_ci * Texture layout for simple color buffers.
128bf215546Sopenharmony_ci */
129bf215546Sopenharmony_cistatic boolean
130bf215546Sopenharmony_cisoftpipe_displaytarget_layout(struct pipe_screen *screen,
131bf215546Sopenharmony_ci                              struct softpipe_resource *spr,
132bf215546Sopenharmony_ci                              const void *map_front_private)
133bf215546Sopenharmony_ci{
134bf215546Sopenharmony_ci   struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci   /* Round up the surface size to a multiple of the tile size?
137bf215546Sopenharmony_ci    */
138bf215546Sopenharmony_ci   spr->dt = winsys->displaytarget_create(winsys,
139bf215546Sopenharmony_ci                                          spr->base.bind,
140bf215546Sopenharmony_ci                                          spr->base.format,
141bf215546Sopenharmony_ci                                          spr->base.width0,
142bf215546Sopenharmony_ci                                          spr->base.height0,
143bf215546Sopenharmony_ci                                          64,
144bf215546Sopenharmony_ci                                          map_front_private,
145bf215546Sopenharmony_ci                                          &spr->stride[0] );
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci   return spr->dt != NULL;
148bf215546Sopenharmony_ci}
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci
151bf215546Sopenharmony_ci/**
152bf215546Sopenharmony_ci * Create new pipe_resource given the template information.
153bf215546Sopenharmony_ci */
154bf215546Sopenharmony_cistatic struct pipe_resource *
155bf215546Sopenharmony_cisoftpipe_resource_create_front(struct pipe_screen *screen,
156bf215546Sopenharmony_ci                               const struct pipe_resource *templat,
157bf215546Sopenharmony_ci                               const void *map_front_private)
158bf215546Sopenharmony_ci{
159bf215546Sopenharmony_ci   struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource);
160bf215546Sopenharmony_ci   if (!spr)
161bf215546Sopenharmony_ci      return NULL;
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_ci   assert(templat->format != PIPE_FORMAT_NONE);
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci   spr->base = *templat;
166bf215546Sopenharmony_ci   pipe_reference_init(&spr->base.reference, 1);
167bf215546Sopenharmony_ci   spr->base.screen = screen;
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_ci   spr->pot = (util_is_power_of_two_or_zero(templat->width0) &&
170bf215546Sopenharmony_ci               util_is_power_of_two_or_zero(templat->height0) &&
171bf215546Sopenharmony_ci               util_is_power_of_two_or_zero(templat->depth0));
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci   if (spr->base.bind & (PIPE_BIND_DISPLAY_TARGET |
174bf215546Sopenharmony_ci			 PIPE_BIND_SCANOUT |
175bf215546Sopenharmony_ci			 PIPE_BIND_SHARED)) {
176bf215546Sopenharmony_ci      if (!softpipe_displaytarget_layout(screen, spr, map_front_private))
177bf215546Sopenharmony_ci         goto fail;
178bf215546Sopenharmony_ci   }
179bf215546Sopenharmony_ci   else {
180bf215546Sopenharmony_ci      if (!softpipe_resource_layout(screen, spr, TRUE))
181bf215546Sopenharmony_ci         goto fail;
182bf215546Sopenharmony_ci   }
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci   return &spr->base;
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci fail:
187bf215546Sopenharmony_ci   FREE(spr);
188bf215546Sopenharmony_ci   return NULL;
189bf215546Sopenharmony_ci}
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_cistatic struct pipe_resource *
192bf215546Sopenharmony_cisoftpipe_resource_create(struct pipe_screen *screen,
193bf215546Sopenharmony_ci                         const struct pipe_resource *templat)
194bf215546Sopenharmony_ci{
195bf215546Sopenharmony_ci   return softpipe_resource_create_front(screen, templat, NULL);
196bf215546Sopenharmony_ci}
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_cistatic void
199bf215546Sopenharmony_cisoftpipe_resource_destroy(struct pipe_screen *pscreen,
200bf215546Sopenharmony_ci			  struct pipe_resource *pt)
201bf215546Sopenharmony_ci{
202bf215546Sopenharmony_ci   struct softpipe_screen *screen = softpipe_screen(pscreen);
203bf215546Sopenharmony_ci   struct softpipe_resource *spr = softpipe_resource(pt);
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_ci   if (spr->dt) {
206bf215546Sopenharmony_ci      /* display target */
207bf215546Sopenharmony_ci      struct sw_winsys *winsys = screen->winsys;
208bf215546Sopenharmony_ci      winsys->displaytarget_destroy(winsys, spr->dt);
209bf215546Sopenharmony_ci   }
210bf215546Sopenharmony_ci   else if (!spr->userBuffer) {
211bf215546Sopenharmony_ci      /* regular texture */
212bf215546Sopenharmony_ci      align_free(spr->data);
213bf215546Sopenharmony_ci   }
214bf215546Sopenharmony_ci
215bf215546Sopenharmony_ci   FREE(spr);
216bf215546Sopenharmony_ci}
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci
219bf215546Sopenharmony_cistatic struct pipe_resource *
220bf215546Sopenharmony_cisoftpipe_resource_from_handle(struct pipe_screen *screen,
221bf215546Sopenharmony_ci                              const struct pipe_resource *templat,
222bf215546Sopenharmony_ci                              struct winsys_handle *whandle,
223bf215546Sopenharmony_ci                              unsigned usage)
224bf215546Sopenharmony_ci{
225bf215546Sopenharmony_ci   struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
226bf215546Sopenharmony_ci   struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource);
227bf215546Sopenharmony_ci   if (!spr)
228bf215546Sopenharmony_ci      return NULL;
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci   spr->base = *templat;
231bf215546Sopenharmony_ci   pipe_reference_init(&spr->base.reference, 1);
232bf215546Sopenharmony_ci   spr->base.screen = screen;
233bf215546Sopenharmony_ci
234bf215546Sopenharmony_ci   spr->pot = (util_is_power_of_two_or_zero(templat->width0) &&
235bf215546Sopenharmony_ci               util_is_power_of_two_or_zero(templat->height0) &&
236bf215546Sopenharmony_ci               util_is_power_of_two_or_zero(templat->depth0));
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_ci   spr->dt = winsys->displaytarget_from_handle(winsys,
239bf215546Sopenharmony_ci                                               templat,
240bf215546Sopenharmony_ci                                               whandle,
241bf215546Sopenharmony_ci                                               &spr->stride[0]);
242bf215546Sopenharmony_ci   if (!spr->dt)
243bf215546Sopenharmony_ci      goto fail;
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_ci   return &spr->base;
246bf215546Sopenharmony_ci
247bf215546Sopenharmony_ci fail:
248bf215546Sopenharmony_ci   FREE(spr);
249bf215546Sopenharmony_ci   return NULL;
250bf215546Sopenharmony_ci}
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci
253bf215546Sopenharmony_cistatic bool
254bf215546Sopenharmony_cisoftpipe_resource_get_handle(struct pipe_screen *screen,
255bf215546Sopenharmony_ci                             struct pipe_context *ctx,
256bf215546Sopenharmony_ci                             struct pipe_resource *pt,
257bf215546Sopenharmony_ci                             struct winsys_handle *whandle,
258bf215546Sopenharmony_ci                             unsigned usage)
259bf215546Sopenharmony_ci{
260bf215546Sopenharmony_ci   struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
261bf215546Sopenharmony_ci   struct softpipe_resource *spr = softpipe_resource(pt);
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_ci   assert(spr->dt);
264bf215546Sopenharmony_ci   if (!spr->dt)
265bf215546Sopenharmony_ci      return false;
266bf215546Sopenharmony_ci
267bf215546Sopenharmony_ci   return winsys->displaytarget_get_handle(winsys, spr->dt, whandle);
268bf215546Sopenharmony_ci}
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci/**
272bf215546Sopenharmony_ci * Helper function to compute offset (in bytes) for a particular
273bf215546Sopenharmony_ci * texture level/face/slice from the start of the buffer.
274bf215546Sopenharmony_ci */
275bf215546Sopenharmony_ciunsigned
276bf215546Sopenharmony_cisoftpipe_get_tex_image_offset(const struct softpipe_resource *spr,
277bf215546Sopenharmony_ci                              unsigned level, unsigned layer)
278bf215546Sopenharmony_ci{
279bf215546Sopenharmony_ci   unsigned offset = spr->level_offset[level];
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_ci   offset += layer * spr->img_stride[level];
282bf215546Sopenharmony_ci
283bf215546Sopenharmony_ci   return offset;
284bf215546Sopenharmony_ci}
285bf215546Sopenharmony_ci
286bf215546Sopenharmony_ci
287bf215546Sopenharmony_ci/**
288bf215546Sopenharmony_ci * Get a pipe_surface "view" into a texture resource.
289bf215546Sopenharmony_ci */
290bf215546Sopenharmony_cistatic struct pipe_surface *
291bf215546Sopenharmony_cisoftpipe_create_surface(struct pipe_context *pipe,
292bf215546Sopenharmony_ci                        struct pipe_resource *pt,
293bf215546Sopenharmony_ci                        const struct pipe_surface *surf_tmpl)
294bf215546Sopenharmony_ci{
295bf215546Sopenharmony_ci   struct pipe_surface *ps;
296bf215546Sopenharmony_ci
297bf215546Sopenharmony_ci   ps = CALLOC_STRUCT(pipe_surface);
298bf215546Sopenharmony_ci   if (ps) {
299bf215546Sopenharmony_ci      pipe_reference_init(&ps->reference, 1);
300bf215546Sopenharmony_ci      pipe_resource_reference(&ps->texture, pt);
301bf215546Sopenharmony_ci      ps->context = pipe;
302bf215546Sopenharmony_ci      ps->format = surf_tmpl->format;
303bf215546Sopenharmony_ci      if (pt->target != PIPE_BUFFER) {
304bf215546Sopenharmony_ci         assert(surf_tmpl->u.tex.level <= pt->last_level);
305bf215546Sopenharmony_ci         ps->width = u_minify(pt->width0, surf_tmpl->u.tex.level);
306bf215546Sopenharmony_ci         ps->height = u_minify(pt->height0, surf_tmpl->u.tex.level);
307bf215546Sopenharmony_ci         ps->u.tex.level = surf_tmpl->u.tex.level;
308bf215546Sopenharmony_ci         ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
309bf215546Sopenharmony_ci         ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
310bf215546Sopenharmony_ci         if (ps->u.tex.first_layer != ps->u.tex.last_layer) {
311bf215546Sopenharmony_ci            debug_printf("creating surface with multiple layers, rendering to first layer only\n");
312bf215546Sopenharmony_ci         }
313bf215546Sopenharmony_ci      }
314bf215546Sopenharmony_ci      else {
315bf215546Sopenharmony_ci         /* setting width as number of elements should get us correct renderbuffer width */
316bf215546Sopenharmony_ci         ps->width = surf_tmpl->u.buf.last_element - surf_tmpl->u.buf.first_element + 1;
317bf215546Sopenharmony_ci         ps->height = pt->height0;
318bf215546Sopenharmony_ci         ps->u.buf.first_element = surf_tmpl->u.buf.first_element;
319bf215546Sopenharmony_ci         ps->u.buf.last_element = surf_tmpl->u.buf.last_element;
320bf215546Sopenharmony_ci         assert(ps->u.buf.first_element <= ps->u.buf.last_element);
321bf215546Sopenharmony_ci         assert(ps->u.buf.last_element < ps->width);
322bf215546Sopenharmony_ci      }
323bf215546Sopenharmony_ci   }
324bf215546Sopenharmony_ci   return ps;
325bf215546Sopenharmony_ci}
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_ci
328bf215546Sopenharmony_ci/**
329bf215546Sopenharmony_ci * Free a pipe_surface which was created with softpipe_create_surface().
330bf215546Sopenharmony_ci */
331bf215546Sopenharmony_cistatic void
332bf215546Sopenharmony_cisoftpipe_surface_destroy(struct pipe_context *pipe,
333bf215546Sopenharmony_ci                         struct pipe_surface *surf)
334bf215546Sopenharmony_ci{
335bf215546Sopenharmony_ci   /* Effectively do the texture_update work here - if texture images
336bf215546Sopenharmony_ci    * needed post-processing to put them into hardware layout, this is
337bf215546Sopenharmony_ci    * where it would happen.  For softpipe, nothing to do.
338bf215546Sopenharmony_ci    */
339bf215546Sopenharmony_ci   assert(surf->texture);
340bf215546Sopenharmony_ci   pipe_resource_reference(&surf->texture, NULL);
341bf215546Sopenharmony_ci   FREE(surf);
342bf215546Sopenharmony_ci}
343bf215546Sopenharmony_ci
344bf215546Sopenharmony_ci
345bf215546Sopenharmony_ci/**
346bf215546Sopenharmony_ci * Geta pipe_transfer object which is used for moving data in/out of
347bf215546Sopenharmony_ci * a resource object.
348bf215546Sopenharmony_ci * \param pipe  rendering context
349bf215546Sopenharmony_ci * \param resource  the resource to transfer in/out of
350bf215546Sopenharmony_ci * \param level  which mipmap level
351bf215546Sopenharmony_ci * \param usage  bitmask of PIPE_MAP_x flags
352bf215546Sopenharmony_ci * \param box  the 1D/2D/3D region of interest
353bf215546Sopenharmony_ci */
354bf215546Sopenharmony_cistatic void *
355bf215546Sopenharmony_cisoftpipe_transfer_map(struct pipe_context *pipe,
356bf215546Sopenharmony_ci                      struct pipe_resource *resource,
357bf215546Sopenharmony_ci                      unsigned level,
358bf215546Sopenharmony_ci                      unsigned usage,
359bf215546Sopenharmony_ci                      const struct pipe_box *box,
360bf215546Sopenharmony_ci                      struct pipe_transfer **transfer)
361bf215546Sopenharmony_ci{
362bf215546Sopenharmony_ci   struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys;
363bf215546Sopenharmony_ci   struct softpipe_resource *spr = softpipe_resource(resource);
364bf215546Sopenharmony_ci   struct softpipe_transfer *spt;
365bf215546Sopenharmony_ci   struct pipe_transfer *pt;
366bf215546Sopenharmony_ci   enum pipe_format format = resource->format;
367bf215546Sopenharmony_ci   uint8_t *map;
368bf215546Sopenharmony_ci
369bf215546Sopenharmony_ci   assert(resource);
370bf215546Sopenharmony_ci   assert(level <= resource->last_level);
371bf215546Sopenharmony_ci
372bf215546Sopenharmony_ci   /* make sure the requested region is in the image bounds */
373bf215546Sopenharmony_ci   assert(box->x + box->width <= (int) u_minify(resource->width0, level));
374bf215546Sopenharmony_ci   if (resource->target == PIPE_TEXTURE_1D_ARRAY) {
375bf215546Sopenharmony_ci      assert(box->y + box->height <= (int) resource->array_size);
376bf215546Sopenharmony_ci   }
377bf215546Sopenharmony_ci   else {
378bf215546Sopenharmony_ci      assert(box->y + box->height <= (int) u_minify(resource->height0, level));
379bf215546Sopenharmony_ci      if (resource->target == PIPE_TEXTURE_2D_ARRAY) {
380bf215546Sopenharmony_ci         assert(box->z + box->depth <= (int) resource->array_size);
381bf215546Sopenharmony_ci      }
382bf215546Sopenharmony_ci      else if (resource->target == PIPE_TEXTURE_CUBE) {
383bf215546Sopenharmony_ci         assert(box->z < 6);
384bf215546Sopenharmony_ci      }
385bf215546Sopenharmony_ci      else if (resource->target == PIPE_TEXTURE_CUBE_ARRAY) {
386bf215546Sopenharmony_ci         assert(box->z <= (int) resource->array_size);
387bf215546Sopenharmony_ci      }
388bf215546Sopenharmony_ci      else {
389bf215546Sopenharmony_ci         assert(box->z + box->depth <= (int) u_minify(resource->depth0, level));
390bf215546Sopenharmony_ci      }
391bf215546Sopenharmony_ci   }
392bf215546Sopenharmony_ci
393bf215546Sopenharmony_ci   /*
394bf215546Sopenharmony_ci    * Transfers, like other pipe operations, must happen in order, so flush the
395bf215546Sopenharmony_ci    * context if necessary.
396bf215546Sopenharmony_ci    */
397bf215546Sopenharmony_ci   if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) {
398bf215546Sopenharmony_ci      boolean read_only = !(usage & PIPE_MAP_WRITE);
399bf215546Sopenharmony_ci      boolean do_not_block = !!(usage & PIPE_MAP_DONTBLOCK);
400bf215546Sopenharmony_ci      if (!softpipe_flush_resource(pipe, resource,
401bf215546Sopenharmony_ci                                   level, box->depth > 1 ? -1 : box->z,
402bf215546Sopenharmony_ci                                   0, /* flush_flags */
403bf215546Sopenharmony_ci                                   read_only,
404bf215546Sopenharmony_ci                                   TRUE, /* cpu_access */
405bf215546Sopenharmony_ci                                   do_not_block)) {
406bf215546Sopenharmony_ci         /*
407bf215546Sopenharmony_ci          * It would have blocked, but state tracker requested no to.
408bf215546Sopenharmony_ci          */
409bf215546Sopenharmony_ci         assert(do_not_block);
410bf215546Sopenharmony_ci         return NULL;
411bf215546Sopenharmony_ci      }
412bf215546Sopenharmony_ci   }
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci   spt = CALLOC_STRUCT(softpipe_transfer);
415bf215546Sopenharmony_ci   if (!spt)
416bf215546Sopenharmony_ci      return NULL;
417bf215546Sopenharmony_ci
418bf215546Sopenharmony_ci   pt = &spt->base;
419bf215546Sopenharmony_ci
420bf215546Sopenharmony_ci   pipe_resource_reference(&pt->resource, resource);
421bf215546Sopenharmony_ci   pt->level = level;
422bf215546Sopenharmony_ci   pt->usage = usage;
423bf215546Sopenharmony_ci   pt->box = *box;
424bf215546Sopenharmony_ci   pt->stride = spr->stride[level];
425bf215546Sopenharmony_ci   pt->layer_stride = spr->img_stride[level];
426bf215546Sopenharmony_ci
427bf215546Sopenharmony_ci   spt->offset = softpipe_get_tex_image_offset(spr, level, box->z);
428bf215546Sopenharmony_ci
429bf215546Sopenharmony_ci   spt->offset +=
430bf215546Sopenharmony_ci         box->y / util_format_get_blockheight(format) * spt->base.stride +
431bf215546Sopenharmony_ci         box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_ci   /* resources backed by display target treated specially:
434bf215546Sopenharmony_ci    */
435bf215546Sopenharmony_ci   if (spr->dt) {
436bf215546Sopenharmony_ci      map = winsys->displaytarget_map(winsys, spr->dt, usage);
437bf215546Sopenharmony_ci   }
438bf215546Sopenharmony_ci   else {
439bf215546Sopenharmony_ci      map = spr->data;
440bf215546Sopenharmony_ci   }
441bf215546Sopenharmony_ci
442bf215546Sopenharmony_ci   if (!map) {
443bf215546Sopenharmony_ci      pipe_resource_reference(&pt->resource, NULL);
444bf215546Sopenharmony_ci      FREE(spt);
445bf215546Sopenharmony_ci      return NULL;
446bf215546Sopenharmony_ci   }
447bf215546Sopenharmony_ci
448bf215546Sopenharmony_ci   *transfer = pt;
449bf215546Sopenharmony_ci   return map + spt->offset;
450bf215546Sopenharmony_ci}
451bf215546Sopenharmony_ci
452bf215546Sopenharmony_ci
453bf215546Sopenharmony_ci/**
454bf215546Sopenharmony_ci * Unmap memory mapping for given pipe_transfer object.
455bf215546Sopenharmony_ci */
456bf215546Sopenharmony_cistatic void
457bf215546Sopenharmony_cisoftpipe_transfer_unmap(struct pipe_context *pipe,
458bf215546Sopenharmony_ci                        struct pipe_transfer *transfer)
459bf215546Sopenharmony_ci{
460bf215546Sopenharmony_ci   struct softpipe_resource *spr;
461bf215546Sopenharmony_ci
462bf215546Sopenharmony_ci   assert(transfer->resource);
463bf215546Sopenharmony_ci   spr = softpipe_resource(transfer->resource);
464bf215546Sopenharmony_ci
465bf215546Sopenharmony_ci   if (spr->dt) {
466bf215546Sopenharmony_ci      /* display target */
467bf215546Sopenharmony_ci      struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys;
468bf215546Sopenharmony_ci      winsys->displaytarget_unmap(winsys, spr->dt);
469bf215546Sopenharmony_ci   }
470bf215546Sopenharmony_ci
471bf215546Sopenharmony_ci   if (transfer->usage & PIPE_MAP_WRITE) {
472bf215546Sopenharmony_ci      /* Mark the texture as dirty to expire the tile caches. */
473bf215546Sopenharmony_ci      spr->timestamp++;
474bf215546Sopenharmony_ci   }
475bf215546Sopenharmony_ci
476bf215546Sopenharmony_ci   pipe_resource_reference(&transfer->resource, NULL);
477bf215546Sopenharmony_ci   FREE(transfer);
478bf215546Sopenharmony_ci}
479bf215546Sopenharmony_ci
480bf215546Sopenharmony_ci/**
481bf215546Sopenharmony_ci * Create buffer which wraps user-space data.
482bf215546Sopenharmony_ci */
483bf215546Sopenharmony_cistruct pipe_resource *
484bf215546Sopenharmony_cisoftpipe_user_buffer_create(struct pipe_screen *screen,
485bf215546Sopenharmony_ci                            void *ptr,
486bf215546Sopenharmony_ci                            unsigned bytes,
487bf215546Sopenharmony_ci			    unsigned bind_flags)
488bf215546Sopenharmony_ci{
489bf215546Sopenharmony_ci   struct softpipe_resource *spr;
490bf215546Sopenharmony_ci
491bf215546Sopenharmony_ci   spr = CALLOC_STRUCT(softpipe_resource);
492bf215546Sopenharmony_ci   if (!spr)
493bf215546Sopenharmony_ci      return NULL;
494bf215546Sopenharmony_ci
495bf215546Sopenharmony_ci   pipe_reference_init(&spr->base.reference, 1);
496bf215546Sopenharmony_ci   spr->base.screen = screen;
497bf215546Sopenharmony_ci   spr->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */
498bf215546Sopenharmony_ci   spr->base.bind = bind_flags;
499bf215546Sopenharmony_ci   spr->base.usage = PIPE_USAGE_IMMUTABLE;
500bf215546Sopenharmony_ci   spr->base.flags = 0;
501bf215546Sopenharmony_ci   spr->base.width0 = bytes;
502bf215546Sopenharmony_ci   spr->base.height0 = 1;
503bf215546Sopenharmony_ci   spr->base.depth0 = 1;
504bf215546Sopenharmony_ci   spr->base.array_size = 1;
505bf215546Sopenharmony_ci   spr->userBuffer = TRUE;
506bf215546Sopenharmony_ci   spr->data = ptr;
507bf215546Sopenharmony_ci
508bf215546Sopenharmony_ci   return &spr->base;
509bf215546Sopenharmony_ci}
510bf215546Sopenharmony_ci
511bf215546Sopenharmony_ci
512bf215546Sopenharmony_civoid
513bf215546Sopenharmony_cisoftpipe_init_texture_funcs(struct pipe_context *pipe)
514bf215546Sopenharmony_ci{
515bf215546Sopenharmony_ci   pipe->buffer_map = softpipe_transfer_map;
516bf215546Sopenharmony_ci   pipe->buffer_unmap = softpipe_transfer_unmap;
517bf215546Sopenharmony_ci   pipe->texture_map = softpipe_transfer_map;
518bf215546Sopenharmony_ci   pipe->texture_unmap = softpipe_transfer_unmap;
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_ci   pipe->transfer_flush_region = u_default_transfer_flush_region;
521bf215546Sopenharmony_ci   pipe->buffer_subdata = u_default_buffer_subdata;
522bf215546Sopenharmony_ci   pipe->texture_subdata = u_default_texture_subdata;
523bf215546Sopenharmony_ci
524bf215546Sopenharmony_ci   pipe->create_surface = softpipe_create_surface;
525bf215546Sopenharmony_ci   pipe->surface_destroy = softpipe_surface_destroy;
526bf215546Sopenharmony_ci   pipe->clear_texture = util_clear_texture;
527bf215546Sopenharmony_ci}
528bf215546Sopenharmony_ci
529bf215546Sopenharmony_ci
530bf215546Sopenharmony_civoid
531bf215546Sopenharmony_cisoftpipe_init_screen_texture_funcs(struct pipe_screen *screen)
532bf215546Sopenharmony_ci{
533bf215546Sopenharmony_ci   screen->resource_create = softpipe_resource_create;
534bf215546Sopenharmony_ci   screen->resource_create_front = softpipe_resource_create_front;
535bf215546Sopenharmony_ci   screen->resource_destroy = softpipe_resource_destroy;
536bf215546Sopenharmony_ci   screen->resource_from_handle = softpipe_resource_from_handle;
537bf215546Sopenharmony_ci   screen->resource_get_handle = softpipe_resource_get_handle;
538bf215546Sopenharmony_ci   screen->can_create_resource = softpipe_can_create_resource;
539bf215546Sopenharmony_ci}
540