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