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