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