Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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