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