Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
  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 TUNGSTEN GRAPHICS 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 <keith@tungstengraphics.com>
  30.   *   Michel Dänzer <michel@tungstengraphics.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.    unsigned buffer_size = 0;
  64.  
  65.    for (level = 0; level <= pt->last_level; level++) {
  66.       unsigned slices;
  67.  
  68.       if (pt->target == PIPE_TEXTURE_CUBE)
  69.          slices = 6;
  70.       else if (pt->target == PIPE_TEXTURE_3D)
  71.          slices = depth;
  72.       else
  73.          slices = pt->array_size;
  74.  
  75.       spr->stride[level] = util_format_get_stride(pt->format, width);
  76.  
  77.       spr->level_offset[level] = buffer_size;
  78.  
  79.       buffer_size += (util_format_get_nblocksy(pt->format, height) *
  80.                       slices * spr->stride[level]);
  81.  
  82.       width  = u_minify(width, 1);
  83.       height = u_minify(height, 1);
  84.       depth = u_minify(depth, 1);
  85.    }
  86.  
  87.    if (buffer_size > SP_MAX_TEXTURE_SIZE)
  88.       return FALSE;
  89.  
  90.    if (allocate) {
  91.       spr->data = align_malloc(buffer_size, 16);
  92.       return spr->data != NULL;
  93.    }
  94.    else {
  95.       return TRUE;
  96.    }
  97. }
  98.  
  99.  
  100. /**
  101.  * Check the size of the texture specified by 'res'.
  102.  * \return TRUE if OK, FALSE if too large.
  103.  */
  104. static boolean
  105. softpipe_can_create_resource(struct pipe_screen *screen,
  106.                              const struct pipe_resource *res)
  107. {
  108.    struct softpipe_resource spr;
  109.    memset(&spr, 0, sizeof(spr));
  110.    spr.base = *res;
  111.    return softpipe_resource_layout(screen, &spr, FALSE);
  112. }
  113.  
  114.  
  115. /**
  116.  * Texture layout for simple color buffers.
  117.  */
  118. static boolean
  119. softpipe_displaytarget_layout(struct pipe_screen *screen,
  120.                               struct softpipe_resource *spr)
  121. {
  122.    struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
  123.  
  124.    /* Round up the surface size to a multiple of the tile size?
  125.     */
  126.    spr->dt = winsys->displaytarget_create(winsys,
  127.                                           spr->base.bind,
  128.                                           spr->base.format,
  129.                                           spr->base.width0,
  130.                                           spr->base.height0,
  131.                                           16,
  132.                                           &spr->stride[0] );
  133.  
  134.    return spr->dt != NULL;
  135. }
  136.  
  137.  
  138. /**
  139.  * Create new pipe_resource given the template information.
  140.  */
  141. static struct pipe_resource *
  142. softpipe_resource_create(struct pipe_screen *screen,
  143.                          const struct pipe_resource *templat)
  144. {
  145.    struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource);
  146.    if (!spr)
  147.       return NULL;
  148.  
  149.    assert(templat->format != PIPE_FORMAT_NONE);
  150.  
  151.    spr->base = *templat;
  152.    pipe_reference_init(&spr->base.reference, 1);
  153.    spr->base.screen = screen;
  154.  
  155.    spr->pot = (util_is_power_of_two(templat->width0) &&
  156.                util_is_power_of_two(templat->height0) &&
  157.                util_is_power_of_two(templat->depth0));
  158.  
  159.    if (spr->base.bind & (PIPE_BIND_DISPLAY_TARGET |
  160.                          PIPE_BIND_SCANOUT |
  161.                          PIPE_BIND_SHARED)) {
  162.       if (!softpipe_displaytarget_layout(screen, spr))
  163.          goto fail;
  164.    }
  165.    else {
  166.       if (!softpipe_resource_layout(screen, spr, TRUE))
  167.          goto fail;
  168.    }
  169.    
  170.    return &spr->base;
  171.  
  172.  fail:
  173.    FREE(spr);
  174.    return NULL;
  175. }
  176.  
  177.  
  178. static void
  179. softpipe_resource_destroy(struct pipe_screen *pscreen,
  180.                           struct pipe_resource *pt)
  181. {
  182.    struct softpipe_screen *screen = softpipe_screen(pscreen);
  183.    struct softpipe_resource *spr = softpipe_resource(pt);
  184.  
  185.    if (spr->dt) {
  186.       /* display target */
  187.       struct sw_winsys *winsys = screen->winsys;
  188.       winsys->displaytarget_destroy(winsys, spr->dt);
  189.    }
  190.    else if (!spr->userBuffer) {
  191.       /* regular texture */
  192.       align_free(spr->data);
  193.    }
  194.  
  195.    FREE(spr);
  196. }
  197.  
  198.  
  199. static struct pipe_resource *
  200. softpipe_resource_from_handle(struct pipe_screen *screen,
  201.                               const struct pipe_resource *templat,
  202.                               struct winsys_handle *whandle)
  203. {
  204.    struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
  205.    struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource);
  206.    if (!spr)
  207.       return NULL;
  208.  
  209.    spr->base = *templat;
  210.    pipe_reference_init(&spr->base.reference, 1);
  211.    spr->base.screen = screen;
  212.  
  213.    spr->pot = (util_is_power_of_two(templat->width0) &&
  214.                util_is_power_of_two(templat->height0) &&
  215.                util_is_power_of_two(templat->depth0));
  216.  
  217.    spr->dt = winsys->displaytarget_from_handle(winsys,
  218.                                                templat,
  219.                                                whandle,
  220.                                                &spr->stride[0]);
  221.    if (!spr->dt)
  222.       goto fail;
  223.  
  224.    return &spr->base;
  225.  
  226.  fail:
  227.    FREE(spr);
  228.    return NULL;
  229. }
  230.  
  231.  
  232. static boolean
  233. softpipe_resource_get_handle(struct pipe_screen *screen,
  234.                              struct pipe_resource *pt,
  235.                              struct winsys_handle *whandle)
  236. {
  237.    struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
  238.    struct softpipe_resource *spr = softpipe_resource(pt);
  239.  
  240.    assert(spr->dt);
  241.    if (!spr->dt)
  242.       return FALSE;
  243.  
  244.    return winsys->displaytarget_get_handle(winsys, spr->dt, whandle);
  245. }
  246.  
  247.  
  248. /**
  249.  * Helper function to compute offset (in bytes) for a particular
  250.  * texture level/face/slice from the start of the buffer.
  251.  */
  252. static unsigned
  253. sp_get_tex_image_offset(const struct softpipe_resource *spr,
  254.                         unsigned level, unsigned layer)
  255. {
  256.    const unsigned hgt = u_minify(spr->base.height0, level);
  257.    const unsigned nblocksy = util_format_get_nblocksy(spr->base.format, hgt);
  258.    unsigned offset = spr->level_offset[level];
  259.  
  260.    if (spr->base.target == PIPE_TEXTURE_CUBE ||
  261.        spr->base.target == PIPE_TEXTURE_CUBE_ARRAY ||
  262.        spr->base.target == PIPE_TEXTURE_3D ||
  263.        spr->base.target == PIPE_TEXTURE_2D_ARRAY) {
  264.       offset += layer * nblocksy * spr->stride[level];
  265.    }
  266.    else if (spr->base.target == PIPE_TEXTURE_1D_ARRAY) {
  267.       offset += layer * spr->stride[level];
  268.    }
  269.    else {
  270.       assert(layer == 0);
  271.    }
  272.  
  273.    return offset;
  274. }
  275.  
  276.  
  277. /**
  278.  * Get a pipe_surface "view" into a texture resource.
  279.  */
  280. static struct pipe_surface *
  281. softpipe_create_surface(struct pipe_context *pipe,
  282.                         struct pipe_resource *pt,
  283.                         const struct pipe_surface *surf_tmpl)
  284. {
  285.    struct pipe_surface *ps;
  286.  
  287.    ps = CALLOC_STRUCT(pipe_surface);
  288.    if (ps) {
  289.       pipe_reference_init(&ps->reference, 1);
  290.       pipe_resource_reference(&ps->texture, pt);
  291.       ps->context = pipe;
  292.       ps->format = surf_tmpl->format;
  293.       if (pt->target != PIPE_BUFFER) {
  294.          assert(surf_tmpl->u.tex.level <= pt->last_level);
  295.          ps->width = u_minify(pt->width0, surf_tmpl->u.tex.level);
  296.          ps->height = u_minify(pt->height0, surf_tmpl->u.tex.level);
  297.          ps->u.tex.level = surf_tmpl->u.tex.level;
  298.          ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
  299.          ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
  300.          if (ps->u.tex.first_layer != ps->u.tex.last_layer) {
  301.             debug_printf("creating surface with multiple layers, rendering to first layer only\n");
  302.          }
  303.       }
  304.       else {
  305.          /* setting width as number of elements should get us correct renderbuffer width */
  306.          ps->width = surf_tmpl->u.buf.last_element - surf_tmpl->u.buf.first_element + 1;
  307.          ps->height = pt->height0;
  308.          ps->u.buf.first_element = surf_tmpl->u.buf.first_element;
  309.          ps->u.buf.last_element = surf_tmpl->u.buf.last_element;
  310.          assert(ps->u.buf.first_element <= ps->u.buf.last_element);
  311.          assert(ps->u.buf.last_element < ps->width);
  312.       }
  313.    }
  314.    return ps;
  315. }
  316.  
  317.  
  318. /**
  319.  * Free a pipe_surface which was created with softpipe_create_surface().
  320.  */
  321. static void
  322. softpipe_surface_destroy(struct pipe_context *pipe,
  323.                          struct pipe_surface *surf)
  324. {
  325.    /* Effectively do the texture_update work here - if texture images
  326.     * needed post-processing to put them into hardware layout, this is
  327.     * where it would happen.  For softpipe, nothing to do.
  328.     */
  329.    assert(surf->texture);
  330.    pipe_resource_reference(&surf->texture, NULL);
  331.    FREE(surf);
  332. }
  333.  
  334.  
  335. /**
  336.  * Geta pipe_transfer object which is used for moving data in/out of
  337.  * a resource object.
  338.  * \param pipe  rendering context
  339.  * \param resource  the resource to transfer in/out of
  340.  * \param level  which mipmap level
  341.  * \param usage  bitmask of PIPE_TRANSFER_x flags
  342.  * \param box  the 1D/2D/3D region of interest
  343.  */
  344. static void *
  345. softpipe_transfer_map(struct pipe_context *pipe,
  346.                       struct pipe_resource *resource,
  347.                       unsigned level,
  348.                       unsigned usage,
  349.                       const struct pipe_box *box,
  350.                       struct pipe_transfer **transfer)
  351. {
  352.    struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys;
  353.    struct softpipe_resource *spr = softpipe_resource(resource);
  354.    struct softpipe_transfer *spt;
  355.    struct pipe_transfer *pt;
  356.    enum pipe_format format = resource->format;
  357.    const unsigned hgt = u_minify(spr->base.height0, level);
  358.    const unsigned nblocksy = util_format_get_nblocksy(format, hgt);
  359.    uint8_t *map;
  360.  
  361.    assert(resource);
  362.    assert(level <= resource->last_level);
  363.  
  364.    /* make sure the requested region is in the image bounds */
  365.    assert(box->x + box->width <= u_minify(resource->width0, level));
  366.    if (resource->target == PIPE_TEXTURE_1D_ARRAY) {
  367.       assert(box->y + box->height <= resource->array_size);
  368.    }
  369.    else {
  370.       assert(box->y + box->height <= u_minify(resource->height0, level));
  371.       if (resource->target == PIPE_TEXTURE_2D_ARRAY) {
  372.          assert(box->z + box->depth <= resource->array_size);
  373.       }
  374.       else if (resource->target == PIPE_TEXTURE_CUBE) {
  375.          assert(box->z < 6);
  376.       }
  377.       else if (resource->target == PIPE_TEXTURE_CUBE_ARRAY) {
  378.          assert(box->z <= resource->array_size);
  379.       }
  380.       else {
  381.          assert(box->z + box->depth <= (u_minify(resource->depth0, level)));
  382.       }
  383.    }
  384.  
  385.    /*
  386.     * Transfers, like other pipe operations, must happen in order, so flush the
  387.     * context if necessary.
  388.     */
  389.    if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
  390.       boolean read_only = !(usage & PIPE_TRANSFER_WRITE);
  391.       boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK);
  392.       if (!softpipe_flush_resource(pipe, resource,
  393.                                    level, box->depth > 1 ? -1 : box->z,
  394.                                    0, /* flush_flags */
  395.                                    read_only,
  396.                                    TRUE, /* cpu_access */
  397.                                    do_not_block)) {
  398.          /*
  399.           * It would have blocked, but state tracker requested no to.
  400.           */
  401.          assert(do_not_block);
  402.          return NULL;
  403.       }
  404.    }
  405.  
  406.    spt = CALLOC_STRUCT(softpipe_transfer);
  407.    if (!spt)
  408.       return NULL;
  409.  
  410.    pt = &spt->base;
  411.  
  412.    pipe_resource_reference(&pt->resource, resource);
  413.    pt->level = level;
  414.    pt->usage = usage;
  415.    pt->box = *box;
  416.    pt->stride = spr->stride[level];
  417.    pt->layer_stride = pt->stride * nblocksy;
  418.  
  419.    spt->offset = sp_get_tex_image_offset(spr, level, box->z);
  420.  
  421.    spt->offset +=
  422.          box->y / util_format_get_blockheight(format) * spt->base.stride +
  423.          box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
  424.  
  425.    /* resources backed by display target treated specially:
  426.     */
  427.    if (spr->dt) {
  428.       map = winsys->displaytarget_map(winsys, spr->dt, usage);
  429.    }
  430.    else {
  431.       map = spr->data;
  432.    }
  433.  
  434.    if (map == NULL) {
  435.       pipe_resource_reference(&pt->resource, NULL);
  436.       FREE(spt);
  437.       return NULL;
  438.    }
  439.  
  440.    *transfer = pt;
  441.    return map + spt->offset;
  442. }
  443.  
  444.  
  445. /**
  446.  * Unmap memory mapping for given pipe_transfer object.
  447.  */
  448. static void
  449. softpipe_transfer_unmap(struct pipe_context *pipe,
  450.                         struct pipe_transfer *transfer)
  451. {
  452.    struct softpipe_resource *spr;
  453.  
  454.    assert(transfer->resource);
  455.    spr = softpipe_resource(transfer->resource);
  456.  
  457.    if (spr->dt) {
  458.       /* display target */
  459.       struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys;
  460.       winsys->displaytarget_unmap(winsys, spr->dt);
  461.    }
  462.  
  463.    if (transfer->usage & PIPE_TRANSFER_WRITE) {
  464.       /* Mark the texture as dirty to expire the tile caches. */
  465.       spr->timestamp++;
  466.    }
  467.  
  468.    pipe_resource_reference(&transfer->resource, NULL);
  469.    FREE(transfer);
  470. }
  471.  
  472. /**
  473.  * Create buffer which wraps user-space data.
  474.  */
  475. struct pipe_resource *
  476. softpipe_user_buffer_create(struct pipe_screen *screen,
  477.                             void *ptr,
  478.                             unsigned bytes,
  479.                             unsigned bind_flags)
  480. {
  481.    struct softpipe_resource *spr;
  482.  
  483.    spr = CALLOC_STRUCT(softpipe_resource);
  484.    if (!spr)
  485.       return NULL;
  486.  
  487.    pipe_reference_init(&spr->base.reference, 1);
  488.    spr->base.screen = screen;
  489.    spr->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */
  490.    spr->base.bind = bind_flags;
  491.    spr->base.usage = PIPE_USAGE_IMMUTABLE;
  492.    spr->base.flags = 0;
  493.    spr->base.width0 = bytes;
  494.    spr->base.height0 = 1;
  495.    spr->base.depth0 = 1;
  496.    spr->base.array_size = 1;
  497.    spr->userBuffer = TRUE;
  498.    spr->data = ptr;
  499.  
  500.    return &spr->base;
  501. }
  502.  
  503.  
  504. void
  505. softpipe_init_texture_funcs(struct pipe_context *pipe)
  506. {
  507.    pipe->transfer_map = softpipe_transfer_map;
  508.    pipe->transfer_unmap = softpipe_transfer_unmap;
  509.  
  510.    pipe->transfer_flush_region = u_default_transfer_flush_region;
  511.    pipe->transfer_inline_write = u_default_transfer_inline_write;
  512.  
  513.    pipe->create_surface = softpipe_create_surface;
  514.    pipe->surface_destroy = softpipe_surface_destroy;
  515. }
  516.  
  517.  
  518. void
  519. softpipe_init_screen_texture_funcs(struct pipe_screen *screen)
  520. {
  521.    screen->resource_create = softpipe_resource_create;
  522.    screen->resource_destroy = softpipe_resource_destroy;
  523.    screen->resource_from_handle = softpipe_resource_from_handle;
  524.    screen->resource_get_handle = softpipe_resource_get_handle;
  525.    screen->can_create_resource = softpipe_can_create_resource;
  526. }
  527.