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