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