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