2 * Copyright (c) 2013 Brian Paul All Rights Reserved.
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:
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * Off-Screen rendering into client memory.
25 * State tracker for gallium (for softpipe and llvmpipe)
29 * If Gallium is built with LLVM support we use the llvmpipe driver.
30 * Otherwise we use softpipe. The GALLIUM_DRIVER environment variable
31 * may be set to "softpipe" or "llvmpipe" to override.
33 * With softpipe we could render directly into the user's buffer by using a
34 * display target resource. However, softpipe doesn't suport "upside-down"
35 * rendering which would be needed for the OSMESA_Y_UP=TRUE case.
37 * With llvmpipe we could only render directly into the user's buffer when its
38 * width and height is a multiple of the tile size (64 pixels).
40 * Because of these constraints we always render into ordinary resources then
41 * copy the results to the user's buffer in the flush_front() function which
42 * is called when the app calls glFlush/Finish.
44 * In general, the OSMesa interface is pretty ugly and not a good match
45 * for Gallium. But we're interested in doing the best we can to preserve
46 * application portability. With a little work we could come up with a
47 * much nicer, new off-screen Gallium interface...
51 #include "GL/osmesa.h"
53 #include "glapi/glapi.h" /* for OSMesaGetProcAddress below */
55 #include "pipe/p_context.h"
56 #include "pipe/p_screen.h"
57 #include "pipe/p_state.h"
59 #include "util/u_atomic.h"
60 #include "util/u_box.h"
61 #include "util/u_format.h"
62 #include "util/u_memory.h"
64 #include "state_tracker/st_api.h"
65 #include "state_tracker/st_gl_api.h"
69 extern struct pipe_screen
*
70 osmesa_create_screen(void);
76 struct st_framebuffer_iface
*stfb
;
77 struct st_visual visual
;
78 unsigned width
, height
;
80 struct pipe_resource
*textures
[ST_ATTACHMENT_COUNT
];
88 struct st_context_iface
*stctx
;
90 struct osmesa_buffer
*current_buffer
;
92 enum pipe_format depth_stencil_format
, accum_format
;
94 GLenum format
; /*< User-specified context format */
95 GLenum type
; /*< Buffer's data type */
96 GLint user_row_length
; /*< user-specified number of pixels per row */
97 GLboolean y_up
; /*< TRUE -> Y increases upward */
98 /*< FALSE -> Y increases downward */
104 * Called from the ST manager.
107 osmesa_st_get_param(struct st_manager
*smapi
, enum st_manager_param param
)
115 * Create/return singleton st_api object.
117 static struct st_api
*
120 static struct st_api
*stapi
= NULL
;
122 stapi
= st_gl_api_create();
129 * Create/return a singleton st_manager object.
131 static struct st_manager
*
134 static struct st_manager
*stmgr
= NULL
;
136 stmgr
= CALLOC_STRUCT(st_manager
);
138 stmgr
->screen
= osmesa_create_screen();
139 stmgr
->get_param
= osmesa_st_get_param
;
140 stmgr
->get_egl_image
= NULL
;
147 static INLINE boolean
150 const unsigned ui
= 1;
151 return *((const char *) &ui
);
156 * Given an OSMESA_x format and a GL_y type, return the best
157 * matching PIPE_FORMAT_z.
158 * Note that we can't exactly match all user format/type combinations
159 * with gallium formats. If we find this to be a problem, we can
160 * implement more elaborate format/type conversion in the flush_front()
163 static enum pipe_format
164 osmesa_choose_format(GLenum format
, GLenum type
)
168 if (type
== GL_UNSIGNED_BYTE
) {
170 return PIPE_FORMAT_R8G8B8A8_UNORM
;
172 return PIPE_FORMAT_A8B8G8R8_UNORM
;
174 else if (type
== GL_UNSIGNED_SHORT
) {
175 return PIPE_FORMAT_R16G16B16A16_UNORM
;
177 else if (type
== GL_FLOAT
) {
178 return PIPE_FORMAT_R32G32B32A32_FLOAT
;
181 return PIPE_FORMAT_NONE
;
185 if (type
== GL_UNSIGNED_BYTE
) {
187 return PIPE_FORMAT_B8G8R8A8_UNORM
;
189 return PIPE_FORMAT_A8R8G8B8_UNORM
;
191 else if (type
== GL_UNSIGNED_SHORT
) {
192 return PIPE_FORMAT_R16G16B16A16_UNORM
;
194 else if (type
== GL_FLOAT
) {
195 return PIPE_FORMAT_R32G32B32A32_FLOAT
;
198 return PIPE_FORMAT_NONE
;
202 if (type
== GL_UNSIGNED_BYTE
) {
204 return PIPE_FORMAT_A8R8G8B8_UNORM
;
206 return PIPE_FORMAT_B8G8R8A8_UNORM
;
208 else if (type
== GL_UNSIGNED_SHORT
) {
209 return PIPE_FORMAT_R16G16B16A16_UNORM
;
211 else if (type
== GL_FLOAT
) {
212 return PIPE_FORMAT_R32G32B32A32_FLOAT
;
215 return PIPE_FORMAT_NONE
;
219 if (type
== GL_UNSIGNED_BYTE
) {
220 return PIPE_FORMAT_R8G8B8_UNORM
;
222 else if (type
== GL_UNSIGNED_SHORT
) {
223 return PIPE_FORMAT_R16G16B16_UNORM
;
225 else if (type
== GL_FLOAT
) {
226 return PIPE_FORMAT_R32G32B32_FLOAT
;
229 return PIPE_FORMAT_NONE
;
233 /* No gallium format for this one */
234 return PIPE_FORMAT_NONE
;
236 return PIPE_FORMAT_B5G6R5_UNORM
;
240 return PIPE_FORMAT_NONE
;
245 * Initialize an st_visual object.
248 osmesa_init_st_visual(struct st_visual
*vis
,
249 enum pipe_format color_format
,
250 enum pipe_format ds_format
,
251 enum pipe_format accum_format
)
253 vis
->buffer_mask
= ST_ATTACHMENT_FRONT_LEFT_MASK
;
254 vis
->color_format
= color_format
;
255 vis
->depth_stencil_format
= ds_format
;
256 vis
->accum_format
= accum_format
;
258 vis
->render_buffer
= ST_ATTACHMENT_FRONT_LEFT
;
263 * Return the osmesa_buffer that corresponds to an st_framebuffer_iface.
265 static INLINE
struct osmesa_buffer
*
266 stfbi_to_osbuffer(struct st_framebuffer_iface
*stfbi
)
268 return (struct osmesa_buffer
*) stfbi
->st_manager_private
;
273 * Called via glFlush/glFinish. This is where we copy the contents
274 * of the driver's color buffer into the user-specified buffer.
277 osmesa_st_framebuffer_flush_front(struct st_context_iface
*stctx
,
278 struct st_framebuffer_iface
*stfbi
,
279 enum st_attachment_type statt
)
281 OSMesaContext osmesa
= OSMesaGetCurrentContext();
282 struct osmesa_buffer
*osbuffer
= stfbi_to_osbuffer(stfbi
);
283 struct pipe_context
*pipe
= stctx
->pipe
;
284 struct pipe_resource
*res
= osbuffer
->textures
[statt
];
285 struct pipe_transfer
*transfer
= NULL
;
289 unsigned y
, bytes
, bpp
;
292 u_box_2d(0, 0, res
->width0
, res
->height0
, &box
);
294 map
= pipe
->transfer_map(pipe
, res
, 0, PIPE_TRANSFER_READ
, &box
,
298 * Copy the color buffer from the resource to the user's buffer.
300 bpp
= util_format_get_blocksize(osbuffer
->visual
.color_format
);
303 if (osmesa
->user_row_length
)
304 dst_stride
= bpp
* osmesa
->user_row_length
;
306 dst_stride
= bpp
* osbuffer
->width
;
307 bytes
= bpp
* res
->width0
;
310 /* need to flip image upside down */
311 dst
= dst
+ (res
->height0
- 1) * dst_stride
;
312 dst_stride
= -dst_stride
;
315 for (y
= 0; y
< res
->height0
; y
++) {
316 memcpy(dst
, src
, bytes
);
318 src
+= transfer
->stride
;
321 pipe
->transfer_unmap(pipe
, transfer
);
328 * Called by the st manager to validate the framebuffer (allocate
332 osmesa_st_framebuffer_validate(struct st_framebuffer_iface
*stfbi
,
333 const enum st_attachment_type
*statts
,
335 struct pipe_resource
**out
)
337 struct pipe_screen
*screen
= get_st_manager()->screen
;
338 enum st_attachment_type i
;
339 struct osmesa_buffer
*osbuffer
= stfbi_to_osbuffer(stfbi
);
340 struct pipe_resource templat
;
342 memset(&templat
, 0, sizeof(templat
));
343 templat
.target
= PIPE_TEXTURE_RECT
;
344 templat
.format
= 0; /* setup below */
345 templat
.last_level
= 0;
346 templat
.width0
= osbuffer
->width
;
347 templat
.height0
= osbuffer
->height
;
349 templat
.array_size
= 1;
350 templat
.usage
= PIPE_USAGE_DEFAULT
;
351 templat
.bind
= 0; /* setup below */
354 for (i
= 0; i
< count
; i
++) {
355 enum pipe_format format
;
359 * At this time, we really only need to handle the front-left color
360 * attachment, since that's all we specified for the visual in
361 * osmesa_init_st_visual().
363 if (statts
[i
] == ST_ATTACHMENT_FRONT_LEFT
) {
364 format
= osbuffer
->visual
.color_format
;
365 bind
= PIPE_BIND_RENDER_TARGET
;
367 else if (statts
[i
] == ST_ATTACHMENT_DEPTH_STENCIL
) {
368 format
= osbuffer
->visual
.depth_stencil_format
;
369 bind
= PIPE_BIND_DEPTH_STENCIL
;
371 else if (statts
[i
] == ST_ATTACHMENT_ACCUM
) {
372 format
= osbuffer
->visual
.accum_format
;
373 bind
= PIPE_BIND_RENDER_TARGET
;
376 templat
.format
= format
;
378 out
[i
] = osbuffer
->textures
[i
] =
379 screen
->resource_create(screen
, &templat
);
386 static struct st_framebuffer_iface
*
387 osmesa_create_st_framebuffer(void)
389 struct st_framebuffer_iface
*stfbi
= CALLOC_STRUCT(st_framebuffer_iface
);
391 stfbi
->flush_front
= osmesa_st_framebuffer_flush_front
;
392 stfbi
->validate
= osmesa_st_framebuffer_validate
;
393 p_atomic_set(&stfbi
->stamp
, 1);
399 static struct osmesa_buffer
*
400 osmesa_create_buffer(enum pipe_format color_format
,
401 enum pipe_format ds_format
,
402 enum pipe_format accum_format
)
404 struct osmesa_buffer
*osbuffer
= CALLOC_STRUCT(osmesa_buffer
);
406 osbuffer
->stfb
= osmesa_create_st_framebuffer();
408 osbuffer
->stfb
->st_manager_private
= osbuffer
;
409 osbuffer
->stfb
->visual
= &osbuffer
->visual
;
411 osmesa_init_st_visual(&osbuffer
->visual
, color_format
,
412 ds_format
, accum_format
);
419 osmesa_destroy_buffer(struct osmesa_buffer
*osbuffer
)
421 FREE(osbuffer
->stfb
);
427 /**********************************************************************/
428 /***** Public Functions *****/
429 /**********************************************************************/
433 * Create an Off-Screen Mesa rendering context. The only attribute needed is
434 * an RGBA vs Color-Index mode flag.
436 * Input: format - Must be GL_RGBA
437 * sharelist - specifies another OSMesaContext with which to share
438 * display lists. NULL indicates no sharing.
439 * Return: an OSMesaContext or 0 if error
441 GLAPI OSMesaContext GLAPIENTRY
442 OSMesaCreateContext(GLenum format
, OSMesaContext sharelist
)
444 return OSMesaCreateContextExt(format
, 24, 8, 0, sharelist
);
451 * Create context and specify size of ancillary buffers.
453 GLAPI OSMesaContext GLAPIENTRY
454 OSMesaCreateContextExt(GLenum format
, GLint depthBits
, GLint stencilBits
,
455 GLint accumBits
, OSMesaContext sharelist
)
457 OSMesaContext osmesa
;
458 struct st_context_iface
*st_shared
;
459 enum st_context_error st_error
= 0;
460 struct st_context_attribs attribs
;
461 struct st_api
*stapi
= get_st_api();
464 st_shared
= sharelist
->stctx
;
470 osmesa
= (OSMesaContext
) CALLOC_STRUCT(osmesa_context
);
474 /* Choose depth/stencil/accum buffer formats */
476 osmesa
->accum_format
= PIPE_FORMAT_R16G16B16A16_SNORM
;
478 if (depthBits
> 0 && stencilBits
> 0) {
479 osmesa
->depth_stencil_format
= PIPE_FORMAT_Z24_UNORM_S8_UINT
;
481 else if (stencilBits
> 0) {
482 osmesa
->depth_stencil_format
= PIPE_FORMAT_S8_UINT
;
484 else if (depthBits
>= 24) {
485 osmesa
->depth_stencil_format
= PIPE_FORMAT_Z24X8_UNORM
;
487 else if (depthBits
>= 16) {
488 osmesa
->depth_stencil_format
= PIPE_FORMAT_Z16_UNORM
;
492 * Create the rendering context
494 attribs
.profile
= ST_PROFILE_DEFAULT
;
497 attribs
.flags
= 0; /* ST_CONTEXT_FLAG_x */
498 attribs
.options
.force_glsl_extensions_warn
= FALSE
;
500 osmesa_init_st_visual(&attribs
.visual
,
501 PIPE_FORMAT_R8G8B8A8_UNORM
,
502 osmesa
->depth_stencil_format
,
503 osmesa
->accum_format
);
505 osmesa
->stctx
= stapi
->create_context(stapi
, get_st_manager(),
506 &attribs
, &st_error
, st_shared
);
507 if (!osmesa
->stctx
) {
512 osmesa
->stctx
->st_manager_private
= osmesa
;
514 osmesa
->format
= format
;
515 osmesa
->user_row_length
= 0;
516 osmesa
->y_up
= GL_TRUE
;
523 * Destroy an Off-Screen Mesa rendering context.
525 * \param osmesa the context to destroy
527 GLAPI
void GLAPIENTRY
528 OSMesaDestroyContext(OSMesaContext osmesa
)
531 osmesa
->stctx
->destroy(osmesa
->stctx
);
538 * Bind an OSMesaContext to an image buffer. The image buffer is just a
539 * block of memory which the client provides. Its size must be at least
540 * as large as width*height*pixelSize. Its address should be a multiple
541 * of 4 if using RGBA mode.
543 * By default, image data is stored in the order of glDrawPixels: row-major
544 * order with the lower-left image pixel stored in the first array position
545 * (ie. bottom-to-top).
547 * If the context's viewport hasn't been initialized yet, it will now be
548 * initialized to (0,0,width,height).
550 * Input: osmesa - the rendering context
551 * buffer - the image buffer memory
552 * type - data type for pixel components
553 * GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT
555 * width, height - size of image buffer in pixels, at least 1
556 * Return: GL_TRUE if success, GL_FALSE if error because of invalid osmesa,
557 * invalid type, invalid size, etc.
559 GLAPI GLboolean GLAPIENTRY
560 OSMesaMakeCurrent(OSMesaContext osmesa
, void *buffer
, GLenum type
,
561 GLsizei width
, GLsizei height
)
563 struct st_api
*stapi
= get_st_api();
564 struct osmesa_buffer
*osbuffer
;
565 enum pipe_format color_format
;
567 if (osmesa
->format
== OSMESA_RGB_565
&& type
!= GL_UNSIGNED_SHORT_5_6_5
) {
570 if (width
< 1 || height
< 1) {
574 color_format
= osmesa_choose_format(osmesa
->format
, type
);
575 if (color_format
== PIPE_FORMAT_NONE
) {
576 fprintf(stderr
, "OSMesaMakeCurrent(unsupported format/type)\n");
580 osbuffer
= osmesa_create_buffer(color_format
,
581 osmesa
->depth_stencil_format
,
582 osmesa
->accum_format
);
584 osbuffer
->width
= width
;
585 osbuffer
->height
= height
;
586 osbuffer
->map
= buffer
;
588 if (osmesa
->current_buffer
) {
589 /* free old buffer */
590 osmesa_destroy_buffer(osmesa
->current_buffer
);
593 osmesa
->current_buffer
= osbuffer
;
596 stapi
->make_current(stapi
, osmesa
->stctx
, osbuffer
->stfb
, osbuffer
->stfb
);
603 GLAPI OSMesaContext GLAPIENTRY
604 OSMesaGetCurrentContext(void)
606 struct st_api
*stapi
= get_st_api();
607 struct st_context_iface
*st
= stapi
->get_current(stapi
);
608 return st
? (OSMesaContext
) st
->st_manager_private
: NULL
;
613 GLAPI
void GLAPIENTRY
614 OSMesaPixelStore(GLint pname
, GLint value
)
616 OSMesaContext osmesa
= OSMesaGetCurrentContext();
619 case OSMESA_ROW_LENGTH
:
620 osmesa
->user_row_length
= value
;
623 osmesa
->y_up
= value
? GL_TRUE
: GL_FALSE
;
626 fprintf(stderr
, "Invalid pname in OSMesaPixelStore()\n");
632 GLAPI
void GLAPIENTRY
633 OSMesaGetIntegerv(GLint pname
, GLint
*value
)
635 OSMesaContext osmesa
= OSMesaGetCurrentContext();
636 struct osmesa_buffer
*osbuffer
= osmesa
? osmesa
->current_buffer
: NULL
;
640 *value
= osbuffer
? osbuffer
->width
: 0;
643 *value
= osbuffer
? osbuffer
->height
: 0;
646 *value
= osmesa
->format
;
649 /* current color buffer's data type */
650 *value
= osmesa
->type
;
652 case OSMESA_ROW_LENGTH
:
653 *value
= osmesa
->user_row_length
;
656 *value
= osmesa
->y_up
;
658 case OSMESA_MAX_WIDTH
:
660 case OSMESA_MAX_HEIGHT
:
662 struct pipe_screen
*screen
= get_st_manager()->screen
;
663 int maxLevels
= screen
->get_param(screen
,
664 PIPE_CAP_MAX_TEXTURE_2D_LEVELS
);
665 *value
= 1 << (maxLevels
- 1);
670 fprintf(stderr
, "Invalid pname in OSMesaGetIntegerv()\n");
677 * Return information about the depth buffer associated with an OSMesa context.
678 * Input: c - the OSMesa context
679 * Output: width, height - size of buffer in pixels
680 * bytesPerValue - bytes per depth value (2 or 4)
681 * buffer - pointer to depth buffer values
682 * Return: GL_TRUE or GL_FALSE to indicate success or failure.
684 GLAPI GLboolean GLAPIENTRY
685 OSMesaGetDepthBuffer(OSMesaContext c
, GLint
*width
, GLint
*height
,
686 GLint
*bytesPerValue
, void **buffer
)
688 struct osmesa_buffer
*osbuffer
= c
->current_buffer
;
689 struct pipe_context
*pipe
= c
->stctx
->pipe
;
690 struct pipe_resource
*res
= osbuffer
->textures
[ST_ATTACHMENT_DEPTH_STENCIL
];
691 struct pipe_transfer
*transfer
= NULL
;
695 * Note: we can't really implement this function with gallium as
696 * we did for swrast. We can't just map the resource and leave it
697 * mapped (and there's no OSMesaUnmapDepthBuffer() function) so
698 * we unmap the buffer here and return a 'stale' pointer. This should
699 * actually be OK in most cases where the caller of this function
700 * immediately uses the pointer.
703 u_box_2d(0, 0, res
->width0
, res
->height0
, &box
);
705 *buffer
= pipe
->transfer_map(pipe
, res
, 0, PIPE_TRANSFER_READ
, &box
,
711 *width
= res
->width0
;
712 *height
= res
->height0
;
713 *bytesPerValue
= util_format_get_blocksize(res
->format
);
715 pipe
->transfer_unmap(pipe
, transfer
);
722 * Return the color buffer associated with an OSMesa context.
723 * Input: c - the OSMesa context
724 * Output: width, height - size of buffer in pixels
725 * format - the pixel format (OSMESA_FORMAT)
726 * buffer - pointer to color buffer values
727 * Return: GL_TRUE or GL_FALSE to indicate success or failure.
729 GLAPI GLboolean GLAPIENTRY
730 OSMesaGetColorBuffer(OSMesaContext osmesa
, GLint
*width
,
731 GLint
*height
, GLint
*format
, void **buffer
)
733 struct osmesa_buffer
*osbuffer
= osmesa
->current_buffer
;
736 *width
= osbuffer
->width
;
737 *height
= osbuffer
->height
;
738 *format
= osmesa
->format
;
739 *buffer
= osbuffer
->map
;
758 static struct name_function functions
[] = {
759 { "OSMesaCreateContext", (OSMESAproc
) OSMesaCreateContext
},
760 { "OSMesaCreateContextExt", (OSMESAproc
) OSMesaCreateContextExt
},
761 { "OSMesaDestroyContext", (OSMESAproc
) OSMesaDestroyContext
},
762 { "OSMesaMakeCurrent", (OSMESAproc
) OSMesaMakeCurrent
},
763 { "OSMesaGetCurrentContext", (OSMESAproc
) OSMesaGetCurrentContext
},
764 { "OSMesaPixelsStore", (OSMESAproc
) OSMesaPixelStore
},
765 { "OSMesaGetIntegerv", (OSMESAproc
) OSMesaGetIntegerv
},
766 { "OSMesaGetDepthBuffer", (OSMESAproc
) OSMesaGetDepthBuffer
},
767 { "OSMesaGetColorBuffer", (OSMESAproc
) OSMesaGetColorBuffer
},
768 { "OSMesaGetProcAddress", (OSMESAproc
) OSMesaGetProcAddress
},
769 { "OSMesaColorClamp", (OSMESAproc
) OSMesaColorClamp
},
774 GLAPI OSMESAproc GLAPIENTRY
775 OSMesaGetProcAddress(const char *funcName
)
778 for (i
= 0; functions
[i
].Name
; i
++) {
779 if (strcmp(functions
[i
].Name
, funcName
) == 0)
780 return functions
[i
].Function
;
782 return _glapi_get_proc_address(funcName
);
786 GLAPI
void GLAPIENTRY
787 OSMesaColorClamp(GLboolean enable
)
789 extern void GLAPIENTRY
_mesa_ClampColor(GLenum target
, GLenum clamp
);
791 _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB
,
792 enable
? GL_TRUE
: GL_FIXED_ONLY_ARB
);