framebuffer.c revision 847160466cb7d1af55f294578c328b01fb3fd3d3
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5 4 * 5 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26/** 27 * Functions for allocating/managing framebuffers and renderbuffers. 28 * Also, routines for reading/writing renderbuffer data as ubytes, 29 * ushorts, uints, etc. 30 */ 31 32 33#include "glheader.h" 34#include "imports.h" 35#include "context.h" 36#include "depthstencil.h" 37#include "mtypes.h" 38#include "fbobject.h" 39#include "framebuffer.h" 40#include "renderbuffer.h" 41 42 43 44/** 45 * Compute/set the _DepthMax field for the given framebuffer. 46 * This value depends on the Z buffer resolution. 47 */ 48static void 49compute_depth_max(struct gl_framebuffer *fb) 50{ 51 if (fb->Visual.depthBits == 0) { 52 /* Special case. Even if we don't have a depth buffer we need 53 * good values for DepthMax for Z vertex transformation purposes 54 * and for per-fragment fog computation. 55 */ 56 fb->_DepthMax = (1 << 16) - 1; 57 } 58 else if (fb->Visual.depthBits < 32) { 59 fb->_DepthMax = (1 << fb->Visual.depthBits) - 1; 60 } 61 else { 62 /* Special case since shift values greater than or equal to the 63 * number of bits in the left hand expression's type are undefined. 64 */ 65 fb->_DepthMax = 0xffffffff; 66 } 67 fb->_DepthMaxF = (GLfloat) fb->_DepthMax; 68 fb->_MRD = 1.0; /* Minimum resolvable depth value, for polygon offset */ 69} 70 71 72/** 73 * Create and initialize a gl_framebuffer object. 74 * This is intended for creating _window_system_ framebuffers, not generic 75 * framebuffer objects ala GL_EXT_framebuffer_object. 76 * 77 * \sa _mesa_new_framebuffer 78 */ 79struct gl_framebuffer * 80_mesa_create_framebuffer(const GLvisual *visual) 81{ 82 struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer); 83 assert(visual); 84 if (fb) { 85 _mesa_initialize_framebuffer(fb, visual); 86 } 87 return fb; 88} 89 90 91/** 92 * Allocate a new gl_framebuffer object. 93 * This is the default function for ctx->Driver.NewFramebuffer(). 94 * This is for allocating user-created framebuffers, not window-system 95 * framebuffers! 96 * \sa _mesa_create_framebuffer 97 */ 98struct gl_framebuffer * 99_mesa_new_framebuffer(GLcontext *ctx, GLuint name) 100{ 101 struct gl_framebuffer *fb; 102 assert(name != 0); 103 fb = CALLOC_STRUCT(gl_framebuffer); 104 if (fb) { 105 fb->Name = name; 106 fb->RefCount = 1; 107 fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT; 108 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_COLOR0; 109 fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT; 110 fb->_ColorReadBufferIndex = BUFFER_COLOR0; 111 fb->Delete = _mesa_destroy_framebuffer; 112 } 113 return fb; 114} 115 116 117/** 118 * Initialize a gl_framebuffer object. Typically used to initialize 119 * window system-created framebuffers, not user-created framebuffers. 120 * \sa _mesa_create_framebuffer 121 */ 122void 123_mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual) 124{ 125 assert(fb); 126 assert(visual); 127 128 _mesa_bzero(fb, sizeof(struct gl_framebuffer)); 129 130 /* save the visual */ 131 fb->Visual = *visual; 132 133 /* Init glRead/DrawBuffer state */ 134 if (visual->doubleBufferMode) { 135 fb->ColorDrawBuffer[0] = GL_BACK; 136 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_BACK_LEFT; 137 fb->ColorReadBuffer = GL_BACK; 138 fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT; 139 } 140 else { 141 fb->ColorDrawBuffer[0] = GL_FRONT; 142 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT; 143 fb->ColorReadBuffer = GL_FRONT; 144 fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT; 145 } 146 147 fb->Delete = _mesa_destroy_framebuffer; 148 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; 149 150 compute_depth_max(fb); 151} 152 153 154/** 155 * Deallocate buffer and everything attached to it. 156 * Typically called via the gl_framebuffer->Delete() method. 157 */ 158void 159_mesa_destroy_framebuffer(struct gl_framebuffer *fb) 160{ 161 if (fb) { 162 _mesa_free_framebuffer_data(fb); 163 _mesa_free(fb); 164 } 165} 166 167 168/** 169 * Free all the data hanging off the given gl_framebuffer, but don't free 170 * the gl_framebuffer object itself. 171 */ 172void 173_mesa_free_framebuffer_data(struct gl_framebuffer *fb) 174{ 175 GLuint i; 176 177 assert(fb); 178 179 for (i = 0; i < BUFFER_COUNT; i++) { 180 struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 181 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) { 182 struct gl_renderbuffer *rb = att->Renderbuffer; 183 rb->RefCount--; 184 if (rb->RefCount == 0) { 185 rb->Delete(rb); 186 } 187 } 188 att->Type = GL_NONE; 189 att->Renderbuffer = NULL; 190 } 191 192 if (fb->_DepthBuffer) { 193 struct gl_renderbuffer *rb = fb->_DepthBuffer; 194 rb->RefCount--; 195 if (rb->RefCount <= 0) { 196 rb->Delete(rb); 197 } 198 fb->_DepthBuffer = NULL; 199 } 200 if (fb->_StencilBuffer) { 201 struct gl_renderbuffer *rb = fb->_StencilBuffer; 202 rb->RefCount--; 203 if (rb->RefCount <= 0) { 204 rb->Delete(rb); 205 } 206 fb->_StencilBuffer = NULL; 207 } 208} 209 210 211/** 212 * Resize the given framebuffer's renderbuffers to the new width and height. 213 * This should only be used for window-system framebuffers, not 214 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object). 215 * This will typically be called via ctx->Driver.ResizeBuffers() or directly 216 * from a device driver. 217 * 218 * \note it's possible for ctx to be null since a window can be resized 219 * without a currently bound rendering context. 220 */ 221void 222_mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb, 223 GLuint width, GLuint height) 224{ 225 GLuint i; 226 227 /* For window system framebuffers, Name is zero */ 228 assert(fb->Name == 0); 229 230 for (i = 0; i < BUFFER_COUNT; i++) { 231 struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 232 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) { 233 struct gl_renderbuffer *rb = att->Renderbuffer; 234 /* only resize if size is changing */ 235 if (rb->Width != width || rb->Height != height) { 236 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { 237 rb->Width = width; 238 rb->Height = height; 239 } 240 else { 241 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); 242 } 243 } 244 } 245 } 246 247 fb->Width = width; 248 fb->Height = height; 249 250 /* to update scissor / window bounds */ 251 if (ctx) 252 ctx->NewState |= _NEW_BUFFERS; 253} 254 255 256/** 257 * Examine all the framebuffer's renderbuffers to update the Width/Height 258 * fields of the framebuffer. If we have renderbuffers with different 259 * sizes, set the framebuffer's width and height to zero. 260 * Note: this is only intended for user-created framebuffers, not 261 * window-system framebuffes. 262 */ 263static void 264update_framebuffer_size(struct gl_framebuffer *fb) 265{ 266 GLboolean haveSize = GL_FALSE; 267 GLuint i; 268 269 /* user-created framebuffers only */ 270 assert(fb->Name); 271 272 for (i = 0; i < BUFFER_COUNT; i++) { 273 struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 274 const struct gl_renderbuffer *rb = att->Renderbuffer; 275 if (rb) { 276 if (haveSize) { 277 if (rb->Width != fb->Width && rb->Height != fb->Height) { 278 /* size mismatch! */ 279 fb->Width = 0; 280 fb->Height = 0; 281 return; 282 } 283 } 284 else { 285 fb->Width = rb->Width; 286 fb->Height = rb->Height; 287 haveSize = GL_TRUE; 288 } 289 } 290 } 291} 292 293 294/** 295 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields. 296 * These values are computed from the buffer's width and height and 297 * the scissor box, if it's enabled. 298 * \param ctx the GL context. 299 */ 300void 301_mesa_update_draw_buffer_bounds(GLcontext *ctx) 302{ 303 struct gl_framebuffer *buffer = ctx->DrawBuffer; 304 305 if (buffer->Name) { 306 /* user-created framebuffer size depends on the renderbuffers */ 307 update_framebuffer_size(buffer); 308 } 309 310 buffer->_Xmin = 0; 311 buffer->_Ymin = 0; 312 buffer->_Xmax = buffer->Width; 313 buffer->_Ymax = buffer->Height; 314 315 if (ctx->Scissor.Enabled) { 316 if (ctx->Scissor.X > buffer->_Xmin) { 317 buffer->_Xmin = ctx->Scissor.X; 318 } 319 if (ctx->Scissor.Y > buffer->_Ymin) { 320 buffer->_Ymin = ctx->Scissor.Y; 321 } 322 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) { 323 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width; 324 } 325 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) { 326 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height; 327 } 328 /* finally, check for empty region */ 329 if (buffer->_Xmin > buffer->_Xmax) { 330 buffer->_Xmin = buffer->_Xmax; 331 } 332 if (buffer->_Ymin > buffer->_Ymax) { 333 buffer->_Ymin = buffer->_Ymax; 334 } 335 } 336 337 ASSERT(buffer->_Xmin <= buffer->_Xmax); 338 ASSERT(buffer->_Ymin <= buffer->_Ymax); 339} 340 341 342/** 343 * The glGet queries of the framebuffer red/green/blue size, stencil size, 344 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can 345 * change depending on the renderbuffer bindings. This function updates 346 * the given framebuffer's Visual from the current renderbuffer bindings. 347 * This is only intended for user-created framebuffers. 348 * 349 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal 350 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits. 351 * The former one is used to convert floating point depth values into 352 * integer Z values. 353 */ 354void 355_mesa_update_framebuffer_visual(struct gl_framebuffer *fb) 356{ 357 GLuint i; 358 359 assert(fb->Name != 0); 360 361 _mesa_bzero(&fb->Visual, sizeof(fb->Visual)); 362 fb->Visual.rgbMode = GL_TRUE; /* assume this */ 363 364 /* find first RGB or CI renderbuffer */ 365 for (i = 0; i < BUFFER_COUNT; i++) { 366 if (fb->Attachment[i].Renderbuffer) { 367 const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; 368 if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) { 369 fb->Visual.redBits = rb->RedBits; 370 fb->Visual.greenBits = rb->GreenBits; 371 fb->Visual.blueBits = rb->BlueBits; 372 fb->Visual.alphaBits = rb->AlphaBits; 373 fb->Visual.rgbBits = fb->Visual.redBits 374 + fb->Visual.greenBits + fb->Visual.blueBits; 375 fb->Visual.floatMode = GL_FALSE; 376 break; 377 } 378 else if (rb->_BaseFormat == GL_COLOR_INDEX) { 379 fb->Visual.indexBits = rb->IndexBits; 380 fb->Visual.rgbMode = GL_FALSE; 381 break; 382 } 383 } 384 } 385 386 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) { 387 fb->Visual.haveDepthBuffer = GL_TRUE; 388 fb->Visual.depthBits 389 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits; 390 } 391 392 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) { 393 fb->Visual.haveStencilBuffer = GL_TRUE; 394 fb->Visual.stencilBits 395 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits; 396 } 397 398 compute_depth_max(fb); 399} 400 401 402/** 403 * Helper function for _mesa_update_framebuffer(). 404 * Set the actual depth renderbuffer for the given framebuffer. 405 * Take care of reference counts, etc. 406 */ 407static void 408set_depth_renderbuffer(struct gl_framebuffer *fb, 409 struct gl_renderbuffer *rb) 410{ 411 if (fb->_DepthBuffer) { 412 fb->_DepthBuffer->RefCount--; 413 if (fb->_DepthBuffer->RefCount <= 0) { 414 fb->_DepthBuffer->Delete(fb->_DepthBuffer); 415 } 416 } 417 fb->_DepthBuffer = rb; 418 if (rb) 419 rb->RefCount++; 420} 421 422/** 423 * \sa set_depth_renderbuffer. 424 */ 425static void 426set_stencil_renderbuffer(struct gl_framebuffer *fb, 427 struct gl_renderbuffer *rb) 428{ 429 if (fb->_StencilBuffer) { 430 fb->_StencilBuffer->RefCount--; 431 if (fb->_StencilBuffer->RefCount <= 0) { 432 fb->_StencilBuffer->Delete(fb->_StencilBuffer); 433 } 434 } 435 fb->_StencilBuffer = rb; 436 if (rb) 437 rb->RefCount++; 438} 439 440 441/** 442 * Update state related to the current draw/read framebuffers. 443 * Specifically, update these framebuffer fields: 444 * _ColorDrawBuffers 445 * _NumColorDrawBuffers 446 * _ColorReadBuffer 447 * If the current framebuffer is user-created, make sure it's complete. 448 * The following functions can effect this state: glReadBuffer, 449 * glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT. 450 */ 451void 452_mesa_update_framebuffer(GLcontext *ctx) 453{ 454 struct gl_framebuffer *fb = ctx->DrawBuffer; 455 GLuint output; 456 457 /* Completeness only matters for user-created framebuffers */ 458 if (fb->Name != 0) { 459 _mesa_test_framebuffer_completeness(ctx, fb); 460 _mesa_update_framebuffer_visual(fb); 461 } 462 463 /* 464 * Update the list of color drawing renderbuffer pointers. 465 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers 466 * writing colors. We need the inner loop here because 467 * glDrawBuffer(GL_FRONT_AND_BACK) can specify writing to two or four 468 * color buffers (for example). 469 */ 470 for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) { 471 GLbitfield bufferMask = fb->_ColorDrawBufferMask[output]; 472 GLuint count = 0; 473 GLuint i; 474 for (i = 0; bufferMask && i < BUFFER_COUNT; i++) { 475 const GLuint bufferBit = 1 << i; 476 if (bufferBit & bufferMask) { 477 struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; 478 if (rb) { 479 fb->_ColorDrawBuffers[output][count] = rb; 480 count++; 481 } 482 else { 483 /*_mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");*/ 484 } 485 bufferMask &= ~bufferBit; 486 } 487 } 488 fb->_NumColorDrawBuffers[output] = count; 489 } 490 491 /* 492 * Update the color read renderbuffer pointer. 493 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers. 494 */ 495 if (fb->_ColorReadBufferIndex == -1) { 496 fb->_ColorReadBuffer = NULL; /* legal! */ 497 } 498 else { 499 ASSERT(fb->_ColorReadBufferIndex >= 0); 500 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT); 501 fb->_ColorReadBuffer 502 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer; 503 } 504 505 /* 506 * Deal with GL_DEPTH_STENCIL renderbuffer(s) attached to the depth 507 * and/or stencil attachment points. 508 */ 509 { 510 struct gl_renderbuffer *depthRb 511 = fb->Attachment[BUFFER_DEPTH].Renderbuffer; 512 struct gl_renderbuffer *stencilRb 513 = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 514 515 if (depthRb && depthRb->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 516 if (!fb->_DepthBuffer || fb->_DepthBuffer->Wrapped != depthRb) { 517 /* need to update wrapper */ 518 struct gl_renderbuffer *wrapper 519 = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb); 520 set_depth_renderbuffer(fb, wrapper); 521 assert(fb->_DepthBuffer->Wrapped == depthRb); 522 } 523 } 524 else { 525 /* depthRb may be null */ 526 set_depth_renderbuffer(fb, depthRb); 527 } 528 529 if (stencilRb && stencilRb->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 530 if (!fb->_StencilBuffer || fb->_StencilBuffer->Wrapped != stencilRb) { 531 /* need to update wrapper */ 532 struct gl_renderbuffer *wrapper 533 = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb); 534 set_stencil_renderbuffer(fb, wrapper); 535 assert(fb->_StencilBuffer->Wrapped == stencilRb); 536 } 537 } 538 else { 539 /* stencilRb may be null */ 540 set_stencil_renderbuffer(fb, stencilRb); 541 } 542 } 543 544 compute_depth_max(fb); 545} 546