blob: c97d2f0077bfc8ef001b927705ce91ef9d8e09fd [file] [log] [blame]
Brian Paule4b23562005-05-04 20:11:35 +00001/*
2 * Mesa 3-D graphics library
Brian Paul57223382006-04-06 04:09:03 +00003 * Version: 6.5.1
Brian Paule4b23562005-05-04 20:11:35 +00004 *
Brian Paul7275d4d2006-03-20 15:25:18 +00005 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
Brian Paule4b23562005-05-04 20:11:35 +00006 *
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"
Brian Paul84716042005-11-16 04:05:54 +000036#include "depthstencil.h"
Brian Paule4b23562005-05-04 20:11:35 +000037#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/**
Brian Paulea4fe662006-03-26 05:22:17 +000073 * Set the framebuffer's _DepthBuffer field, taking care of
74 * reference counts, etc.
75 */
76static void
77set_depth_renderbuffer(struct gl_framebuffer *fb,
78 struct gl_renderbuffer *rb)
79{
80 if (fb->_DepthBuffer) {
Briana510bc32007-03-06 10:07:59 -070081 _mesa_unreference_renderbuffer(&fb->_DepthBuffer);
Brian Paulea4fe662006-03-26 05:22:17 +000082 }
83 fb->_DepthBuffer = rb;
84 if (rb) {
85 rb->RefCount++;
86 }
87}
88
89
90/**
91 * Set the framebuffer's _StencilBuffer field, taking care of
92 * reference counts, etc.
93 */
94static void
95set_stencil_renderbuffer(struct gl_framebuffer *fb,
96 struct gl_renderbuffer *rb)
97{
98 if (fb->_StencilBuffer) {
Briana510bc32007-03-06 10:07:59 -070099 _mesa_unreference_renderbuffer(&fb->_StencilBuffer);
Brian Paulea4fe662006-03-26 05:22:17 +0000100 }
101 fb->_StencilBuffer = rb;
102 if (rb) {
103 rb->RefCount++;
104 }
105}
106
107
108/**
Brian Paule4b23562005-05-04 20:11:35 +0000109 * Create and initialize a gl_framebuffer object.
110 * This is intended for creating _window_system_ framebuffers, not generic
111 * framebuffer objects ala GL_EXT_framebuffer_object.
112 *
113 * \sa _mesa_new_framebuffer
114 */
115struct gl_framebuffer *
116_mesa_create_framebuffer(const GLvisual *visual)
117{
118 struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer);
119 assert(visual);
120 if (fb) {
121 _mesa_initialize_framebuffer(fb, visual);
122 }
123 return fb;
124}
125
126
127/**
128 * Allocate a new gl_framebuffer object.
129 * This is the default function for ctx->Driver.NewFramebuffer().
130 * This is for allocating user-created framebuffers, not window-system
131 * framebuffers!
132 * \sa _mesa_create_framebuffer
133 */
134struct gl_framebuffer *
135_mesa_new_framebuffer(GLcontext *ctx, GLuint name)
136{
137 struct gl_framebuffer *fb;
Brian Paul28b014e2006-04-05 03:05:17 +0000138 (void) ctx;
Brian Paule4b23562005-05-04 20:11:35 +0000139 assert(name != 0);
140 fb = CALLOC_STRUCT(gl_framebuffer);
141 if (fb) {
142 fb->Name = name;
143 fb->RefCount = 1;
Brian Paule4b23562005-05-04 20:11:35 +0000144 fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT;
145 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_COLOR0;
146 fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT;
Brian Paul048b13d2005-09-23 03:22:20 +0000147 fb->_ColorReadBufferIndex = BUFFER_COLOR0;
Brian Paule4b23562005-05-04 20:11:35 +0000148 fb->Delete = _mesa_destroy_framebuffer;
149 }
150 return fb;
151}
152
153
154/**
Brian Paulf084f602005-09-13 23:37:50 +0000155 * Initialize a gl_framebuffer object. Typically used to initialize
156 * window system-created framebuffers, not user-created framebuffers.
Brian Paule4b23562005-05-04 20:11:35 +0000157 * \sa _mesa_create_framebuffer
158 */
159void
160_mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual)
161{
162 assert(fb);
163 assert(visual);
164
165 _mesa_bzero(fb, sizeof(struct gl_framebuffer));
166
Brian Paulea4fe662006-03-26 05:22:17 +0000167 _glthread_INIT_MUTEX(fb->Mutex);
168
Briane6a93812007-02-26 11:37:37 -0700169 fb->RefCount = 1;
170
Brian Paule4b23562005-05-04 20:11:35 +0000171 /* save the visual */
172 fb->Visual = *visual;
173
174 /* Init glRead/DrawBuffer state */
175 if (visual->doubleBufferMode) {
176 fb->ColorDrawBuffer[0] = GL_BACK;
177 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_BACK_LEFT;
178 fb->ColorReadBuffer = GL_BACK;
Brian Paul048b13d2005-09-23 03:22:20 +0000179 fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT;
Brian Paule4b23562005-05-04 20:11:35 +0000180 }
181 else {
182 fb->ColorDrawBuffer[0] = GL_FRONT;
183 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT;
184 fb->ColorReadBuffer = GL_FRONT;
Brian Paul048b13d2005-09-23 03:22:20 +0000185 fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT;
Brian Paule4b23562005-05-04 20:11:35 +0000186 }
187
188 fb->Delete = _mesa_destroy_framebuffer;
Brian Pauld95000d2005-09-28 15:46:46 +0000189 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
Brian Paule4b23562005-05-04 20:11:35 +0000190
191 compute_depth_max(fb);
192}
193
194
195/**
Brian Paule4b23562005-05-04 20:11:35 +0000196 * Deallocate buffer and everything attached to it.
Brian Paulf084f602005-09-13 23:37:50 +0000197 * Typically called via the gl_framebuffer->Delete() method.
Brian Paule4b23562005-05-04 20:11:35 +0000198 */
199void
Brian Paulf084f602005-09-13 23:37:50 +0000200_mesa_destroy_framebuffer(struct gl_framebuffer *fb)
Brian Paule4b23562005-05-04 20:11:35 +0000201{
Brian Paulf084f602005-09-13 23:37:50 +0000202 if (fb) {
203 _mesa_free_framebuffer_data(fb);
Brian Paul84716042005-11-16 04:05:54 +0000204 _mesa_free(fb);
Brian Paule4b23562005-05-04 20:11:35 +0000205 }
206}
207
208
209/**
210 * Free all the data hanging off the given gl_framebuffer, but don't free
211 * the gl_framebuffer object itself.
212 */
213void
214_mesa_free_framebuffer_data(struct gl_framebuffer *fb)
215{
216 GLuint i;
217
218 assert(fb);
Brianf30e3122007-02-27 11:09:28 -0700219 assert(fb->RefCount == 0);
Brian Paule4b23562005-05-04 20:11:35 +0000220
Briane6a93812007-02-26 11:37:37 -0700221 _glthread_DESTROY_MUTEX(fb->Mutex);
222
Brian Paule4b23562005-05-04 20:11:35 +0000223 for (i = 0; i < BUFFER_COUNT; i++) {
224 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
Brian Paul753af3a2006-03-25 17:57:52 +0000225 if (att->Renderbuffer) {
Briana510bc32007-03-06 10:07:59 -0700226 _mesa_unreference_renderbuffer(&att->Renderbuffer);
Brian593802c2007-03-06 09:49:15 -0700227 }
228 if (att->Texture) {
229 /* render to texture */
230 att->Texture->RefCount--;
231 if (att->Texture->RefCount == 0) {
232 GET_CURRENT_CONTEXT(ctx);
233 if (ctx) {
234 ctx->Driver.DeleteTexture(ctx, att->Texture);
235 }
Brian Paule4b23562005-05-04 20:11:35 +0000236 }
237 }
238 att->Type = GL_NONE;
Brian593802c2007-03-06 09:49:15 -0700239 att->Texture = NULL;
Brian Paule4b23562005-05-04 20:11:35 +0000240 }
Brian Paul84716042005-11-16 04:05:54 +0000241
Brian Paulea4fe662006-03-26 05:22:17 +0000242 /* unbind depth/stencil to decr ref counts */
243 set_depth_renderbuffer(fb, NULL);
244 set_stencil_renderbuffer(fb, NULL);
Brian Paule4b23562005-05-04 20:11:35 +0000245}
246
247
248/**
Briana510bc32007-03-06 10:07:59 -0700249 * Set *ptr to point to fb, with refcounting and locking.
Brian Paul2eb88c172006-05-20 15:06:35 +0000250 */
251void
Briana510bc32007-03-06 10:07:59 -0700252_mesa_reference_framebuffer(struct gl_framebuffer **ptr,
253 struct gl_framebuffer *fb)
Brian Paul2eb88c172006-05-20 15:06:35 +0000254{
Briana510bc32007-03-06 10:07:59 -0700255 assert(ptr);
256 assert(!*ptr);
257 assert(fb);
258 _glthread_LOCK_MUTEX(fb->Mutex);
259 fb->RefCount++;
260 _glthread_UNLOCK_MUTEX(fb->Mutex);
261 *ptr = fb;
262}
Brian Paul2eb88c172006-05-20 15:06:35 +0000263
Briana510bc32007-03-06 10:07:59 -0700264
265/**
266 * Undo/remove a reference to a framebuffer object.
267 * Decrement the framebuffer object's reference count and delete it when
268 * the refcount hits zero.
269 * Note: we pass the address of a pointer and set it to NULL.
270 */
271void
272_mesa_unreference_framebuffer(struct gl_framebuffer **fb)
273{
274 assert(fb);
275 if (*fb) {
276 GLboolean deleteFlag = GL_FALSE;
277
278 _glthread_LOCK_MUTEX((*fb)->Mutex);
Brian Paul2eb88c172006-05-20 15:06:35 +0000279 ASSERT((*fb)->RefCount > 0);
280 (*fb)->RefCount--;
281 deleteFlag = ((*fb)->RefCount == 0);
Briana510bc32007-03-06 10:07:59 -0700282 _glthread_UNLOCK_MUTEX((*fb)->Mutex);
283
284 if (deleteFlag)
285 (*fb)->Delete(*fb);
Brian Paul2eb88c172006-05-20 15:06:35 +0000286
Brian Paul2eb88c172006-05-20 15:06:35 +0000287 *fb = NULL;
288 }
289}
290
291
292
293
294/**
Brian Paule4b23562005-05-04 20:11:35 +0000295 * Resize the given framebuffer's renderbuffers to the new width and height.
296 * This should only be used for window-system framebuffers, not
297 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object).
Brian Paul84716042005-11-16 04:05:54 +0000298 * This will typically be called via ctx->Driver.ResizeBuffers() or directly
299 * from a device driver.
300 *
301 * \note it's possible for ctx to be null since a window can be resized
302 * without a currently bound rendering context.
Brian Paule4b23562005-05-04 20:11:35 +0000303 */
304void
305_mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
306 GLuint width, GLuint height)
307{
308 GLuint i;
309
Brian Paulea4fe662006-03-26 05:22:17 +0000310 /* XXX I think we could check if the size is not changing
311 * and return early.
312 */
313
Brian Paule4b23562005-05-04 20:11:35 +0000314 /* For window system framebuffers, Name is zero */
315 assert(fb->Name == 0);
316
317 for (i = 0; i < BUFFER_COUNT; i++) {
318 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
319 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
320 struct gl_renderbuffer *rb = att->Renderbuffer;
321 /* only resize if size is changing */
322 if (rb->Width != width || rb->Height != height) {
Brian Paulea4fe662006-03-26 05:22:17 +0000323 /* could just as well pass rb->_ActualFormat here */
Brian Paule4b23562005-05-04 20:11:35 +0000324 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
Brian Paulea4fe662006-03-26 05:22:17 +0000325 ASSERT(rb->Width == width);
326 ASSERT(rb->Height == height);
Brian Paule4b23562005-05-04 20:11:35 +0000327 }
328 else {
329 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
Brian Paulea4fe662006-03-26 05:22:17 +0000330 /* no return */
Brian Paule4b23562005-05-04 20:11:35 +0000331 }
332 }
333 }
334 }
335
Brian Paulea4fe662006-03-26 05:22:17 +0000336 if (fb->_DepthBuffer) {
337 struct gl_renderbuffer *rb = fb->_DepthBuffer;
338 if (rb->Width != width || rb->Height != height) {
339 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
340 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
341 }
342 }
343 }
344
345 if (fb->_StencilBuffer) {
346 struct gl_renderbuffer *rb = fb->_StencilBuffer;
347 if (rb->Width != width || rb->Height != height) {
348 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
349 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
350 }
351 }
352 }
353
Brian Paule4b23562005-05-04 20:11:35 +0000354 fb->Width = width;
355 fb->Height = height;
Brian Paul52f686c2005-10-21 21:39:10 +0000356
Brian Paul041d6482006-10-16 17:26:30 +0000357 if (ctx) {
358 /* update scissor / window bounds */
Alan Hourihanefeb0ff12006-06-21 10:58:04 +0000359 _mesa_update_draw_buffer_bounds(ctx);
Brian Paul041d6482006-10-16 17:26:30 +0000360 /* Signal new buffer state so that swrast will update its clipping
361 * info (the CLIP_BIT flag).
362 */
363 ctx->NewState |= _NEW_BUFFERS;
364 }
Brian Paule4b23562005-05-04 20:11:35 +0000365}
366
367
368/**
369 * Examine all the framebuffer's renderbuffers to update the Width/Height
370 * fields of the framebuffer. If we have renderbuffers with different
371 * sizes, set the framebuffer's width and height to zero.
372 * Note: this is only intended for user-created framebuffers, not
373 * window-system framebuffes.
374 */
375static void
376update_framebuffer_size(struct gl_framebuffer *fb)
377{
378 GLboolean haveSize = GL_FALSE;
379 GLuint i;
380
381 /* user-created framebuffers only */
382 assert(fb->Name);
383
384 for (i = 0; i < BUFFER_COUNT; i++) {
385 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
386 const struct gl_renderbuffer *rb = att->Renderbuffer;
387 if (rb) {
388 if (haveSize) {
389 if (rb->Width != fb->Width && rb->Height != fb->Height) {
390 /* size mismatch! */
391 fb->Width = 0;
392 fb->Height = 0;
393 return;
394 }
395 }
396 else {
397 fb->Width = rb->Width;
398 fb->Height = rb->Height;
399 haveSize = GL_TRUE;
400 }
401 }
402 }
403}
404
405
406/**
407 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
408 * These values are computed from the buffer's width and height and
409 * the scissor box, if it's enabled.
410 * \param ctx the GL context.
411 */
412void
413_mesa_update_draw_buffer_bounds(GLcontext *ctx)
414{
415 struct gl_framebuffer *buffer = ctx->DrawBuffer;
416
Alan Hourihane161de102006-06-19 09:27:04 +0000417 if (!buffer)
418 return;
419
Brian Paule4b23562005-05-04 20:11:35 +0000420 if (buffer->Name) {
421 /* user-created framebuffer size depends on the renderbuffers */
422 update_framebuffer_size(buffer);
423 }
424
425 buffer->_Xmin = 0;
426 buffer->_Ymin = 0;
427 buffer->_Xmax = buffer->Width;
428 buffer->_Ymax = buffer->Height;
429
430 if (ctx->Scissor.Enabled) {
431 if (ctx->Scissor.X > buffer->_Xmin) {
432 buffer->_Xmin = ctx->Scissor.X;
433 }
434 if (ctx->Scissor.Y > buffer->_Ymin) {
435 buffer->_Ymin = ctx->Scissor.Y;
436 }
437 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
438 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
439 }
440 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
441 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
442 }
443 /* finally, check for empty region */
444 if (buffer->_Xmin > buffer->_Xmax) {
445 buffer->_Xmin = buffer->_Xmax;
446 }
447 if (buffer->_Ymin > buffer->_Ymax) {
448 buffer->_Ymin = buffer->_Ymax;
449 }
450 }
451
452 ASSERT(buffer->_Xmin <= buffer->_Xmax);
453 ASSERT(buffer->_Ymin <= buffer->_Ymax);
454}
455
456
457/**
458 * The glGet queries of the framebuffer red/green/blue size, stencil size,
459 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can
Brian Paulf084f602005-09-13 23:37:50 +0000460 * change depending on the renderbuffer bindings. This function updates
Brian Paule4b23562005-05-04 20:11:35 +0000461 * the given framebuffer's Visual from the current renderbuffer bindings.
Brian Paul02aa5fb2006-09-11 15:04:23 +0000462 *
463 * This may apply to user-created framebuffers or window system framebuffers.
Brian Pauleb063cf2005-10-04 14:48:24 +0000464 *
465 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal
466 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits.
467 * The former one is used to convert floating point depth values into
468 * integer Z values.
Brian Paule4b23562005-05-04 20:11:35 +0000469 */
470void
471_mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
472{
Brian Paul474f28e2005-10-08 14:41:17 +0000473 GLuint i;
474
Brian Paule4b23562005-05-04 20:11:35 +0000475 _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
Brian Paul474f28e2005-10-08 14:41:17 +0000476 fb->Visual.rgbMode = GL_TRUE; /* assume this */
Brian Paule4b23562005-05-04 20:11:35 +0000477
Brian Paul34b3b402006-04-20 00:45:08 +0000478#if 0 /* this _might_ be needed */
479 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
480 /* leave visual fields zero'd */
481 return;
482 }
483#endif
484
Brian Paul474f28e2005-10-08 14:41:17 +0000485 /* find first RGB or CI renderbuffer */
486 for (i = 0; i < BUFFER_COUNT; i++) {
487 if (fb->Attachment[i].Renderbuffer) {
488 const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
489 if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) {
490 fb->Visual.redBits = rb->RedBits;
491 fb->Visual.greenBits = rb->GreenBits;
492 fb->Visual.blueBits = rb->BlueBits;
493 fb->Visual.alphaBits = rb->AlphaBits;
494 fb->Visual.rgbBits = fb->Visual.redBits
495 + fb->Visual.greenBits + fb->Visual.blueBits;
496 fb->Visual.floatMode = GL_FALSE;
497 break;
498 }
499 else if (rb->_BaseFormat == GL_COLOR_INDEX) {
500 fb->Visual.indexBits = rb->IndexBits;
501 fb->Visual.rgbMode = GL_FALSE;
502 break;
503 }
504 }
Brian Paule4b23562005-05-04 20:11:35 +0000505 }
506
507 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
508 fb->Visual.haveDepthBuffer = GL_TRUE;
509 fb->Visual.depthBits
Brian Paul676d0ac2005-09-22 05:19:57 +0000510 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits;
Brian Paule4b23562005-05-04 20:11:35 +0000511 }
512
513 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
514 fb->Visual.haveStencilBuffer = GL_TRUE;
515 fb->Visual.stencilBits
Brian Paul676d0ac2005-09-22 05:19:57 +0000516 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits;
Brian Paule4b23562005-05-04 20:11:35 +0000517 }
518
Brian Paul02aa5fb2006-09-11 15:04:23 +0000519 if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) {
520 fb->Visual.haveAccumBuffer = GL_TRUE;
521 fb->Visual.accumRedBits
522 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->RedBits;
523 fb->Visual.accumGreenBits
524 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->GreenBits;
525 fb->Visual.accumBlueBits
526 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->BlueBits;
527 fb->Visual.accumAlphaBits
528 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->AlphaBits;
529 }
530
Brian Paule4b23562005-05-04 20:11:35 +0000531 compute_depth_max(fb);
532}
533
534
535/**
Brian Paulea4fe662006-03-26 05:22:17 +0000536 * Update the framebuffer's _DepthBuffer field using the renderbuffer
537 * found at the given attachment index.
538 *
539 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
540 * create and install a depth wrapper/adaptor.
541 *
542 * \param fb the framebuffer whose _DepthBuffer field to update
543 * \param attIndex indicates the renderbuffer to possibly wrap
Brian Paul84716042005-11-16 04:05:54 +0000544 */
Brian Paulea4fe662006-03-26 05:22:17 +0000545void
546_mesa_update_depth_buffer(GLcontext *ctx,
547 struct gl_framebuffer *fb,
548 GLuint attIndex)
Brian Paul84716042005-11-16 04:05:54 +0000549{
Brian Paulea4fe662006-03-26 05:22:17 +0000550 struct gl_renderbuffer *depthRb;
551
552 /* only one possiblity for now */
553 ASSERT(attIndex == BUFFER_DEPTH);
554
555 depthRb = fb->Attachment[attIndex].Renderbuffer;
556
557 if (depthRb && depthRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
558 /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */
Brian Paul57223382006-04-06 04:09:03 +0000559 if (!fb->_DepthBuffer
560 || fb->_DepthBuffer->Wrapped != depthRb
561 || fb->_DepthBuffer->_BaseFormat != GL_DEPTH_COMPONENT) {
Brian Paulea4fe662006-03-26 05:22:17 +0000562 /* need to update wrapper */
563 struct gl_renderbuffer *wrapper
564 = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb);
565 set_depth_renderbuffer(fb, wrapper);
566 ASSERT(fb->_DepthBuffer->Wrapped == depthRb);
Brian Paul84716042005-11-16 04:05:54 +0000567 }
568 }
Brian Paulea4fe662006-03-26 05:22:17 +0000569 else {
570 /* depthRb may be null */
571 set_depth_renderbuffer(fb, depthRb);
572 }
Brian Paul84716042005-11-16 04:05:54 +0000573}
574
Brian Paulea4fe662006-03-26 05:22:17 +0000575
Brian Paul84716042005-11-16 04:05:54 +0000576/**
Brian Paulea4fe662006-03-26 05:22:17 +0000577 * Update the framebuffer's _StencilBuffer field using the renderbuffer
578 * found at the given attachment index.
579 *
580 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
581 * create and install a stencil wrapper/adaptor.
582 *
583 * \param fb the framebuffer whose _StencilBuffer field to update
584 * \param attIndex indicates the renderbuffer to possibly wrap
Brian Paul84716042005-11-16 04:05:54 +0000585 */
Brian Paulea4fe662006-03-26 05:22:17 +0000586void
587_mesa_update_stencil_buffer(GLcontext *ctx,
588 struct gl_framebuffer *fb,
589 GLuint attIndex)
Brian Paul84716042005-11-16 04:05:54 +0000590{
Brian Paulea4fe662006-03-26 05:22:17 +0000591 struct gl_renderbuffer *stencilRb;
592
593 ASSERT(attIndex == BUFFER_DEPTH ||
594 attIndex == BUFFER_STENCIL);
595
596 stencilRb = fb->Attachment[attIndex].Renderbuffer;
597
598 if (stencilRb && stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
599 /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */
Brian Paul57223382006-04-06 04:09:03 +0000600 if (!fb->_StencilBuffer
601 || fb->_StencilBuffer->Wrapped != stencilRb
602 || fb->_StencilBuffer->_BaseFormat != GL_STENCIL_INDEX) {
Brian Paulea4fe662006-03-26 05:22:17 +0000603 /* need to update wrapper */
604 struct gl_renderbuffer *wrapper
605 = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb);
606 set_stencil_renderbuffer(fb, wrapper);
607 ASSERT(fb->_StencilBuffer->Wrapped == stencilRb);
Brian Paul84716042005-11-16 04:05:54 +0000608 }
609 }
Brian Paulea4fe662006-03-26 05:22:17 +0000610 else {
611 /* stencilRb may be null */
612 set_stencil_renderbuffer(fb, stencilRb);
613 }
614}
615
616
617/**
618 * Update the list of color drawing renderbuffer pointers.
619 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
620 * writing colors.
621 */
622static void
623update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb)
624{
625 GLuint output;
626
627 /*
628 * Fragment programs can write to multiple colorbuffers with
629 * the GL_ARB_draw_buffers extension.
630 */
631 for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) {
632 GLbitfield bufferMask = fb->_ColorDrawBufferMask[output];
633 GLuint count = 0;
634 GLuint i;
Briane6a93812007-02-26 11:37:37 -0700635 if (!fb->DeletePending) {
636 /* We need the inner loop here because glDrawBuffer(GL_FRONT_AND_BACK)
637 * can specify writing to two or four color buffers (for example).
638 */
639 for (i = 0; bufferMask && i < BUFFER_COUNT; i++) {
640 const GLuint bufferBit = 1 << i;
641 if (bufferBit & bufferMask) {
642 struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
643 if (rb) {
644 fb->_ColorDrawBuffers[output][count] = rb;
645 count++;
646 }
647 else {
648 /*
649 _mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");
650 */
651 }
652 bufferMask &= ~bufferBit;
Brian Paulea4fe662006-03-26 05:22:17 +0000653 }
Brian Paulea4fe662006-03-26 05:22:17 +0000654 }
655 }
656 fb->_NumColorDrawBuffers[output] = count;
657 }
658}
659
660
661/**
662 * Update the color read renderbuffer pointer.
663 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
664 */
665static void
666update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
667{
Brian Paul28b014e2006-04-05 03:05:17 +0000668 (void) ctx;
Briane6a93812007-02-26 11:37:37 -0700669 if (fb->_ColorReadBufferIndex == -1 || fb->DeletePending) {
Brian Paulea4fe662006-03-26 05:22:17 +0000670 fb->_ColorReadBuffer = NULL; /* legal! */
671 }
672 else {
673 ASSERT(fb->_ColorReadBufferIndex >= 0);
674 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT);
675 fb->_ColorReadBuffer
676 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
677 }
Brian Paul84716042005-11-16 04:05:54 +0000678}
679
680
681/**
Brian Paule4b23562005-05-04 20:11:35 +0000682 * Update state related to the current draw/read framebuffers.
Brian Paul52783592005-08-31 21:38:53 +0000683 * Specifically, update these framebuffer fields:
684 * _ColorDrawBuffers
Brian Paul52783592005-08-31 21:38:53 +0000685 * _NumColorDrawBuffers
686 * _ColorReadBuffer
Brian Paul0f29ef62005-11-16 04:17:20 +0000687 * _DepthBuffer
688 * _StencilBuffer
Brian Paule4b23562005-05-04 20:11:35 +0000689 * If the current framebuffer is user-created, make sure it's complete.
Brian Paul52783592005-08-31 21:38:53 +0000690 * The following functions can effect this state: glReadBuffer,
Brian Paul0f29ef62005-11-16 04:17:20 +0000691 * glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT,
692 * glRenderbufferStorageEXT.
Brian Paule4b23562005-05-04 20:11:35 +0000693 */
694void
695_mesa_update_framebuffer(GLcontext *ctx)
696{
697 struct gl_framebuffer *fb = ctx->DrawBuffer;
Brian Paule4b23562005-05-04 20:11:35 +0000698
699 /* Completeness only matters for user-created framebuffers */
Brian Paul474f28e2005-10-08 14:41:17 +0000700 if (fb->Name != 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000701 _mesa_test_framebuffer_completeness(ctx, fb);
Brian Paul474f28e2005-10-08 14:41:17 +0000702 _mesa_update_framebuffer_visual(fb);
703 }
Brian Paule4b23562005-05-04 20:11:35 +0000704
Brian Paulea4fe662006-03-26 05:22:17 +0000705 update_color_draw_buffers(ctx, fb);
706 update_color_read_buffer(ctx, fb);
707 _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH);
708 _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL);
Brian Paul84716042005-11-16 04:05:54 +0000709
Brian Paule4b23562005-05-04 20:11:35 +0000710 compute_depth_max(fb);
711}
Brian Paul7275d4d2006-03-20 15:25:18 +0000712
713
714/**
715 * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels,
716 * glCopyTex[Sub]Image, etc. exists.
717 * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA,
718 * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL.
719 * \return GL_TRUE if buffer exists, GL_FALSE otherwise
720 */
721GLboolean
722_mesa_source_buffer_exists(GLcontext *ctx, GLenum format)
723{
724 const struct gl_renderbuffer_attachment *att
725 = ctx->ReadBuffer->Attachment;
726
727 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
728 return GL_FALSE;
729 }
730
731 switch (format) {
732 case GL_COLOR:
Brian Paul590cd262006-03-24 22:53:00 +0000733 case GL_RED:
734 case GL_GREEN:
735 case GL_BLUE:
Brian Paul7275d4d2006-03-20 15:25:18 +0000736 case GL_ALPHA:
737 case GL_LUMINANCE:
738 case GL_LUMINANCE_ALPHA:
739 case GL_INTENSITY:
740 case GL_RGB:
Brian Paul590cd262006-03-24 22:53:00 +0000741 case GL_BGR:
Brian Paul7275d4d2006-03-20 15:25:18 +0000742 case GL_RGBA:
Brian Paul590cd262006-03-24 22:53:00 +0000743 case GL_BGRA:
744 case GL_ABGR_EXT:
Brian Paul7275d4d2006-03-20 15:25:18 +0000745 case GL_COLOR_INDEX:
746 if (ctx->ReadBuffer->_ColorReadBuffer == NULL) {
747 return GL_FALSE;
748 }
Brian Paul84c5d0a2006-03-30 16:29:41 +0000749 /* XXX enable this post 6.5 release:
750 ASSERT(ctx->ReadBuffer->_ColorReadBuffer->RedBits > 0 ||
751 ctx->ReadBuffer->_ColorReadBuffer->IndexBits > 0);
752 */
Brian Paul7275d4d2006-03-20 15:25:18 +0000753 break;
754 case GL_DEPTH:
755 case GL_DEPTH_COMPONENT:
756 if (!att[BUFFER_DEPTH].Renderbuffer) {
757 return GL_FALSE;
758 }
759 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
760 break;
761 case GL_STENCIL:
762 case GL_STENCIL_INDEX:
763 if (!att[BUFFER_STENCIL].Renderbuffer) {
764 return GL_FALSE;
765 }
766 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
767 break;
768 case GL_DEPTH_STENCIL_EXT:
769 if (!att[BUFFER_DEPTH].Renderbuffer ||
770 !att[BUFFER_STENCIL].Renderbuffer) {
771 return GL_FALSE;
772 }
773 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
774 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
775 break;
776 default:
777 _mesa_problem(ctx,
Brian Paul590cd262006-03-24 22:53:00 +0000778 "Unexpected format 0x%x in _mesa_source_buffer_exists",
779 format);
Brian Paul7275d4d2006-03-20 15:25:18 +0000780 return GL_FALSE;
781 }
782
783 /* OK */
784 return GL_TRUE;
785}
786
787
788/**
789 * As above, but for drawing operations.
790 * XXX code do some code merging w/ above function.
791 */
792GLboolean
793_mesa_dest_buffer_exists(GLcontext *ctx, GLenum format)
794{
795 const struct gl_renderbuffer_attachment *att
796 = ctx->ReadBuffer->Attachment;
797
798 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
799 return GL_FALSE;
800 }
801
802 switch (format) {
803 case GL_COLOR:
Brian Paul590cd262006-03-24 22:53:00 +0000804 case GL_RED:
805 case GL_GREEN:
806 case GL_BLUE:
Brian Paul7275d4d2006-03-20 15:25:18 +0000807 case GL_ALPHA:
808 case GL_LUMINANCE:
809 case GL_LUMINANCE_ALPHA:
810 case GL_INTENSITY:
811 case GL_RGB:
Brian Paul590cd262006-03-24 22:53:00 +0000812 case GL_BGR:
Brian Paul7275d4d2006-03-20 15:25:18 +0000813 case GL_RGBA:
Brian Paul590cd262006-03-24 22:53:00 +0000814 case GL_BGRA:
815 case GL_ABGR_EXT:
Brian Paul7275d4d2006-03-20 15:25:18 +0000816 case GL_COLOR_INDEX:
817 /* nothing special */
Brian Paul84c5d0a2006-03-30 16:29:41 +0000818 /* Could assert that colorbuffer has RedBits > 0 */
Brian Paul7275d4d2006-03-20 15:25:18 +0000819 break;
820 case GL_DEPTH:
821 case GL_DEPTH_COMPONENT:
822 if (!att[BUFFER_DEPTH].Renderbuffer) {
823 return GL_FALSE;
824 }
825 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
826 break;
827 case GL_STENCIL:
828 case GL_STENCIL_INDEX:
829 if (!att[BUFFER_STENCIL].Renderbuffer) {
830 return GL_FALSE;
831 }
832 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
833 break;
834 case GL_DEPTH_STENCIL_EXT:
835 if (!att[BUFFER_DEPTH].Renderbuffer ||
836 !att[BUFFER_STENCIL].Renderbuffer) {
837 return GL_FALSE;
838 }
839 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
840 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
841 break;
842 default:
843 _mesa_problem(ctx,
Brian Paul590cd262006-03-24 22:53:00 +0000844 "Unexpected format 0x%x in _mesa_source_buffer_exists",
845 format);
Brian Paul7275d4d2006-03-20 15:25:18 +0000846 return GL_FALSE;
847 }
848
849 /* OK */
850 return GL_TRUE;
851}