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