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