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