Home | History | Annotate | Download | only in osmesa
      1 /*
      2  * Copyright (c) 2013  Brian Paul   All Rights Reserved.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice shall be included
     12  * in all copies or substantial portions of the Software.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20  * OTHER DEALINGS IN THE SOFTWARE.
     21  */
     22 
     23 
     24 /*
     25  * Off-Screen rendering into client memory.
     26  * State tracker for gallium (for softpipe and llvmpipe)
     27  *
     28  * Notes:
     29  *
     30  * If Gallium is built with LLVM support we use the llvmpipe driver.
     31  * Otherwise we use softpipe.  The GALLIUM_DRIVER environment variable
     32  * may be set to "softpipe" or "llvmpipe" to override.
     33  *
     34  * With softpipe we could render directly into the user's buffer by using a
     35  * display target resource.  However, softpipe doesn't support "upside-down"
     36  * rendering which would be needed for the OSMESA_Y_UP=TRUE case.
     37  *
     38  * With llvmpipe we could only render directly into the user's buffer when its
     39  * width and height is a multiple of the tile size (64 pixels).
     40  *
     41  * Because of these constraints we always render into ordinary resources then
     42  * copy the results to the user's buffer in the flush_front() function which
     43  * is called when the app calls glFlush/Finish.
     44  *
     45  * In general, the OSMesa interface is pretty ugly and not a good match
     46  * for Gallium.  But we're interested in doing the best we can to preserve
     47  * application portability.  With a little work we could come up with a
     48  * much nicer, new off-screen Gallium interface...
     49  */
     50 
     51 
     52 #include <stdio.h>
     53 #include "GL/osmesa.h"
     54 
     55 #include "glapi/glapi.h"  /* for OSMesaGetProcAddress below */
     56 
     57 #include "pipe/p_context.h"
     58 #include "pipe/p_screen.h"
     59 #include "pipe/p_state.h"
     60 
     61 #include "util/u_atomic.h"
     62 #include "util/u_box.h"
     63 #include "util/u_debug.h"
     64 #include "util/u_format.h"
     65 #include "util/u_memory.h"
     66 
     67 #include "postprocess/filters.h"
     68 #include "postprocess/postprocess.h"
     69 
     70 #include "state_tracker/st_api.h"
     71 #include "state_tracker/st_gl_api.h"
     72 
     73 
     74 
     75 extern struct pipe_screen *
     76 osmesa_create_screen(void);
     77 
     78 
     79 
     80 struct osmesa_buffer
     81 {
     82    struct st_framebuffer_iface *stfb;
     83    struct st_visual visual;
     84    unsigned width, height;
     85 
     86    struct pipe_resource *textures[ST_ATTACHMENT_COUNT];
     87 
     88    void *map;
     89 
     90    struct osmesa_buffer *next;  /**< next in linked list */
     91 };
     92 
     93 
     94 struct osmesa_context
     95 {
     96    struct st_context_iface *stctx;
     97 
     98    boolean ever_used;     /*< Has this context ever been current? */
     99 
    100    struct osmesa_buffer *current_buffer;
    101 
    102    enum pipe_format depth_stencil_format, accum_format;
    103 
    104    GLenum format;         /*< User-specified context format */
    105    GLenum type;           /*< Buffer's data type */
    106    GLint user_row_length; /*< user-specified number of pixels per row */
    107    GLboolean y_up;        /*< TRUE  -> Y increases upward */
    108                           /*< FALSE -> Y increases downward */
    109 
    110    /** Which postprocessing filters are enabled. */
    111    unsigned pp_enabled[PP_FILTERS];
    112    struct pp_queue_t *pp;
    113 };
    114 
    115 
    116 /**
    117  * Linked list of all osmesa_buffers.
    118  * We can re-use an osmesa_buffer from one OSMesaMakeCurrent() call to
    119  * the next unless the color/depth/stencil/accum formats change.
    120  * We have to do this to be compatible with the original OSMesa implementation
    121  * because some apps call OSMesaMakeCurrent() several times during rendering
    122  * a frame.
    123  */
    124 static struct osmesa_buffer *BufferList = NULL;
    125 
    126 
    127 /**
    128  * Called from the ST manager.
    129  */
    130 static int
    131 osmesa_st_get_param(struct st_manager *smapi, enum st_manager_param param)
    132 {
    133    /* no-op */
    134    return 0;
    135 }
    136 
    137 
    138 /**
    139  * Create/return singleton st_api object.
    140  */
    141 static struct st_api *
    142 get_st_api(void)
    143 {
    144    static struct st_api *stapi = NULL;
    145    if (!stapi) {
    146       stapi = st_gl_api_create();
    147    }
    148    return stapi;
    149 }
    150 
    151 
    152 /**
    153  * Create/return a singleton st_manager object.
    154  */
    155 static struct st_manager *
    156 get_st_manager(void)
    157 {
    158    static struct st_manager *stmgr = NULL;
    159    if (!stmgr) {
    160       stmgr = CALLOC_STRUCT(st_manager);
    161       if (stmgr) {
    162          stmgr->screen = osmesa_create_screen();
    163          stmgr->get_param = osmesa_st_get_param;
    164          stmgr->get_egl_image = NULL;
    165       }
    166    }
    167    return stmgr;
    168 }
    169 
    170 
    171 static inline boolean
    172 little_endian(void)
    173 {
    174    const unsigned ui = 1;
    175    return *((const char *) &ui);
    176 }
    177 
    178 
    179 /**
    180  * Given an OSMESA_x format and a GL_y type, return the best
    181  * matching PIPE_FORMAT_z.
    182  * Note that we can't exactly match all user format/type combinations
    183  * with gallium formats.  If we find this to be a problem, we can
    184  * implement more elaborate format/type conversion in the flush_front()
    185  * function.
    186  */
    187 static enum pipe_format
    188 osmesa_choose_format(GLenum format, GLenum type)
    189 {
    190    switch (format) {
    191    case OSMESA_RGBA:
    192       if (type == GL_UNSIGNED_BYTE) {
    193          if (little_endian())
    194             return PIPE_FORMAT_R8G8B8A8_UNORM;
    195          else
    196             return PIPE_FORMAT_A8B8G8R8_UNORM;
    197       }
    198       else if (type == GL_UNSIGNED_SHORT) {
    199          return PIPE_FORMAT_R16G16B16A16_UNORM;
    200       }
    201       else if (type == GL_FLOAT) {
    202          return PIPE_FORMAT_R32G32B32A32_FLOAT;
    203       }
    204       else {
    205          return PIPE_FORMAT_NONE;
    206       }
    207       break;
    208    case OSMESA_BGRA:
    209       if (type == GL_UNSIGNED_BYTE) {
    210          if (little_endian())
    211             return PIPE_FORMAT_B8G8R8A8_UNORM;
    212          else
    213             return PIPE_FORMAT_A8R8G8B8_UNORM;
    214       }
    215       else if (type == GL_UNSIGNED_SHORT) {
    216          return PIPE_FORMAT_R16G16B16A16_UNORM;
    217       }
    218       else if (type == GL_FLOAT) {
    219          return PIPE_FORMAT_R32G32B32A32_FLOAT;
    220       }
    221       else {
    222          return PIPE_FORMAT_NONE;
    223       }
    224       break;
    225    case OSMESA_ARGB:
    226       if (type == GL_UNSIGNED_BYTE) {
    227          if (little_endian())
    228             return PIPE_FORMAT_A8R8G8B8_UNORM;
    229          else
    230             return PIPE_FORMAT_B8G8R8A8_UNORM;
    231       }
    232       else if (type == GL_UNSIGNED_SHORT) {
    233          return PIPE_FORMAT_R16G16B16A16_UNORM;
    234       }
    235       else if (type == GL_FLOAT) {
    236          return PIPE_FORMAT_R32G32B32A32_FLOAT;
    237       }
    238       else {
    239          return PIPE_FORMAT_NONE;
    240       }
    241       break;
    242    case OSMESA_RGB:
    243       if (type == GL_UNSIGNED_BYTE) {
    244          return PIPE_FORMAT_R8G8B8_UNORM;
    245       }
    246       else if (type == GL_UNSIGNED_SHORT) {
    247          return PIPE_FORMAT_R16G16B16_UNORM;
    248       }
    249       else if (type == GL_FLOAT) {
    250          return PIPE_FORMAT_R32G32B32_FLOAT;
    251       }
    252       else {
    253          return PIPE_FORMAT_NONE;
    254       }
    255       break;
    256    case OSMESA_BGR:
    257       /* No gallium format for this one */
    258       return PIPE_FORMAT_NONE;
    259    case OSMESA_RGB_565:
    260       return PIPE_FORMAT_B5G6R5_UNORM;
    261    default:
    262       ; /* fall-through */
    263    }
    264    return PIPE_FORMAT_NONE;
    265 }
    266 
    267 
    268 /**
    269  * Initialize an st_visual object.
    270  */
    271 static void
    272 osmesa_init_st_visual(struct st_visual *vis,
    273                       enum pipe_format color_format,
    274                       enum pipe_format ds_format,
    275                       enum pipe_format accum_format)
    276 {
    277    vis->buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK;
    278 
    279    if (ds_format != PIPE_FORMAT_NONE)
    280       vis->buffer_mask |= ST_ATTACHMENT_DEPTH_STENCIL_MASK;
    281    if (accum_format != PIPE_FORMAT_NONE)
    282       vis->buffer_mask |= ST_ATTACHMENT_ACCUM;
    283 
    284    vis->color_format = color_format;
    285    vis->depth_stencil_format = ds_format;
    286    vis->accum_format = accum_format;
    287    vis->samples = 1;
    288    vis->render_buffer = ST_ATTACHMENT_FRONT_LEFT;
    289 }
    290 
    291 
    292 /**
    293  * Return the osmesa_buffer that corresponds to an st_framebuffer_iface.
    294  */
    295 static inline struct osmesa_buffer *
    296 stfbi_to_osbuffer(struct st_framebuffer_iface *stfbi)
    297 {
    298    return (struct osmesa_buffer *) stfbi->st_manager_private;
    299 }
    300 
    301 
    302 /**
    303  * Called via glFlush/glFinish.  This is where we copy the contents
    304  * of the driver's color buffer into the user-specified buffer.
    305  */
    306 static boolean
    307 osmesa_st_framebuffer_flush_front(struct st_context_iface *stctx,
    308                                   struct st_framebuffer_iface *stfbi,
    309                                   enum st_attachment_type statt)
    310 {
    311    OSMesaContext osmesa = OSMesaGetCurrentContext();
    312    struct osmesa_buffer *osbuffer = stfbi_to_osbuffer(stfbi);
    313    struct pipe_context *pipe = stctx->pipe;
    314    struct pipe_resource *res = osbuffer->textures[statt];
    315    struct pipe_transfer *transfer = NULL;
    316    struct pipe_box box;
    317    void *map;
    318    ubyte *src, *dst;
    319    unsigned y, bytes, bpp;
    320    int dst_stride;
    321 
    322    if (osmesa->pp) {
    323       struct pipe_resource *zsbuf = NULL;
    324       unsigned i;
    325 
    326       /* Find the z/stencil buffer if there is one */
    327       for (i = 0; i < ARRAY_SIZE(osbuffer->textures); i++) {
    328          struct pipe_resource *res = osbuffer->textures[i];
    329          if (res) {
    330             const struct util_format_description *desc =
    331                util_format_description(res->format);
    332 
    333             if (util_format_has_depth(desc)) {
    334                zsbuf = res;
    335                break;
    336             }
    337          }
    338       }
    339 
    340       /* run the postprocess stage(s) */
    341       pp_run(osmesa->pp, res, res, zsbuf);
    342    }
    343 
    344    u_box_2d(0, 0, res->width0, res->height0, &box);
    345 
    346    map = pipe->transfer_map(pipe, res, 0, PIPE_TRANSFER_READ, &box,
    347                             &transfer);
    348 
    349    /*
    350     * Copy the color buffer from the resource to the user's buffer.
    351     */
    352    bpp = util_format_get_blocksize(osbuffer->visual.color_format);
    353    src = map;
    354    dst = osbuffer->map;
    355    if (osmesa->user_row_length)
    356       dst_stride = bpp * osmesa->user_row_length;
    357    else
    358       dst_stride = bpp * osbuffer->width;
    359    bytes = bpp * res->width0;
    360 
    361    if (osmesa->y_up) {
    362       /* need to flip image upside down */
    363       dst = dst + (res->height0 - 1) * dst_stride;
    364       dst_stride = -dst_stride;
    365    }
    366 
    367    for (y = 0; y < res->height0; y++) {
    368       memcpy(dst, src, bytes);
    369       dst += dst_stride;
    370       src += transfer->stride;
    371    }
    372 
    373    pipe->transfer_unmap(pipe, transfer);
    374 
    375    return TRUE;
    376 }
    377 
    378 
    379 /**
    380  * Called by the st manager to validate the framebuffer (allocate
    381  * its resources).
    382  */
    383 static boolean
    384 osmesa_st_framebuffer_validate(struct st_context_iface *stctx,
    385                                struct st_framebuffer_iface *stfbi,
    386                                const enum st_attachment_type *statts,
    387                                unsigned count,
    388                                struct pipe_resource **out)
    389 {
    390    struct pipe_screen *screen = get_st_manager()->screen;
    391    enum st_attachment_type i;
    392    struct osmesa_buffer *osbuffer = stfbi_to_osbuffer(stfbi);
    393    struct pipe_resource templat;
    394 
    395    memset(&templat, 0, sizeof(templat));
    396    templat.target = PIPE_TEXTURE_RECT;
    397    templat.format = 0; /* setup below */
    398    templat.last_level = 0;
    399    templat.width0 = osbuffer->width;
    400    templat.height0 = osbuffer->height;
    401    templat.depth0 = 1;
    402    templat.array_size = 1;
    403    templat.usage = PIPE_USAGE_DEFAULT;
    404    templat.bind = 0; /* setup below */
    405    templat.flags = 0;
    406 
    407    for (i = 0; i < count; i++) {
    408       enum pipe_format format = PIPE_FORMAT_NONE;
    409       unsigned bind = 0;
    410 
    411       /*
    412        * At this time, we really only need to handle the front-left color
    413        * attachment, since that's all we specified for the visual in
    414        * osmesa_init_st_visual().
    415        */
    416       if (statts[i] == ST_ATTACHMENT_FRONT_LEFT) {
    417          format = osbuffer->visual.color_format;
    418          bind = PIPE_BIND_RENDER_TARGET;
    419       }
    420       else if (statts[i] == ST_ATTACHMENT_DEPTH_STENCIL) {
    421          format = osbuffer->visual.depth_stencil_format;
    422          bind = PIPE_BIND_DEPTH_STENCIL;
    423       }
    424       else if (statts[i] == ST_ATTACHMENT_ACCUM) {
    425          format = osbuffer->visual.accum_format;
    426          bind = PIPE_BIND_RENDER_TARGET;
    427       }
    428       else {
    429          debug_warning("Unexpected attachment type in "
    430                        "osmesa_st_framebuffer_validate()");
    431       }
    432 
    433       templat.format = format;
    434       templat.bind = bind;
    435       out[i] = osbuffer->textures[statts[i]] =
    436          screen->resource_create(screen, &templat);
    437    }
    438 
    439    return TRUE;
    440 }
    441 
    442 
    443 static struct st_framebuffer_iface *
    444 osmesa_create_st_framebuffer(void)
    445 {
    446    struct st_framebuffer_iface *stfbi = CALLOC_STRUCT(st_framebuffer_iface);
    447    if (stfbi) {
    448       stfbi->flush_front = osmesa_st_framebuffer_flush_front;
    449       stfbi->validate = osmesa_st_framebuffer_validate;
    450       p_atomic_set(&stfbi->stamp, 1);
    451    }
    452    return stfbi;
    453 }
    454 
    455 
    456 /**
    457  * Create new buffer and add to linked list.
    458  */
    459 static struct osmesa_buffer *
    460 osmesa_create_buffer(enum pipe_format color_format,
    461                      enum pipe_format ds_format,
    462                      enum pipe_format accum_format)
    463 {
    464    struct osmesa_buffer *osbuffer = CALLOC_STRUCT(osmesa_buffer);
    465    if (osbuffer) {
    466       osbuffer->stfb = osmesa_create_st_framebuffer();
    467 
    468       osbuffer->stfb->st_manager_private = osbuffer;
    469       osbuffer->stfb->visual = &osbuffer->visual;
    470 
    471       osmesa_init_st_visual(&osbuffer->visual, color_format,
    472                             ds_format, accum_format);
    473 
    474       /* insert into linked list */
    475       osbuffer->next = BufferList;
    476       BufferList = osbuffer;
    477    }
    478 
    479    return osbuffer;
    480 }
    481 
    482 
    483 /**
    484  * Search linked list for a buffer with matching pixel formats and size.
    485  */
    486 static struct osmesa_buffer *
    487 osmesa_find_buffer(enum pipe_format color_format,
    488                    enum pipe_format ds_format,
    489                    enum pipe_format accum_format,
    490                    GLsizei width, GLsizei height)
    491 {
    492    struct osmesa_buffer *b;
    493 
    494    /* Check if we already have a suitable buffer for the given formats */
    495    for (b = BufferList; b; b = b->next) {
    496       if (b->visual.color_format == color_format &&
    497           b->visual.depth_stencil_format == ds_format &&
    498           b->visual.accum_format == accum_format &&
    499           b->width == width &&
    500           b->height == height) {
    501          return b;
    502       }
    503    }
    504    return NULL;
    505 }
    506 
    507 
    508 static void
    509 osmesa_destroy_buffer(struct osmesa_buffer *osbuffer)
    510 {
    511    FREE(osbuffer->stfb);
    512    FREE(osbuffer);
    513 }
    514 
    515 
    516 
    517 /**********************************************************************/
    518 /*****                    Public Functions                        *****/
    519 /**********************************************************************/
    520 
    521 
    522 /**
    523  * Create an Off-Screen Mesa rendering context.  The only attribute needed is
    524  * an RGBA vs Color-Index mode flag.
    525  *
    526  * Input:  format - Must be GL_RGBA
    527  *         sharelist - specifies another OSMesaContext with which to share
    528  *                     display lists.  NULL indicates no sharing.
    529  * Return:  an OSMesaContext or 0 if error
    530  */
    531 GLAPI OSMesaContext GLAPIENTRY
    532 OSMesaCreateContext(GLenum format, OSMesaContext sharelist)
    533 {
    534    return OSMesaCreateContextExt(format, 24, 8, 0, sharelist);
    535 }
    536 
    537 
    538 /**
    539  * New in Mesa 3.5
    540  *
    541  * Create context and specify size of ancillary buffers.
    542  */
    543 GLAPI OSMesaContext GLAPIENTRY
    544 OSMesaCreateContextExt(GLenum format, GLint depthBits, GLint stencilBits,
    545                        GLint accumBits, OSMesaContext sharelist)
    546 {
    547    int attribs[100], n = 0;
    548 
    549    attribs[n++] = OSMESA_FORMAT;
    550    attribs[n++] = format;
    551    attribs[n++] = OSMESA_DEPTH_BITS;
    552    attribs[n++] = depthBits;
    553    attribs[n++] = OSMESA_STENCIL_BITS;
    554    attribs[n++] = stencilBits;
    555    attribs[n++] = OSMESA_ACCUM_BITS;
    556    attribs[n++] = accumBits;
    557    attribs[n++] = 0;
    558 
    559    return OSMesaCreateContextAttribs(attribs, sharelist);
    560 }
    561 
    562 
    563 /**
    564  * New in Mesa 11.2
    565  *
    566  * Create context with attribute list.
    567  */
    568 GLAPI OSMesaContext GLAPIENTRY
    569 OSMesaCreateContextAttribs(const int *attribList, OSMesaContext sharelist)
    570 {
    571    OSMesaContext osmesa;
    572    struct st_context_iface *st_shared;
    573    enum st_context_error st_error = 0;
    574    struct st_context_attribs attribs;
    575    struct st_api *stapi = get_st_api();
    576    GLenum format = GL_RGBA;
    577    int depthBits = 0, stencilBits = 0, accumBits = 0;
    578    int profile = OSMESA_COMPAT_PROFILE, version_major = 1, version_minor = 0;
    579    int i;
    580 
    581    if (sharelist) {
    582       st_shared = sharelist->stctx;
    583    }
    584    else {
    585       st_shared = NULL;
    586    }
    587 
    588    for (i = 0; attribList[i]; i += 2) {
    589       switch (attribList[i]) {
    590       case OSMESA_FORMAT:
    591          format = attribList[i+1];
    592          switch (format) {
    593          case OSMESA_COLOR_INDEX:
    594          case OSMESA_RGBA:
    595          case OSMESA_BGRA:
    596          case OSMESA_ARGB:
    597          case OSMESA_RGB:
    598          case OSMESA_BGR:
    599          case OSMESA_RGB_565:
    600             /* legal */
    601             break;
    602          default:
    603             return NULL;
    604          }
    605          break;
    606       case OSMESA_DEPTH_BITS:
    607          depthBits = attribList[i+1];
    608          if (depthBits < 0)
    609             return NULL;
    610          break;
    611       case OSMESA_STENCIL_BITS:
    612          stencilBits = attribList[i+1];
    613          if (stencilBits < 0)
    614             return NULL;
    615          break;
    616       case OSMESA_ACCUM_BITS:
    617          accumBits = attribList[i+1];
    618          if (accumBits < 0)
    619             return NULL;
    620          break;
    621       case OSMESA_PROFILE:
    622          profile = attribList[i+1];
    623          if (profile != OSMESA_CORE_PROFILE &&
    624              profile != OSMESA_COMPAT_PROFILE)
    625             return NULL;
    626          break;
    627       case OSMESA_CONTEXT_MAJOR_VERSION:
    628          version_major = attribList[i+1];
    629          if (version_major < 1)
    630             return NULL;
    631          break;
    632       case OSMESA_CONTEXT_MINOR_VERSION:
    633          version_minor = attribList[i+1];
    634          if (version_minor < 0)
    635             return NULL;
    636          break;
    637       case 0:
    638          /* end of list */
    639          break;
    640       default:
    641          fprintf(stderr, "Bad attribute in OSMesaCreateContextAttribs()\n");
    642          return NULL;
    643       }
    644    }
    645 
    646    osmesa = (OSMesaContext) CALLOC_STRUCT(osmesa_context);
    647    if (!osmesa)
    648       return NULL;
    649 
    650    /* Choose depth/stencil/accum buffer formats */
    651    if (accumBits > 0) {
    652       osmesa->accum_format = PIPE_FORMAT_R16G16B16A16_SNORM;
    653    }
    654    if (depthBits > 0 && stencilBits > 0) {
    655       osmesa->depth_stencil_format = PIPE_FORMAT_Z24_UNORM_S8_UINT;
    656    }
    657    else if (stencilBits > 0) {
    658       osmesa->depth_stencil_format = PIPE_FORMAT_S8_UINT;
    659    }
    660    else if (depthBits >= 24) {
    661       osmesa->depth_stencil_format = PIPE_FORMAT_Z24X8_UNORM;
    662    }
    663    else if (depthBits >= 16) {
    664       osmesa->depth_stencil_format = PIPE_FORMAT_Z16_UNORM;
    665    }
    666 
    667    /*
    668     * Create the rendering context
    669     */
    670    memset(&attribs, 0, sizeof(attribs));
    671    attribs.profile = (profile == OSMESA_CORE_PROFILE)
    672       ? ST_PROFILE_OPENGL_CORE : ST_PROFILE_DEFAULT;
    673    attribs.major = version_major;
    674    attribs.minor = version_minor;
    675    attribs.flags = 0;  /* ST_CONTEXT_FLAG_x */
    676    attribs.options.force_glsl_extensions_warn = FALSE;
    677    attribs.options.disable_blend_func_extended = FALSE;
    678    attribs.options.disable_glsl_line_continuations = FALSE;
    679    attribs.options.disable_shader_bit_encoding = FALSE;
    680    attribs.options.force_s3tc_enable = FALSE;
    681    attribs.options.force_glsl_version = 0;
    682 
    683    osmesa_init_st_visual(&attribs.visual,
    684                          PIPE_FORMAT_R8G8B8A8_UNORM,
    685                          osmesa->depth_stencil_format,
    686                          osmesa->accum_format);
    687 
    688    osmesa->stctx = stapi->create_context(stapi, get_st_manager(),
    689                                          &attribs, &st_error, st_shared);
    690    if (!osmesa->stctx) {
    691       FREE(osmesa);
    692       return NULL;
    693    }
    694 
    695    osmesa->stctx->st_manager_private = osmesa;
    696 
    697    osmesa->format = format;
    698    osmesa->user_row_length = 0;
    699    osmesa->y_up = GL_TRUE;
    700 
    701    return osmesa;
    702 }
    703 
    704 
    705 
    706 /**
    707  * Destroy an Off-Screen Mesa rendering context.
    708  *
    709  * \param osmesa  the context to destroy
    710  */
    711 GLAPI void GLAPIENTRY
    712 OSMesaDestroyContext(OSMesaContext osmesa)
    713 {
    714    if (osmesa) {
    715       pp_free(osmesa->pp);
    716       osmesa->stctx->destroy(osmesa->stctx);
    717       FREE(osmesa);
    718    }
    719 }
    720 
    721 
    722 /**
    723  * Bind an OSMesaContext to an image buffer.  The image buffer is just a
    724  * block of memory which the client provides.  Its size must be at least
    725  * as large as width*height*pixelSize.  Its address should be a multiple
    726  * of 4 if using RGBA mode.
    727  *
    728  * By default, image data is stored in the order of glDrawPixels: row-major
    729  * order with the lower-left image pixel stored in the first array position
    730  * (ie. bottom-to-top).
    731  *
    732  * If the context's viewport hasn't been initialized yet, it will now be
    733  * initialized to (0,0,width,height).
    734  *
    735  * Input:  osmesa - the rendering context
    736  *         buffer - the image buffer memory
    737  *         type - data type for pixel components
    738  *                GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT
    739  *                or GL_FLOAT.
    740  *         width, height - size of image buffer in pixels, at least 1
    741  * Return:  GL_TRUE if success, GL_FALSE if error because of invalid osmesa,
    742  *          invalid type, invalid size, etc.
    743  */
    744 GLAPI GLboolean GLAPIENTRY
    745 OSMesaMakeCurrent(OSMesaContext osmesa, void *buffer, GLenum type,
    746                   GLsizei width, GLsizei height)
    747 {
    748    struct st_api *stapi = get_st_api();
    749    struct osmesa_buffer *osbuffer;
    750    enum pipe_format color_format;
    751 
    752    if (!osmesa || !buffer || width < 1 || height < 1) {
    753       return GL_FALSE;
    754    }
    755 
    756    if (osmesa->format == OSMESA_RGB_565 && type != GL_UNSIGNED_SHORT_5_6_5) {
    757       return GL_FALSE;
    758    }
    759 
    760    color_format = osmesa_choose_format(osmesa->format, type);
    761    if (color_format == PIPE_FORMAT_NONE) {
    762       fprintf(stderr, "OSMesaMakeCurrent(unsupported format/type)\n");
    763       return GL_FALSE;
    764    }
    765 
    766    /* See if we already have a buffer that uses these pixel formats */
    767    osbuffer = osmesa_find_buffer(color_format,
    768                                  osmesa->depth_stencil_format,
    769                                  osmesa->accum_format, width, height);
    770    if (!osbuffer) {
    771       /* Existing buffer found, create new buffer */
    772       osbuffer = osmesa_create_buffer(color_format,
    773                                       osmesa->depth_stencil_format,
    774                                       osmesa->accum_format);
    775    }
    776 
    777    osbuffer->width = width;
    778    osbuffer->height = height;
    779    osbuffer->map = buffer;
    780 
    781    /* XXX unused for now */
    782    (void) osmesa_destroy_buffer;
    783 
    784    osmesa->current_buffer = osbuffer;
    785    osmesa->type = type;
    786 
    787    stapi->make_current(stapi, osmesa->stctx, osbuffer->stfb, osbuffer->stfb);
    788 
    789    if (!osmesa->ever_used) {
    790       /* one-time init, just postprocessing for now */
    791       boolean any_pp_enabled = FALSE;
    792       unsigned i;
    793 
    794       for (i = 0; i < ARRAY_SIZE(osmesa->pp_enabled); i++) {
    795          if (osmesa->pp_enabled[i]) {
    796             any_pp_enabled = TRUE;
    797             break;
    798          }
    799       }
    800 
    801       if (any_pp_enabled) {
    802          osmesa->pp = pp_init(osmesa->stctx->pipe,
    803                               osmesa->pp_enabled,
    804                               osmesa->stctx->cso_context);
    805 
    806          pp_init_fbos(osmesa->pp, width, height);
    807       }
    808 
    809       osmesa->ever_used = TRUE;
    810    }
    811 
    812    return GL_TRUE;
    813 }
    814 
    815 
    816 
    817 GLAPI OSMesaContext GLAPIENTRY
    818 OSMesaGetCurrentContext(void)
    819 {
    820    struct st_api *stapi = get_st_api();
    821    struct st_context_iface *st = stapi->get_current(stapi);
    822    return st ? (OSMesaContext) st->st_manager_private : NULL;
    823 }
    824 
    825 
    826 
    827 GLAPI void GLAPIENTRY
    828 OSMesaPixelStore(GLint pname, GLint value)
    829 {
    830    OSMesaContext osmesa = OSMesaGetCurrentContext();
    831 
    832    switch (pname) {
    833    case OSMESA_ROW_LENGTH:
    834       osmesa->user_row_length = value;
    835       break;
    836    case OSMESA_Y_UP:
    837       osmesa->y_up = value ? GL_TRUE : GL_FALSE;
    838       break;
    839    default:
    840       fprintf(stderr, "Invalid pname in OSMesaPixelStore()\n");
    841       return;
    842    }
    843 }
    844 
    845 
    846 GLAPI void GLAPIENTRY
    847 OSMesaGetIntegerv(GLint pname, GLint *value)
    848 {
    849    OSMesaContext osmesa = OSMesaGetCurrentContext();
    850    struct osmesa_buffer *osbuffer = osmesa ? osmesa->current_buffer : NULL;
    851 
    852    switch (pname) {
    853    case OSMESA_WIDTH:
    854       *value = osbuffer ? osbuffer->width : 0;
    855       return;
    856    case OSMESA_HEIGHT:
    857       *value = osbuffer ? osbuffer->height : 0;
    858       return;
    859    case OSMESA_FORMAT:
    860       *value = osmesa->format;
    861       return;
    862    case OSMESA_TYPE:
    863       /* current color buffer's data type */
    864       *value = osmesa->type;
    865       return;
    866    case OSMESA_ROW_LENGTH:
    867       *value = osmesa->user_row_length;
    868       return;
    869    case OSMESA_Y_UP:
    870       *value = osmesa->y_up;
    871       return;
    872    case OSMESA_MAX_WIDTH:
    873       /* fall-through */
    874    case OSMESA_MAX_HEIGHT:
    875       {
    876          struct pipe_screen *screen = get_st_manager()->screen;
    877          int maxLevels = screen->get_param(screen,
    878                                            PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
    879          *value = 1 << (maxLevels - 1);
    880       }
    881       return;
    882    default:
    883       fprintf(stderr, "Invalid pname in OSMesaGetIntegerv()\n");
    884       return;
    885    }
    886 }
    887 
    888 
    889 /**
    890  * Return information about the depth buffer associated with an OSMesa context.
    891  * Input:  c - the OSMesa context
    892  * Output:  width, height - size of buffer in pixels
    893  *          bytesPerValue - bytes per depth value (2 or 4)
    894  *          buffer - pointer to depth buffer values
    895  * Return:  GL_TRUE or GL_FALSE to indicate success or failure.
    896  */
    897 GLAPI GLboolean GLAPIENTRY
    898 OSMesaGetDepthBuffer(OSMesaContext c, GLint *width, GLint *height,
    899                      GLint *bytesPerValue, void **buffer)
    900 {
    901    struct osmesa_buffer *osbuffer = c->current_buffer;
    902    struct pipe_context *pipe = c->stctx->pipe;
    903    struct pipe_resource *res = osbuffer->textures[ST_ATTACHMENT_DEPTH_STENCIL];
    904    struct pipe_transfer *transfer = NULL;
    905    struct pipe_box box;
    906 
    907    /*
    908     * Note: we can't really implement this function with gallium as
    909     * we did for swrast.  We can't just map the resource and leave it
    910     * mapped (and there's no OSMesaUnmapDepthBuffer() function) so
    911     * we unmap the buffer here and return a 'stale' pointer.  This should
    912     * actually be OK in most cases where the caller of this function
    913     * immediately uses the pointer.
    914     */
    915 
    916    u_box_2d(0, 0, res->width0, res->height0, &box);
    917 
    918    *buffer = pipe->transfer_map(pipe, res, 0, PIPE_TRANSFER_READ, &box,
    919                                 &transfer);
    920    if (!*buffer) {
    921       return GL_FALSE;
    922    }
    923 
    924    *width = res->width0;
    925    *height = res->height0;
    926    *bytesPerValue = util_format_get_blocksize(res->format);
    927 
    928    pipe->transfer_unmap(pipe, transfer);
    929 
    930    return GL_TRUE;
    931 }
    932 
    933 
    934 /**
    935  * Return the color buffer associated with an OSMesa context.
    936  * Input:  c - the OSMesa context
    937  * Output:  width, height - size of buffer in pixels
    938  *          format - the pixel format (OSMESA_FORMAT)
    939  *          buffer - pointer to color buffer values
    940  * Return:  GL_TRUE or GL_FALSE to indicate success or failure.
    941  */
    942 GLAPI GLboolean GLAPIENTRY
    943 OSMesaGetColorBuffer(OSMesaContext osmesa, GLint *width,
    944                       GLint *height, GLint *format, void **buffer)
    945 {
    946    struct osmesa_buffer *osbuffer = osmesa->current_buffer;
    947 
    948    if (osbuffer) {
    949       *width = osbuffer->width;
    950       *height = osbuffer->height;
    951       *format = osmesa->format;
    952       *buffer = osbuffer->map;
    953       return GL_TRUE;
    954    }
    955    else {
    956       *width = 0;
    957       *height = 0;
    958       *format = 0;
    959       *buffer = 0;
    960       return GL_FALSE;
    961    }
    962 }
    963 
    964 
    965 struct name_function
    966 {
    967    const char *Name;
    968    OSMESAproc Function;
    969 };
    970 
    971 static struct name_function functions[] = {
    972    { "OSMesaCreateContext", (OSMESAproc) OSMesaCreateContext },
    973    { "OSMesaCreateContextExt", (OSMESAproc) OSMesaCreateContextExt },
    974    { "OSMesaCreateContextAttribs", (OSMESAproc) OSMesaCreateContextAttribs },
    975    { "OSMesaDestroyContext", (OSMESAproc) OSMesaDestroyContext },
    976    { "OSMesaMakeCurrent", (OSMESAproc) OSMesaMakeCurrent },
    977    { "OSMesaGetCurrentContext", (OSMESAproc) OSMesaGetCurrentContext },
    978    { "OSMesaPixelStore", (OSMESAproc) OSMesaPixelStore },
    979    { "OSMesaGetIntegerv", (OSMESAproc) OSMesaGetIntegerv },
    980    { "OSMesaGetDepthBuffer", (OSMESAproc) OSMesaGetDepthBuffer },
    981    { "OSMesaGetColorBuffer", (OSMESAproc) OSMesaGetColorBuffer },
    982    { "OSMesaGetProcAddress", (OSMESAproc) OSMesaGetProcAddress },
    983    { "OSMesaColorClamp", (OSMESAproc) OSMesaColorClamp },
    984    { "OSMesaPostprocess", (OSMESAproc) OSMesaPostprocess },
    985    { NULL, NULL }
    986 };
    987 
    988 
    989 GLAPI OSMESAproc GLAPIENTRY
    990 OSMesaGetProcAddress(const char *funcName)
    991 {
    992    int i;
    993    for (i = 0; functions[i].Name; i++) {
    994       if (strcmp(functions[i].Name, funcName) == 0)
    995          return functions[i].Function;
    996    }
    997    return _glapi_get_proc_address(funcName);
    998 }
    999 
   1000 
   1001 GLAPI void GLAPIENTRY
   1002 OSMesaColorClamp(GLboolean enable)
   1003 {
   1004    extern void GLAPIENTRY _mesa_ClampColor(GLenum target, GLenum clamp);
   1005 
   1006    _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB,
   1007                     enable ? GL_TRUE : GL_FIXED_ONLY_ARB);
   1008 }
   1009 
   1010 
   1011 GLAPI void GLAPIENTRY
   1012 OSMesaPostprocess(OSMesaContext osmesa, const char *filter,
   1013                   unsigned enable_value)
   1014 {
   1015    if (!osmesa->ever_used) {
   1016       /* We can only enable/disable postprocess filters before a context
   1017        * is made current for the first time.
   1018        */
   1019       unsigned i;
   1020 
   1021       for (i = 0; i < PP_FILTERS; i++) {
   1022          if (strcmp(pp_filters[i].name, filter) == 0) {
   1023             osmesa->pp_enabled[i] = enable_value;
   1024             return;
   1025          }
   1026       }
   1027       debug_warning("OSMesaPostprocess(unknown filter)\n");
   1028    }
   1029    else {
   1030       debug_warning("Calling OSMesaPostprocess() after OSMesaMakeCurrent()\n");
   1031    }
   1032 }
   1033