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