osmesa.c revision 848b8605
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 74extern struct pipe_screen * 75osmesa_create_screen(void); 76 77 78 79struct 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 93struct 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 */ 123static struct osmesa_buffer *BufferList = NULL; 124 125 126/** 127 * Called from the ST manager. 128 */ 129static int 130osmesa_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 */ 140static struct st_api * 141get_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 */ 154static struct st_manager * 155get_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 170static INLINE boolean 171little_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 */ 186static enum pipe_format 187osmesa_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 */ 270static void 271osmesa_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 */ 294static INLINE struct osmesa_buffer * 295stfbi_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 */ 305static boolean 306osmesa_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 */ 382static boolean 383osmesa_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[i] = 435 screen->resource_create(screen, &templat); 436 } 437 438 return TRUE; 439} 440 441 442static struct st_framebuffer_iface * 443osmesa_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 */ 458static struct osmesa_buffer * 459osmesa_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 */ 485static struct osmesa_buffer * 486osmesa_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 507static void 508osmesa_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 */ 530GLAPI OSMesaContext GLAPIENTRY 531OSMesaCreateContext(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 */ 542GLAPI OSMesaContext GLAPIENTRY 543OSMesaCreateContextExt(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 */ 621GLAPI void GLAPIENTRY 622OSMesaDestroyContext(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 */ 654GLAPI GLboolean GLAPIENTRY 655OSMesaMakeCurrent(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 727GLAPI OSMesaContext GLAPIENTRY 728OSMesaGetCurrentContext(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 737GLAPI void GLAPIENTRY 738OSMesaPixelStore(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 756GLAPI void GLAPIENTRY 757OSMesaGetIntegerv(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 */ 808GLAPI GLboolean GLAPIENTRY 809OSMesaGetDepthBuffer(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 */ 853GLAPI GLboolean GLAPIENTRY 854OSMesaGetColorBuffer(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 876struct name_function 877{ 878 const char *Name; 879 OSMESAproc Function; 880}; 881 882static 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 899GLAPI OSMESAproc GLAPIENTRY 900OSMesaGetProcAddress(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 911GLAPI void GLAPIENTRY 912OSMesaColorClamp(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 921GLAPI void GLAPIENTRY 922OSMesaPostprocess(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} 943