framebuffer.c revision 79b4dbc4961a80e6a88235ae7455ffdcec23e982
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 "mtypes.h" 37#include "fbobject.h" 38#include "framebuffer.h" 39#include "renderbuffer.h" 40 41 42 43/** 44 * Compute/set the _DepthMax field for the given framebuffer. 45 * This value depends on the Z buffer resolution. 46 */ 47static void 48compute_depth_max(struct gl_framebuffer *fb) 49{ 50 if (fb->Visual.depthBits == 0) { 51 /* Special case. Even if we don't have a depth buffer we need 52 * good values for DepthMax for Z vertex transformation purposes 53 * and for per-fragment fog computation. 54 */ 55 fb->_DepthMax = (1 << 16) - 1; 56 } 57 else if (fb->Visual.depthBits < 32) { 58 fb->_DepthMax = (1 << fb->Visual.depthBits) - 1; 59 } 60 else { 61 /* Special case since shift values greater than or equal to the 62 * number of bits in the left hand expression's type are undefined. 63 */ 64 fb->_DepthMax = 0xffffffff; 65 } 66 fb->_DepthMaxF = (GLfloat) fb->_DepthMax; 67 fb->_MRD = 1.0; /* Minimum resolvable depth value, for polygon offset */ 68} 69 70 71/** 72 * Create and initialize a gl_framebuffer object. 73 * This is intended for creating _window_system_ framebuffers, not generic 74 * framebuffer objects ala GL_EXT_framebuffer_object. 75 * 76 * \sa _mesa_new_framebuffer 77 */ 78struct gl_framebuffer * 79_mesa_create_framebuffer(const GLvisual *visual) 80{ 81 struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer); 82 assert(visual); 83 if (fb) { 84 _mesa_initialize_framebuffer(fb, visual); 85 } 86 return fb; 87} 88 89 90/** 91 * Allocate a new gl_framebuffer object. 92 * This is the default function for ctx->Driver.NewFramebuffer(). 93 * This is for allocating user-created framebuffers, not window-system 94 * framebuffers! 95 * \sa _mesa_create_framebuffer 96 */ 97struct gl_framebuffer * 98_mesa_new_framebuffer(GLcontext *ctx, GLuint name) 99{ 100 struct gl_framebuffer *fb; 101 assert(name != 0); 102 fb = CALLOC_STRUCT(gl_framebuffer); 103 if (fb) { 104 fb->Name = name; 105 fb->RefCount = 1; 106 fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT; 107 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_COLOR0; 108 fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT; 109 fb->_ColorReadBufferIndex = BUFFER_COLOR0; 110 fb->Delete = _mesa_destroy_framebuffer; 111 } 112 return fb; 113} 114 115 116/** 117 * Initialize a gl_framebuffer object. Typically used to initialize 118 * window system-created framebuffers, not user-created framebuffers. 119 * \sa _mesa_create_framebuffer 120 */ 121void 122_mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual) 123{ 124 assert(fb); 125 assert(visual); 126 127 _mesa_bzero(fb, sizeof(struct gl_framebuffer)); 128 129 /* save the visual */ 130 fb->Visual = *visual; 131 132 /* Init glRead/DrawBuffer state */ 133 if (visual->doubleBufferMode) { 134 fb->ColorDrawBuffer[0] = GL_BACK; 135 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_BACK_LEFT; 136 fb->ColorReadBuffer = GL_BACK; 137 fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT; 138 } 139 else { 140 fb->ColorDrawBuffer[0] = GL_FRONT; 141 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT; 142 fb->ColorReadBuffer = GL_FRONT; 143 fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT; 144 } 145 146 fb->Delete = _mesa_destroy_framebuffer; 147 148 compute_depth_max(fb); 149} 150 151 152/** 153 * Deallocate buffer and everything attached to it. 154 * Typically called via the gl_framebuffer->Delete() method. 155 */ 156void 157_mesa_destroy_framebuffer(struct gl_framebuffer *fb) 158{ 159 if (fb) { 160 _mesa_free_framebuffer_data(fb); 161 FREE(fb); 162 } 163} 164 165 166/** 167 * Free all the data hanging off the given gl_framebuffer, but don't free 168 * the gl_framebuffer object itself. 169 */ 170void 171_mesa_free_framebuffer_data(struct gl_framebuffer *fb) 172{ 173 GLuint i; 174 175 assert(fb); 176 177 for (i = 0; i < BUFFER_COUNT; i++) { 178 struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 179 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) { 180 struct gl_renderbuffer *rb = att->Renderbuffer; 181 rb->RefCount--; 182 if (rb->RefCount == 0) { 183 rb->Delete(rb); 184 } 185 } 186 att->Type = GL_NONE; 187 att->Renderbuffer = NULL; 188 } 189} 190 191 192/** 193 * Resize the given framebuffer's renderbuffers to the new width and height. 194 * This should only be used for window-system framebuffers, not 195 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object). 196 * This will typically be called via ctx->Driver.ResizeBuffers() 197 */ 198void 199_mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb, 200 GLuint width, GLuint height) 201{ 202 GLuint i; 203 204 /* For window system framebuffers, Name is zero */ 205 assert(fb->Name == 0); 206 207 for (i = 0; i < BUFFER_COUNT; i++) { 208 struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 209 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) { 210 struct gl_renderbuffer *rb = att->Renderbuffer; 211 /* only resize if size is changing */ 212 if (rb->Width != width || rb->Height != height) { 213 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { 214 rb->Width = width; 215 rb->Height = height; 216 } 217 else { 218 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); 219 } 220 } 221 } 222 } 223 224 fb->Width = width; 225 fb->Height = height; 226} 227 228 229/** 230 * Examine all the framebuffer's renderbuffers to update the Width/Height 231 * fields of the framebuffer. If we have renderbuffers with different 232 * sizes, set the framebuffer's width and height to zero. 233 * Note: this is only intended for user-created framebuffers, not 234 * window-system framebuffes. 235 */ 236static void 237update_framebuffer_size(struct gl_framebuffer *fb) 238{ 239 GLboolean haveSize = GL_FALSE; 240 GLuint i; 241 242 /* user-created framebuffers only */ 243 assert(fb->Name); 244 245 for (i = 0; i < BUFFER_COUNT; i++) { 246 struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 247 const struct gl_renderbuffer *rb = att->Renderbuffer; 248 if (rb) { 249 if (haveSize) { 250 if (rb->Width != fb->Width && rb->Height != fb->Height) { 251 /* size mismatch! */ 252 fb->Width = 0; 253 fb->Height = 0; 254 return; 255 } 256 } 257 else { 258 fb->Width = rb->Width; 259 fb->Height = rb->Height; 260 haveSize = GL_TRUE; 261 } 262 } 263 } 264} 265 266 267/** 268 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields. 269 * These values are computed from the buffer's width and height and 270 * the scissor box, if it's enabled. 271 * \param ctx the GL context. 272 */ 273void 274_mesa_update_draw_buffer_bounds(GLcontext *ctx) 275{ 276 struct gl_framebuffer *buffer = ctx->DrawBuffer; 277 278 if (buffer->Name) { 279 /* user-created framebuffer size depends on the renderbuffers */ 280 update_framebuffer_size(buffer); 281 } 282 283 buffer->_Xmin = 0; 284 buffer->_Ymin = 0; 285 buffer->_Xmax = buffer->Width; 286 buffer->_Ymax = buffer->Height; 287 288 if (ctx->Scissor.Enabled) { 289 if (ctx->Scissor.X > buffer->_Xmin) { 290 buffer->_Xmin = ctx->Scissor.X; 291 } 292 if (ctx->Scissor.Y > buffer->_Ymin) { 293 buffer->_Ymin = ctx->Scissor.Y; 294 } 295 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) { 296 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width; 297 } 298 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) { 299 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height; 300 } 301 /* finally, check for empty region */ 302 if (buffer->_Xmin > buffer->_Xmax) { 303 buffer->_Xmin = buffer->_Xmax; 304 } 305 if (buffer->_Ymin > buffer->_Ymax) { 306 buffer->_Ymin = buffer->_Ymax; 307 } 308 } 309 310 ASSERT(buffer->_Xmin <= buffer->_Xmax); 311 ASSERT(buffer->_Ymin <= buffer->_Ymax); 312} 313 314 315/** 316 * The glGet queries of the framebuffer red/green/blue size, stencil size, 317 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can 318 * change depending on the renderbuffer bindings. This function updates 319 * the given framebuffer's Visual from the current renderbuffer bindings. 320 * This is only intended for user-created framebuffers. 321 */ 322void 323_mesa_update_framebuffer_visual(struct gl_framebuffer *fb) 324{ 325 assert(fb->Name != 0); 326 327 _mesa_bzero(&fb->Visual, sizeof(fb->Visual)); 328 fb->Visual.rgbMode = GL_TRUE; 329 330 if (fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer) { 331 fb->Visual.redBits 332 = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer->RedBits; 333 fb->Visual.greenBits 334 = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer->GreenBits; 335 fb->Visual.blueBits 336 = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer->BlueBits; 337 fb->Visual.alphaBits 338 = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer->AlphaBits; 339 fb->Visual.rgbBits 340 = fb->Visual.redBits + fb->Visual.greenBits + fb->Visual.blueBits; 341 fb->Visual.floatMode = GL_FALSE; 342 } 343 344 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) { 345 fb->Visual.haveDepthBuffer = GL_TRUE; 346 fb->Visual.depthBits 347 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits; 348 } 349 350 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) { 351 fb->Visual.haveStencilBuffer = GL_TRUE; 352 fb->Visual.stencilBits 353 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits; 354 } 355 356 compute_depth_max(fb); 357} 358 359 360/** 361 * Update state related to the current draw/read framebuffers. 362 * Specifically, update these framebuffer fields: 363 * _ColorDrawBuffers 364 * _NumColorDrawBuffers 365 * _ColorReadBuffer 366 * If the current framebuffer is user-created, make sure it's complete. 367 * The following functions can effect this state: glReadBuffer, 368 * glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT. 369 */ 370void 371_mesa_update_framebuffer(GLcontext *ctx) 372{ 373 struct gl_framebuffer *fb = ctx->DrawBuffer; 374 GLuint output; 375 376 /* Completeness only matters for user-created framebuffers */ 377 if (fb->Name != 0) 378 _mesa_test_framebuffer_completeness(ctx, fb); 379 380 /* 381 * Update the list of color drawing renderbuffer pointers. 382 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers 383 * writing colors. We need the inner loop here because 384 * glDrawBuffer(GL_FRONT_AND_BACK) can specify writing to two or four 385 * color buffers (for example). 386 */ 387 for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) { 388 GLbitfield bufferMask = fb->_ColorDrawBufferMask[output]; 389 GLuint count = 0; 390 GLuint i; 391 for (i = 0; bufferMask && i < BUFFER_COUNT; i++) { 392 const GLuint bufferBit = 1 << i; 393 if (bufferBit & bufferMask) { 394 struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; 395 if (rb) { 396 fb->_ColorDrawBuffers[output][count] = rb; 397 count++; 398 } 399 else { 400 _mesa_warning(ctx, "DrawBuffer names a missing buffer!"); 401 } 402 bufferMask &= ~bufferBit; 403 } 404 } 405 fb->_NumColorDrawBuffers[output] = count; 406 } 407 408 /* 409 * Update the color read renderbuffer pointer. 410 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers. 411 */ 412 if (fb->_ColorReadBufferIndex == -1) { 413 fb->_ColorReadBuffer = NULL; /* legal! */ 414 } 415 else { 416 ASSERT(fb->_ColorReadBufferIndex >= 0); 417 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT); 418 fb->_ColorReadBuffer 419 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer; 420 } 421 compute_depth_max(fb); 422} 423