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