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