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