Home | History | Annotate | Download | only in state_tracker
      1 /**************************************************************************
      2  *
      3  * Copyright 2007 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 #include <stdio.h>
     29 
     30 #include "st_context.h"
     31 #include "st_format.h"
     32 #include "st_texture.h"
     33 #include "st_cb_fbo.h"
     34 #include "main/enums.h"
     35 
     36 #include "pipe/p_state.h"
     37 #include "pipe/p_context.h"
     38 #include "pipe/p_defines.h"
     39 #include "util/u_inlines.h"
     40 #include "util/u_format.h"
     41 #include "util/u_rect.h"
     42 #include "util/u_math.h"
     43 
     44 
     45 #define DBG if(0) printf
     46 
     47 
     48 /**
     49  * Allocate a new pipe_resource object
     50  * width0, height0, depth0 are the dimensions of the level 0 image
     51  * (the highest resolution).  last_level indicates how many mipmap levels
     52  * to allocate storage for.  For non-mipmapped textures, this will be zero.
     53  */
     54 struct pipe_resource *
     55 st_texture_create(struct st_context *st,
     56                   enum pipe_texture_target target,
     57 		  enum pipe_format format,
     58 		  GLuint last_level,
     59 		  GLuint width0,
     60 		  GLuint height0,
     61 		  GLuint depth0,
     62                   GLuint layers,
     63                   GLuint bind )
     64 {
     65    struct pipe_resource pt, *newtex;
     66    struct pipe_screen *screen = st->pipe->screen;
     67 
     68    assert(target < PIPE_MAX_TEXTURE_TYPES);
     69    assert(width0 > 0);
     70    assert(height0 > 0);
     71    assert(depth0 > 0);
     72    if (target == PIPE_TEXTURE_CUBE)
     73       assert(layers == 6);
     74 
     75    DBG("%s target %d format %s last_level %d\n", __FUNCTION__,
     76        (int) target, util_format_name(format), last_level);
     77 
     78    assert(format);
     79    assert(screen->is_format_supported(screen, format, target, 0,
     80                                       PIPE_BIND_SAMPLER_VIEW));
     81 
     82    memset(&pt, 0, sizeof(pt));
     83    pt.target = target;
     84    pt.format = format;
     85    pt.last_level = last_level;
     86    pt.width0 = width0;
     87    pt.height0 = height0;
     88    pt.depth0 = depth0;
     89    pt.array_size = (target == PIPE_TEXTURE_CUBE ? 6 : layers);
     90    pt.usage = PIPE_USAGE_DEFAULT;
     91    pt.bind = bind;
     92    pt.flags = 0;
     93 
     94    newtex = screen->resource_create(screen, &pt);
     95 
     96    assert(!newtex || pipe_is_referenced(&newtex->reference));
     97 
     98    return newtex;
     99 }
    100 
    101 
    102 /**
    103  * In OpenGL the number of 1D array texture layers is the "height" and
    104  * the number of 2D array texture layers is the "depth".  In Gallium the
    105  * number of layers in an array texture is a separate 'array_size' field.
    106  * This function converts dimensions from the former to the later.
    107  */
    108 void
    109 st_gl_texture_dims_to_pipe_dims(GLenum texture,
    110                                 GLuint widthIn,
    111                                 GLuint heightIn,
    112                                 GLuint depthIn,
    113                                 GLuint *widthOut,
    114                                 GLuint *heightOut,
    115                                 GLuint *depthOut,
    116                                 GLuint *layersOut)
    117 {
    118    switch (texture) {
    119    case GL_TEXTURE_1D:
    120       assert(heightIn == 1);
    121       assert(depthIn == 1);
    122       *widthOut = widthIn;
    123       *heightOut = 1;
    124       *depthOut = 1;
    125       *layersOut = 1;
    126       break;
    127    case GL_TEXTURE_1D_ARRAY:
    128       assert(depthIn == 1);
    129       *widthOut = widthIn;
    130       *heightOut = 1;
    131       *depthOut = 1;
    132       *layersOut = heightIn;
    133       break;
    134    case GL_TEXTURE_2D:
    135    case GL_TEXTURE_RECTANGLE:
    136    case GL_TEXTURE_EXTERNAL_OES:
    137       assert(depthIn == 1);
    138       *widthOut = widthIn;
    139       *heightOut = heightIn;
    140       *depthOut = 1;
    141       *layersOut = 1;
    142       break;
    143    case GL_TEXTURE_CUBE_MAP:
    144       assert(depthIn == 1);
    145       *widthOut = widthIn;
    146       *heightOut = heightIn;
    147       *depthOut = 1;
    148       *layersOut = 6;
    149       break;
    150    case GL_TEXTURE_2D_ARRAY:
    151       *widthOut = widthIn;
    152       *heightOut = heightIn;
    153       *depthOut = 1;
    154       *layersOut = depthIn;
    155       break;
    156    default:
    157       assert(0 && "Unexpected texture in st_gl_texture_dims_to_pipe_dims()");
    158       /* fall-through */
    159    case GL_TEXTURE_3D:
    160       *widthOut = widthIn;
    161       *heightOut = heightIn;
    162       *depthOut = depthIn;
    163       *layersOut = 1;
    164       break;
    165    }
    166 }
    167 
    168 
    169 /**
    170  * Check if a texture image can be pulled into a unified mipmap texture.
    171  */
    172 GLboolean
    173 st_texture_match_image(const struct pipe_resource *pt,
    174                        const struct gl_texture_image *image)
    175 {
    176    GLuint ptWidth, ptHeight, ptDepth, ptLayers;
    177 
    178    /* Images with borders are never pulled into mipmap textures.
    179     */
    180    if (image->Border)
    181       return GL_FALSE;
    182 
    183    /* Check if this image's format matches the established texture's format.
    184     */
    185    if (st_mesa_format_to_pipe_format(image->TexFormat) != pt->format)
    186       return GL_FALSE;
    187 
    188    st_gl_texture_dims_to_pipe_dims(image->TexObject->Target,
    189                                    image->Width, image->Height, image->Depth,
    190                                    &ptWidth, &ptHeight, &ptDepth, &ptLayers);
    191 
    192    /* Test if this image's size matches what's expected in the
    193     * established texture.
    194     */
    195    if (ptWidth != u_minify(pt->width0, image->Level) ||
    196        ptHeight != u_minify(pt->height0, image->Level) ||
    197        ptDepth != u_minify(pt->depth0, image->Level) ||
    198        ptLayers != pt->array_size)
    199       return GL_FALSE;
    200 
    201    return GL_TRUE;
    202 }
    203 
    204 
    205 /**
    206  * Map a texture image and return the address for a particular 2D face/slice/
    207  * layer.  The stImage indicates the cube face and mipmap level.  The slice
    208  * of the 3D texture is passed in 'zoffset'.
    209  * \param usage  one of the PIPE_TRANSFER_x values
    210  * \param x, y, w, h  the region of interest of the 2D image.
    211  * \return address of mapping or NULL if any error
    212  */
    213 GLubyte *
    214 st_texture_image_map(struct st_context *st, struct st_texture_image *stImage,
    215                      GLuint zoffset, enum pipe_transfer_usage usage,
    216                      GLuint x, GLuint y, GLuint w, GLuint h)
    217 {
    218    struct st_texture_object *stObj =
    219       st_texture_object(stImage->base.TexObject);
    220    struct pipe_context *pipe = st->pipe;
    221    GLuint level;
    222 
    223    DBG("%s \n", __FUNCTION__);
    224 
    225    if (!stImage->pt)
    226       return NULL;
    227 
    228    if (stObj->pt != stImage->pt)
    229       level = 0;
    230    else
    231       level = stImage->base.Level;
    232 
    233    stImage->transfer = pipe_get_transfer(st->pipe, stImage->pt, level,
    234                                          stImage->base.Face + zoffset,
    235                                          usage, x, y, w, h);
    236 
    237    if (stImage->transfer)
    238       return pipe_transfer_map(pipe, stImage->transfer);
    239    else
    240       return NULL;
    241 }
    242 
    243 
    244 void
    245 st_texture_image_unmap(struct st_context *st,
    246                        struct st_texture_image *stImage)
    247 {
    248    struct pipe_context *pipe = st->pipe;
    249 
    250    DBG("%s\n", __FUNCTION__);
    251 
    252    pipe_transfer_unmap(pipe, stImage->transfer);
    253 
    254    pipe->transfer_destroy(pipe, stImage->transfer);
    255    stImage->transfer = NULL;
    256 }
    257 
    258 
    259 
    260 /**
    261  * Upload data to a rectangular sub-region.  Lots of choices how to do this:
    262  *
    263  * - memcpy by span to current destination
    264  * - upload data as new buffer and blit
    265  *
    266  * Currently always memcpy.
    267  */
    268 static void
    269 st_surface_data(struct pipe_context *pipe,
    270 		struct pipe_transfer *dst,
    271 		unsigned dstx, unsigned dsty,
    272 		const void *src, unsigned src_stride,
    273 		unsigned srcx, unsigned srcy, unsigned width, unsigned height)
    274 {
    275    void *map = pipe_transfer_map(pipe, dst);
    276 
    277    assert(dst->resource);
    278    util_copy_rect(map,
    279                   dst->resource->format,
    280                   dst->stride,
    281                   dstx, dsty,
    282                   width, height,
    283                   src, src_stride,
    284                   srcx, srcy);
    285 
    286    pipe_transfer_unmap(pipe, dst);
    287 }
    288 
    289 
    290 /* Upload data for a particular image.
    291  */
    292 void
    293 st_texture_image_data(struct st_context *st,
    294                       struct pipe_resource *dst,
    295                       GLuint face,
    296                       GLuint level,
    297                       void *src,
    298                       GLuint src_row_stride, GLuint src_image_stride)
    299 {
    300    struct pipe_context *pipe = st->pipe;
    301    GLuint i;
    302    const GLubyte *srcUB = src;
    303    struct pipe_transfer *dst_transfer;
    304    GLuint layers;
    305 
    306    if (dst->target == PIPE_TEXTURE_1D_ARRAY ||
    307        dst->target == PIPE_TEXTURE_2D_ARRAY)
    308       layers = dst->array_size;
    309    else
    310       layers = u_minify(dst->depth0, level);
    311 
    312    DBG("%s\n", __FUNCTION__);
    313 
    314    for (i = 0; i < layers; i++) {
    315       dst_transfer = pipe_get_transfer(st->pipe, dst, level, face + i,
    316                                        PIPE_TRANSFER_WRITE, 0, 0,
    317                                        u_minify(dst->width0, level),
    318                                        u_minify(dst->height0, level));
    319 
    320       st_surface_data(pipe, dst_transfer,
    321 		      0, 0,                             /* dstx, dsty */
    322 		      srcUB,
    323 		      src_row_stride,
    324 		      0, 0,                             /* source x, y */
    325 		      u_minify(dst->width0, level),
    326                       u_minify(dst->height0, level));    /* width, height */
    327 
    328       pipe->transfer_destroy(pipe, dst_transfer);
    329 
    330       srcUB += src_image_stride;
    331    }
    332 }
    333 
    334 
    335 /**
    336  * For debug only: get/print center pixel in the src resource.
    337  */
    338 static void
    339 print_center_pixel(struct pipe_context *pipe, struct pipe_resource *src)
    340 {
    341    struct pipe_transfer *xfer;
    342    struct pipe_box region;
    343    ubyte *map;
    344 
    345    region.x = src->width0 / 2;
    346    region.y = src->height0 / 2;
    347    region.z = 0;
    348    region.width = 1;
    349    region.height = 1;
    350    region.depth = 1;
    351 
    352    xfer = pipe->get_transfer(pipe, src, 0, PIPE_TRANSFER_READ, &region);
    353    map = pipe->transfer_map(pipe, xfer);
    354 
    355    printf("center pixel: %d %d %d %d\n", map[0], map[1], map[2], map[3]);
    356 
    357    pipe->transfer_unmap(pipe, xfer);
    358    pipe->transfer_destroy(pipe, xfer);
    359 }
    360 
    361 
    362 /**
    363  * Copy the image at level=0 in 'src' to the 'dst' resource at 'dstLevel'.
    364  * This is used to copy mipmap images from one texture buffer to another.
    365  * This typically happens when our initial guess at the total texture size
    366  * is incorrect (see the guess_and_alloc_texture() function).
    367  */
    368 void
    369 st_texture_image_copy(struct pipe_context *pipe,
    370                       struct pipe_resource *dst, GLuint dstLevel,
    371                       struct pipe_resource *src, GLuint srcLevel,
    372                       GLuint face)
    373 {
    374    GLuint width = u_minify(dst->width0, dstLevel);
    375    GLuint height = u_minify(dst->height0, dstLevel);
    376    GLuint depth = u_minify(dst->depth0, dstLevel);
    377    struct pipe_box src_box;
    378    GLuint i;
    379 
    380    if (u_minify(src->width0, srcLevel) != width ||
    381        u_minify(src->height0, srcLevel) != height ||
    382        u_minify(src->depth0, srcLevel) != depth) {
    383       /* The source image size doesn't match the destination image size.
    384        * This can happen in some degenerate situations such as rendering to a
    385        * cube map face which was set up with mismatched texture sizes.
    386        */
    387       return;
    388    }
    389 
    390    src_box.x = 0;
    391    src_box.y = 0;
    392    src_box.width = width;
    393    src_box.height = height;
    394    src_box.depth = 1;
    395    /* Loop over 3D image slices */
    396    /* could (and probably should) use "true" 3d box here -
    397       but drivers can't quite handle it yet */
    398    for (i = face; i < face + depth; i++) {
    399       src_box.z = i;
    400 
    401       if (0)  {
    402          print_center_pixel(pipe, src);
    403       }
    404 
    405       pipe->resource_copy_region(pipe,
    406                                  dst,
    407                                  dstLevel,
    408                                  0, 0, i,/* destX, Y, Z */
    409                                  src,
    410                                  srcLevel,
    411                                  &src_box);
    412    }
    413 }
    414 
    415 
    416 struct pipe_resource *
    417 st_create_color_map_texture(struct gl_context *ctx)
    418 {
    419    struct st_context *st = st_context(ctx);
    420    struct pipe_context *pipe = st->pipe;
    421    struct pipe_resource *pt;
    422    enum pipe_format format;
    423    const uint texSize = 256; /* simple, and usually perfect */
    424 
    425    /* find an RGBA texture format */
    426    format = st_choose_format(pipe->screen, GL_RGBA, GL_NONE, GL_NONE,
    427                              PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW);
    428 
    429    /* create texture for color map/table */
    430    pt = st_texture_create(st, PIPE_TEXTURE_2D, format, 0,
    431                           texSize, texSize, 1, 1, PIPE_BIND_SAMPLER_VIEW);
    432    return pt;
    433 }
    434 
    435