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