Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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 suport "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 "GL/osmesa.h"
  53.  
  54. #include "glapi/glapi.h"  /* for OSMesaGetProcAddress below */
  55.  
  56. #include "pipe/p_context.h"
  57. #include "pipe/p_screen.h"
  58. #include "pipe/p_state.h"
  59.  
  60. #include "util/u_atomic.h"
  61. #include "util/u_box.h"
  62. #include "util/u_format.h"
  63. #include "util/u_memory.h"
  64.  
  65. #include "state_tracker/st_api.h"
  66. #include "state_tracker/st_gl_api.h"
  67.  
  68.  
  69.  
  70. extern struct pipe_screen *
  71. osmesa_create_screen(void);
  72.  
  73.  
  74.  
  75. struct osmesa_buffer
  76. {
  77.    struct st_framebuffer_iface *stfb;
  78.    struct st_visual visual;
  79.    unsigned width, height;
  80.  
  81.    struct pipe_resource *textures[ST_ATTACHMENT_COUNT];
  82.  
  83.    void *map;
  84.  
  85.    struct osmesa_buffer *next;  /**< next in linked list */
  86. };
  87.  
  88.  
  89. struct osmesa_context
  90. {
  91.    struct st_context_iface *stctx;
  92.  
  93.    struct osmesa_buffer *current_buffer;
  94.  
  95.    enum pipe_format depth_stencil_format, accum_format;
  96.  
  97.    GLenum format;         /*< User-specified context format */
  98.    GLenum type;           /*< Buffer's data type */
  99.    GLint user_row_length; /*< user-specified number of pixels per row */
  100.    GLboolean y_up;        /*< TRUE  -> Y increases upward */
  101.                           /*< FALSE -> Y increases downward */
  102. };
  103.  
  104.  
  105. /**
  106.  * Linked list of all osmesa_buffers.
  107.  * We can re-use an osmesa_buffer from one OSMesaMakeCurrent() call to
  108.  * the next unless the color/depth/stencil/accum formats change.
  109.  * We have to do this to be compatible with the original OSMesa implementation
  110.  * because some apps call OSMesaMakeCurrent() several times during rendering
  111.  * a frame.
  112.  */
  113. static struct osmesa_buffer *BufferList = NULL;
  114.  
  115.  
  116. /**
  117.  * Called from the ST manager.
  118.  */
  119. static int
  120. osmesa_st_get_param(struct st_manager *smapi, enum st_manager_param param)
  121. {
  122.    /* no-op */
  123.    return 0;
  124. }
  125.  
  126.  
  127. /**
  128.  * Create/return singleton st_api object.
  129.  */
  130. static struct st_api *
  131. get_st_api(void)
  132. {
  133.    static struct st_api *stapi = NULL;
  134.    if (!stapi) {
  135.       stapi = st_gl_api_create();
  136.    }
  137.    return stapi;
  138. }
  139.  
  140.  
  141. /**
  142.  * Create/return a singleton st_manager object.
  143.  */
  144. static struct st_manager *
  145. get_st_manager(void)
  146. {
  147.    static struct st_manager *stmgr = NULL;
  148.    if (!stmgr) {
  149.       stmgr = CALLOC_STRUCT(st_manager);
  150.       if (stmgr) {
  151.          stmgr->screen = osmesa_create_screen();
  152.          stmgr->get_param = osmesa_st_get_param;
  153.          stmgr->get_egl_image = NULL;
  154.       }        
  155.    }
  156.    return stmgr;
  157. }
  158.  
  159.  
  160. static INLINE boolean
  161. little_endian(void)
  162. {
  163.    const unsigned ui = 1;
  164.    return *((const char *) &ui);
  165. }
  166.  
  167.  
  168. /**
  169.  * Given an OSMESA_x format and a GL_y type, return the best
  170.  * matching PIPE_FORMAT_z.
  171.  * Note that we can't exactly match all user format/type combinations
  172.  * with gallium formats.  If we find this to be a problem, we can
  173.  * implement more elaborate format/type conversion in the flush_front()
  174.  * function.
  175.  */
  176. static enum pipe_format
  177. osmesa_choose_format(GLenum format, GLenum type)
  178. {
  179.    switch (format) {
  180.    case OSMESA_RGBA:
  181.       if (type == GL_UNSIGNED_BYTE) {
  182.          if (little_endian())
  183.             return PIPE_FORMAT_R8G8B8A8_UNORM;
  184.          else
  185.             return PIPE_FORMAT_A8B8G8R8_UNORM;
  186.       }
  187.       else if (type == GL_UNSIGNED_SHORT) {
  188.          return PIPE_FORMAT_R16G16B16A16_UNORM;
  189.       }
  190.       else if (type == GL_FLOAT) {
  191.          return PIPE_FORMAT_R32G32B32A32_FLOAT;
  192.       }
  193.       else {
  194.          return PIPE_FORMAT_NONE;
  195.       }
  196.       break;
  197.    case OSMESA_BGRA:
  198.       if (type == GL_UNSIGNED_BYTE) {
  199.          if (little_endian())
  200.             return PIPE_FORMAT_B8G8R8A8_UNORM;
  201.          else
  202.             return PIPE_FORMAT_A8R8G8B8_UNORM;
  203.       }
  204.       else if (type == GL_UNSIGNED_SHORT) {
  205.          return PIPE_FORMAT_R16G16B16A16_UNORM;
  206.       }
  207.       else if (type == GL_FLOAT) {
  208.          return PIPE_FORMAT_R32G32B32A32_FLOAT;
  209.       }
  210.       else {
  211.          return PIPE_FORMAT_NONE;
  212.       }
  213.       break;
  214.    case OSMESA_ARGB:
  215.       if (type == GL_UNSIGNED_BYTE) {
  216.          if (little_endian())
  217.             return PIPE_FORMAT_A8R8G8B8_UNORM;
  218.          else
  219.             return PIPE_FORMAT_B8G8R8A8_UNORM;
  220.       }
  221.       else if (type == GL_UNSIGNED_SHORT) {
  222.          return PIPE_FORMAT_R16G16B16A16_UNORM;
  223.       }
  224.       else if (type == GL_FLOAT) {
  225.          return PIPE_FORMAT_R32G32B32A32_FLOAT;
  226.       }
  227.       else {
  228.          return PIPE_FORMAT_NONE;
  229.       }
  230.       break;
  231.    case OSMESA_RGB:
  232.       if (type == GL_UNSIGNED_BYTE) {
  233.          return PIPE_FORMAT_R8G8B8_UNORM;
  234.       }
  235.       else if (type == GL_UNSIGNED_SHORT) {
  236.          return PIPE_FORMAT_R16G16B16_UNORM;
  237.       }
  238.       else if (type == GL_FLOAT) {
  239.          return PIPE_FORMAT_R32G32B32_FLOAT;
  240.       }
  241.       else {
  242.          return PIPE_FORMAT_NONE;
  243.       }
  244.       break;
  245.    case OSMESA_BGR:
  246.       /* No gallium format for this one */
  247.       return PIPE_FORMAT_NONE;
  248.    case OSMESA_RGB_565:
  249.       return PIPE_FORMAT_B5G6R5_UNORM;
  250.    default:
  251.       ; /* fall-through */
  252.    }
  253.    return PIPE_FORMAT_NONE;
  254. }
  255.  
  256.  
  257. /**
  258.  * Initialize an st_visual object.
  259.  */
  260. static void
  261. osmesa_init_st_visual(struct st_visual *vis,
  262.                       enum pipe_format color_format,
  263.                       enum pipe_format ds_format,
  264.                       enum pipe_format accum_format)
  265. {
  266.    vis->buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK;
  267.    vis->color_format = color_format;
  268.    vis->depth_stencil_format = ds_format;
  269.    vis->accum_format = accum_format;
  270.    vis->samples = 1;
  271.    vis->render_buffer = ST_ATTACHMENT_FRONT_LEFT;
  272. }
  273.  
  274.  
  275. /**
  276.  * Return the osmesa_buffer that corresponds to an st_framebuffer_iface.
  277.  */
  278. static INLINE struct osmesa_buffer *
  279. stfbi_to_osbuffer(struct st_framebuffer_iface *stfbi)
  280. {
  281.    return (struct osmesa_buffer *) stfbi->st_manager_private;
  282. }
  283.  
  284.  
  285. /**
  286.  * Called via glFlush/glFinish.  This is where we copy the contents
  287.  * of the driver's color buffer into the user-specified buffer.
  288.  */
  289. static boolean
  290. osmesa_st_framebuffer_flush_front(struct st_context_iface *stctx,
  291.                                   struct st_framebuffer_iface *stfbi,
  292.                                   enum st_attachment_type statt)
  293. {
  294.    OSMesaContext osmesa = OSMesaGetCurrentContext();
  295.    struct osmesa_buffer *osbuffer = stfbi_to_osbuffer(stfbi);
  296.    struct pipe_context *pipe = stctx->pipe;
  297.    struct pipe_resource *res = osbuffer->textures[statt];
  298.    struct pipe_transfer *transfer = NULL;
  299.    struct pipe_box box;
  300.    void *map;
  301.    ubyte *src, *dst;
  302.    unsigned y, bytes, bpp;
  303.    int dst_stride;
  304.  
  305.    u_box_2d(0, 0, res->width0, res->height0, &box);
  306.  
  307.    map = pipe->transfer_map(pipe, res, 0, PIPE_TRANSFER_READ, &box,
  308.                             &transfer);
  309.  
  310.    /*
  311.     * Copy the color buffer from the resource to the user's buffer.
  312.     */
  313.    bpp = util_format_get_blocksize(osbuffer->visual.color_format);
  314.    src = map;
  315.    dst = osbuffer->map;
  316.    if (osmesa->user_row_length)
  317.       dst_stride = bpp * osmesa->user_row_length;
  318.    else
  319.       dst_stride = bpp * osbuffer->width;
  320.    bytes = bpp * res->width0;
  321.  
  322.    if (osmesa->y_up) {
  323.       /* need to flip image upside down */
  324.       dst = dst + (res->height0 - 1) * dst_stride;
  325.       dst_stride = -dst_stride;
  326.    }
  327.  
  328.    for (y = 0; y < res->height0; y++) {
  329.       memcpy(dst, src, bytes);
  330.       dst += dst_stride;
  331.       src += transfer->stride;
  332.    }
  333.  
  334.    pipe->transfer_unmap(pipe, transfer);
  335.  
  336.    return TRUE;
  337. }
  338.  
  339.  
  340. /**
  341.  * Called by the st manager to validate the framebuffer (allocate
  342.  * its resources).
  343.  */
  344. static boolean
  345. osmesa_st_framebuffer_validate(struct st_context_iface *stctx,
  346.                                struct st_framebuffer_iface *stfbi,
  347.                                const enum st_attachment_type *statts,
  348.                                unsigned count,
  349.                                struct pipe_resource **out)
  350. {
  351.    struct pipe_screen *screen = get_st_manager()->screen;
  352.    enum st_attachment_type i;
  353.    struct osmesa_buffer *osbuffer = stfbi_to_osbuffer(stfbi);
  354.    struct pipe_resource templat;
  355.  
  356.    memset(&templat, 0, sizeof(templat));
  357.    templat.target = PIPE_TEXTURE_RECT;
  358.    templat.format = 0; /* setup below */
  359.    templat.last_level = 0;
  360.    templat.width0 = osbuffer->width;
  361.    templat.height0 = osbuffer->height;
  362.    templat.depth0 = 1;
  363.    templat.array_size = 1;
  364.    templat.usage = PIPE_USAGE_DEFAULT;
  365.    templat.bind = 0; /* setup below */
  366.    templat.flags = 0;
  367.  
  368.    for (i = 0; i < count; i++) {
  369.       enum pipe_format format = PIPE_FORMAT_NONE;
  370.       unsigned bind = 0;
  371.  
  372.       /*
  373.        * At this time, we really only need to handle the front-left color
  374.        * attachment, since that's all we specified for the visual in
  375.        * osmesa_init_st_visual().
  376.        */
  377.       if (statts[i] == ST_ATTACHMENT_FRONT_LEFT) {
  378.          format = osbuffer->visual.color_format;
  379.          bind = PIPE_BIND_RENDER_TARGET;
  380.       }
  381.       else if (statts[i] == ST_ATTACHMENT_DEPTH_STENCIL) {
  382.          format = osbuffer->visual.depth_stencil_format;
  383.          bind = PIPE_BIND_DEPTH_STENCIL;
  384.       }
  385.       else if (statts[i] == ST_ATTACHMENT_ACCUM) {
  386.          format = osbuffer->visual.accum_format;
  387.          bind = PIPE_BIND_RENDER_TARGET;
  388.       }
  389.       else {
  390.          debug_warning("Unexpected attachment type in "
  391.                        "osmesa_st_framebuffer_validate()");
  392.       }
  393.  
  394.       templat.format = format;
  395.       templat.bind = bind;
  396.       out[i] = osbuffer->textures[i] =
  397.          screen->resource_create(screen, &templat);
  398.    }
  399.  
  400.    return TRUE;
  401. }
  402.  
  403.  
  404. static struct st_framebuffer_iface *
  405. osmesa_create_st_framebuffer(void)
  406. {
  407.    struct st_framebuffer_iface *stfbi = CALLOC_STRUCT(st_framebuffer_iface);
  408.    if (stfbi) {
  409.       stfbi->flush_front = osmesa_st_framebuffer_flush_front;
  410.       stfbi->validate = osmesa_st_framebuffer_validate;
  411.       p_atomic_set(&stfbi->stamp, 1);
  412.    }
  413.    return stfbi;
  414. }
  415.  
  416.  
  417. /**
  418.  * Create new buffer and add to linked list.
  419.  */
  420. static struct osmesa_buffer *
  421. osmesa_create_buffer(enum pipe_format color_format,
  422.                      enum pipe_format ds_format,
  423.                      enum pipe_format accum_format)
  424. {
  425.    struct osmesa_buffer *osbuffer = CALLOC_STRUCT(osmesa_buffer);
  426.    if (osbuffer) {
  427.       osbuffer->stfb = osmesa_create_st_framebuffer();
  428.  
  429.       osbuffer->stfb->st_manager_private = osbuffer;
  430.       osbuffer->stfb->visual = &osbuffer->visual;
  431.  
  432.       osmesa_init_st_visual(&osbuffer->visual, color_format,
  433.                             ds_format, accum_format);
  434.  
  435.       /* insert into linked list */
  436.       osbuffer->next = BufferList;
  437.       BufferList = osbuffer;
  438.    }
  439.  
  440.    return osbuffer;
  441. }
  442.  
  443.  
  444. /**
  445.  * Search linked list for a buffer with matching pixel formats.
  446.  */
  447. static struct osmesa_buffer *
  448. osmesa_find_buffer(enum pipe_format color_format,
  449.                    enum pipe_format ds_format,
  450.                    enum pipe_format accum_format)
  451. {
  452.    struct osmesa_buffer *b;
  453.  
  454.    /* Check if we already have a suitable buffer for the given formats */
  455.    for (b = BufferList; b; b = b->next) {
  456.       if (b->visual.color_format == color_format &&
  457.           b->visual.depth_stencil_format == ds_format &&
  458.           b->visual.accum_format == accum_format) {
  459.          return b;
  460.       }
  461.    }
  462.    return NULL;
  463. }
  464.  
  465.  
  466. static void
  467. osmesa_destroy_buffer(struct osmesa_buffer *osbuffer)
  468. {
  469.    FREE(osbuffer->stfb);
  470.    FREE(osbuffer);
  471. }
  472.  
  473.  
  474.  
  475. /**********************************************************************/
  476. /*****                    Public Functions                        *****/
  477. /**********************************************************************/
  478.  
  479.  
  480. /**
  481.  * Create an Off-Screen Mesa rendering context.  The only attribute needed is
  482.  * an RGBA vs Color-Index mode flag.
  483.  *
  484.  * Input:  format - Must be GL_RGBA
  485.  *         sharelist - specifies another OSMesaContext with which to share
  486.  *                     display lists.  NULL indicates no sharing.
  487.  * Return:  an OSMesaContext or 0 if error
  488.  */
  489. GLAPI OSMesaContext GLAPIENTRY
  490. OSMesaCreateContext(GLenum format, OSMesaContext sharelist)
  491. {
  492.    return OSMesaCreateContextExt(format, 24, 8, 0, sharelist);
  493. }
  494.  
  495.  
  496. /**
  497.  * New in Mesa 3.5
  498.  *
  499.  * Create context and specify size of ancillary buffers.
  500.  */
  501. GLAPI OSMesaContext GLAPIENTRY
  502. OSMesaCreateContextExt(GLenum format, GLint depthBits, GLint stencilBits,
  503.                        GLint accumBits, OSMesaContext sharelist)
  504. {
  505.    OSMesaContext osmesa;
  506.    struct st_context_iface *st_shared;
  507.    enum st_context_error st_error = 0;
  508.    struct st_context_attribs attribs;
  509.    struct st_api *stapi = get_st_api();
  510.  
  511.    if (sharelist) {
  512.       st_shared = sharelist->stctx;
  513.    }
  514.    else {
  515.       st_shared = NULL;
  516.    }
  517.  
  518.    osmesa = (OSMesaContext) CALLOC_STRUCT(osmesa_context);
  519.    if (!osmesa)
  520.       return NULL;
  521.  
  522.    /* Choose depth/stencil/accum buffer formats */
  523.    if (accumBits > 0) {
  524.       osmesa->accum_format = PIPE_FORMAT_R16G16B16A16_SNORM;
  525.    }
  526.    if (depthBits > 0 && stencilBits > 0) {
  527.       osmesa->depth_stencil_format = PIPE_FORMAT_Z24_UNORM_S8_UINT;
  528.    }
  529.    else if (stencilBits > 0) {
  530.       osmesa->depth_stencil_format = PIPE_FORMAT_S8_UINT;
  531.    }
  532.    else if (depthBits >= 24) {
  533.       osmesa->depth_stencil_format = PIPE_FORMAT_Z24X8_UNORM;
  534.    }
  535.    else if (depthBits >= 16) {
  536.       osmesa->depth_stencil_format = PIPE_FORMAT_Z16_UNORM;
  537.    }
  538.  
  539.    /*
  540.     * Create the rendering context
  541.     */
  542.    attribs.profile = ST_PROFILE_DEFAULT;
  543.    attribs.major = 2;
  544.    attribs.minor = 1;
  545.    attribs.flags = 0;  /* ST_CONTEXT_FLAG_x */
  546.    attribs.options.force_glsl_extensions_warn = FALSE;
  547.    attribs.options.disable_blend_func_extended = FALSE;
  548.    attribs.options.disable_glsl_line_continuations = FALSE;
  549.    attribs.options.disable_shader_bit_encoding = FALSE;
  550.    attribs.options.force_s3tc_enable = FALSE;
  551.    attribs.options.force_glsl_version = 0;
  552.  
  553.    osmesa_init_st_visual(&attribs.visual,
  554.                          PIPE_FORMAT_R8G8B8A8_UNORM,
  555.                          osmesa->depth_stencil_format,
  556.                          osmesa->accum_format);
  557.  
  558.    osmesa->stctx = stapi->create_context(stapi, get_st_manager(),
  559.                                          &attribs, &st_error, st_shared);
  560.    if (!osmesa->stctx) {
  561.       FREE(osmesa);
  562.       return NULL;
  563.    }
  564.  
  565.    osmesa->stctx->st_manager_private = osmesa;
  566.  
  567.    osmesa->format = format;
  568.    osmesa->user_row_length = 0;
  569.    osmesa->y_up = GL_TRUE;
  570.  
  571.    return osmesa;
  572. }
  573.  
  574.  
  575. /**
  576.  * Destroy an Off-Screen Mesa rendering context.
  577.  *
  578.  * \param osmesa  the context to destroy
  579.  */
  580. GLAPI void GLAPIENTRY
  581. OSMesaDestroyContext(OSMesaContext osmesa)
  582. {
  583.    if (osmesa) {
  584.       osmesa->stctx->destroy(osmesa->stctx);
  585.       FREE(osmesa);
  586.    }
  587. }
  588.  
  589.  
  590. /**
  591.  * Bind an OSMesaContext to an image buffer.  The image buffer is just a
  592.  * block of memory which the client provides.  Its size must be at least
  593.  * as large as width*height*pixelSize.  Its address should be a multiple
  594.  * of 4 if using RGBA mode.
  595.  *
  596.  * By default, image data is stored in the order of glDrawPixels: row-major
  597.  * order with the lower-left image pixel stored in the first array position
  598.  * (ie. bottom-to-top).
  599.  *
  600.  * If the context's viewport hasn't been initialized yet, it will now be
  601.  * initialized to (0,0,width,height).
  602.  *
  603.  * Input:  osmesa - the rendering context
  604.  *         buffer - the image buffer memory
  605.  *         type - data type for pixel components
  606.  *                GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT
  607.  *                or GL_FLOAT.
  608.  *         width, height - size of image buffer in pixels, at least 1
  609.  * Return:  GL_TRUE if success, GL_FALSE if error because of invalid osmesa,
  610.  *          invalid type, invalid size, etc.
  611.  */
  612. GLAPI GLboolean GLAPIENTRY
  613. OSMesaMakeCurrent(OSMesaContext osmesa, void *buffer, GLenum type,
  614.                   GLsizei width, GLsizei height)
  615. {
  616.    struct st_api *stapi = get_st_api();
  617.    struct osmesa_buffer *osbuffer;
  618.    enum pipe_format color_format;
  619.  
  620.    if (!osmesa || !buffer || width < 1 || height < 1) {
  621.       return GL_FALSE;
  622.    }
  623.  
  624.    if (osmesa->format == OSMESA_RGB_565 && type != GL_UNSIGNED_SHORT_5_6_5) {
  625.       return GL_FALSE;
  626.    }
  627.  
  628.    color_format = osmesa_choose_format(osmesa->format, type);
  629.    if (color_format == PIPE_FORMAT_NONE) {
  630.       fprintf(stderr, "OSMesaMakeCurrent(unsupported format/type)\n");
  631.       return GL_FALSE;
  632.    }
  633.  
  634.    /* See if we already have a buffer that uses these pixel formats */
  635.    osbuffer = osmesa_find_buffer(color_format,
  636.                                  osmesa->depth_stencil_format,
  637.                                  osmesa->accum_format);
  638.    if (!osbuffer) {
  639.       /* Existing buffer found, create new buffer */
  640.       osbuffer = osmesa_create_buffer(color_format,
  641.                                       osmesa->depth_stencil_format,
  642.                                       osmesa->accum_format);
  643.    }
  644.  
  645.    osbuffer->width = width;
  646.    osbuffer->height = height;
  647.    osbuffer->map = buffer;
  648.  
  649.    /* XXX unused for now */
  650.    (void) osmesa_destroy_buffer;
  651.  
  652.    osmesa->current_buffer = osbuffer;
  653.    osmesa->type = type;
  654.  
  655.    stapi->make_current(stapi, osmesa->stctx, osbuffer->stfb, osbuffer->stfb);
  656.  
  657.    return GL_TRUE;
  658. }
  659.  
  660.  
  661.  
  662. GLAPI OSMesaContext GLAPIENTRY
  663. OSMesaGetCurrentContext(void)
  664. {
  665.    struct st_api *stapi = get_st_api();
  666.    struct st_context_iface *st = stapi->get_current(stapi);
  667.    return st ? (OSMesaContext) st->st_manager_private : NULL;
  668. }
  669.  
  670.  
  671.  
  672. GLAPI void GLAPIENTRY
  673. OSMesaPixelStore(GLint pname, GLint value)
  674. {
  675.    OSMesaContext osmesa = OSMesaGetCurrentContext();
  676.  
  677.    switch (pname) {
  678.    case OSMESA_ROW_LENGTH:
  679.       osmesa->user_row_length = value;
  680.       break;
  681.    case OSMESA_Y_UP:
  682.       osmesa->y_up = value ? GL_TRUE : GL_FALSE;
  683.       break;
  684.    default:
  685.       fprintf(stderr, "Invalid pname in OSMesaPixelStore()\n");
  686.       return;
  687.    }
  688. }
  689.  
  690.  
  691. GLAPI void GLAPIENTRY
  692. OSMesaGetIntegerv(GLint pname, GLint *value)
  693. {
  694.    OSMesaContext osmesa = OSMesaGetCurrentContext();
  695.    struct osmesa_buffer *osbuffer = osmesa ? osmesa->current_buffer : NULL;
  696.  
  697.    switch (pname) {
  698.    case OSMESA_WIDTH:
  699.       *value = osbuffer ? osbuffer->width : 0;
  700.       return;
  701.    case OSMESA_HEIGHT:
  702.       *value = osbuffer ? osbuffer->height : 0;
  703.       return;
  704.    case OSMESA_FORMAT:
  705.       *value = osmesa->format;
  706.       return;
  707.    case OSMESA_TYPE:
  708.       /* current color buffer's data type */
  709.       *value = osmesa->type;
  710.       return;
  711.    case OSMESA_ROW_LENGTH:
  712.       *value = osmesa->user_row_length;
  713.       return;
  714.    case OSMESA_Y_UP:
  715.       *value = osmesa->y_up;
  716.       return;
  717.    case OSMESA_MAX_WIDTH:
  718.       /* fall-through */
  719.    case OSMESA_MAX_HEIGHT:
  720.       {
  721.          struct pipe_screen *screen = get_st_manager()->screen;
  722.          int maxLevels = screen->get_param(screen,
  723.                                            PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
  724.          *value = 1 << (maxLevels - 1);
  725.          *value = 8 * 1024;
  726.       }
  727.       return;
  728.    default:
  729.       fprintf(stderr, "Invalid pname in OSMesaGetIntegerv()\n");
  730.       return;
  731.    }
  732. }
  733.  
  734.  
  735. /**
  736.  * Return information about the depth buffer associated with an OSMesa context.
  737.  * Input:  c - the OSMesa context
  738.  * Output:  width, height - size of buffer in pixels
  739.  *          bytesPerValue - bytes per depth value (2 or 4)
  740.  *          buffer - pointer to depth buffer values
  741.  * Return:  GL_TRUE or GL_FALSE to indicate success or failure.
  742.  */
  743. GLAPI GLboolean GLAPIENTRY
  744. OSMesaGetDepthBuffer(OSMesaContext c, GLint *width, GLint *height,
  745.                      GLint *bytesPerValue, void **buffer)
  746. {
  747.    struct osmesa_buffer *osbuffer = c->current_buffer;
  748.    struct pipe_context *pipe = c->stctx->pipe;
  749.    struct pipe_resource *res = osbuffer->textures[ST_ATTACHMENT_DEPTH_STENCIL];
  750.    struct pipe_transfer *transfer = NULL;
  751.    struct pipe_box box;
  752.  
  753.    /*
  754.     * Note: we can't really implement this function with gallium as
  755.     * we did for swrast.  We can't just map the resource and leave it
  756.     * mapped (and there's no OSMesaUnmapDepthBuffer() function) so
  757.     * we unmap the buffer here and return a 'stale' pointer.  This should
  758.     * actually be OK in most cases where the caller of this function
  759.     * immediately uses the pointer.
  760.     */
  761.  
  762.    u_box_2d(0, 0, res->width0, res->height0, &box);
  763.  
  764.    *buffer = pipe->transfer_map(pipe, res, 0, PIPE_TRANSFER_READ, &box,
  765.                                 &transfer);
  766.    if (!*buffer) {
  767.       return GL_FALSE;
  768.    }
  769.  
  770.    *width = res->width0;
  771.    *height = res->height0;
  772.    *bytesPerValue = util_format_get_blocksize(res->format);
  773.  
  774.    pipe->transfer_unmap(pipe, transfer);
  775.  
  776.    return GL_TRUE;
  777. }
  778.  
  779.  
  780. /**
  781.  * Return the color buffer associated with an OSMesa context.
  782.  * Input:  c - the OSMesa context
  783.  * Output:  width, height - size of buffer in pixels
  784.  *          format - the pixel format (OSMESA_FORMAT)
  785.  *          buffer - pointer to color buffer values
  786.  * Return:  GL_TRUE or GL_FALSE to indicate success or failure.
  787.  */
  788. GLAPI GLboolean GLAPIENTRY
  789. OSMesaGetColorBuffer(OSMesaContext osmesa, GLint *width,
  790.                       GLint *height, GLint *format, void **buffer)
  791. {
  792.    struct osmesa_buffer *osbuffer = osmesa->current_buffer;
  793.  
  794.    if (osbuffer) {
  795.       *width = osbuffer->width;
  796.       *height = osbuffer->height;
  797.       *format = osmesa->format;
  798.       *buffer = osbuffer->map;
  799.       return GL_TRUE;
  800.    }
  801.    else {
  802.       *width = 0;
  803.       *height = 0;
  804.       *format = 0;
  805.       *buffer = 0;
  806.       return GL_FALSE;
  807.    }
  808. }
  809.  
  810.  
  811. struct name_function
  812. {
  813.    const char *Name;
  814.    OSMESAproc Function;
  815. };
  816.  
  817. static struct name_function functions[] = {
  818.    { "OSMesaCreateContext", (OSMESAproc) OSMesaCreateContext },
  819.    { "OSMesaCreateContextExt", (OSMESAproc) OSMesaCreateContextExt },
  820.    { "OSMesaDestroyContext", (OSMESAproc) OSMesaDestroyContext },
  821.    { "OSMesaMakeCurrent", (OSMESAproc) OSMesaMakeCurrent },
  822.    { "OSMesaGetCurrentContext", (OSMESAproc) OSMesaGetCurrentContext },
  823.    { "OSMesaPixelsStore", (OSMESAproc) OSMesaPixelStore },
  824.    { "OSMesaGetIntegerv", (OSMESAproc) OSMesaGetIntegerv },
  825.    { "OSMesaGetDepthBuffer", (OSMESAproc) OSMesaGetDepthBuffer },
  826.    { "OSMesaGetColorBuffer", (OSMESAproc) OSMesaGetColorBuffer },
  827.    { "OSMesaGetProcAddress", (OSMESAproc) OSMesaGetProcAddress },
  828.    { "OSMesaColorClamp", (OSMESAproc) OSMesaColorClamp },
  829.    { NULL, NULL }
  830. };
  831.  
  832.  
  833. GLAPI OSMESAproc GLAPIENTRY
  834. OSMesaGetProcAddress(const char *funcName)
  835. {
  836.    int i;
  837.    for (i = 0; functions[i].Name; i++) {
  838.       if (strcmp(functions[i].Name, funcName) == 0)
  839.          return functions[i].Function;
  840.    }
  841.    return _glapi_get_proc_address(funcName);
  842. }
  843.  
  844.  
  845. GLAPI void GLAPIENTRY
  846. OSMesaColorClamp(GLboolean enable)
  847. {
  848.    extern void GLAPIENTRY _mesa_ClampColor(GLenum target, GLenum clamp);
  849.  
  850.    _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB,
  851.                     enable ? GL_TRUE : GL_FIXED_ONLY_ARB);
  852. }
  853.