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 
77 extern struct pipe_screen *
78 osmesa_create_screen(void);
79 
80 
81 
82 struct 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 
96 struct 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  */
127 static int
osmesa_st_get_param(struct st_manager * smapi,enum st_manager_param param)128 osmesa_st_get_param(struct st_manager *smapi, enum st_manager_param param)
129 {
130    /* no-op */
131    return 0;
132 }
133 
134 static struct st_manager *stmgr = NULL;
135 static struct st_api *stapi = NULL;
136 
137 static void
destroy_st_manager(void)138 destroy_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 
151 static void
create_st_manager(void)152 create_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  */
170 static struct st_manager *
get_st_manager(void)171 get_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  */
183 static struct st_api *
get_st_api(void)184 get_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  */
193 static void
osmesa_read_buffer(OSMesaContext osmesa,struct pipe_resource * res,void * dst,int dst_stride,bool y_up)194 osmesa_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  */
236 static enum pipe_format
osmesa_choose_format(GLenum format,GLenum type)237 osmesa_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  */
324 static void
osmesa_init_st_visual(struct st_visual * vis,enum pipe_format color_format,enum pipe_format ds_format,enum pipe_format accum_format)325 osmesa_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  */
347 static inline struct osmesa_buffer *
stfbi_to_osbuffer(struct st_framebuffer_iface * stfbi)348 stfbi_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  */
358 static bool
osmesa_st_framebuffer_flush_front(struct st_context_iface * stctx,struct st_framebuffer_iface * stfbi,enum st_attachment_type statt)359 osmesa_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  */
417 static bool
osmesa_st_framebuffer_validate(struct st_context_iface * stctx,struct st_framebuffer_iface * stfbi,const enum st_attachment_type * statts,unsigned count,struct pipe_resource ** out)418 osmesa_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 
477 static uint32_t osmesa_fb_ID = 0;
478 
479 static struct st_framebuffer_iface *
osmesa_create_st_framebuffer(void)480 osmesa_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  */
497 static struct osmesa_buffer *
osmesa_create_buffer(enum pipe_format color_format,enum pipe_format ds_format,enum pipe_format accum_format)498 osmesa_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 
517 static void
osmesa_destroy_buffer(struct osmesa_buffer * osbuffer)518 osmesa_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  */
546 GLAPI OSMesaContext GLAPIENTRY
OSMesaCreateContext(GLenum format,OSMesaContext sharelist)547 OSMesaCreateContext(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  */
558 GLAPI OSMesaContext GLAPIENTRY
OSMesaCreateContextExt(GLenum format,GLint depthBits,GLint stencilBits,GLint accumBits,OSMesaContext sharelist)559 OSMesaCreateContextExt(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  */
583 GLAPI OSMesaContext GLAPIENTRY
OSMesaCreateContextAttribs(const int * attribList,OSMesaContext sharelist)584 OSMesaCreateContextAttribs(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  */
724 GLAPI void GLAPIENTRY
OSMesaDestroyContext(OSMesaContext osmesa)725 OSMesaDestroyContext(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  */
758 GLAPI GLboolean GLAPIENTRY
OSMesaMakeCurrent(OSMesaContext osmesa,void * buffer,GLenum type,GLsizei width,GLsizei height)759 OSMesaMakeCurrent(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 
841 GLAPI OSMesaContext GLAPIENTRY
OSMesaGetCurrentContext(void)842 OSMesaGetCurrentContext(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 
851 GLAPI void GLAPIENTRY
OSMesaPixelStore(GLint pname,GLint value)852 OSMesaPixelStore(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 
870 GLAPI void GLAPIENTRY
OSMesaGetIntegerv(GLint pname,GLint * value)871 OSMesaGetIntegerv(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  */
919 GLAPI GLboolean GLAPIENTRY
OSMesaGetDepthBuffer(OSMesaContext c,GLint * width,GLint * height,GLint * bytesPerValue,void ** buffer)920 OSMesaGetDepthBuffer(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  */
961 GLAPI GLboolean GLAPIENTRY
OSMesaGetColorBuffer(OSMesaContext osmesa,GLint * width,GLint * height,GLint * format,void ** buffer)962 OSMesaGetColorBuffer(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 
984 struct name_function
985 {
986    const char *Name;
987    OSMESAproc Function;
988 };
989 
990 static 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 
1008 GLAPI OSMESAproc GLAPIENTRY
OSMesaGetProcAddress(const char * funcName)1009 OSMesaGetProcAddress(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 
1020 GLAPI void GLAPIENTRY
OSMesaColorClamp(GLboolean enable)1021 OSMesaColorClamp(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 
1030 GLAPI void GLAPIENTRY
OSMesaPostprocess(OSMesaContext osmesa,const char * filter,unsigned enable_value)1031 OSMesaPostprocess(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