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