1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26/* 27 * Off-Screen Mesa rendering / Rendering into client memory space 28 * 29 * Note on thread safety: this driver is thread safe. All 30 * functions are reentrant. The notion of current context is 31 * managed by the core _mesa_make_current() and _mesa_get_current_context() 32 * functions. Those functions are thread-safe. 33 */ 34 35 36#include <stdio.h> 37#include "main/glheader.h" 38#include "GL/osmesa.h" 39#include "main/api_exec.h" 40#include "main/context.h" 41#include "main/extensions.h" 42#include "main/formats.h" 43#include "main/framebuffer.h" 44#include "main/imports.h" 45#include "main/macros.h" 46#include "main/mipmap.h" 47#include "main/mtypes.h" 48#include "main/renderbuffer.h" 49#include "main/version.h" 50#include "main/vtxfmt.h" 51#include "swrast/swrast.h" 52#include "swrast_setup/swrast_setup.h" 53#include "swrast/s_context.h" 54#include "swrast/s_lines.h" 55#include "swrast/s_renderbuffer.h" 56#include "swrast/s_triangle.h" 57#include "tnl/tnl.h" 58#include "tnl/t_context.h" 59#include "tnl/t_pipeline.h" 60#include "drivers/common/driverfuncs.h" 61#include "drivers/common/meta.h" 62#include "vbo/vbo.h" 63 64 65#define OSMESA_RENDERBUFFER_CLASS 0x053 66 67 68/** 69 * OSMesa rendering context, derived from core Mesa struct gl_context. 70 */ 71struct osmesa_context 72{ 73 struct gl_context mesa; /*< Base class - this must be first */ 74 struct gl_config *gl_visual; /*< Describes the buffers */ 75 struct swrast_renderbuffer *srb; /*< The user's colorbuffer */ 76 struct gl_framebuffer *gl_buffer; /*< The framebuffer, containing user's rb */ 77 GLenum format; /*< User-specified context format */ 78 GLint userRowLength; /*< user-specified number of pixels per row */ 79 GLint rInd, gInd, bInd, aInd;/*< index offsets for RGBA formats */ 80 GLvoid *rowaddr[SWRAST_MAX_HEIGHT]; /*< address of first pixel in each image row */ 81 GLboolean yup; /*< TRUE -> Y increases upward */ 82 /*< FALSE -> Y increases downward */ 83 GLenum DataType; 84}; 85 86 87static inline OSMesaContext 88OSMESA_CONTEXT(struct gl_context *ctx) 89{ 90 /* Just cast, since we're using structure containment */ 91 return (OSMesaContext) ctx; 92} 93 94 95/**********************************************************************/ 96/*** Private Device Driver Functions ***/ 97/**********************************************************************/ 98 99 100static const GLubyte * 101get_string( struct gl_context *ctx, GLenum name ) 102{ 103 (void) ctx; 104 switch (name) { 105 case GL_RENDERER: 106#if CHAN_BITS == 32 107 return (const GLubyte *) "Mesa OffScreen32"; 108#elif CHAN_BITS == 16 109 return (const GLubyte *) "Mesa OffScreen16"; 110#else 111 return (const GLubyte *) "Mesa OffScreen"; 112#endif 113 default: 114 return NULL; 115 } 116} 117 118 119static void 120osmesa_update_state(struct gl_context *ctx, GLuint new_state) 121{ 122 if (new_state & (_NEW_SCISSOR | _NEW_BUFFERS | _NEW_VIEWPORT)) 123 _mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer); 124 125 /* easy - just propogate */ 126 _swrast_InvalidateState( ctx, new_state ); 127 _swsetup_InvalidateState( ctx, new_state ); 128 _tnl_InvalidateState( ctx, new_state ); 129} 130 131static void 132osmesa_update_state_wrapper(struct gl_context *ctx) 133{ 134 osmesa_update_state(ctx, ctx->NewState); 135} 136 137 138/** 139 * Macros for optimized line/triangle rendering. 140 * Only for 8-bit channel, RGBA, BGRA, ARGB formats. 141 */ 142 143#define PACK_RGBA(DST, R, G, B, A) \ 144do { \ 145 (DST)[osmesa->rInd] = R; \ 146 (DST)[osmesa->gInd] = G; \ 147 (DST)[osmesa->bInd] = B; \ 148 (DST)[osmesa->aInd] = A; \ 149} while (0) 150 151#define PIXELADDR4(X,Y) ((GLchan *) osmesa->rowaddr[Y] + 4 * (X)) 152 153 154/** 155 * Draw a flat-shaded, RGB line into an osmesa buffer. 156 */ 157#define NAME flat_rgba_line 158#define CLIP_HACK 1 159#define SETUP_CODE \ 160 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); \ 161 const GLchan *color = vert1->color; 162 163#define PLOT(X, Y) \ 164do { \ 165 GLchan *p = PIXELADDR4(X, Y); \ 166 PACK_RGBA(p, color[0], color[1], color[2], color[3]); \ 167} while (0) 168 169#include "swrast/s_linetemp.h" 170 171 172 173/** 174 * Draw a flat-shaded, Z-less, RGB line into an osmesa buffer. 175 */ 176#define NAME flat_rgba_z_line 177#define CLIP_HACK 1 178#define INTERP_Z 1 179#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE 180#define SETUP_CODE \ 181 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); \ 182 const GLchan *color = vert1->color; 183 184#define PLOT(X, Y) \ 185do { \ 186 if (Z < *zPtr) { \ 187 GLchan *p = PIXELADDR4(X, Y); \ 188 PACK_RGBA(p, color[RCOMP], color[GCOMP], \ 189 color[BCOMP], color[ACOMP]); \ 190 *zPtr = Z; \ 191 } \ 192} while (0) 193 194#include "swrast/s_linetemp.h" 195 196 197 198/** 199 * Analyze context state to see if we can provide a fast line drawing 200 * function. Otherwise, return NULL. 201 */ 202static swrast_line_func 203osmesa_choose_line_function( struct gl_context *ctx ) 204{ 205 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 206 const SWcontext *swrast = SWRAST_CONTEXT(ctx); 207 208 if (ctx->DrawBuffer && 209 ctx->DrawBuffer->Visual.redBits == 32) { 210 /* the special-case line functions in this file don't work 211 * for float color channels. 212 */ 213 return NULL; 214 } 215 216 if (ctx->RenderMode != GL_RENDER || 217 ctx->Texture._MaxEnabledTexImageUnit == -1 || 218 ctx->Light.ShadeModel != GL_FLAT || 219 ctx->Line.Width != 1.0F || 220 ctx->Line.StippleFlag || 221 ctx->Line.SmoothFlag) { 222 return NULL; 223 } 224 225 if (osmesa->format != OSMESA_RGBA && 226 osmesa->format != OSMESA_BGRA && 227 osmesa->format != OSMESA_ARGB) { 228 return NULL; 229 } 230 231 if (swrast->_RasterMask == DEPTH_BIT 232 && ctx->Depth.Func == GL_LESS 233 && ctx->Depth.Mask == GL_TRUE 234 && ctx->Visual.depthBits == DEFAULT_SOFTWARE_DEPTH_BITS) { 235 return flat_rgba_z_line; 236 } 237 238 if (swrast->_RasterMask == 0) { 239 return flat_rgba_line; 240 } 241 242 return (swrast_line_func) NULL; 243} 244 245 246/**********************************************************************/ 247/***** Optimized triangle rendering *****/ 248/**********************************************************************/ 249 250 251/* 252 * Smooth-shaded, z-less triangle, RGBA color. 253 */ 254#define NAME smooth_rgba_z_triangle 255#define INTERP_Z 1 256#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE 257#define INTERP_RGB 1 258#define INTERP_ALPHA 1 259#define SETUP_CODE \ 260 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 261#define RENDER_SPAN( span ) { \ 262 GLuint i; \ 263 GLchan *img = PIXELADDR4(span.x, span.y); \ 264 for (i = 0; i < span.end; i++, img += 4) { \ 265 const GLuint z = FixedToDepth(span.z); \ 266 if (z < zRow[i]) { \ 267 PACK_RGBA(img, FixedToChan(span.red), \ 268 FixedToChan(span.green), FixedToChan(span.blue), \ 269 FixedToChan(span.alpha)); \ 270 zRow[i] = z; \ 271 } \ 272 span.red += span.redStep; \ 273 span.green += span.greenStep; \ 274 span.blue += span.blueStep; \ 275 span.alpha += span.alphaStep; \ 276 span.z += span.zStep; \ 277 } \ 278} 279#include "swrast/s_tritemp.h" 280 281 282 283/* 284 * Flat-shaded, z-less triangle, RGBA color. 285 */ 286#define NAME flat_rgba_z_triangle 287#define INTERP_Z 1 288#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE 289#define SETUP_CODE \ 290 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); \ 291 GLuint pixel; \ 292 PACK_RGBA((GLchan *) &pixel, v2->color[0], v2->color[1], \ 293 v2->color[2], v2->color[3]); 294 295#define RENDER_SPAN( span ) { \ 296 GLuint i; \ 297 GLuint *img = (GLuint *) PIXELADDR4(span.x, span.y); \ 298 for (i = 0; i < span.end; i++) { \ 299 const GLuint z = FixedToDepth(span.z); \ 300 if (z < zRow[i]) { \ 301 img[i] = pixel; \ 302 zRow[i] = z; \ 303 } \ 304 span.z += span.zStep; \ 305 } \ 306} 307 308#include "swrast/s_tritemp.h" 309 310 311 312/** 313 * Return pointer to an optimized triangle function if possible. 314 */ 315static swrast_tri_func 316osmesa_choose_triangle_function( struct gl_context *ctx ) 317{ 318 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 319 const SWcontext *swrast = SWRAST_CONTEXT(ctx); 320 321 if (ctx->DrawBuffer && 322 ctx->DrawBuffer->Visual.redBits == 32) { 323 /* the special-case triangle functions in this file don't work 324 * for float color channels. 325 */ 326 return NULL; 327 } 328 329 if (ctx->RenderMode != GL_RENDER || 330 ctx->Polygon.SmoothFlag || 331 ctx->Polygon.StippleFlag || 332 ctx->Texture._MaxEnabledTexImageUnit != -1) { 333 return NULL; 334 } 335 336 if (osmesa->format != OSMESA_RGBA && 337 osmesa->format != OSMESA_BGRA && 338 osmesa->format != OSMESA_ARGB) { 339 return NULL; 340 } 341 342 if (ctx->Polygon.CullFlag && 343 ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK) { 344 return NULL; 345 } 346 347 if (swrast->_RasterMask == DEPTH_BIT && 348 ctx->Depth.Func == GL_LESS && 349 ctx->Depth.Mask == GL_TRUE && 350 ctx->Visual.depthBits == DEFAULT_SOFTWARE_DEPTH_BITS) { 351 if (ctx->Light.ShadeModel == GL_SMOOTH) { 352 return smooth_rgba_z_triangle; 353 } 354 else { 355 return flat_rgba_z_triangle; 356 } 357 } 358 359 return NULL; 360} 361 362 363 364/* Override for the swrast triangle-selection function. Try to use one 365 * of our internal triangle functions, otherwise fall back to the 366 * standard swrast functions. 367 */ 368static void 369osmesa_choose_triangle( struct gl_context *ctx ) 370{ 371 SWcontext *swrast = SWRAST_CONTEXT(ctx); 372 373 swrast->Triangle = osmesa_choose_triangle_function( ctx ); 374 if (!swrast->Triangle) 375 _swrast_choose_triangle( ctx ); 376} 377 378static void 379osmesa_choose_line( struct gl_context *ctx ) 380{ 381 SWcontext *swrast = SWRAST_CONTEXT(ctx); 382 383 swrast->Line = osmesa_choose_line_function( ctx ); 384 if (!swrast->Line) 385 _swrast_choose_line( ctx ); 386} 387 388 389 390/** 391 * Recompute the values of the context's rowaddr array. 392 */ 393static void 394compute_row_addresses( OSMesaContext osmesa ) 395{ 396 GLint bytesPerRow, i; 397 GLubyte *origin = (GLubyte *) osmesa->srb->Buffer; 398 GLint rowlength; /* in pixels */ 399 GLint height = osmesa->srb->Base.Height; 400 401 if (osmesa->userRowLength) 402 rowlength = osmesa->userRowLength; 403 else 404 rowlength = osmesa->srb->Base.Width; 405 406 bytesPerRow = rowlength * _mesa_get_format_bytes(osmesa->srb->Base.Format); 407 408 if (osmesa->yup) { 409 /* Y=0 is bottom line of window */ 410 for (i = 0; i < height; i++) { 411 osmesa->rowaddr[i] = (GLvoid *) ((GLubyte *) origin + i * bytesPerRow); 412 } 413 } 414 else { 415 /* Y=0 is top line of window */ 416 for (i = 0; i < height; i++) { 417 GLint j = height - i - 1; 418 osmesa->rowaddr[i] = (GLvoid *) ((GLubyte *) origin + j * bytesPerRow); 419 } 420 } 421} 422 423 424 425/** 426 * Don't use _mesa_delete_renderbuffer since we can't free rb->Buffer. 427 */ 428static void 429osmesa_delete_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb) 430{ 431 _mesa_delete_renderbuffer(ctx, rb); 432} 433 434 435/** 436 * Allocate renderbuffer storage. We don't actually allocate any storage 437 * since we're using a user-provided buffer. 438 * Just set up all the gl_renderbuffer methods. 439 */ 440static GLboolean 441osmesa_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, 442 GLenum internalFormat, GLuint width, GLuint height) 443{ 444 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 445 446 /* Note: we can ignoring internalFormat for "window-system" renderbuffers */ 447 (void) internalFormat; 448 449 /* Given the user-provided format and type, figure out which MESA_FORMAT_x 450 * to use. 451 * XXX There aren't Mesa formats for all the possible combinations here! 452 * XXX Specifically, there's only RGBA-order 16-bit/channel and float 453 * XXX formats. 454 * XXX The 8-bit/channel formats should all be OK. 455 */ 456 if (osmesa->format == OSMESA_RGBA) { 457 if (osmesa->DataType == GL_UNSIGNED_BYTE) { 458 if (_mesa_little_endian()) 459 rb->Format = MESA_FORMAT_R8G8B8A8_UNORM; 460 else 461 rb->Format = MESA_FORMAT_A8B8G8R8_UNORM; 462 } 463 else if (osmesa->DataType == GL_UNSIGNED_SHORT) { 464 rb->Format = MESA_FORMAT_RGBA_UNORM16; 465 } 466 else { 467 rb->Format = MESA_FORMAT_RGBA_FLOAT32; 468 } 469 } 470 else if (osmesa->format == OSMESA_BGRA) { 471 if (osmesa->DataType == GL_UNSIGNED_BYTE) { 472 if (_mesa_little_endian()) 473 rb->Format = MESA_FORMAT_B8G8R8A8_UNORM; 474 else 475 rb->Format = MESA_FORMAT_A8R8G8B8_UNORM; 476 } 477 else if (osmesa->DataType == GL_UNSIGNED_SHORT) { 478 _mesa_warning(ctx, "Unsupported OSMesa format BGRA/GLushort"); 479 rb->Format = MESA_FORMAT_RGBA_UNORM16; /* not exactly right */ 480 } 481 else { 482 _mesa_warning(ctx, "Unsupported OSMesa format BGRA/GLfloat"); 483 rb->Format = MESA_FORMAT_RGBA_FLOAT32; /* not exactly right */ 484 } 485 } 486 else if (osmesa->format == OSMESA_ARGB) { 487 if (osmesa->DataType == GL_UNSIGNED_BYTE) { 488 if (_mesa_little_endian()) 489 rb->Format = MESA_FORMAT_A8R8G8B8_UNORM; 490 else 491 rb->Format = MESA_FORMAT_B8G8R8A8_UNORM; 492 } 493 else if (osmesa->DataType == GL_UNSIGNED_SHORT) { 494 _mesa_warning(ctx, "Unsupported OSMesa format ARGB/GLushort"); 495 rb->Format = MESA_FORMAT_RGBA_UNORM16; /* not exactly right */ 496 } 497 else { 498 _mesa_warning(ctx, "Unsupported OSMesa format ARGB/GLfloat"); 499 rb->Format = MESA_FORMAT_RGBA_FLOAT32; /* not exactly right */ 500 } 501 } 502 else if (osmesa->format == OSMESA_RGB) { 503 if (osmesa->DataType == GL_UNSIGNED_BYTE) { 504 rb->Format = MESA_FORMAT_BGR_UNORM8; 505 } 506 else if (osmesa->DataType == GL_UNSIGNED_SHORT) { 507 _mesa_warning(ctx, "Unsupported OSMesa format RGB/GLushort"); 508 rb->Format = MESA_FORMAT_RGBA_UNORM16; /* not exactly right */ 509 } 510 else { 511 _mesa_warning(ctx, "Unsupported OSMesa format RGB/GLfloat"); 512 rb->Format = MESA_FORMAT_RGBA_FLOAT32; /* not exactly right */ 513 } 514 } 515 else if (osmesa->format == OSMESA_BGR) { 516 if (osmesa->DataType == GL_UNSIGNED_BYTE) { 517 rb->Format = MESA_FORMAT_RGB_UNORM8; 518 } 519 else if (osmesa->DataType == GL_UNSIGNED_SHORT) { 520 _mesa_warning(ctx, "Unsupported OSMesa format BGR/GLushort"); 521 rb->Format = MESA_FORMAT_RGBA_UNORM16; /* not exactly right */ 522 } 523 else { 524 _mesa_warning(ctx, "Unsupported OSMesa format BGR/GLfloat"); 525 rb->Format = MESA_FORMAT_RGBA_FLOAT32; /* not exactly right */ 526 } 527 } 528 else if (osmesa->format == OSMESA_RGB_565) { 529 assert(osmesa->DataType == GL_UNSIGNED_BYTE); 530 rb->Format = MESA_FORMAT_B5G6R5_UNORM; 531 } 532 else { 533 _mesa_problem(ctx, "bad pixel format in osmesa renderbuffer_storage"); 534 } 535 536 rb->Width = width; 537 rb->Height = height; 538 539 compute_row_addresses( osmesa ); 540 541 return GL_TRUE; 542} 543 544 545/** 546 * Allocate a new renderbuffer to describe the user-provided color buffer. 547 */ 548static struct swrast_renderbuffer * 549new_osmesa_renderbuffer(struct gl_context *ctx, GLenum format, GLenum type) 550{ 551 const GLuint name = 0; 552 struct swrast_renderbuffer *srb = CALLOC_STRUCT(swrast_renderbuffer); 553 554 if (srb) { 555 _mesa_init_renderbuffer(&srb->Base, name); 556 557 srb->Base.ClassID = OSMESA_RENDERBUFFER_CLASS; 558 srb->Base.Delete = osmesa_delete_renderbuffer; 559 srb->Base.AllocStorage = osmesa_renderbuffer_storage; 560 561 srb->Base.InternalFormat = GL_RGBA; 562 srb->Base._BaseFormat = GL_RGBA; 563 564 return srb; 565 } 566 return NULL; 567} 568 569 570 571static void 572osmesa_MapRenderbuffer(struct gl_context *ctx, 573 struct gl_renderbuffer *rb, 574 GLuint x, GLuint y, GLuint w, GLuint h, 575 GLbitfield mode, 576 GLubyte **mapOut, GLint *rowStrideOut, 577 bool flip_y) 578{ 579 const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); 580 581 if (rb->ClassID == OSMESA_RENDERBUFFER_CLASS) { 582 /* this is an OSMesa renderbuffer which wraps user memory */ 583 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); 584 const GLuint bpp = _mesa_get_format_bytes(rb->Format); 585 GLint rowStride; /* in bytes */ 586 587 if (osmesa->userRowLength) 588 rowStride = osmesa->userRowLength * bpp; 589 else 590 rowStride = rb->Width * bpp; 591 592 if (!osmesa->yup) { 593 /* Y=0 is top line of window */ 594 y = rb->Height - y - 1; 595 *rowStrideOut = -rowStride; 596 } 597 else { 598 *rowStrideOut = rowStride; 599 } 600 601 *mapOut = (GLubyte *) srb->Buffer + y * rowStride + x * bpp; 602 } 603 else { 604 _swrast_map_soft_renderbuffer(ctx, rb, x, y, w, h, mode, 605 mapOut, rowStrideOut, flip_y); 606 } 607} 608 609 610static void 611osmesa_UnmapRenderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb) 612{ 613 if (rb->ClassID == OSMESA_RENDERBUFFER_CLASS) { 614 /* no-op */ 615 } 616 else { 617 _swrast_unmap_soft_renderbuffer(ctx, rb); 618 } 619} 620 621 622/**********************************************************************/ 623/***** Public Functions *****/ 624/**********************************************************************/ 625 626 627/** 628 * Create an Off-Screen Mesa rendering context. The only attribute needed is 629 * an RGBA vs Color-Index mode flag. 630 * 631 * Input: format - Must be GL_RGBA 632 * sharelist - specifies another OSMesaContext with which to share 633 * display lists. NULL indicates no sharing. 634 * Return: an OSMesaContext or 0 if error 635 */ 636GLAPI OSMesaContext GLAPIENTRY 637OSMesaCreateContext( GLenum format, OSMesaContext sharelist ) 638{ 639 return OSMesaCreateContextExt(format, DEFAULT_SOFTWARE_DEPTH_BITS, 640 8, 0, sharelist); 641} 642 643 644 645/** 646 * New in Mesa 3.5 647 * 648 * Create context and specify size of ancillary buffers. 649 */ 650GLAPI OSMesaContext GLAPIENTRY 651OSMesaCreateContextExt( GLenum format, GLint depthBits, GLint stencilBits, 652 GLint accumBits, OSMesaContext sharelist ) 653{ 654 int attribs[100], n = 0; 655 656 attribs[n++] = OSMESA_FORMAT; 657 attribs[n++] = format; 658 attribs[n++] = OSMESA_DEPTH_BITS; 659 attribs[n++] = depthBits; 660 attribs[n++] = OSMESA_STENCIL_BITS; 661 attribs[n++] = stencilBits; 662 attribs[n++] = OSMESA_ACCUM_BITS; 663 attribs[n++] = accumBits; 664 attribs[n++] = 0; 665 666 return OSMesaCreateContextAttribs(attribs, sharelist); 667} 668 669 670/** 671 * New in Mesa 11.2 672 * 673 * Create context with attribute list. 674 */ 675GLAPI OSMesaContext GLAPIENTRY 676OSMesaCreateContextAttribs(const int *attribList, OSMesaContext sharelist) 677{ 678 OSMesaContext osmesa; 679 struct dd_function_table functions; 680 GLint rind, gind, bind, aind; 681 GLint redBits = 0, greenBits = 0, blueBits = 0, alphaBits =0; 682 GLenum format = OSMESA_RGBA; 683 GLint depthBits = 0, stencilBits = 0, accumBits = 0; 684 int profile = OSMESA_COMPAT_PROFILE, version_major = 1, version_minor = 0; 685 gl_api api_profile = API_OPENGL_COMPAT; 686 int i; 687 688 for (i = 0; attribList[i]; i += 2) { 689 switch (attribList[i]) { 690 case OSMESA_FORMAT: 691 format = attribList[i+1]; 692 switch (format) { 693 case OSMESA_COLOR_INDEX: 694 case OSMESA_RGBA: 695 case OSMESA_BGRA: 696 case OSMESA_ARGB: 697 case OSMESA_RGB: 698 case OSMESA_BGR: 699 case OSMESA_RGB_565: 700 /* legal */ 701 break; 702 default: 703 return NULL; 704 } 705 break; 706 case OSMESA_DEPTH_BITS: 707 depthBits = attribList[i+1]; 708 if (depthBits < 0) 709 return NULL; 710 break; 711 case OSMESA_STENCIL_BITS: 712 stencilBits = attribList[i+1]; 713 if (stencilBits < 0) 714 return NULL; 715 break; 716 case OSMESA_ACCUM_BITS: 717 accumBits = attribList[i+1]; 718 if (accumBits < 0) 719 return NULL; 720 break; 721 case OSMESA_PROFILE: 722 profile = attribList[i+1]; 723 if (profile == OSMESA_COMPAT_PROFILE) 724 api_profile = API_OPENGL_COMPAT; 725 else if (profile == OSMESA_CORE_PROFILE) 726 api_profile = API_OPENGL_CORE; 727 else 728 return NULL; 729 break; 730 case OSMESA_CONTEXT_MAJOR_VERSION: 731 version_major = attribList[i+1]; 732 if (version_major < 1) 733 return NULL; 734 break; 735 case OSMESA_CONTEXT_MINOR_VERSION: 736 version_minor = attribList[i+1]; 737 if (version_minor < 0) 738 return NULL; 739 break; 740 case 0: 741 /* end of list */ 742 break; 743 default: 744 fprintf(stderr, "Bad attribute in OSMesaCreateContextAttribs()\n"); 745 return NULL; 746 } 747 } 748 749 rind = gind = bind = aind = 0; 750 if (format==OSMESA_RGBA) { 751 redBits = CHAN_BITS; 752 greenBits = CHAN_BITS; 753 blueBits = CHAN_BITS; 754 alphaBits = CHAN_BITS; 755 rind = 0; 756 gind = 1; 757 bind = 2; 758 aind = 3; 759 } 760 else if (format==OSMESA_BGRA) { 761 redBits = CHAN_BITS; 762 greenBits = CHAN_BITS; 763 blueBits = CHAN_BITS; 764 alphaBits = CHAN_BITS; 765 bind = 0; 766 gind = 1; 767 rind = 2; 768 aind = 3; 769 } 770 else if (format==OSMESA_ARGB) { 771 redBits = CHAN_BITS; 772 greenBits = CHAN_BITS; 773 blueBits = CHAN_BITS; 774 alphaBits = CHAN_BITS; 775 aind = 0; 776 rind = 1; 777 gind = 2; 778 bind = 3; 779 } 780 else if (format==OSMESA_RGB) { 781 redBits = CHAN_BITS; 782 greenBits = CHAN_BITS; 783 blueBits = CHAN_BITS; 784 alphaBits = 0; 785 rind = 0; 786 gind = 1; 787 bind = 2; 788 } 789 else if (format==OSMESA_BGR) { 790 redBits = CHAN_BITS; 791 greenBits = CHAN_BITS; 792 blueBits = CHAN_BITS; 793 alphaBits = 0; 794 rind = 2; 795 gind = 1; 796 bind = 0; 797 } 798#if CHAN_TYPE == GL_UNSIGNED_BYTE 799 else if (format==OSMESA_RGB_565) { 800 redBits = 5; 801 greenBits = 6; 802 blueBits = 5; 803 alphaBits = 0; 804 rind = 0; /* not used */ 805 gind = 0; 806 bind = 0; 807 } 808#endif 809 else { 810 return NULL; 811 } 812 813 osmesa = (OSMesaContext) CALLOC_STRUCT(osmesa_context); 814 if (osmesa) { 815 osmesa->gl_visual = _mesa_create_visual( GL_FALSE, /* double buffer */ 816 GL_FALSE, /* stereo */ 817 redBits, 818 greenBits, 819 blueBits, 820 alphaBits, 821 depthBits, 822 stencilBits, 823 accumBits, 824 accumBits, 825 accumBits, 826 alphaBits ? accumBits : 0, 827 1 /* num samples */ 828 ); 829 if (!osmesa->gl_visual) { 830 free(osmesa); 831 return NULL; 832 } 833 834 /* Initialize device driver function table */ 835 _mesa_init_driver_functions(&functions); 836 _tnl_init_driver_draw_function(&functions); 837 /* override with our functions */ 838 functions.GetString = get_string; 839 functions.UpdateState = osmesa_update_state_wrapper; 840 841 if (!_mesa_initialize_context(&osmesa->mesa, 842 api_profile, 843 osmesa->gl_visual, 844 sharelist ? &sharelist->mesa 845 : (struct gl_context *) NULL, 846 &functions)) { 847 _mesa_destroy_visual( osmesa->gl_visual ); 848 free(osmesa); 849 return NULL; 850 } 851 852 _mesa_enable_sw_extensions(&(osmesa->mesa)); 853 854 osmesa->gl_buffer = _mesa_create_framebuffer(osmesa->gl_visual); 855 if (!osmesa->gl_buffer) { 856 _mesa_destroy_visual( osmesa->gl_visual ); 857 _mesa_free_context_data(&osmesa->mesa, true); 858 free(osmesa); 859 return NULL; 860 } 861 862 /* Create depth/stencil/accum buffers. We'll create the color 863 * buffer later in OSMesaMakeCurrent(). 864 */ 865 _swrast_add_soft_renderbuffers(osmesa->gl_buffer, 866 GL_FALSE, /* color */ 867 osmesa->gl_visual->haveDepthBuffer, 868 osmesa->gl_visual->haveStencilBuffer, 869 osmesa->gl_visual->haveAccumBuffer, 870 GL_FALSE, /* alpha */ 871 GL_FALSE /* aux */ ); 872 873 osmesa->format = format; 874 osmesa->userRowLength = 0; 875 osmesa->yup = GL_TRUE; 876 osmesa->rInd = rind; 877 osmesa->gInd = gind; 878 osmesa->bInd = bind; 879 osmesa->aInd = aind; 880 881 _mesa_meta_init(&osmesa->mesa); 882 883 /* Initialize the software rasterizer and helper modules. */ 884 { 885 struct gl_context *ctx = &osmesa->mesa; 886 SWcontext *swrast; 887 TNLcontext *tnl; 888 889 if (!_swrast_CreateContext( ctx ) || 890 !_vbo_CreateContext( ctx ) || 891 !_tnl_CreateContext( ctx ) || 892 !_swsetup_CreateContext( ctx )) { 893 _mesa_destroy_visual(osmesa->gl_visual); 894 _mesa_free_context_data(ctx, true); 895 free(osmesa); 896 return NULL; 897 } 898 899 _swsetup_Wakeup( ctx ); 900 901 /* use default TCL pipeline */ 902 tnl = TNL_CONTEXT(ctx); 903 tnl->Driver.RunPipeline = _tnl_run_pipeline; 904 905 ctx->Driver.MapRenderbuffer = osmesa_MapRenderbuffer; 906 ctx->Driver.UnmapRenderbuffer = osmesa_UnmapRenderbuffer; 907 908 ctx->Driver.GenerateMipmap = _mesa_generate_mipmap; 909 910 /* Extend the software rasterizer with our optimized line and triangle 911 * drawing functions. 912 */ 913 swrast = SWRAST_CONTEXT( ctx ); 914 swrast->choose_line = osmesa_choose_line; 915 swrast->choose_triangle = osmesa_choose_triangle; 916 917 _mesa_override_extensions(ctx); 918 _mesa_compute_version(ctx); 919 920 if (ctx->Version < version_major * 10 + version_minor) { 921 _mesa_destroy_visual(osmesa->gl_visual); 922 _mesa_free_context_data(ctx, true); 923 free(osmesa); 924 return NULL; 925 } 926 927 /* Exec table initialization requires the version to be computed */ 928 _mesa_initialize_dispatch_tables(ctx); 929 _mesa_initialize_vbo_vtxfmt(ctx); 930 } 931 } 932 return osmesa; 933} 934 935 936/** 937 * Destroy an Off-Screen Mesa rendering context. 938 * 939 * \param osmesa the context to destroy 940 */ 941GLAPI void GLAPIENTRY 942OSMesaDestroyContext( OSMesaContext osmesa ) 943{ 944 if (osmesa) { 945 if (osmesa->srb) 946 _mesa_reference_renderbuffer((struct gl_renderbuffer **) &osmesa->srb, NULL); 947 948 _mesa_meta_free( &osmesa->mesa ); 949 950 _swsetup_DestroyContext( &osmesa->mesa ); 951 _tnl_DestroyContext( &osmesa->mesa ); 952 _vbo_DestroyContext( &osmesa->mesa ); 953 _swrast_DestroyContext( &osmesa->mesa ); 954 955 _mesa_destroy_visual( osmesa->gl_visual ); 956 _mesa_reference_framebuffer( &osmesa->gl_buffer, NULL ); 957 958 _mesa_free_context_data(&osmesa->mesa, true); 959 free( osmesa ); 960 } 961} 962 963 964/** 965 * Bind an OSMesaContext to an image buffer. The image buffer is just a 966 * block of memory which the client provides. Its size must be at least 967 * as large as width*height*sizeof(type). Its address should be a multiple 968 * of 4 if using RGBA mode. 969 * 970 * Image data is stored in the order of glDrawPixels: row-major order 971 * with the lower-left image pixel stored in the first array position 972 * (ie. bottom-to-top). 973 * 974 * If the context's viewport hasn't been initialized yet, it will now be 975 * initialized to (0,0,width,height). 976 * 977 * If both the context and the buffer are null, the current context will be 978 * unbound. 979 * 980 * Input: osmesa - the rendering context 981 * buffer - the image buffer memory 982 * type - data type for pixel components 983 * Normally, only GL_UNSIGNED_BYTE and GL_UNSIGNED_SHORT_5_6_5 984 * are supported. But if Mesa's been compiled with CHAN_BITS==16 985 * then type may be GL_UNSIGNED_SHORT or GL_UNSIGNED_BYTE. And if 986 * Mesa's been build with CHAN_BITS==32 then type may be GL_FLOAT, 987 * GL_UNSIGNED_SHORT or GL_UNSIGNED_BYTE. 988 * width, height - size of image buffer in pixels, at least 1 989 * Return: GL_TRUE if success, GL_FALSE if error because of invalid osmesa, 990 * invalid buffer address, invalid type, width<1, height<1, 991 * width>internal limit or height>internal limit. 992 */ 993GLAPI GLboolean GLAPIENTRY 994OSMesaMakeCurrent( OSMesaContext osmesa, void *buffer, GLenum type, 995 GLsizei width, GLsizei height ) 996{ 997 if (!osmesa && !buffer) { 998 return _mesa_make_current(NULL, NULL, NULL); 999 } 1000 1001 if (!osmesa || !buffer || 1002 width < 1 || height < 1 || 1003 width > SWRAST_MAX_WIDTH || height > SWRAST_MAX_HEIGHT) { 1004 return GL_FALSE; 1005 } 1006 1007 if (osmesa->format == OSMESA_RGB_565 && type != GL_UNSIGNED_SHORT_5_6_5) { 1008 return GL_FALSE; 1009 } 1010 1011#if 0 1012 if (!(type == GL_UNSIGNED_BYTE || 1013 (type == GL_UNSIGNED_SHORT && CHAN_BITS >= 16) || 1014 (type == GL_FLOAT && CHAN_BITS == 32))) { 1015 /* i.e. is sizeof(type) * 8 > CHAN_BITS? */ 1016 return GL_FALSE; 1017 } 1018#endif 1019 1020 osmesa_update_state( &osmesa->mesa, 0 ); 1021 1022 /* Create a front/left color buffer which wraps the user-provided buffer. 1023 * There is no back color buffer. 1024 * If the user tries to use a 8, 16 or 32-bit/channel buffer that 1025 * doesn't match what Mesa was compiled for (CHAN_BITS) the 1026 * _mesa_attach_and_reference_rb() function will create a "wrapper" 1027 * renderbuffer that converts rendering from CHAN_BITS to the 1028 * user-requested channel size. 1029 */ 1030 if (!osmesa->srb) { 1031 osmesa->srb = new_osmesa_renderbuffer(&osmesa->mesa, osmesa->format, type); 1032 _mesa_remove_renderbuffer(osmesa->gl_buffer, BUFFER_FRONT_LEFT); 1033 _mesa_attach_and_reference_rb(osmesa->gl_buffer, BUFFER_FRONT_LEFT, 1034 &osmesa->srb->Base); 1035 assert(osmesa->srb->Base.RefCount == 2); 1036 } 1037 1038 osmesa->DataType = type; 1039 1040 /* Set renderbuffer fields. Set width/height = 0 to force 1041 * osmesa_renderbuffer_storage() being called by _mesa_resize_framebuffer() 1042 */ 1043 osmesa->srb->Buffer = buffer; 1044 osmesa->srb->Base.Width = osmesa->srb->Base.Height = 0; 1045 1046 /* Set the framebuffer's size. This causes the 1047 * osmesa_renderbuffer_storage() function to get called. 1048 */ 1049 _mesa_resize_framebuffer(&osmesa->mesa, osmesa->gl_buffer, width, height); 1050 1051 _mesa_make_current( &osmesa->mesa, osmesa->gl_buffer, osmesa->gl_buffer ); 1052 1053 /* Remove renderbuffer attachment, then re-add. This installs the 1054 * renderbuffer adaptor/wrapper if needed (for bpp conversion). 1055 */ 1056 _mesa_remove_renderbuffer(osmesa->gl_buffer, BUFFER_FRONT_LEFT); 1057 _mesa_attach_and_reference_rb(osmesa->gl_buffer, BUFFER_FRONT_LEFT, 1058 &osmesa->srb->Base); 1059 1060 1061 /* this updates the visual's red/green/blue/alphaBits fields */ 1062 _mesa_update_framebuffer_visual(&osmesa->mesa, osmesa->gl_buffer); 1063 1064 /* update the framebuffer size */ 1065 _mesa_resize_framebuffer(&osmesa->mesa, osmesa->gl_buffer, width, height); 1066 1067 return GL_TRUE; 1068} 1069 1070 1071 1072GLAPI OSMesaContext GLAPIENTRY 1073OSMesaGetCurrentContext( void ) 1074{ 1075 struct gl_context *ctx = _mesa_get_current_context(); 1076 if (ctx) 1077 return (OSMesaContext) ctx; 1078 else 1079 return NULL; 1080} 1081 1082 1083 1084GLAPI void GLAPIENTRY 1085OSMesaPixelStore( GLint pname, GLint value ) 1086{ 1087 OSMesaContext osmesa = OSMesaGetCurrentContext(); 1088 1089 switch (pname) { 1090 case OSMESA_ROW_LENGTH: 1091 if (value<0) { 1092 _mesa_error( &osmesa->mesa, GL_INVALID_VALUE, 1093 "OSMesaPixelStore(value)" ); 1094 return; 1095 } 1096 osmesa->userRowLength = value; 1097 break; 1098 case OSMESA_Y_UP: 1099 osmesa->yup = value ? GL_TRUE : GL_FALSE; 1100 break; 1101 default: 1102 _mesa_error( &osmesa->mesa, GL_INVALID_ENUM, "OSMesaPixelStore(pname)" ); 1103 return; 1104 } 1105 1106 compute_row_addresses( osmesa ); 1107} 1108 1109 1110GLAPI void GLAPIENTRY 1111OSMesaGetIntegerv( GLint pname, GLint *value ) 1112{ 1113 OSMesaContext osmesa = OSMesaGetCurrentContext(); 1114 1115 switch (pname) { 1116 case OSMESA_WIDTH: 1117 if (osmesa->gl_buffer) 1118 *value = osmesa->gl_buffer->Width; 1119 else 1120 *value = 0; 1121 return; 1122 case OSMESA_HEIGHT: 1123 if (osmesa->gl_buffer) 1124 *value = osmesa->gl_buffer->Height; 1125 else 1126 *value = 0; 1127 return; 1128 case OSMESA_FORMAT: 1129 *value = osmesa->format; 1130 return; 1131 case OSMESA_TYPE: 1132 /* current color buffer's data type */ 1133 *value = osmesa->DataType; 1134 return; 1135 case OSMESA_ROW_LENGTH: 1136 *value = osmesa->userRowLength; 1137 return; 1138 case OSMESA_Y_UP: 1139 *value = osmesa->yup; 1140 return; 1141 case OSMESA_MAX_WIDTH: 1142 *value = SWRAST_MAX_WIDTH; 1143 return; 1144 case OSMESA_MAX_HEIGHT: 1145 *value = SWRAST_MAX_HEIGHT; 1146 return; 1147 default: 1148 _mesa_error(&osmesa->mesa, GL_INVALID_ENUM, "OSMesaGetIntergerv(pname)"); 1149 return; 1150 } 1151} 1152 1153 1154/** 1155 * Return the depth buffer associated with an OSMesa context. 1156 * Input: c - the OSMesa context 1157 * Output: width, height - size of buffer in pixels 1158 * bytesPerValue - bytes per depth value (2 or 4) 1159 * buffer - pointer to depth buffer values 1160 * Return: GL_TRUE or GL_FALSE to indicate success or failure. 1161 */ 1162GLAPI GLboolean GLAPIENTRY 1163OSMesaGetDepthBuffer( OSMesaContext c, GLint *width, GLint *height, 1164 GLint *bytesPerValue, void **buffer ) 1165{ 1166 struct swrast_renderbuffer *srb = NULL; 1167 1168 if (c->gl_buffer) 1169 srb = swrast_renderbuffer(c->gl_buffer-> 1170 Attachment[BUFFER_DEPTH].Renderbuffer); 1171 1172 if (!srb || !srb->Buffer) { 1173 *width = 0; 1174 *height = 0; 1175 *bytesPerValue = 0; 1176 *buffer = 0; 1177 return GL_FALSE; 1178 } 1179 else { 1180 *width = srb->Base.Width; 1181 *height = srb->Base.Height; 1182 if (c->gl_visual->depthBits <= 16) 1183 *bytesPerValue = sizeof(GLushort); 1184 else 1185 *bytesPerValue = sizeof(GLuint); 1186 *buffer = (void *) srb->Buffer; 1187 return GL_TRUE; 1188 } 1189} 1190 1191 1192/** 1193 * Return the color buffer associated with an OSMesa context. 1194 * Input: c - the OSMesa context 1195 * Output: width, height - size of buffer in pixels 1196 * format - the pixel format (OSMESA_FORMAT) 1197 * buffer - pointer to color buffer values 1198 * Return: GL_TRUE or GL_FALSE to indicate success or failure. 1199 */ 1200GLAPI GLboolean GLAPIENTRY 1201OSMesaGetColorBuffer( OSMesaContext osmesa, GLint *width, 1202 GLint *height, GLint *format, void **buffer ) 1203{ 1204 if (osmesa->srb && osmesa->srb->Buffer) { 1205 *width = osmesa->srb->Base.Width; 1206 *height = osmesa->srb->Base.Height; 1207 *format = osmesa->format; 1208 *buffer = (void *) osmesa->srb->Buffer; 1209 return GL_TRUE; 1210 } 1211 else { 1212 *width = 0; 1213 *height = 0; 1214 *format = 0; 1215 *buffer = 0; 1216 return GL_FALSE; 1217 } 1218} 1219 1220 1221struct name_function 1222{ 1223 const char *Name; 1224 OSMESAproc Function; 1225}; 1226 1227static struct name_function functions[] = { 1228 { "OSMesaCreateContext", (OSMESAproc) OSMesaCreateContext }, 1229 { "OSMesaCreateContextExt", (OSMESAproc) OSMesaCreateContextExt }, 1230 { "OSMesaCreateContextAttribs", (OSMESAproc) OSMesaCreateContextAttribs }, 1231 { "OSMesaDestroyContext", (OSMESAproc) OSMesaDestroyContext }, 1232 { "OSMesaMakeCurrent", (OSMESAproc) OSMesaMakeCurrent }, 1233 { "OSMesaGetCurrentContext", (OSMESAproc) OSMesaGetCurrentContext }, 1234 { "OSMesaPixelStore", (OSMESAproc) OSMesaPixelStore }, 1235 { "OSMesaGetIntegerv", (OSMESAproc) OSMesaGetIntegerv }, 1236 { "OSMesaGetDepthBuffer", (OSMESAproc) OSMesaGetDepthBuffer }, 1237 { "OSMesaGetColorBuffer", (OSMESAproc) OSMesaGetColorBuffer }, 1238 { "OSMesaGetProcAddress", (OSMESAproc) OSMesaGetProcAddress }, 1239 { "OSMesaColorClamp", (OSMESAproc) OSMesaColorClamp }, 1240 { "OSMesaPostprocess", (OSMESAproc) OSMesaPostprocess }, 1241 { NULL, NULL } 1242}; 1243 1244 1245GLAPI OSMESAproc GLAPIENTRY 1246OSMesaGetProcAddress( const char *funcName ) 1247{ 1248 int i; 1249 for (i = 0; functions[i].Name; i++) { 1250 if (strcmp(functions[i].Name, funcName) == 0) 1251 return functions[i].Function; 1252 } 1253 return _glapi_get_proc_address(funcName); 1254} 1255 1256 1257GLAPI void GLAPIENTRY 1258OSMesaColorClamp(GLboolean enable) 1259{ 1260 OSMesaContext osmesa = OSMesaGetCurrentContext(); 1261 1262 if (enable == GL_TRUE) { 1263 osmesa->mesa.Color.ClampFragmentColor = GL_TRUE; 1264 } 1265 else { 1266 osmesa->mesa.Color.ClampFragmentColor = GL_FIXED_ONLY_ARB; 1267 } 1268} 1269 1270 1271GLAPI void GLAPIENTRY 1272OSMesaPostprocess(OSMesaContext osmesa, const char *filter, 1273 unsigned enable_value) 1274{ 1275 fprintf(stderr, 1276 "OSMesaPostProcess() is only available with gallium drivers\n"); 1277} 1278 1279 1280 1281/** 1282 * When GLX_INDIRECT_RENDERING is defined, some symbols are missing in 1283 * libglapi.a. We need to define them here. 1284 */ 1285#ifdef GLX_INDIRECT_RENDERING 1286 1287#define GL_GLEXT_PROTOTYPES 1288#include "GL/gl.h" 1289#include "glapi/glapi.h" 1290#include "glapitable.h" 1291 1292#if defined(USE_MGL_NAMESPACE) 1293#define NAME(func) mgl##func 1294#else 1295#define NAME(func) gl##func 1296#endif 1297 1298#define DISPATCH(FUNC, ARGS, MESSAGE) \ 1299 GET_DISPATCH()->FUNC ARGS 1300 1301#define RETURN_DISPATCH(FUNC, ARGS, MESSAGE) \ 1302 return GET_DISPATCH()->FUNC ARGS 1303 1304/* skip normal ones */ 1305#define _GLAPI_SKIP_NORMAL_ENTRY_POINTS 1306#include "glapitemp.h" 1307 1308#endif /* GLX_INDIRECT_RENDERING */ 1309