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