17ec681f3Smrg/*
27ec681f3Smrg * Copyright (c) 2013  Brian Paul   All Rights Reserved.
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice shall be included
127ec681f3Smrg * in all copies or substantial portions of the Software.
137ec681f3Smrg *
147ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
157ec681f3Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
167ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
177ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
187ec681f3Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
197ec681f3Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
207ec681f3Smrg * OTHER DEALINGS IN THE SOFTWARE.
217ec681f3Smrg */
227ec681f3Smrg
237ec681f3Smrg
247ec681f3Smrg/*
257ec681f3Smrg * Off-Screen rendering into client memory.
267ec681f3Smrg * OpenGL gallium frontend for softpipe and llvmpipe.
277ec681f3Smrg *
287ec681f3Smrg * Notes:
297ec681f3Smrg *
307ec681f3Smrg * If Gallium is built with LLVM support we use the llvmpipe driver.
317ec681f3Smrg * Otherwise we use softpipe.  The GALLIUM_DRIVER environment variable
327ec681f3Smrg * may be set to "softpipe" or "llvmpipe" to override.
337ec681f3Smrg *
347ec681f3Smrg * With softpipe we could render directly into the user's buffer by using a
357ec681f3Smrg * display target resource.  However, softpipe doesn't support "upside-down"
367ec681f3Smrg * rendering which would be needed for the OSMESA_Y_UP=TRUE case.
377ec681f3Smrg *
387ec681f3Smrg * With llvmpipe we could only render directly into the user's buffer when its
397ec681f3Smrg * width and height is a multiple of the tile size (64 pixels).
407ec681f3Smrg *
417ec681f3Smrg * Because of these constraints we always render into ordinary resources then
427ec681f3Smrg * copy the results to the user's buffer in the flush_front() function which
437ec681f3Smrg * is called when the app calls glFlush/Finish.
447ec681f3Smrg *
457ec681f3Smrg * In general, the OSMesa interface is pretty ugly and not a good match
467ec681f3Smrg * for Gallium.  But we're interested in doing the best we can to preserve
477ec681f3Smrg * application portability.  With a little work we could come up with a
487ec681f3Smrg * much nicer, new off-screen Gallium interface...
497ec681f3Smrg */
507ec681f3Smrg
517ec681f3Smrg
527ec681f3Smrg#include <stdio.h>
537ec681f3Smrg#include <c11/threads.h>
547ec681f3Smrg#include "GL/osmesa.h"
557ec681f3Smrg
567ec681f3Smrg#include "glapi/glapi.h"  /* for OSMesaGetProcAddress below */
577ec681f3Smrg
587ec681f3Smrg#include "pipe/p_context.h"
597ec681f3Smrg#include "pipe/p_screen.h"
607ec681f3Smrg#include "pipe/p_state.h"
617ec681f3Smrg
627ec681f3Smrg#include "util/u_atomic.h"
637ec681f3Smrg#include "util/u_box.h"
647ec681f3Smrg#include "util/u_debug.h"
657ec681f3Smrg#include "util/format/u_format.h"
667ec681f3Smrg#include "util/u_inlines.h"
677ec681f3Smrg#include "util/u_memory.h"
687ec681f3Smrg
697ec681f3Smrg#include "postprocess/filters.h"
707ec681f3Smrg#include "postprocess/postprocess.h"
717ec681f3Smrg
727ec681f3Smrg#include "frontend/api.h"
737ec681f3Smrg#include "state_tracker/st_gl_api.h"
747ec681f3Smrg
757ec681f3Smrg
767ec681f3Smrg
777ec681f3Smrgextern struct pipe_screen *
787ec681f3Smrgosmesa_create_screen(void);
797ec681f3Smrg
807ec681f3Smrg
817ec681f3Smrg
827ec681f3Smrgstruct osmesa_buffer
837ec681f3Smrg{
847ec681f3Smrg   struct st_framebuffer_iface *stfb;
857ec681f3Smrg   struct st_visual visual;
867ec681f3Smrg   unsigned width, height;
877ec681f3Smrg
887ec681f3Smrg   struct pipe_resource *textures[ST_ATTACHMENT_COUNT];
897ec681f3Smrg
907ec681f3Smrg   void *map;
917ec681f3Smrg
927ec681f3Smrg   struct osmesa_buffer *next;  /**< next in linked list */
937ec681f3Smrg};
947ec681f3Smrg
957ec681f3Smrg
967ec681f3Smrgstruct osmesa_context
977ec681f3Smrg{
987ec681f3Smrg   struct st_context_iface *stctx;
997ec681f3Smrg
1007ec681f3Smrg   boolean ever_used;     /*< Has this context ever been current? */
1017ec681f3Smrg
1027ec681f3Smrg   struct osmesa_buffer *current_buffer;
1037ec681f3Smrg
1047ec681f3Smrg   /* Storage for depth/stencil, if the user has requested access.  The backing
1057ec681f3Smrg    * driver always has its own storage for the actual depth/stencil, which we
1067ec681f3Smrg    * have to transfer in and out.
1077ec681f3Smrg    */
1087ec681f3Smrg   void *zs;
1097ec681f3Smrg   unsigned zs_stride;
1107ec681f3Smrg
1117ec681f3Smrg   enum pipe_format depth_stencil_format, accum_format;
1127ec681f3Smrg
1137ec681f3Smrg   GLenum format;         /*< User-specified context format */
1147ec681f3Smrg   GLenum type;           /*< Buffer's data type */
1157ec681f3Smrg   GLint user_row_length; /*< user-specified number of pixels per row */
1167ec681f3Smrg   GLboolean y_up;        /*< TRUE  -> Y increases upward */
1177ec681f3Smrg                          /*< FALSE -> Y increases downward */
1187ec681f3Smrg
1197ec681f3Smrg   /** Which postprocessing filters are enabled. */
1207ec681f3Smrg   unsigned pp_enabled[PP_FILTERS];
1217ec681f3Smrg   struct pp_queue_t *pp;
1227ec681f3Smrg};
1237ec681f3Smrg
1247ec681f3Smrg/**
1257ec681f3Smrg * Called from the ST manager.
1267ec681f3Smrg */
1277ec681f3Smrgstatic int
1287ec681f3Smrgosmesa_st_get_param(struct st_manager *smapi, enum st_manager_param param)
1297ec681f3Smrg{
1307ec681f3Smrg   /* no-op */
1317ec681f3Smrg   return 0;
1327ec681f3Smrg}
1337ec681f3Smrg
1347ec681f3Smrgstatic struct st_manager *stmgr = NULL;
1357ec681f3Smrgstatic struct st_api *stapi = NULL;
1367ec681f3Smrg
1377ec681f3Smrgstatic void
1387ec681f3Smrgdestroy_st_manager(void)
1397ec681f3Smrg{
1407ec681f3Smrg   if (stmgr) {
1417ec681f3Smrg      if (stmgr->screen)
1427ec681f3Smrg         stmgr->screen->destroy(stmgr->screen);
1437ec681f3Smrg      FREE(stmgr);
1447ec681f3Smrg   }
1457ec681f3Smrg
1467ec681f3Smrg   if (stapi && stapi->destroy) {
1477ec681f3Smrg      stapi->destroy(stapi);
1487ec681f3Smrg   }
1497ec681f3Smrg}
1507ec681f3Smrg
1517ec681f3Smrgstatic void
1527ec681f3Smrgcreate_st_manager(void)
1537ec681f3Smrg{
1547ec681f3Smrg   if (atexit(destroy_st_manager) != 0)
1557ec681f3Smrg      return;
1567ec681f3Smrg
1577ec681f3Smrg   stmgr = CALLOC_STRUCT(st_manager);
1587ec681f3Smrg   if (stmgr) {
1597ec681f3Smrg      stmgr->screen = osmesa_create_screen();
1607ec681f3Smrg      stmgr->get_param = osmesa_st_get_param;
1617ec681f3Smrg      stmgr->get_egl_image = NULL;
1627ec681f3Smrg   }
1637ec681f3Smrg
1647ec681f3Smrg   stapi = st_gl_api_create();
1657ec681f3Smrg}
1667ec681f3Smrg
1677ec681f3Smrg/**
1687ec681f3Smrg * Create/return a singleton st_manager object.
1697ec681f3Smrg */
1707ec681f3Smrgstatic struct st_manager *
1717ec681f3Smrgget_st_manager(void)
1727ec681f3Smrg{
1737ec681f3Smrg   static once_flag create_once_flag = ONCE_FLAG_INIT;
1747ec681f3Smrg
1757ec681f3Smrg   call_once(&create_once_flag, create_st_manager);
1767ec681f3Smrg
1777ec681f3Smrg   return stmgr;
1787ec681f3Smrg}
1797ec681f3Smrg
1807ec681f3Smrg/**
1817ec681f3Smrg * Create/return singleton st_api object.
1827ec681f3Smrg */
1837ec681f3Smrgstatic struct st_api *
1847ec681f3Smrgget_st_api(void)
1857ec681f3Smrg{
1867ec681f3Smrg   get_st_manager();
1877ec681f3Smrg   return stapi;
1887ec681f3Smrg}
1897ec681f3Smrg
1907ec681f3Smrg/* Reads the color or depth buffer from the backing context to either the user storage
1917ec681f3Smrg * (color buffer) or our temporary (z/s)
1927ec681f3Smrg */
1937ec681f3Smrgstatic void
1947ec681f3Smrgosmesa_read_buffer(OSMesaContext osmesa, struct pipe_resource *res, void *dst,
1957ec681f3Smrg                   int dst_stride, bool y_up)
1967ec681f3Smrg{
1977ec681f3Smrg   struct pipe_context *pipe = osmesa->stctx->pipe;
1987ec681f3Smrg
1997ec681f3Smrg   struct pipe_box box;
2007ec681f3Smrg   u_box_2d(0, 0, res->width0, res->height0, &box);
2017ec681f3Smrg
2027ec681f3Smrg   struct pipe_transfer *transfer = NULL;
2037ec681f3Smrg   ubyte *src = pipe->texture_map(pipe, res, 0, PIPE_MAP_READ, &box,
2047ec681f3Smrg                                   &transfer);
2057ec681f3Smrg
2067ec681f3Smrg   /*
2077ec681f3Smrg    * Copy the color buffer from the resource to the user's buffer.
2087ec681f3Smrg    */
2097ec681f3Smrg
2107ec681f3Smrg   if (y_up) {
2117ec681f3Smrg      /* need to flip image upside down */
2127ec681f3Smrg      dst = (ubyte *)dst + (res->height0 - 1) * dst_stride;
2137ec681f3Smrg      dst_stride = -dst_stride;
2147ec681f3Smrg   }
2157ec681f3Smrg
2167ec681f3Smrg   unsigned bpp = util_format_get_blocksize(res->format);
2177ec681f3Smrg   for (unsigned y = 0; y < res->height0; y++)
2187ec681f3Smrg   {
2197ec681f3Smrg      memcpy(dst, src, bpp * res->width0);
2207ec681f3Smrg      dst = (ubyte *)dst + dst_stride;
2217ec681f3Smrg      src += transfer->stride;
2227ec681f3Smrg   }
2237ec681f3Smrg
2247ec681f3Smrg   pipe->texture_unmap(pipe, transfer);
2257ec681f3Smrg}
2267ec681f3Smrg
2277ec681f3Smrg
2287ec681f3Smrg/**
2297ec681f3Smrg * Given an OSMESA_x format and a GL_y type, return the best
2307ec681f3Smrg * matching PIPE_FORMAT_z.
2317ec681f3Smrg * Note that we can't exactly match all user format/type combinations
2327ec681f3Smrg * with gallium formats.  If we find this to be a problem, we can
2337ec681f3Smrg * implement more elaborate format/type conversion in the flush_front()
2347ec681f3Smrg * function.
2357ec681f3Smrg */
2367ec681f3Smrgstatic enum pipe_format
2377ec681f3Smrgosmesa_choose_format(GLenum format, GLenum type)
2387ec681f3Smrg{
2397ec681f3Smrg   switch (format) {
2407ec681f3Smrg   case OSMESA_RGBA:
2417ec681f3Smrg      if (type == GL_UNSIGNED_BYTE) {
2427ec681f3Smrg#if UTIL_ARCH_LITTLE_ENDIAN
2437ec681f3Smrg         return PIPE_FORMAT_R8G8B8A8_UNORM;
2447ec681f3Smrg#else
2457ec681f3Smrg         return PIPE_FORMAT_A8B8G8R8_UNORM;
2467ec681f3Smrg#endif
2477ec681f3Smrg      }
2487ec681f3Smrg      else if (type == GL_UNSIGNED_SHORT) {
2497ec681f3Smrg         return PIPE_FORMAT_R16G16B16A16_UNORM;
2507ec681f3Smrg      }
2517ec681f3Smrg      else if (type == GL_FLOAT) {
2527ec681f3Smrg         return PIPE_FORMAT_R32G32B32A32_FLOAT;
2537ec681f3Smrg      }
2547ec681f3Smrg      else {
2557ec681f3Smrg         return PIPE_FORMAT_NONE;
2567ec681f3Smrg      }
2577ec681f3Smrg      break;
2587ec681f3Smrg   case OSMESA_BGRA:
2597ec681f3Smrg      if (type == GL_UNSIGNED_BYTE) {
2607ec681f3Smrg#if UTIL_ARCH_LITTLE_ENDIAN
2617ec681f3Smrg         return PIPE_FORMAT_B8G8R8A8_UNORM;
2627ec681f3Smrg#else
2637ec681f3Smrg         return PIPE_FORMAT_A8R8G8B8_UNORM;
2647ec681f3Smrg#endif
2657ec681f3Smrg      }
2667ec681f3Smrg      else if (type == GL_UNSIGNED_SHORT) {
2677ec681f3Smrg         return PIPE_FORMAT_R16G16B16A16_UNORM;
2687ec681f3Smrg      }
2697ec681f3Smrg      else if (type == GL_FLOAT) {
2707ec681f3Smrg         return PIPE_FORMAT_R32G32B32A32_FLOAT;
2717ec681f3Smrg      }
2727ec681f3Smrg      else {
2737ec681f3Smrg         return PIPE_FORMAT_NONE;
2747ec681f3Smrg      }
2757ec681f3Smrg      break;
2767ec681f3Smrg   case OSMESA_ARGB:
2777ec681f3Smrg      if (type == GL_UNSIGNED_BYTE) {
2787ec681f3Smrg#if UTIL_ARCH_LITTLE_ENDIAN
2797ec681f3Smrg         return PIPE_FORMAT_A8R8G8B8_UNORM;
2807ec681f3Smrg#else
2817ec681f3Smrg         return PIPE_FORMAT_B8G8R8A8_UNORM;
2827ec681f3Smrg#endif
2837ec681f3Smrg      }
2847ec681f3Smrg      else if (type == GL_UNSIGNED_SHORT) {
2857ec681f3Smrg         return PIPE_FORMAT_R16G16B16A16_UNORM;
2867ec681f3Smrg      }
2877ec681f3Smrg      else if (type == GL_FLOAT) {
2887ec681f3Smrg         return PIPE_FORMAT_R32G32B32A32_FLOAT;
2897ec681f3Smrg      }
2907ec681f3Smrg      else {
2917ec681f3Smrg         return PIPE_FORMAT_NONE;
2927ec681f3Smrg      }
2937ec681f3Smrg      break;
2947ec681f3Smrg   case OSMESA_RGB:
2957ec681f3Smrg      if (type == GL_UNSIGNED_BYTE) {
2967ec681f3Smrg         return PIPE_FORMAT_R8G8B8_UNORM;
2977ec681f3Smrg      }
2987ec681f3Smrg      else if (type == GL_UNSIGNED_SHORT) {
2997ec681f3Smrg         return PIPE_FORMAT_R16G16B16_UNORM;
3007ec681f3Smrg      }
3017ec681f3Smrg      else if (type == GL_FLOAT) {
3027ec681f3Smrg         return PIPE_FORMAT_R32G32B32_FLOAT;
3037ec681f3Smrg      }
3047ec681f3Smrg      else {
3057ec681f3Smrg         return PIPE_FORMAT_NONE;
3067ec681f3Smrg      }
3077ec681f3Smrg      break;
3087ec681f3Smrg   case OSMESA_BGR:
3097ec681f3Smrg      /* No gallium format for this one */
3107ec681f3Smrg      return PIPE_FORMAT_NONE;
3117ec681f3Smrg   case OSMESA_RGB_565:
3127ec681f3Smrg      if (type != GL_UNSIGNED_SHORT_5_6_5)
3137ec681f3Smrg         return PIPE_FORMAT_NONE;
3147ec681f3Smrg      return PIPE_FORMAT_B5G6R5_UNORM;
3157ec681f3Smrg   default:
3167ec681f3Smrg      return PIPE_FORMAT_NONE;
3177ec681f3Smrg   }
3187ec681f3Smrg}
3197ec681f3Smrg
3207ec681f3Smrg
3217ec681f3Smrg/**
3227ec681f3Smrg * Initialize an st_visual object.
3237ec681f3Smrg */
3247ec681f3Smrgstatic void
3257ec681f3Smrgosmesa_init_st_visual(struct st_visual *vis,
3267ec681f3Smrg                      enum pipe_format color_format,
3277ec681f3Smrg                      enum pipe_format ds_format,
3287ec681f3Smrg                      enum pipe_format accum_format)
3297ec681f3Smrg{
3307ec681f3Smrg   vis->buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK;
3317ec681f3Smrg
3327ec681f3Smrg   if (ds_format != PIPE_FORMAT_NONE)
3337ec681f3Smrg      vis->buffer_mask |= ST_ATTACHMENT_DEPTH_STENCIL_MASK;
3347ec681f3Smrg   if (accum_format != PIPE_FORMAT_NONE)
3357ec681f3Smrg      vis->buffer_mask |= ST_ATTACHMENT_ACCUM;
3367ec681f3Smrg
3377ec681f3Smrg   vis->color_format = color_format;
3387ec681f3Smrg   vis->depth_stencil_format = ds_format;
3397ec681f3Smrg   vis->accum_format = accum_format;
3407ec681f3Smrg   vis->samples = 1;
3417ec681f3Smrg}
3427ec681f3Smrg
3437ec681f3Smrg
3447ec681f3Smrg/**
3457ec681f3Smrg * Return the osmesa_buffer that corresponds to an st_framebuffer_iface.
3467ec681f3Smrg */
3477ec681f3Smrgstatic inline struct osmesa_buffer *
3487ec681f3Smrgstfbi_to_osbuffer(struct st_framebuffer_iface *stfbi)
3497ec681f3Smrg{
3507ec681f3Smrg   return (struct osmesa_buffer *) stfbi->st_manager_private;
3517ec681f3Smrg}
3527ec681f3Smrg
3537ec681f3Smrg
3547ec681f3Smrg/**
3557ec681f3Smrg * Called via glFlush/glFinish.  This is where we copy the contents
3567ec681f3Smrg * of the driver's color buffer into the user-specified buffer.
3577ec681f3Smrg */
3587ec681f3Smrgstatic bool
3597ec681f3Smrgosmesa_st_framebuffer_flush_front(struct st_context_iface *stctx,
3607ec681f3Smrg                                  struct st_framebuffer_iface *stfbi,
3617ec681f3Smrg                                  enum st_attachment_type statt)
3627ec681f3Smrg{
3637ec681f3Smrg   OSMesaContext osmesa = OSMesaGetCurrentContext();
3647ec681f3Smrg   struct osmesa_buffer *osbuffer = stfbi_to_osbuffer(stfbi);
3657ec681f3Smrg   struct pipe_resource *res = osbuffer->textures[statt];
3667ec681f3Smrg   unsigned bpp;
3677ec681f3Smrg   int dst_stride;
3687ec681f3Smrg
3697ec681f3Smrg   if (statt != ST_ATTACHMENT_FRONT_LEFT)
3707ec681f3Smrg      return false;
3717ec681f3Smrg
3727ec681f3Smrg   if (osmesa->pp) {
3737ec681f3Smrg      struct pipe_resource *zsbuf = NULL;
3747ec681f3Smrg      unsigned i;
3757ec681f3Smrg
3767ec681f3Smrg      /* Find the z/stencil buffer if there is one */
3777ec681f3Smrg      for (i = 0; i < ARRAY_SIZE(osbuffer->textures); i++) {
3787ec681f3Smrg         struct pipe_resource *res = osbuffer->textures[i];
3797ec681f3Smrg         if (res) {
3807ec681f3Smrg            const struct util_format_description *desc =
3817ec681f3Smrg               util_format_description(res->format);
3827ec681f3Smrg
3837ec681f3Smrg            if (util_format_has_depth(desc)) {
3847ec681f3Smrg               zsbuf = res;
3857ec681f3Smrg               break;
3867ec681f3Smrg            }
3877ec681f3Smrg         }
3887ec681f3Smrg      }
3897ec681f3Smrg
3907ec681f3Smrg      /* run the postprocess stage(s) */
3917ec681f3Smrg      pp_run(osmesa->pp, res, res, zsbuf);
3927ec681f3Smrg   }
3937ec681f3Smrg
3947ec681f3Smrg   /* Snapshot the color buffer to the user's buffer. */
3957ec681f3Smrg   bpp = util_format_get_blocksize(osbuffer->visual.color_format);
3967ec681f3Smrg   if (osmesa->user_row_length)
3977ec681f3Smrg      dst_stride = bpp * osmesa->user_row_length;
3987ec681f3Smrg   else
3997ec681f3Smrg      dst_stride = bpp * osbuffer->width;
4007ec681f3Smrg
4017ec681f3Smrg   osmesa_read_buffer(osmesa, res, osbuffer->map, dst_stride, osmesa->y_up);
4027ec681f3Smrg
4037ec681f3Smrg   /* If the user has requested the Z/S buffer, then snapshot that one too. */
4047ec681f3Smrg   if (osmesa->zs) {
4057ec681f3Smrg      osmesa_read_buffer(osmesa, osbuffer->textures[ST_ATTACHMENT_DEPTH_STENCIL],
4067ec681f3Smrg                         osmesa->zs, osmesa->zs_stride, true);
4077ec681f3Smrg   }
4087ec681f3Smrg
4097ec681f3Smrg   return true;
4107ec681f3Smrg}
4117ec681f3Smrg
4127ec681f3Smrg
4137ec681f3Smrg/**
4147ec681f3Smrg * Called by the st manager to validate the framebuffer (allocate
4157ec681f3Smrg * its resources).
4167ec681f3Smrg */
4177ec681f3Smrgstatic bool
4187ec681f3Smrgosmesa_st_framebuffer_validate(struct st_context_iface *stctx,
4197ec681f3Smrg                               struct st_framebuffer_iface *stfbi,
4207ec681f3Smrg                               const enum st_attachment_type *statts,
4217ec681f3Smrg                               unsigned count,
4227ec681f3Smrg                               struct pipe_resource **out)
4237ec681f3Smrg{
4247ec681f3Smrg   struct pipe_screen *screen = get_st_manager()->screen;
4257ec681f3Smrg   enum st_attachment_type i;
4267ec681f3Smrg   struct osmesa_buffer *osbuffer = stfbi_to_osbuffer(stfbi);
4277ec681f3Smrg   struct pipe_resource templat;
4287ec681f3Smrg
4297ec681f3Smrg   memset(&templat, 0, sizeof(templat));
4307ec681f3Smrg   templat.target = PIPE_TEXTURE_RECT;
4317ec681f3Smrg   templat.format = 0; /* setup below */
4327ec681f3Smrg   templat.last_level = 0;
4337ec681f3Smrg   templat.width0 = osbuffer->width;
4347ec681f3Smrg   templat.height0 = osbuffer->height;
4357ec681f3Smrg   templat.depth0 = 1;
4367ec681f3Smrg   templat.array_size = 1;
4377ec681f3Smrg   templat.usage = PIPE_USAGE_DEFAULT;
4387ec681f3Smrg   templat.bind = 0; /* setup below */
4397ec681f3Smrg   templat.flags = 0;
4407ec681f3Smrg
4417ec681f3Smrg   for (i = 0; i < count; i++) {
4427ec681f3Smrg      enum pipe_format format = PIPE_FORMAT_NONE;
4437ec681f3Smrg      unsigned bind = 0;
4447ec681f3Smrg
4457ec681f3Smrg      /*
4467ec681f3Smrg       * At this time, we really only need to handle the front-left color
4477ec681f3Smrg       * attachment, since that's all we specified for the visual in
4487ec681f3Smrg       * osmesa_init_st_visual().
4497ec681f3Smrg       */
4507ec681f3Smrg      if (statts[i] == ST_ATTACHMENT_FRONT_LEFT) {
4517ec681f3Smrg         format = osbuffer->visual.color_format;
4527ec681f3Smrg         bind = PIPE_BIND_RENDER_TARGET;
4537ec681f3Smrg      }
4547ec681f3Smrg      else if (statts[i] == ST_ATTACHMENT_DEPTH_STENCIL) {
4557ec681f3Smrg         format = osbuffer->visual.depth_stencil_format;
4567ec681f3Smrg         bind = PIPE_BIND_DEPTH_STENCIL;
4577ec681f3Smrg      }
4587ec681f3Smrg      else if (statts[i] == ST_ATTACHMENT_ACCUM) {
4597ec681f3Smrg         format = osbuffer->visual.accum_format;
4607ec681f3Smrg         bind = PIPE_BIND_RENDER_TARGET;
4617ec681f3Smrg      }
4627ec681f3Smrg      else {
4637ec681f3Smrg         debug_warning("Unexpected attachment type in "
4647ec681f3Smrg                       "osmesa_st_framebuffer_validate()");
4657ec681f3Smrg      }
4667ec681f3Smrg
4677ec681f3Smrg      templat.format = format;
4687ec681f3Smrg      templat.bind = bind;
4697ec681f3Smrg      pipe_resource_reference(&out[i], NULL);
4707ec681f3Smrg      out[i] = osbuffer->textures[statts[i]] =
4717ec681f3Smrg         screen->resource_create(screen, &templat);
4727ec681f3Smrg   }
4737ec681f3Smrg
4747ec681f3Smrg   return true;
4757ec681f3Smrg}
4767ec681f3Smrg
4777ec681f3Smrgstatic uint32_t osmesa_fb_ID = 0;
4787ec681f3Smrg
4797ec681f3Smrgstatic struct st_framebuffer_iface *
4807ec681f3Smrgosmesa_create_st_framebuffer(void)
4817ec681f3Smrg{
4827ec681f3Smrg   struct st_framebuffer_iface *stfbi = CALLOC_STRUCT(st_framebuffer_iface);
4837ec681f3Smrg   if (stfbi) {
4847ec681f3Smrg      stfbi->flush_front = osmesa_st_framebuffer_flush_front;
4857ec681f3Smrg      stfbi->validate = osmesa_st_framebuffer_validate;
4867ec681f3Smrg      p_atomic_set(&stfbi->stamp, 1);
4877ec681f3Smrg      stfbi->ID = p_atomic_inc_return(&osmesa_fb_ID);
4887ec681f3Smrg      stfbi->state_manager = get_st_manager();
4897ec681f3Smrg   }
4907ec681f3Smrg   return stfbi;
4917ec681f3Smrg}
4927ec681f3Smrg
4937ec681f3Smrg
4947ec681f3Smrg/**
4957ec681f3Smrg * Create new buffer and add to linked list.
4967ec681f3Smrg */
4977ec681f3Smrgstatic struct osmesa_buffer *
4987ec681f3Smrgosmesa_create_buffer(enum pipe_format color_format,
4997ec681f3Smrg                     enum pipe_format ds_format,
5007ec681f3Smrg                     enum pipe_format accum_format)
5017ec681f3Smrg{
5027ec681f3Smrg   struct osmesa_buffer *osbuffer = CALLOC_STRUCT(osmesa_buffer);
5037ec681f3Smrg   if (osbuffer) {
5047ec681f3Smrg      osbuffer->stfb = osmesa_create_st_framebuffer();
5057ec681f3Smrg
5067ec681f3Smrg      osbuffer->stfb->st_manager_private = osbuffer;
5077ec681f3Smrg      osbuffer->stfb->visual = &osbuffer->visual;
5087ec681f3Smrg
5097ec681f3Smrg      osmesa_init_st_visual(&osbuffer->visual, color_format,
5107ec681f3Smrg                            ds_format, accum_format);
5117ec681f3Smrg   }
5127ec681f3Smrg
5137ec681f3Smrg   return osbuffer;
5147ec681f3Smrg}
5157ec681f3Smrg
5167ec681f3Smrg
5177ec681f3Smrgstatic void
5187ec681f3Smrgosmesa_destroy_buffer(struct osmesa_buffer *osbuffer)
5197ec681f3Smrg{
5207ec681f3Smrg   /*
5217ec681f3Smrg    * Notify the state manager that the associated framebuffer interface
5227ec681f3Smrg    * is no longer valid.
5237ec681f3Smrg    */
5247ec681f3Smrg   stapi->destroy_drawable(stapi, osbuffer->stfb);
5257ec681f3Smrg
5267ec681f3Smrg   FREE(osbuffer->stfb);
5277ec681f3Smrg   FREE(osbuffer);
5287ec681f3Smrg}
5297ec681f3Smrg
5307ec681f3Smrg
5317ec681f3Smrg
5327ec681f3Smrg/**********************************************************************/
5337ec681f3Smrg/*****                    Public Functions                        *****/
5347ec681f3Smrg/**********************************************************************/
5357ec681f3Smrg
5367ec681f3Smrg
5377ec681f3Smrg/**
5387ec681f3Smrg * Create an Off-Screen Mesa rendering context.  The only attribute needed is
5397ec681f3Smrg * an RGBA vs Color-Index mode flag.
5407ec681f3Smrg *
5417ec681f3Smrg * Input:  format - Must be GL_RGBA
5427ec681f3Smrg *         sharelist - specifies another OSMesaContext with which to share
5437ec681f3Smrg *                     display lists.  NULL indicates no sharing.
5447ec681f3Smrg * Return:  an OSMesaContext or 0 if error
5457ec681f3Smrg */
5467ec681f3SmrgGLAPI OSMesaContext GLAPIENTRY
5477ec681f3SmrgOSMesaCreateContext(GLenum format, OSMesaContext sharelist)
5487ec681f3Smrg{
5497ec681f3Smrg   return OSMesaCreateContextExt(format, 24, 8, 0, sharelist);
5507ec681f3Smrg}
5517ec681f3Smrg
5527ec681f3Smrg
5537ec681f3Smrg/**
5547ec681f3Smrg * New in Mesa 3.5
5557ec681f3Smrg *
5567ec681f3Smrg * Create context and specify size of ancillary buffers.
5577ec681f3Smrg */
5587ec681f3SmrgGLAPI OSMesaContext GLAPIENTRY
5597ec681f3SmrgOSMesaCreateContextExt(GLenum format, GLint depthBits, GLint stencilBits,
5607ec681f3Smrg                       GLint accumBits, OSMesaContext sharelist)
5617ec681f3Smrg{
5627ec681f3Smrg   int attribs[100], n = 0;
5637ec681f3Smrg
5647ec681f3Smrg   attribs[n++] = OSMESA_FORMAT;
5657ec681f3Smrg   attribs[n++] = format;
5667ec681f3Smrg   attribs[n++] = OSMESA_DEPTH_BITS;
5677ec681f3Smrg   attribs[n++] = depthBits;
5687ec681f3Smrg   attribs[n++] = OSMESA_STENCIL_BITS;
5697ec681f3Smrg   attribs[n++] = stencilBits;
5707ec681f3Smrg   attribs[n++] = OSMESA_ACCUM_BITS;
5717ec681f3Smrg   attribs[n++] = accumBits;
5727ec681f3Smrg   attribs[n++] = 0;
5737ec681f3Smrg
5747ec681f3Smrg   return OSMesaCreateContextAttribs(attribs, sharelist);
5757ec681f3Smrg}
5767ec681f3Smrg
5777ec681f3Smrg
5787ec681f3Smrg/**
5797ec681f3Smrg * New in Mesa 11.2
5807ec681f3Smrg *
5817ec681f3Smrg * Create context with attribute list.
5827ec681f3Smrg */
5837ec681f3SmrgGLAPI OSMesaContext GLAPIENTRY
5847ec681f3SmrgOSMesaCreateContextAttribs(const int *attribList, OSMesaContext sharelist)
5857ec681f3Smrg{
5867ec681f3Smrg   OSMesaContext osmesa;
5877ec681f3Smrg   struct st_context_iface *st_shared;
5887ec681f3Smrg   enum st_context_error st_error = 0;
5897ec681f3Smrg   struct st_context_attribs attribs;
5907ec681f3Smrg   struct st_api *stapi = get_st_api();
5917ec681f3Smrg   GLenum format = GL_RGBA;
5927ec681f3Smrg   int depthBits = 0, stencilBits = 0, accumBits = 0;
5937ec681f3Smrg   int profile = OSMESA_COMPAT_PROFILE, version_major = 1, version_minor = 0;
5947ec681f3Smrg   int i;
5957ec681f3Smrg
5967ec681f3Smrg   if (sharelist) {
5977ec681f3Smrg      st_shared = sharelist->stctx;
5987ec681f3Smrg   }
5997ec681f3Smrg   else {
6007ec681f3Smrg      st_shared = NULL;
6017ec681f3Smrg   }
6027ec681f3Smrg
6037ec681f3Smrg   for (i = 0; attribList[i]; i += 2) {
6047ec681f3Smrg      switch (attribList[i]) {
6057ec681f3Smrg      case OSMESA_FORMAT:
6067ec681f3Smrg         format = attribList[i+1];
6077ec681f3Smrg         switch (format) {
6087ec681f3Smrg         case OSMESA_COLOR_INDEX:
6097ec681f3Smrg         case OSMESA_RGBA:
6107ec681f3Smrg         case OSMESA_BGRA:
6117ec681f3Smrg         case OSMESA_ARGB:
6127ec681f3Smrg         case OSMESA_RGB:
6137ec681f3Smrg         case OSMESA_BGR:
6147ec681f3Smrg         case OSMESA_RGB_565:
6157ec681f3Smrg            /* legal */
6167ec681f3Smrg            break;
6177ec681f3Smrg         default:
6187ec681f3Smrg            return NULL;
6197ec681f3Smrg         }
6207ec681f3Smrg         break;
6217ec681f3Smrg      case OSMESA_DEPTH_BITS:
6227ec681f3Smrg         depthBits = attribList[i+1];
6237ec681f3Smrg         if (depthBits < 0)
6247ec681f3Smrg            return NULL;
6257ec681f3Smrg         break;
6267ec681f3Smrg      case OSMESA_STENCIL_BITS:
6277ec681f3Smrg         stencilBits = attribList[i+1];
6287ec681f3Smrg         if (stencilBits < 0)
6297ec681f3Smrg            return NULL;
6307ec681f3Smrg         break;
6317ec681f3Smrg      case OSMESA_ACCUM_BITS:
6327ec681f3Smrg         accumBits = attribList[i+1];
6337ec681f3Smrg         if (accumBits < 0)
6347ec681f3Smrg            return NULL;
6357ec681f3Smrg         break;
6367ec681f3Smrg      case OSMESA_PROFILE:
6377ec681f3Smrg         profile = attribList[i+1];
6387ec681f3Smrg         if (profile != OSMESA_CORE_PROFILE &&
6397ec681f3Smrg             profile != OSMESA_COMPAT_PROFILE)
6407ec681f3Smrg            return NULL;
6417ec681f3Smrg         break;
6427ec681f3Smrg      case OSMESA_CONTEXT_MAJOR_VERSION:
6437ec681f3Smrg         version_major = attribList[i+1];
6447ec681f3Smrg         if (version_major < 1)
6457ec681f3Smrg            return NULL;
6467ec681f3Smrg         break;
6477ec681f3Smrg      case OSMESA_CONTEXT_MINOR_VERSION:
6487ec681f3Smrg         version_minor = attribList[i+1];
6497ec681f3Smrg         if (version_minor < 0)
6507ec681f3Smrg            return NULL;
6517ec681f3Smrg         break;
6527ec681f3Smrg      case 0:
6537ec681f3Smrg         /* end of list */
6547ec681f3Smrg         break;
6557ec681f3Smrg      default:
6567ec681f3Smrg         fprintf(stderr, "Bad attribute in OSMesaCreateContextAttribs()\n");
6577ec681f3Smrg         return NULL;
6587ec681f3Smrg      }
6597ec681f3Smrg   }
6607ec681f3Smrg
6617ec681f3Smrg   osmesa = (OSMesaContext) CALLOC_STRUCT(osmesa_context);
6627ec681f3Smrg   if (!osmesa)
6637ec681f3Smrg      return NULL;
6647ec681f3Smrg
6657ec681f3Smrg   /* Choose depth/stencil/accum buffer formats */
6667ec681f3Smrg   if (accumBits > 0) {
6677ec681f3Smrg      osmesa->accum_format = PIPE_FORMAT_R16G16B16A16_SNORM;
6687ec681f3Smrg   }
6697ec681f3Smrg   if (depthBits > 0 && stencilBits > 0) {
6707ec681f3Smrg      osmesa->depth_stencil_format = PIPE_FORMAT_Z24_UNORM_S8_UINT;
6717ec681f3Smrg   }
6727ec681f3Smrg   else if (stencilBits > 0) {
6737ec681f3Smrg      osmesa->depth_stencil_format = PIPE_FORMAT_S8_UINT;
6747ec681f3Smrg   }
6757ec681f3Smrg   else if (depthBits >= 24) {
6767ec681f3Smrg      osmesa->depth_stencil_format = PIPE_FORMAT_Z24X8_UNORM;
6777ec681f3Smrg   }
6787ec681f3Smrg   else if (depthBits >= 16) {
6797ec681f3Smrg      osmesa->depth_stencil_format = PIPE_FORMAT_Z16_UNORM;
6807ec681f3Smrg   }
6817ec681f3Smrg
6827ec681f3Smrg   /*
6837ec681f3Smrg    * Create the rendering context
6847ec681f3Smrg    */
6857ec681f3Smrg   memset(&attribs, 0, sizeof(attribs));
6867ec681f3Smrg   attribs.profile = (profile == OSMESA_CORE_PROFILE)
6877ec681f3Smrg      ? ST_PROFILE_OPENGL_CORE : ST_PROFILE_DEFAULT;
6887ec681f3Smrg   attribs.major = version_major;
6897ec681f3Smrg   attribs.minor = version_minor;
6907ec681f3Smrg   attribs.flags = 0;  /* ST_CONTEXT_FLAG_x */
6917ec681f3Smrg   attribs.options.force_glsl_extensions_warn = FALSE;
6927ec681f3Smrg   attribs.options.disable_blend_func_extended = FALSE;
6937ec681f3Smrg   attribs.options.disable_glsl_line_continuations = FALSE;
6947ec681f3Smrg   attribs.options.force_glsl_version = 0;
6957ec681f3Smrg
6967ec681f3Smrg   osmesa_init_st_visual(&attribs.visual,
6977ec681f3Smrg                         PIPE_FORMAT_NONE,
6987ec681f3Smrg                         osmesa->depth_stencil_format,
6997ec681f3Smrg                         osmesa->accum_format);
7007ec681f3Smrg
7017ec681f3Smrg   osmesa->stctx = stapi->create_context(stapi, get_st_manager(),
7027ec681f3Smrg                                         &attribs, &st_error, st_shared);
7037ec681f3Smrg   if (!osmesa->stctx) {
7047ec681f3Smrg      FREE(osmesa);
7057ec681f3Smrg      return NULL;
7067ec681f3Smrg   }
7077ec681f3Smrg
7087ec681f3Smrg   osmesa->stctx->st_manager_private = osmesa;
7097ec681f3Smrg
7107ec681f3Smrg   osmesa->format = format;
7117ec681f3Smrg   osmesa->user_row_length = 0;
7127ec681f3Smrg   osmesa->y_up = GL_TRUE;
7137ec681f3Smrg
7147ec681f3Smrg   return osmesa;
7157ec681f3Smrg}
7167ec681f3Smrg
7177ec681f3Smrg
7187ec681f3Smrg
7197ec681f3Smrg/**
7207ec681f3Smrg * Destroy an Off-Screen Mesa rendering context.
7217ec681f3Smrg *
7227ec681f3Smrg * \param osmesa  the context to destroy
7237ec681f3Smrg */
7247ec681f3SmrgGLAPI void GLAPIENTRY
7257ec681f3SmrgOSMesaDestroyContext(OSMesaContext osmesa)
7267ec681f3Smrg{
7277ec681f3Smrg   if (osmesa) {
7287ec681f3Smrg      pp_free(osmesa->pp);
7297ec681f3Smrg      osmesa->stctx->destroy(osmesa->stctx);
7307ec681f3Smrg      free(osmesa->zs);
7317ec681f3Smrg      FREE(osmesa);
7327ec681f3Smrg   }
7337ec681f3Smrg}
7347ec681f3Smrg
7357ec681f3Smrg
7367ec681f3Smrg/**
7377ec681f3Smrg * Bind an OSMesaContext to an image buffer.  The image buffer is just a
7387ec681f3Smrg * block of memory which the client provides.  Its size must be at least
7397ec681f3Smrg * as large as width*height*pixelSize.  Its address should be a multiple
7407ec681f3Smrg * of 4 if using RGBA mode.
7417ec681f3Smrg *
7427ec681f3Smrg * By default, image data is stored in the order of glDrawPixels: row-major
7437ec681f3Smrg * order with the lower-left image pixel stored in the first array position
7447ec681f3Smrg * (ie. bottom-to-top).
7457ec681f3Smrg *
7467ec681f3Smrg * If the context's viewport hasn't been initialized yet, it will now be
7477ec681f3Smrg * initialized to (0,0,width,height).
7487ec681f3Smrg *
7497ec681f3Smrg * Input:  osmesa - the rendering context
7507ec681f3Smrg *         buffer - the image buffer memory
7517ec681f3Smrg *         type - data type for pixel components
7527ec681f3Smrg *                GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT
7537ec681f3Smrg *                or GL_FLOAT.
7547ec681f3Smrg *         width, height - size of image buffer in pixels, at least 1
7557ec681f3Smrg * Return:  GL_TRUE if success, GL_FALSE if error because of invalid osmesa,
7567ec681f3Smrg *          invalid type, invalid size, etc.
7577ec681f3Smrg */
7587ec681f3SmrgGLAPI GLboolean GLAPIENTRY
7597ec681f3SmrgOSMesaMakeCurrent(OSMesaContext osmesa, void *buffer, GLenum type,
7607ec681f3Smrg                  GLsizei width, GLsizei height)
7617ec681f3Smrg{
7627ec681f3Smrg   struct st_api *stapi = get_st_api();
7637ec681f3Smrg   enum pipe_format color_format;
7647ec681f3Smrg
7657ec681f3Smrg   if (!osmesa && !buffer) {
7667ec681f3Smrg      stapi->make_current(stapi, NULL, NULL, NULL);
7677ec681f3Smrg      return GL_TRUE;
7687ec681f3Smrg   }
7697ec681f3Smrg
7707ec681f3Smrg   if (!osmesa || !buffer || width < 1 || height < 1) {
7717ec681f3Smrg      return GL_FALSE;
7727ec681f3Smrg   }
7737ec681f3Smrg
7747ec681f3Smrg   color_format = osmesa_choose_format(osmesa->format, type);
7757ec681f3Smrg   if (color_format == PIPE_FORMAT_NONE) {
7767ec681f3Smrg      fprintf(stderr, "OSMesaMakeCurrent(unsupported format/type)\n");
7777ec681f3Smrg      return GL_FALSE;
7787ec681f3Smrg   }
7797ec681f3Smrg
7807ec681f3Smrg   /* See if we already have a buffer that uses these pixel formats */
7817ec681f3Smrg   if (osmesa->current_buffer &&
7827ec681f3Smrg       (osmesa->current_buffer->visual.color_format != color_format ||
7837ec681f3Smrg        osmesa->current_buffer->visual.depth_stencil_format != osmesa->depth_stencil_format ||
7847ec681f3Smrg        osmesa->current_buffer->visual.accum_format != osmesa->accum_format ||
7857ec681f3Smrg        osmesa->current_buffer->width != width ||
7867ec681f3Smrg        osmesa->current_buffer->height != height)) {
7877ec681f3Smrg      osmesa_destroy_buffer(osmesa->current_buffer);
7887ec681f3Smrg      osmesa->current_buffer = NULL;
7897ec681f3Smrg   }
7907ec681f3Smrg
7917ec681f3Smrg   if (!osmesa->current_buffer) {
7927ec681f3Smrg      osmesa->current_buffer = osmesa_create_buffer(color_format,
7937ec681f3Smrg                                      osmesa->depth_stencil_format,
7947ec681f3Smrg                                      osmesa->accum_format);
7957ec681f3Smrg   }
7967ec681f3Smrg
7977ec681f3Smrg   struct osmesa_buffer *osbuffer = osmesa->current_buffer;
7987ec681f3Smrg
7997ec681f3Smrg   osbuffer->width = width;
8007ec681f3Smrg   osbuffer->height = height;
8017ec681f3Smrg   osbuffer->map = buffer;
8027ec681f3Smrg
8037ec681f3Smrg   osmesa->type = type;
8047ec681f3Smrg
8057ec681f3Smrg   stapi->make_current(stapi, osmesa->stctx, osbuffer->stfb, osbuffer->stfb);
8067ec681f3Smrg
8077ec681f3Smrg   /* XXX: We should probably load the current color value into the buffer here
8087ec681f3Smrg    * to match classic swrast behavior (context's fb starts with the contents of
8097ec681f3Smrg    * your pixel buffer).
8107ec681f3Smrg    */
8117ec681f3Smrg
8127ec681f3Smrg   if (!osmesa->ever_used) {
8137ec681f3Smrg      /* one-time init, just postprocessing for now */
8147ec681f3Smrg      boolean any_pp_enabled = FALSE;
8157ec681f3Smrg      unsigned i;
8167ec681f3Smrg
8177ec681f3Smrg      for (i = 0; i < ARRAY_SIZE(osmesa->pp_enabled); i++) {
8187ec681f3Smrg         if (osmesa->pp_enabled[i]) {
8197ec681f3Smrg            any_pp_enabled = TRUE;
8207ec681f3Smrg            break;
8217ec681f3Smrg         }
8227ec681f3Smrg      }
8237ec681f3Smrg
8247ec681f3Smrg      if (any_pp_enabled) {
8257ec681f3Smrg         osmesa->pp = pp_init(osmesa->stctx->pipe,
8267ec681f3Smrg                              osmesa->pp_enabled,
8277ec681f3Smrg                              osmesa->stctx->cso_context,
8287ec681f3Smrg                              osmesa->stctx);
8297ec681f3Smrg
8307ec681f3Smrg         pp_init_fbos(osmesa->pp, width, height);
8317ec681f3Smrg      }
8327ec681f3Smrg
8337ec681f3Smrg      osmesa->ever_used = TRUE;
8347ec681f3Smrg   }
8357ec681f3Smrg
8367ec681f3Smrg   return GL_TRUE;
8377ec681f3Smrg}
8387ec681f3Smrg
8397ec681f3Smrg
8407ec681f3Smrg
8417ec681f3SmrgGLAPI OSMesaContext GLAPIENTRY
8427ec681f3SmrgOSMesaGetCurrentContext(void)
8437ec681f3Smrg{
8447ec681f3Smrg   struct st_api *stapi = get_st_api();
8457ec681f3Smrg   struct st_context_iface *st = stapi->get_current(stapi);
8467ec681f3Smrg   return st ? (OSMesaContext) st->st_manager_private : NULL;
8477ec681f3Smrg}
8487ec681f3Smrg
8497ec681f3Smrg
8507ec681f3Smrg
8517ec681f3SmrgGLAPI void GLAPIENTRY
8527ec681f3SmrgOSMesaPixelStore(GLint pname, GLint value)
8537ec681f3Smrg{
8547ec681f3Smrg   OSMesaContext osmesa = OSMesaGetCurrentContext();
8557ec681f3Smrg
8567ec681f3Smrg   switch (pname) {
8577ec681f3Smrg   case OSMESA_ROW_LENGTH:
8587ec681f3Smrg      osmesa->user_row_length = value;
8597ec681f3Smrg      break;
8607ec681f3Smrg   case OSMESA_Y_UP:
8617ec681f3Smrg      osmesa->y_up = value ? GL_TRUE : GL_FALSE;
8627ec681f3Smrg      break;
8637ec681f3Smrg   default:
8647ec681f3Smrg      fprintf(stderr, "Invalid pname in OSMesaPixelStore()\n");
8657ec681f3Smrg      return;
8667ec681f3Smrg   }
8677ec681f3Smrg}
8687ec681f3Smrg
8697ec681f3Smrg
8707ec681f3SmrgGLAPI void GLAPIENTRY
8717ec681f3SmrgOSMesaGetIntegerv(GLint pname, GLint *value)
8727ec681f3Smrg{
8737ec681f3Smrg   OSMesaContext osmesa = OSMesaGetCurrentContext();
8747ec681f3Smrg   struct osmesa_buffer *osbuffer = osmesa ? osmesa->current_buffer : NULL;
8757ec681f3Smrg
8767ec681f3Smrg   switch (pname) {
8777ec681f3Smrg   case OSMESA_WIDTH:
8787ec681f3Smrg      *value = osbuffer ? osbuffer->width : 0;
8797ec681f3Smrg      return;
8807ec681f3Smrg   case OSMESA_HEIGHT:
8817ec681f3Smrg      *value = osbuffer ? osbuffer->height : 0;
8827ec681f3Smrg      return;
8837ec681f3Smrg   case OSMESA_FORMAT:
8847ec681f3Smrg      *value = osmesa->format;
8857ec681f3Smrg      return;
8867ec681f3Smrg   case OSMESA_TYPE:
8877ec681f3Smrg      /* current color buffer's data type */
8887ec681f3Smrg      *value = osmesa->type;
8897ec681f3Smrg      return;
8907ec681f3Smrg   case OSMESA_ROW_LENGTH:
8917ec681f3Smrg      *value = osmesa->user_row_length;
8927ec681f3Smrg      return;
8937ec681f3Smrg   case OSMESA_Y_UP:
8947ec681f3Smrg      *value = osmesa->y_up;
8957ec681f3Smrg      return;
8967ec681f3Smrg   case OSMESA_MAX_WIDTH:
8977ec681f3Smrg      FALLTHROUGH;
8987ec681f3Smrg   case OSMESA_MAX_HEIGHT:
8997ec681f3Smrg      {
9007ec681f3Smrg         struct pipe_screen *screen = get_st_manager()->screen;
9017ec681f3Smrg         *value = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_SIZE);
9027ec681f3Smrg      }
9037ec681f3Smrg      return;
9047ec681f3Smrg   default:
9057ec681f3Smrg      fprintf(stderr, "Invalid pname in OSMesaGetIntegerv()\n");
9067ec681f3Smrg      return;
9077ec681f3Smrg   }
9087ec681f3Smrg}
9097ec681f3Smrg
9107ec681f3Smrg
9117ec681f3Smrg/**
9127ec681f3Smrg * Return information about the depth buffer associated with an OSMesa context.
9137ec681f3Smrg * Input:  c - the OSMesa context
9147ec681f3Smrg * Output:  width, height - size of buffer in pixels
9157ec681f3Smrg *          bytesPerValue - bytes per depth value (2 or 4)
9167ec681f3Smrg *          buffer - pointer to depth buffer values
9177ec681f3Smrg * Return:  GL_TRUE or GL_FALSE to indicate success or failure.
9187ec681f3Smrg */
9197ec681f3SmrgGLAPI GLboolean GLAPIENTRY
9207ec681f3SmrgOSMesaGetDepthBuffer(OSMesaContext c, GLint *width, GLint *height,
9217ec681f3Smrg                     GLint *bytesPerValue, void **buffer)
9227ec681f3Smrg{
9237ec681f3Smrg   struct osmesa_buffer *osbuffer = c->current_buffer;
9247ec681f3Smrg   struct pipe_resource *res = osbuffer->textures[ST_ATTACHMENT_DEPTH_STENCIL];
9257ec681f3Smrg
9267ec681f3Smrg   if (!res) {
9277ec681f3Smrg      *width = 0;
9287ec681f3Smrg      *height = 0;
9297ec681f3Smrg      *bytesPerValue = 0;
9307ec681f3Smrg      *buffer = NULL;
9317ec681f3Smrg      return GL_FALSE;
9327ec681f3Smrg   }
9337ec681f3Smrg
9347ec681f3Smrg   *width = res->width0;
9357ec681f3Smrg   *height = res->height0;
9367ec681f3Smrg   *bytesPerValue = util_format_get_blocksize(res->format);
9377ec681f3Smrg
9387ec681f3Smrg   if (!c->zs) {
9397ec681f3Smrg      c->zs_stride = *width * *bytesPerValue;
9407ec681f3Smrg      c->zs = calloc(c->zs_stride, *height);
9417ec681f3Smrg      if (!c->zs)
9427ec681f3Smrg         return GL_FALSE;
9437ec681f3Smrg
9447ec681f3Smrg      osmesa_read_buffer(c, res, c->zs, c->zs_stride, true);
9457ec681f3Smrg   }
9467ec681f3Smrg
9477ec681f3Smrg   *buffer = c->zs;
9487ec681f3Smrg
9497ec681f3Smrg   return GL_TRUE;
9507ec681f3Smrg}
9517ec681f3Smrg
9527ec681f3Smrg
9537ec681f3Smrg/**
9547ec681f3Smrg * Return the color buffer associated with an OSMesa context.
9557ec681f3Smrg * Input:  c - the OSMesa context
9567ec681f3Smrg * Output:  width, height - size of buffer in pixels
9577ec681f3Smrg *          format - the pixel format (OSMESA_FORMAT)
9587ec681f3Smrg *          buffer - pointer to color buffer values
9597ec681f3Smrg * Return:  GL_TRUE or GL_FALSE to indicate success or failure.
9607ec681f3Smrg */
9617ec681f3SmrgGLAPI GLboolean GLAPIENTRY
9627ec681f3SmrgOSMesaGetColorBuffer(OSMesaContext osmesa, GLint *width,
9637ec681f3Smrg                      GLint *height, GLint *format, void **buffer)
9647ec681f3Smrg{
9657ec681f3Smrg   struct osmesa_buffer *osbuffer = osmesa->current_buffer;
9667ec681f3Smrg
9677ec681f3Smrg   if (osbuffer) {
9687ec681f3Smrg      *width = osbuffer->width;
9697ec681f3Smrg      *height = osbuffer->height;
9707ec681f3Smrg      *format = osmesa->format;
9717ec681f3Smrg      *buffer = osbuffer->map;
9727ec681f3Smrg      return GL_TRUE;
9737ec681f3Smrg   }
9747ec681f3Smrg   else {
9757ec681f3Smrg      *width = 0;
9767ec681f3Smrg      *height = 0;
9777ec681f3Smrg      *format = 0;
9787ec681f3Smrg      *buffer = 0;
9797ec681f3Smrg      return GL_FALSE;
9807ec681f3Smrg   }
9817ec681f3Smrg}
9827ec681f3Smrg
9837ec681f3Smrg
9847ec681f3Smrgstruct name_function
9857ec681f3Smrg{
9867ec681f3Smrg   const char *Name;
9877ec681f3Smrg   OSMESAproc Function;
9887ec681f3Smrg};
9897ec681f3Smrg
9907ec681f3Smrgstatic struct name_function functions[] = {
9917ec681f3Smrg   { "OSMesaCreateContext", (OSMESAproc) OSMesaCreateContext },
9927ec681f3Smrg   { "OSMesaCreateContextExt", (OSMESAproc) OSMesaCreateContextExt },
9937ec681f3Smrg   { "OSMesaCreateContextAttribs", (OSMESAproc) OSMesaCreateContextAttribs },
9947ec681f3Smrg   { "OSMesaDestroyContext", (OSMESAproc) OSMesaDestroyContext },
9957ec681f3Smrg   { "OSMesaMakeCurrent", (OSMESAproc) OSMesaMakeCurrent },
9967ec681f3Smrg   { "OSMesaGetCurrentContext", (OSMESAproc) OSMesaGetCurrentContext },
9977ec681f3Smrg   { "OSMesaPixelStore", (OSMESAproc) OSMesaPixelStore },
9987ec681f3Smrg   { "OSMesaGetIntegerv", (OSMESAproc) OSMesaGetIntegerv },
9997ec681f3Smrg   { "OSMesaGetDepthBuffer", (OSMESAproc) OSMesaGetDepthBuffer },
10007ec681f3Smrg   { "OSMesaGetColorBuffer", (OSMESAproc) OSMesaGetColorBuffer },
10017ec681f3Smrg   { "OSMesaGetProcAddress", (OSMESAproc) OSMesaGetProcAddress },
10027ec681f3Smrg   { "OSMesaColorClamp", (OSMESAproc) OSMesaColorClamp },
10037ec681f3Smrg   { "OSMesaPostprocess", (OSMESAproc) OSMesaPostprocess },
10047ec681f3Smrg   { NULL, NULL }
10057ec681f3Smrg};
10067ec681f3Smrg
10077ec681f3Smrg
10087ec681f3SmrgGLAPI OSMESAproc GLAPIENTRY
10097ec681f3SmrgOSMesaGetProcAddress(const char *funcName)
10107ec681f3Smrg{
10117ec681f3Smrg   int i;
10127ec681f3Smrg   for (i = 0; functions[i].Name; i++) {
10137ec681f3Smrg      if (strcmp(functions[i].Name, funcName) == 0)
10147ec681f3Smrg         return functions[i].Function;
10157ec681f3Smrg   }
10167ec681f3Smrg   return _glapi_get_proc_address(funcName);
10177ec681f3Smrg}
10187ec681f3Smrg
10197ec681f3Smrg
10207ec681f3SmrgGLAPI void GLAPIENTRY
10217ec681f3SmrgOSMesaColorClamp(GLboolean enable)
10227ec681f3Smrg{
10237ec681f3Smrg   extern void GLAPIENTRY _mesa_ClampColor(GLenum target, GLenum clamp);
10247ec681f3Smrg
10257ec681f3Smrg   _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB,
10267ec681f3Smrg                    enable ? GL_TRUE : GL_FIXED_ONLY_ARB);
10277ec681f3Smrg}
10287ec681f3Smrg
10297ec681f3Smrg
10307ec681f3SmrgGLAPI void GLAPIENTRY
10317ec681f3SmrgOSMesaPostprocess(OSMesaContext osmesa, const char *filter,
10327ec681f3Smrg                  unsigned enable_value)
10337ec681f3Smrg{
10347ec681f3Smrg   if (!osmesa->ever_used) {
10357ec681f3Smrg      /* We can only enable/disable postprocess filters before a context
10367ec681f3Smrg       * is made current for the first time.
10377ec681f3Smrg       */
10387ec681f3Smrg      unsigned i;
10397ec681f3Smrg
10407ec681f3Smrg      for (i = 0; i < PP_FILTERS; i++) {
10417ec681f3Smrg         if (strcmp(pp_filters[i].name, filter) == 0) {
10427ec681f3Smrg            osmesa->pp_enabled[i] = enable_value;
10437ec681f3Smrg            return;
10447ec681f3Smrg         }
10457ec681f3Smrg      }
10467ec681f3Smrg      debug_warning("OSMesaPostprocess(unknown filter)\n");
10477ec681f3Smrg   }
10487ec681f3Smrg   else {
10497ec681f3Smrg      debug_warning("Calling OSMesaPostprocess() after OSMesaMakeCurrent()\n");
10507ec681f3Smrg   }
10517ec681f3Smrg}
1052