14a49301eSmrg/**************************************************************************
24a49301eSmrg *
3af69d88dSmrg * Copyright 2006 VMware, Inc.
44a49301eSmrg * All Rights Reserved.
54a49301eSmrg *
64a49301eSmrg * Permission is hereby granted, free of charge, to any person obtaining a
74a49301eSmrg * copy of this software and associated documentation files (the
84a49301eSmrg * "Software"), to deal in the Software without restriction, including
94a49301eSmrg * without limitation the rights to use, copy, modify, merge, publish,
104a49301eSmrg * distribute, sub license, and/or sell copies of the Software, and to
114a49301eSmrg * permit persons to whom the Software is furnished to do so, subject to
124a49301eSmrg * the following conditions:
134a49301eSmrg *
144a49301eSmrg * The above copyright notice and this permission notice (including the
154a49301eSmrg * next paragraph) shall be included in all copies or substantial portions
164a49301eSmrg * of the Software.
174a49301eSmrg *
184a49301eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
194a49301eSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
204a49301eSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21af69d88dSmrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
224a49301eSmrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
234a49301eSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
244a49301eSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
254a49301eSmrg *
264a49301eSmrg **************************************************************************/
274a49301eSmrg /*
284a49301eSmrg  * Authors:
29af69d88dSmrg  *   Keith Whitwell <keithw@vmware.com>
30af69d88dSmrg  *   Michel Dänzer <daenzer@vmware.com>
314a49301eSmrg  */
324a49301eSmrg
334a49301eSmrg#include "pipe/p_defines.h"
34cdc920a0Smrg#include "util/u_inlines.h"
35cdc920a0Smrg
367ec681f3Smrg#include "util/format/u_format.h"
374a49301eSmrg#include "util/u_math.h"
384a49301eSmrg#include "util/u_memory.h"
393464ebd5Sriastradh#include "util/u_transfer.h"
4001e04c3fSmrg#include "util/u_surface.h"
414a49301eSmrg
424a49301eSmrg#include "sp_context.h"
433464ebd5Sriastradh#include "sp_flush.h"
444a49301eSmrg#include "sp_texture.h"
454a49301eSmrg#include "sp_screen.h"
463464ebd5Sriastradh
477ec681f3Smrg#include "frontend/sw_winsys.h"
484a49301eSmrg
494a49301eSmrg
504a49301eSmrg/**
514a49301eSmrg * Conventional allocation path for non-display textures:
524a49301eSmrg * Use a simple, maximally packed layout.
534a49301eSmrg */
544a49301eSmrgstatic boolean
553464ebd5Sriastradhsoftpipe_resource_layout(struct pipe_screen *screen,
56af69d88dSmrg                         struct softpipe_resource *spr,
57af69d88dSmrg                         boolean allocate)
584a49301eSmrg{
593464ebd5Sriastradh   struct pipe_resource *pt = &spr->base;
604a49301eSmrg   unsigned level;
61cdc920a0Smrg   unsigned width = pt->width0;
62cdc920a0Smrg   unsigned height = pt->height0;
63cdc920a0Smrg   unsigned depth = pt->depth0;
64af69d88dSmrg   uint64_t buffer_size = 0;
654a49301eSmrg
664a49301eSmrg   for (level = 0; level <= pt->last_level; level++) {
6701e04c3fSmrg      unsigned slices, nblocksy;
6801e04c3fSmrg
6901e04c3fSmrg      nblocksy = util_format_get_nblocksy(pt->format, height);
703464ebd5Sriastradh
713464ebd5Sriastradh      if (pt->target == PIPE_TEXTURE_CUBE)
7201e04c3fSmrg         assert(pt->array_size == 6);
7301e04c3fSmrg
7401e04c3fSmrg      if (pt->target == PIPE_TEXTURE_3D)
753464ebd5Sriastradh         slices = depth;
763464ebd5Sriastradh      else
773464ebd5Sriastradh         slices = pt->array_size;
784a49301eSmrg
793464ebd5Sriastradh      spr->stride[level] = util_format_get_stride(pt->format, width);
803464ebd5Sriastradh
813464ebd5Sriastradh      spr->level_offset[level] = buffer_size;
824a49301eSmrg
8301e04c3fSmrg      /* if row_stride * height > SP_MAX_TEXTURE_SIZE */
8401e04c3fSmrg      if ((uint64_t)spr->stride[level] * nblocksy > SP_MAX_TEXTURE_SIZE) {
8501e04c3fSmrg         /* image too large */
8601e04c3fSmrg         return FALSE;
8701e04c3fSmrg      }
8801e04c3fSmrg
8901e04c3fSmrg      spr->img_stride[level] = spr->stride[level] * nblocksy;
9001e04c3fSmrg
9101e04c3fSmrg      buffer_size += (uint64_t) spr->img_stride[level] * slices;
924a49301eSmrg
93cdc920a0Smrg      width  = u_minify(width, 1);
94cdc920a0Smrg      height = u_minify(height, 1);
95cdc920a0Smrg      depth = u_minify(depth, 1);
964a49301eSmrg   }
974a49301eSmrg
98af69d88dSmrg   if (buffer_size > SP_MAX_TEXTURE_SIZE)
99af69d88dSmrg      return FALSE;
1004a49301eSmrg
101af69d88dSmrg   if (allocate) {
102af69d88dSmrg      spr->data = align_malloc(buffer_size, 64);
103af69d88dSmrg      return spr->data != NULL;
104af69d88dSmrg   }
105af69d88dSmrg   else {
106af69d88dSmrg      return TRUE;
107af69d88dSmrg   }
108af69d88dSmrg}
109af69d88dSmrg
110af69d88dSmrg
111af69d88dSmrg/**
112af69d88dSmrg * Check the size of the texture specified by 'res'.
113af69d88dSmrg * \return TRUE if OK, FALSE if too large.
114af69d88dSmrg */
1157ec681f3Smrgstatic bool
116af69d88dSmrgsoftpipe_can_create_resource(struct pipe_screen *screen,
117af69d88dSmrg                             const struct pipe_resource *res)
118af69d88dSmrg{
119af69d88dSmrg   struct softpipe_resource spr;
120af69d88dSmrg   memset(&spr, 0, sizeof(spr));
121af69d88dSmrg   spr.base = *res;
122af69d88dSmrg   return softpipe_resource_layout(screen, &spr, FALSE);
1234a49301eSmrg}
1244a49301eSmrg
1254a49301eSmrg
1264a49301eSmrg/**
1274a49301eSmrg * Texture layout for simple color buffers.
1284a49301eSmrg */
1294a49301eSmrgstatic boolean
1304a49301eSmrgsoftpipe_displaytarget_layout(struct pipe_screen *screen,
13101e04c3fSmrg                              struct softpipe_resource *spr,
13201e04c3fSmrg                              const void *map_front_private)
1334a49301eSmrg{
1343464ebd5Sriastradh   struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
1353464ebd5Sriastradh
1363464ebd5Sriastradh   /* Round up the surface size to a multiple of the tile size?
1373464ebd5Sriastradh    */
1383464ebd5Sriastradh   spr->dt = winsys->displaytarget_create(winsys,
1393464ebd5Sriastradh                                          spr->base.bind,
1403464ebd5Sriastradh                                          spr->base.format,
1413464ebd5Sriastradh                                          spr->base.width0,
1423464ebd5Sriastradh                                          spr->base.height0,
143af69d88dSmrg                                          64,
14401e04c3fSmrg                                          map_front_private,
1453464ebd5Sriastradh                                          &spr->stride[0] );
1463464ebd5Sriastradh
1473464ebd5Sriastradh   return spr->dt != NULL;
1484a49301eSmrg}
1494a49301eSmrg
1504a49301eSmrg
1514a49301eSmrg/**
1523464ebd5Sriastradh * Create new pipe_resource given the template information.
1534a49301eSmrg */
1543464ebd5Sriastradhstatic struct pipe_resource *
15501e04c3fSmrgsoftpipe_resource_create_front(struct pipe_screen *screen,
15601e04c3fSmrg                               const struct pipe_resource *templat,
15701e04c3fSmrg                               const void *map_front_private)
1584a49301eSmrg{
1593464ebd5Sriastradh   struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource);
1603464ebd5Sriastradh   if (!spr)
1614a49301eSmrg      return NULL;
1624a49301eSmrg
1633464ebd5Sriastradh   assert(templat->format != PIPE_FORMAT_NONE);
1643464ebd5Sriastradh
1653464ebd5Sriastradh   spr->base = *templat;
1663464ebd5Sriastradh   pipe_reference_init(&spr->base.reference, 1);
1673464ebd5Sriastradh   spr->base.screen = screen;
1684a49301eSmrg
16901e04c3fSmrg   spr->pot = (util_is_power_of_two_or_zero(templat->width0) &&
17001e04c3fSmrg               util_is_power_of_two_or_zero(templat->height0) &&
17101e04c3fSmrg               util_is_power_of_two_or_zero(templat->depth0));
1724a49301eSmrg
1733464ebd5Sriastradh   if (spr->base.bind & (PIPE_BIND_DISPLAY_TARGET |
1743464ebd5Sriastradh			 PIPE_BIND_SCANOUT |
1753464ebd5Sriastradh			 PIPE_BIND_SHARED)) {
17601e04c3fSmrg      if (!softpipe_displaytarget_layout(screen, spr, map_front_private))
1774a49301eSmrg         goto fail;
1784a49301eSmrg   }
1794a49301eSmrg   else {
180af69d88dSmrg      if (!softpipe_resource_layout(screen, spr, TRUE))
1814a49301eSmrg         goto fail;
1824a49301eSmrg   }
1834a49301eSmrg
1843464ebd5Sriastradh   return &spr->base;
1854a49301eSmrg
1864a49301eSmrg fail:
1873464ebd5Sriastradh   FREE(spr);
1884a49301eSmrg   return NULL;
1894a49301eSmrg}
1904a49301eSmrg
19101e04c3fSmrgstatic struct pipe_resource *
19201e04c3fSmrgsoftpipe_resource_create(struct pipe_screen *screen,
19301e04c3fSmrg                         const struct pipe_resource *templat)
19401e04c3fSmrg{
19501e04c3fSmrg   return softpipe_resource_create_front(screen, templat, NULL);
19601e04c3fSmrg}
1974a49301eSmrg
1983464ebd5Sriastradhstatic void
1993464ebd5Sriastradhsoftpipe_resource_destroy(struct pipe_screen *pscreen,
2003464ebd5Sriastradh			  struct pipe_resource *pt)
2014a49301eSmrg{
2023464ebd5Sriastradh   struct softpipe_screen *screen = softpipe_screen(pscreen);
2033464ebd5Sriastradh   struct softpipe_resource *spr = softpipe_resource(pt);
2044a49301eSmrg
2053464ebd5Sriastradh   if (spr->dt) {
2063464ebd5Sriastradh      /* display target */
2073464ebd5Sriastradh      struct sw_winsys *winsys = screen->winsys;
2083464ebd5Sriastradh      winsys->displaytarget_destroy(winsys, spr->dt);
2094a49301eSmrg   }
2103464ebd5Sriastradh   else if (!spr->userBuffer) {
2113464ebd5Sriastradh      /* regular texture */
2123464ebd5Sriastradh      align_free(spr->data);
2133464ebd5Sriastradh   }
2143464ebd5Sriastradh
2153464ebd5Sriastradh   FREE(spr);
2163464ebd5Sriastradh}
2174a49301eSmrg
2183464ebd5Sriastradh
2193464ebd5Sriastradhstatic struct pipe_resource *
2203464ebd5Sriastradhsoftpipe_resource_from_handle(struct pipe_screen *screen,
2213464ebd5Sriastradh                              const struct pipe_resource *templat,
22201e04c3fSmrg                              struct winsys_handle *whandle,
22301e04c3fSmrg                              unsigned usage)
2243464ebd5Sriastradh{
2253464ebd5Sriastradh   struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
2263464ebd5Sriastradh   struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource);
2273464ebd5Sriastradh   if (!spr)
2284a49301eSmrg      return NULL;
2294a49301eSmrg
2303464ebd5Sriastradh   spr->base = *templat;
2313464ebd5Sriastradh   pipe_reference_init(&spr->base.reference, 1);
2323464ebd5Sriastradh   spr->base.screen = screen;
2333464ebd5Sriastradh
23401e04c3fSmrg   spr->pot = (util_is_power_of_two_or_zero(templat->width0) &&
23501e04c3fSmrg               util_is_power_of_two_or_zero(templat->height0) &&
23601e04c3fSmrg               util_is_power_of_two_or_zero(templat->depth0));
2374a49301eSmrg
2383464ebd5Sriastradh   spr->dt = winsys->displaytarget_from_handle(winsys,
2393464ebd5Sriastradh                                               templat,
2403464ebd5Sriastradh                                               whandle,
2413464ebd5Sriastradh                                               &spr->stride[0]);
2423464ebd5Sriastradh   if (!spr->dt)
2433464ebd5Sriastradh      goto fail;
2444a49301eSmrg
2453464ebd5Sriastradh   return &spr->base;
2463464ebd5Sriastradh
2473464ebd5Sriastradh fail:
2483464ebd5Sriastradh   FREE(spr);
2493464ebd5Sriastradh   return NULL;
2504a49301eSmrg}
2514a49301eSmrg
2524a49301eSmrg
2537ec681f3Smrgstatic bool
2543464ebd5Sriastradhsoftpipe_resource_get_handle(struct pipe_screen *screen,
25501e04c3fSmrg                             struct pipe_context *ctx,
2563464ebd5Sriastradh                             struct pipe_resource *pt,
25701e04c3fSmrg                             struct winsys_handle *whandle,
25801e04c3fSmrg                             unsigned usage)
2594a49301eSmrg{
2603464ebd5Sriastradh   struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
2613464ebd5Sriastradh   struct softpipe_resource *spr = softpipe_resource(pt);
2623464ebd5Sriastradh
2633464ebd5Sriastradh   assert(spr->dt);
2643464ebd5Sriastradh   if (!spr->dt)
2657ec681f3Smrg      return false;
2664a49301eSmrg
2673464ebd5Sriastradh   return winsys->displaytarget_get_handle(winsys, spr->dt, whandle);
2684a49301eSmrg}
2694a49301eSmrg
2704a49301eSmrg
2714a49301eSmrg/**
2723464ebd5Sriastradh * Helper function to compute offset (in bytes) for a particular
2733464ebd5Sriastradh * texture level/face/slice from the start of the buffer.
2743464ebd5Sriastradh */
27501e04c3fSmrgunsigned
27601e04c3fSmrgsoftpipe_get_tex_image_offset(const struct softpipe_resource *spr,
27701e04c3fSmrg                              unsigned level, unsigned layer)
2783464ebd5Sriastradh{
2793464ebd5Sriastradh   unsigned offset = spr->level_offset[level];
2803464ebd5Sriastradh
28101e04c3fSmrg   offset += layer * spr->img_stride[level];
2823464ebd5Sriastradh
2833464ebd5Sriastradh   return offset;
2843464ebd5Sriastradh}
2853464ebd5Sriastradh
2863464ebd5Sriastradh
2873464ebd5Sriastradh/**
2883464ebd5Sriastradh * Get a pipe_surface "view" into a texture resource.
2894a49301eSmrg */
2904a49301eSmrgstatic struct pipe_surface *
2913464ebd5Sriastradhsoftpipe_create_surface(struct pipe_context *pipe,
2923464ebd5Sriastradh                        struct pipe_resource *pt,
2933464ebd5Sriastradh                        const struct pipe_surface *surf_tmpl)
2944a49301eSmrg{
2954a49301eSmrg   struct pipe_surface *ps;
2964a49301eSmrg
2974a49301eSmrg   ps = CALLOC_STRUCT(pipe_surface);
2984a49301eSmrg   if (ps) {
2994a49301eSmrg      pipe_reference_init(&ps->reference, 1);
3003464ebd5Sriastradh      pipe_resource_reference(&ps->texture, pt);
3013464ebd5Sriastradh      ps->context = pipe;
3023464ebd5Sriastradh      ps->format = surf_tmpl->format;
303af69d88dSmrg      if (pt->target != PIPE_BUFFER) {
304af69d88dSmrg         assert(surf_tmpl->u.tex.level <= pt->last_level);
305af69d88dSmrg         ps->width = u_minify(pt->width0, surf_tmpl->u.tex.level);
306af69d88dSmrg         ps->height = u_minify(pt->height0, surf_tmpl->u.tex.level);
307af69d88dSmrg         ps->u.tex.level = surf_tmpl->u.tex.level;
308af69d88dSmrg         ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
309af69d88dSmrg         ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
310af69d88dSmrg         if (ps->u.tex.first_layer != ps->u.tex.last_layer) {
311af69d88dSmrg            debug_printf("creating surface with multiple layers, rendering to first layer only\n");
312af69d88dSmrg         }
313af69d88dSmrg      }
314af69d88dSmrg      else {
315af69d88dSmrg         /* setting width as number of elements should get us correct renderbuffer width */
316af69d88dSmrg         ps->width = surf_tmpl->u.buf.last_element - surf_tmpl->u.buf.first_element + 1;
317af69d88dSmrg         ps->height = pt->height0;
318af69d88dSmrg         ps->u.buf.first_element = surf_tmpl->u.buf.first_element;
319af69d88dSmrg         ps->u.buf.last_element = surf_tmpl->u.buf.last_element;
320af69d88dSmrg         assert(ps->u.buf.first_element <= ps->u.buf.last_element);
321af69d88dSmrg         assert(ps->u.buf.last_element < ps->width);
322af69d88dSmrg      }
3234a49301eSmrg   }
3244a49301eSmrg   return ps;
3254a49301eSmrg}
3264a49301eSmrg
3274a49301eSmrg
3284a49301eSmrg/**
3293464ebd5Sriastradh * Free a pipe_surface which was created with softpipe_create_surface().
3304a49301eSmrg */
3314a49301eSmrgstatic void
3323464ebd5Sriastradhsoftpipe_surface_destroy(struct pipe_context *pipe,
3333464ebd5Sriastradh                         struct pipe_surface *surf)
3344a49301eSmrg{
3354a49301eSmrg   /* Effectively do the texture_update work here - if texture images
3364a49301eSmrg    * needed post-processing to put them into hardware layout, this is
3374a49301eSmrg    * where it would happen.  For softpipe, nothing to do.
3384a49301eSmrg    */
3394a49301eSmrg   assert(surf->texture);
3403464ebd5Sriastradh   pipe_resource_reference(&surf->texture, NULL);
3414a49301eSmrg   FREE(surf);
3424a49301eSmrg}
3434a49301eSmrg
3444a49301eSmrg
3454a49301eSmrg/**
3464a49301eSmrg * Geta pipe_transfer object which is used for moving data in/out of
3473464ebd5Sriastradh * a resource object.
3483464ebd5Sriastradh * \param pipe  rendering context
3493464ebd5Sriastradh * \param resource  the resource to transfer in/out of
3503464ebd5Sriastradh * \param level  which mipmap level
3517ec681f3Smrg * \param usage  bitmask of PIPE_MAP_x flags
3523464ebd5Sriastradh * \param box  the 1D/2D/3D region of interest
3534a49301eSmrg */
354af69d88dSmrgstatic void *
355af69d88dSmrgsoftpipe_transfer_map(struct pipe_context *pipe,
3563464ebd5Sriastradh                      struct pipe_resource *resource,
3573464ebd5Sriastradh                      unsigned level,
3583464ebd5Sriastradh                      unsigned usage,
359af69d88dSmrg                      const struct pipe_box *box,
360af69d88dSmrg                      struct pipe_transfer **transfer)
3614a49301eSmrg{
362af69d88dSmrg   struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys;
3633464ebd5Sriastradh   struct softpipe_resource *spr = softpipe_resource(resource);
3644a49301eSmrg   struct softpipe_transfer *spt;
365af69d88dSmrg   struct pipe_transfer *pt;
366af69d88dSmrg   enum pipe_format format = resource->format;
367af69d88dSmrg   uint8_t *map;
3684a49301eSmrg
3693464ebd5Sriastradh   assert(resource);
3703464ebd5Sriastradh   assert(level <= resource->last_level);
3714a49301eSmrg
372cdc920a0Smrg   /* make sure the requested region is in the image bounds */
373af69d88dSmrg   assert(box->x + box->width <= (int) u_minify(resource->width0, level));
3743464ebd5Sriastradh   if (resource->target == PIPE_TEXTURE_1D_ARRAY) {
375af69d88dSmrg      assert(box->y + box->height <= (int) resource->array_size);
3763464ebd5Sriastradh   }
3773464ebd5Sriastradh   else {
378af69d88dSmrg      assert(box->y + box->height <= (int) u_minify(resource->height0, level));
3793464ebd5Sriastradh      if (resource->target == PIPE_TEXTURE_2D_ARRAY) {
380af69d88dSmrg         assert(box->z + box->depth <= (int) resource->array_size);
3813464ebd5Sriastradh      }
3823464ebd5Sriastradh      else if (resource->target == PIPE_TEXTURE_CUBE) {
3833464ebd5Sriastradh         assert(box->z < 6);
3843464ebd5Sriastradh      }
385af69d88dSmrg      else if (resource->target == PIPE_TEXTURE_CUBE_ARRAY) {
386af69d88dSmrg         assert(box->z <= (int) resource->array_size);
387af69d88dSmrg      }
3883464ebd5Sriastradh      else {
389af69d88dSmrg         assert(box->z + box->depth <= (int) u_minify(resource->depth0, level));
3903464ebd5Sriastradh      }
3913464ebd5Sriastradh   }
3923464ebd5Sriastradh
3933464ebd5Sriastradh   /*
3943464ebd5Sriastradh    * Transfers, like other pipe operations, must happen in order, so flush the
3953464ebd5Sriastradh    * context if necessary.
3963464ebd5Sriastradh    */
3977ec681f3Smrg   if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) {
3987ec681f3Smrg      boolean read_only = !(usage & PIPE_MAP_WRITE);
3997ec681f3Smrg      boolean do_not_block = !!(usage & PIPE_MAP_DONTBLOCK);
4003464ebd5Sriastradh      if (!softpipe_flush_resource(pipe, resource,
4013464ebd5Sriastradh                                   level, box->depth > 1 ? -1 : box->z,
4023464ebd5Sriastradh                                   0, /* flush_flags */
4033464ebd5Sriastradh                                   read_only,
4043464ebd5Sriastradh                                   TRUE, /* cpu_access */
4053464ebd5Sriastradh                                   do_not_block)) {
4063464ebd5Sriastradh         /*
4073464ebd5Sriastradh          * It would have blocked, but state tracker requested no to.
4083464ebd5Sriastradh          */
4093464ebd5Sriastradh         assert(do_not_block);
4103464ebd5Sriastradh         return NULL;
4113464ebd5Sriastradh      }
4123464ebd5Sriastradh   }
413cdc920a0Smrg
4144a49301eSmrg   spt = CALLOC_STRUCT(softpipe_transfer);
415af69d88dSmrg   if (!spt)
416af69d88dSmrg      return NULL;
4174a49301eSmrg
418af69d88dSmrg   pt = &spt->base;
4194a49301eSmrg
420af69d88dSmrg   pipe_resource_reference(&pt->resource, resource);
421af69d88dSmrg   pt->level = level;
422af69d88dSmrg   pt->usage = usage;
423af69d88dSmrg   pt->box = *box;
424af69d88dSmrg   pt->stride = spr->stride[level];
42501e04c3fSmrg   pt->layer_stride = spr->img_stride[level];
4264a49301eSmrg
42701e04c3fSmrg   spt->offset = softpipe_get_tex_image_offset(spr, level, box->z);
4284a49301eSmrg
429af69d88dSmrg   spt->offset +=
430af69d88dSmrg         box->y / util_format_get_blockheight(format) * spt->base.stride +
431af69d88dSmrg         box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
4324a49301eSmrg
4333464ebd5Sriastradh   /* resources backed by display target treated specially:
4344a49301eSmrg    */
4353464ebd5Sriastradh   if (spr->dt) {
436af69d88dSmrg      map = winsys->displaytarget_map(winsys, spr->dt, usage);
4373464ebd5Sriastradh   }
4383464ebd5Sriastradh   else {
4393464ebd5Sriastradh      map = spr->data;
4404a49301eSmrg   }
4414a49301eSmrg
44201e04c3fSmrg   if (!map) {
443af69d88dSmrg      pipe_resource_reference(&pt->resource, NULL);
444af69d88dSmrg      FREE(spt);
4453464ebd5Sriastradh      return NULL;
446af69d88dSmrg   }
447af69d88dSmrg
448af69d88dSmrg   *transfer = pt;
449af69d88dSmrg   return map + spt->offset;
4504a49301eSmrg}
4514a49301eSmrg
4524a49301eSmrg
4534a49301eSmrg/**
4544a49301eSmrg * Unmap memory mapping for given pipe_transfer object.
4554a49301eSmrg */
4564a49301eSmrgstatic void
4573464ebd5Sriastradhsoftpipe_transfer_unmap(struct pipe_context *pipe,
4584a49301eSmrg                        struct pipe_transfer *transfer)
4594a49301eSmrg{
4603464ebd5Sriastradh   struct softpipe_resource *spr;
4614a49301eSmrg
4623464ebd5Sriastradh   assert(transfer->resource);
4633464ebd5Sriastradh   spr = softpipe_resource(transfer->resource);
4644a49301eSmrg
4653464ebd5Sriastradh   if (spr->dt) {
4663464ebd5Sriastradh      /* display target */
4673464ebd5Sriastradh      struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys;
4683464ebd5Sriastradh      winsys->displaytarget_unmap(winsys, spr->dt);
4693464ebd5Sriastradh   }
4704a49301eSmrg
4717ec681f3Smrg   if (transfer->usage & PIPE_MAP_WRITE) {
4724a49301eSmrg      /* Mark the texture as dirty to expire the tile caches. */
4733464ebd5Sriastradh      spr->timestamp++;
4744a49301eSmrg   }
475af69d88dSmrg
476af69d88dSmrg   pipe_resource_reference(&transfer->resource, NULL);
477af69d88dSmrg   FREE(transfer);
4784a49301eSmrg}
4794a49301eSmrg
4803464ebd5Sriastradh/**
4813464ebd5Sriastradh * Create buffer which wraps user-space data.
4823464ebd5Sriastradh */
483af69d88dSmrgstruct pipe_resource *
4843464ebd5Sriastradhsoftpipe_user_buffer_create(struct pipe_screen *screen,
4853464ebd5Sriastradh                            void *ptr,
4863464ebd5Sriastradh                            unsigned bytes,
4873464ebd5Sriastradh			    unsigned bind_flags)
4884a49301eSmrg{
4893464ebd5Sriastradh   struct softpipe_resource *spr;
4904a49301eSmrg
4913464ebd5Sriastradh   spr = CALLOC_STRUCT(softpipe_resource);
4923464ebd5Sriastradh   if (!spr)
4934a49301eSmrg      return NULL;
4944a49301eSmrg
4953464ebd5Sriastradh   pipe_reference_init(&spr->base.reference, 1);
4963464ebd5Sriastradh   spr->base.screen = screen;
4973464ebd5Sriastradh   spr->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */
4983464ebd5Sriastradh   spr->base.bind = bind_flags;
4993464ebd5Sriastradh   spr->base.usage = PIPE_USAGE_IMMUTABLE;
5003464ebd5Sriastradh   spr->base.flags = 0;
5013464ebd5Sriastradh   spr->base.width0 = bytes;
5023464ebd5Sriastradh   spr->base.height0 = 1;
5033464ebd5Sriastradh   spr->base.depth0 = 1;
5043464ebd5Sriastradh   spr->base.array_size = 1;
5053464ebd5Sriastradh   spr->userBuffer = TRUE;
5063464ebd5Sriastradh   spr->data = ptr;
5073464ebd5Sriastradh
5083464ebd5Sriastradh   return &spr->base;
5094a49301eSmrg}
5104a49301eSmrg
5114a49301eSmrg
5124a49301eSmrgvoid
5133464ebd5Sriastradhsoftpipe_init_texture_funcs(struct pipe_context *pipe)
5144a49301eSmrg{
5157ec681f3Smrg   pipe->buffer_map = softpipe_transfer_map;
5167ec681f3Smrg   pipe->buffer_unmap = softpipe_transfer_unmap;
5177ec681f3Smrg   pipe->texture_map = softpipe_transfer_map;
5187ec681f3Smrg   pipe->texture_unmap = softpipe_transfer_unmap;
5194a49301eSmrg
5203464ebd5Sriastradh   pipe->transfer_flush_region = u_default_transfer_flush_region;
52101e04c3fSmrg   pipe->buffer_subdata = u_default_buffer_subdata;
52201e04c3fSmrg   pipe->texture_subdata = u_default_texture_subdata;
5234a49301eSmrg
5243464ebd5Sriastradh   pipe->create_surface = softpipe_create_surface;
5253464ebd5Sriastradh   pipe->surface_destroy = softpipe_surface_destroy;
52601e04c3fSmrg   pipe->clear_texture = util_clear_texture;
5274a49301eSmrg}
5284a49301eSmrg
5294a49301eSmrg
5303464ebd5Sriastradhvoid
5313464ebd5Sriastradhsoftpipe_init_screen_texture_funcs(struct pipe_screen *screen)
5324a49301eSmrg{
5333464ebd5Sriastradh   screen->resource_create = softpipe_resource_create;
53401e04c3fSmrg   screen->resource_create_front = softpipe_resource_create_front;
5353464ebd5Sriastradh   screen->resource_destroy = softpipe_resource_destroy;
5363464ebd5Sriastradh   screen->resource_from_handle = softpipe_resource_from_handle;
5373464ebd5Sriastradh   screen->resource_get_handle = softpipe_resource_get_handle;
538af69d88dSmrg   screen->can_create_resource = softpipe_can_create_resource;
5394a49301eSmrg}
540