blob: 3fe70f449c286a655897dc859dfc9644b2f503db [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) {
Brian Paul2eb88c172006-05-20 15:06:35 +000081 _mesa_dereference_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) {
Brian Paul2eb88c172006-05-20 15:06:35 +000099 _mesa_dereference_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) {
Brian Paule4b23562005-05-04 20:11:35 +0000226 struct gl_renderbuffer *rb = att->Renderbuffer;
Brian Paul2eb88c172006-05-20 15:06:35 +0000227 /* remove framebuffer's reference to renderbuffer */
228 _mesa_dereference_renderbuffer(&rb);
229 if (rb && rb->Name == 0) {
230 /* delete window system renderbuffer */
231 _mesa_dereference_renderbuffer(&rb);
Brian Paule4b23562005-05-04 20:11:35 +0000232 }
233 }
234 att->Type = GL_NONE;
235 att->Renderbuffer = NULL;
236 }
Brian Paul84716042005-11-16 04:05:54 +0000237
Brian Paulea4fe662006-03-26 05:22:17 +0000238 /* unbind depth/stencil to decr ref counts */
239 set_depth_renderbuffer(fb, NULL);
240 set_stencil_renderbuffer(fb, NULL);
Brian Paule4b23562005-05-04 20:11:35 +0000241}
242
243
244/**
Brian Paul2eb88c172006-05-20 15:06:35 +0000245 * Decrement the reference count on a framebuffer and delete it when
246 * the refcount hits zero.
247 * Note: we pass the address of a pointer and set it to NULL if we delete it.
248 */
249void
250_mesa_dereference_framebuffer(struct gl_framebuffer **fb)
251{
252 GLboolean deleteFlag = GL_FALSE;
253
254 _glthread_LOCK_MUTEX((*fb)->Mutex);
255 {
256 ASSERT((*fb)->RefCount > 0);
257 (*fb)->RefCount--;
258 deleteFlag = ((*fb)->RefCount == 0);
259 }
260 _glthread_UNLOCK_MUTEX((*fb)->Mutex);
261
262 if (deleteFlag) {
263 (*fb)->Delete(*fb);
264 *fb = NULL;
265 }
266}
267
268
269
270
271/**
Brian Paule4b23562005-05-04 20:11:35 +0000272 * Resize the given framebuffer's renderbuffers to the new width and height.
273 * This should only be used for window-system framebuffers, not
274 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object).
Brian Paul84716042005-11-16 04:05:54 +0000275 * This will typically be called via ctx->Driver.ResizeBuffers() or directly
276 * from a device driver.
277 *
278 * \note it's possible for ctx to be null since a window can be resized
279 * without a currently bound rendering context.
Brian Paule4b23562005-05-04 20:11:35 +0000280 */
281void
282_mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
283 GLuint width, GLuint height)
284{
285 GLuint i;
286
Brian Paulea4fe662006-03-26 05:22:17 +0000287 /* XXX I think we could check if the size is not changing
288 * and return early.
289 */
290
Brian Paule4b23562005-05-04 20:11:35 +0000291 /* For window system framebuffers, Name is zero */
292 assert(fb->Name == 0);
293
294 for (i = 0; i < BUFFER_COUNT; i++) {
295 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
296 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
297 struct gl_renderbuffer *rb = att->Renderbuffer;
298 /* only resize if size is changing */
299 if (rb->Width != width || rb->Height != height) {
Brian Paulea4fe662006-03-26 05:22:17 +0000300 /* could just as well pass rb->_ActualFormat here */
Brian Paule4b23562005-05-04 20:11:35 +0000301 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
Brian Paulea4fe662006-03-26 05:22:17 +0000302 ASSERT(rb->Width == width);
303 ASSERT(rb->Height == height);
Brian Paule4b23562005-05-04 20:11:35 +0000304 }
305 else {
306 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
Brian Paulea4fe662006-03-26 05:22:17 +0000307 /* no return */
Brian Paule4b23562005-05-04 20:11:35 +0000308 }
309 }
310 }
311 }
312
Brian Paulea4fe662006-03-26 05:22:17 +0000313 if (fb->_DepthBuffer) {
314 struct gl_renderbuffer *rb = fb->_DepthBuffer;
315 if (rb->Width != width || rb->Height != height) {
316 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
317 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
318 }
319 }
320 }
321
322 if (fb->_StencilBuffer) {
323 struct gl_renderbuffer *rb = fb->_StencilBuffer;
324 if (rb->Width != width || rb->Height != height) {
325 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
326 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
327 }
328 }
329 }
330
Brian Paule4b23562005-05-04 20:11:35 +0000331 fb->Width = width;
332 fb->Height = height;
Brian Paul52f686c2005-10-21 21:39:10 +0000333
Brian Paul041d6482006-10-16 17:26:30 +0000334 if (ctx) {
335 /* update scissor / window bounds */
Alan Hourihanefeb0ff12006-06-21 10:58:04 +0000336 _mesa_update_draw_buffer_bounds(ctx);
Brian Paul041d6482006-10-16 17:26:30 +0000337 /* Signal new buffer state so that swrast will update its clipping
338 * info (the CLIP_BIT flag).
339 */
340 ctx->NewState |= _NEW_BUFFERS;
341 }
Brian Paule4b23562005-05-04 20:11:35 +0000342}
343
344
345/**
346 * Examine all the framebuffer's renderbuffers to update the Width/Height
347 * fields of the framebuffer. If we have renderbuffers with different
348 * sizes, set the framebuffer's width and height to zero.
349 * Note: this is only intended for user-created framebuffers, not
350 * window-system framebuffes.
351 */
352static void
353update_framebuffer_size(struct gl_framebuffer *fb)
354{
355 GLboolean haveSize = GL_FALSE;
356 GLuint i;
357
358 /* user-created framebuffers only */
359 assert(fb->Name);
360
361 for (i = 0; i < BUFFER_COUNT; i++) {
362 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
363 const struct gl_renderbuffer *rb = att->Renderbuffer;
364 if (rb) {
365 if (haveSize) {
366 if (rb->Width != fb->Width && rb->Height != fb->Height) {
367 /* size mismatch! */
368 fb->Width = 0;
369 fb->Height = 0;
370 return;
371 }
372 }
373 else {
374 fb->Width = rb->Width;
375 fb->Height = rb->Height;
376 haveSize = GL_TRUE;
377 }
378 }
379 }
380}
381
382
383/**
384 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
385 * These values are computed from the buffer's width and height and
386 * the scissor box, if it's enabled.
387 * \param ctx the GL context.
388 */
389void
390_mesa_update_draw_buffer_bounds(GLcontext *ctx)
391{
392 struct gl_framebuffer *buffer = ctx->DrawBuffer;
393
Alan Hourihane161de102006-06-19 09:27:04 +0000394 if (!buffer)
395 return;
396
Brian Paule4b23562005-05-04 20:11:35 +0000397 if (buffer->Name) {
398 /* user-created framebuffer size depends on the renderbuffers */
399 update_framebuffer_size(buffer);
400 }
401
402 buffer->_Xmin = 0;
403 buffer->_Ymin = 0;
404 buffer->_Xmax = buffer->Width;
405 buffer->_Ymax = buffer->Height;
406
407 if (ctx->Scissor.Enabled) {
408 if (ctx->Scissor.X > buffer->_Xmin) {
409 buffer->_Xmin = ctx->Scissor.X;
410 }
411 if (ctx->Scissor.Y > buffer->_Ymin) {
412 buffer->_Ymin = ctx->Scissor.Y;
413 }
414 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
415 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
416 }
417 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
418 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
419 }
420 /* finally, check for empty region */
421 if (buffer->_Xmin > buffer->_Xmax) {
422 buffer->_Xmin = buffer->_Xmax;
423 }
424 if (buffer->_Ymin > buffer->_Ymax) {
425 buffer->_Ymin = buffer->_Ymax;
426 }
427 }
428
429 ASSERT(buffer->_Xmin <= buffer->_Xmax);
430 ASSERT(buffer->_Ymin <= buffer->_Ymax);
431}
432
433
434/**
435 * The glGet queries of the framebuffer red/green/blue size, stencil size,
436 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can
Brian Paulf084f602005-09-13 23:37:50 +0000437 * change depending on the renderbuffer bindings. This function updates
Brian Paule4b23562005-05-04 20:11:35 +0000438 * the given framebuffer's Visual from the current renderbuffer bindings.
Brian Paul02aa5fb2006-09-11 15:04:23 +0000439 *
440 * This may apply to user-created framebuffers or window system framebuffers.
Brian Pauleb063cf2005-10-04 14:48:24 +0000441 *
442 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal
443 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits.
444 * The former one is used to convert floating point depth values into
445 * integer Z values.
Brian Paule4b23562005-05-04 20:11:35 +0000446 */
447void
448_mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
449{
Brian Paul474f28e2005-10-08 14:41:17 +0000450 GLuint i;
451
Brian Paule4b23562005-05-04 20:11:35 +0000452 _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
Brian Paul474f28e2005-10-08 14:41:17 +0000453 fb->Visual.rgbMode = GL_TRUE; /* assume this */
Brian Paule4b23562005-05-04 20:11:35 +0000454
Brian Paul34b3b402006-04-20 00:45:08 +0000455#if 0 /* this _might_ be needed */
456 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
457 /* leave visual fields zero'd */
458 return;
459 }
460#endif
461
Brian Paul474f28e2005-10-08 14:41:17 +0000462 /* find first RGB or CI renderbuffer */
463 for (i = 0; i < BUFFER_COUNT; i++) {
464 if (fb->Attachment[i].Renderbuffer) {
465 const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
466 if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) {
467 fb->Visual.redBits = rb->RedBits;
468 fb->Visual.greenBits = rb->GreenBits;
469 fb->Visual.blueBits = rb->BlueBits;
470 fb->Visual.alphaBits = rb->AlphaBits;
471 fb->Visual.rgbBits = fb->Visual.redBits
472 + fb->Visual.greenBits + fb->Visual.blueBits;
473 fb->Visual.floatMode = GL_FALSE;
474 break;
475 }
476 else if (rb->_BaseFormat == GL_COLOR_INDEX) {
477 fb->Visual.indexBits = rb->IndexBits;
478 fb->Visual.rgbMode = GL_FALSE;
479 break;
480 }
481 }
Brian Paule4b23562005-05-04 20:11:35 +0000482 }
483
484 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
485 fb->Visual.haveDepthBuffer = GL_TRUE;
486 fb->Visual.depthBits
Brian Paul676d0ac2005-09-22 05:19:57 +0000487 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits;
Brian Paule4b23562005-05-04 20:11:35 +0000488 }
489
490 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
491 fb->Visual.haveStencilBuffer = GL_TRUE;
492 fb->Visual.stencilBits
Brian Paul676d0ac2005-09-22 05:19:57 +0000493 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits;
Brian Paule4b23562005-05-04 20:11:35 +0000494 }
495
Brian Paul02aa5fb2006-09-11 15:04:23 +0000496 if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) {
497 fb->Visual.haveAccumBuffer = GL_TRUE;
498 fb->Visual.accumRedBits
499 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->RedBits;
500 fb->Visual.accumGreenBits
501 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->GreenBits;
502 fb->Visual.accumBlueBits
503 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->BlueBits;
504 fb->Visual.accumAlphaBits
505 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->AlphaBits;
506 }
507
Brian Paule4b23562005-05-04 20:11:35 +0000508 compute_depth_max(fb);
509}
510
511
512/**
Brian Paulea4fe662006-03-26 05:22:17 +0000513 * Update the framebuffer's _DepthBuffer field using the renderbuffer
514 * found at the given attachment index.
515 *
516 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
517 * create and install a depth wrapper/adaptor.
518 *
519 * \param fb the framebuffer whose _DepthBuffer field to update
520 * \param attIndex indicates the renderbuffer to possibly wrap
Brian Paul84716042005-11-16 04:05:54 +0000521 */
Brian Paulea4fe662006-03-26 05:22:17 +0000522void
523_mesa_update_depth_buffer(GLcontext *ctx,
524 struct gl_framebuffer *fb,
525 GLuint attIndex)
Brian Paul84716042005-11-16 04:05:54 +0000526{
Brian Paulea4fe662006-03-26 05:22:17 +0000527 struct gl_renderbuffer *depthRb;
528
529 /* only one possiblity for now */
530 ASSERT(attIndex == BUFFER_DEPTH);
531
532 depthRb = fb->Attachment[attIndex].Renderbuffer;
533
534 if (depthRb && depthRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
535 /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */
Brian Paul57223382006-04-06 04:09:03 +0000536 if (!fb->_DepthBuffer
537 || fb->_DepthBuffer->Wrapped != depthRb
538 || fb->_DepthBuffer->_BaseFormat != GL_DEPTH_COMPONENT) {
Brian Paulea4fe662006-03-26 05:22:17 +0000539 /* need to update wrapper */
540 struct gl_renderbuffer *wrapper
541 = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb);
542 set_depth_renderbuffer(fb, wrapper);
543 ASSERT(fb->_DepthBuffer->Wrapped == depthRb);
Brian Paul84716042005-11-16 04:05:54 +0000544 }
545 }
Brian Paulea4fe662006-03-26 05:22:17 +0000546 else {
547 /* depthRb may be null */
548 set_depth_renderbuffer(fb, depthRb);
549 }
Brian Paul84716042005-11-16 04:05:54 +0000550}
551
Brian Paulea4fe662006-03-26 05:22:17 +0000552
Brian Paul84716042005-11-16 04:05:54 +0000553/**
Brian Paulea4fe662006-03-26 05:22:17 +0000554 * Update the framebuffer's _StencilBuffer field using the renderbuffer
555 * found at the given attachment index.
556 *
557 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
558 * create and install a stencil wrapper/adaptor.
559 *
560 * \param fb the framebuffer whose _StencilBuffer field to update
561 * \param attIndex indicates the renderbuffer to possibly wrap
Brian Paul84716042005-11-16 04:05:54 +0000562 */
Brian Paulea4fe662006-03-26 05:22:17 +0000563void
564_mesa_update_stencil_buffer(GLcontext *ctx,
565 struct gl_framebuffer *fb,
566 GLuint attIndex)
Brian Paul84716042005-11-16 04:05:54 +0000567{
Brian Paulea4fe662006-03-26 05:22:17 +0000568 struct gl_renderbuffer *stencilRb;
569
570 ASSERT(attIndex == BUFFER_DEPTH ||
571 attIndex == BUFFER_STENCIL);
572
573 stencilRb = fb->Attachment[attIndex].Renderbuffer;
574
575 if (stencilRb && stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
576 /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */
Brian Paul57223382006-04-06 04:09:03 +0000577 if (!fb->_StencilBuffer
578 || fb->_StencilBuffer->Wrapped != stencilRb
579 || fb->_StencilBuffer->_BaseFormat != GL_STENCIL_INDEX) {
Brian Paulea4fe662006-03-26 05:22:17 +0000580 /* need to update wrapper */
581 struct gl_renderbuffer *wrapper
582 = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb);
583 set_stencil_renderbuffer(fb, wrapper);
584 ASSERT(fb->_StencilBuffer->Wrapped == stencilRb);
Brian Paul84716042005-11-16 04:05:54 +0000585 }
586 }
Brian Paulea4fe662006-03-26 05:22:17 +0000587 else {
588 /* stencilRb may be null */
589 set_stencil_renderbuffer(fb, stencilRb);
590 }
591}
592
593
594/**
595 * Update the list of color drawing renderbuffer pointers.
596 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
597 * writing colors.
598 */
599static void
600update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb)
601{
602 GLuint output;
603
604 /*
605 * Fragment programs can write to multiple colorbuffers with
606 * the GL_ARB_draw_buffers extension.
607 */
608 for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) {
609 GLbitfield bufferMask = fb->_ColorDrawBufferMask[output];
610 GLuint count = 0;
611 GLuint i;
Briane6a93812007-02-26 11:37:37 -0700612 if (!fb->DeletePending) {
613 /* We need the inner loop here because glDrawBuffer(GL_FRONT_AND_BACK)
614 * can specify writing to two or four color buffers (for example).
615 */
616 for (i = 0; bufferMask && i < BUFFER_COUNT; i++) {
617 const GLuint bufferBit = 1 << i;
618 if (bufferBit & bufferMask) {
619 struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
620 if (rb) {
621 fb->_ColorDrawBuffers[output][count] = rb;
622 count++;
623 }
624 else {
625 /*
626 _mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");
627 */
628 }
629 bufferMask &= ~bufferBit;
Brian Paulea4fe662006-03-26 05:22:17 +0000630 }
Brian Paulea4fe662006-03-26 05:22:17 +0000631 }
632 }
633 fb->_NumColorDrawBuffers[output] = count;
634 }
635}
636
637
638/**
639 * Update the color read renderbuffer pointer.
640 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
641 */
642static void
643update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
644{
Brian Paul28b014e2006-04-05 03:05:17 +0000645 (void) ctx;
Briane6a93812007-02-26 11:37:37 -0700646 if (fb->_ColorReadBufferIndex == -1 || fb->DeletePending) {
Brian Paulea4fe662006-03-26 05:22:17 +0000647 fb->_ColorReadBuffer = NULL; /* legal! */
648 }
649 else {
650 ASSERT(fb->_ColorReadBufferIndex >= 0);
651 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT);
652 fb->_ColorReadBuffer
653 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
654 }
Brian Paul84716042005-11-16 04:05:54 +0000655}
656
657
658/**
Brian Paule4b23562005-05-04 20:11:35 +0000659 * Update state related to the current draw/read framebuffers.
Brian Paul52783592005-08-31 21:38:53 +0000660 * Specifically, update these framebuffer fields:
661 * _ColorDrawBuffers
Brian Paul52783592005-08-31 21:38:53 +0000662 * _NumColorDrawBuffers
663 * _ColorReadBuffer
Brian Paul0f29ef62005-11-16 04:17:20 +0000664 * _DepthBuffer
665 * _StencilBuffer
Brian Paule4b23562005-05-04 20:11:35 +0000666 * If the current framebuffer is user-created, make sure it's complete.
Brian Paul52783592005-08-31 21:38:53 +0000667 * The following functions can effect this state: glReadBuffer,
Brian Paul0f29ef62005-11-16 04:17:20 +0000668 * glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT,
669 * glRenderbufferStorageEXT.
Brian Paule4b23562005-05-04 20:11:35 +0000670 */
671void
672_mesa_update_framebuffer(GLcontext *ctx)
673{
674 struct gl_framebuffer *fb = ctx->DrawBuffer;
Brian Paule4b23562005-05-04 20:11:35 +0000675
676 /* Completeness only matters for user-created framebuffers */
Brian Paul474f28e2005-10-08 14:41:17 +0000677 if (fb->Name != 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000678 _mesa_test_framebuffer_completeness(ctx, fb);
Brian Paul474f28e2005-10-08 14:41:17 +0000679 _mesa_update_framebuffer_visual(fb);
680 }
Brian Paule4b23562005-05-04 20:11:35 +0000681
Brian Paulea4fe662006-03-26 05:22:17 +0000682 update_color_draw_buffers(ctx, fb);
683 update_color_read_buffer(ctx, fb);
684 _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH);
685 _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL);
Brian Paul84716042005-11-16 04:05:54 +0000686
Brian Paule4b23562005-05-04 20:11:35 +0000687 compute_depth_max(fb);
688}
Brian Paul7275d4d2006-03-20 15:25:18 +0000689
690
691/**
692 * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels,
693 * glCopyTex[Sub]Image, etc. exists.
694 * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA,
695 * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL.
696 * \return GL_TRUE if buffer exists, GL_FALSE otherwise
697 */
698GLboolean
699_mesa_source_buffer_exists(GLcontext *ctx, GLenum format)
700{
701 const struct gl_renderbuffer_attachment *att
702 = ctx->ReadBuffer->Attachment;
703
704 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
705 return GL_FALSE;
706 }
707
708 switch (format) {
709 case GL_COLOR:
Brian Paul590cd262006-03-24 22:53:00 +0000710 case GL_RED:
711 case GL_GREEN:
712 case GL_BLUE:
Brian Paul7275d4d2006-03-20 15:25:18 +0000713 case GL_ALPHA:
714 case GL_LUMINANCE:
715 case GL_LUMINANCE_ALPHA:
716 case GL_INTENSITY:
717 case GL_RGB:
Brian Paul590cd262006-03-24 22:53:00 +0000718 case GL_BGR:
Brian Paul7275d4d2006-03-20 15:25:18 +0000719 case GL_RGBA:
Brian Paul590cd262006-03-24 22:53:00 +0000720 case GL_BGRA:
721 case GL_ABGR_EXT:
Brian Paul7275d4d2006-03-20 15:25:18 +0000722 case GL_COLOR_INDEX:
723 if (ctx->ReadBuffer->_ColorReadBuffer == NULL) {
724 return GL_FALSE;
725 }
Brian Paul84c5d0a2006-03-30 16:29:41 +0000726 /* XXX enable this post 6.5 release:
727 ASSERT(ctx->ReadBuffer->_ColorReadBuffer->RedBits > 0 ||
728 ctx->ReadBuffer->_ColorReadBuffer->IndexBits > 0);
729 */
Brian Paul7275d4d2006-03-20 15:25:18 +0000730 break;
731 case GL_DEPTH:
732 case GL_DEPTH_COMPONENT:
733 if (!att[BUFFER_DEPTH].Renderbuffer) {
734 return GL_FALSE;
735 }
736 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
737 break;
738 case GL_STENCIL:
739 case GL_STENCIL_INDEX:
740 if (!att[BUFFER_STENCIL].Renderbuffer) {
741 return GL_FALSE;
742 }
743 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
744 break;
745 case GL_DEPTH_STENCIL_EXT:
746 if (!att[BUFFER_DEPTH].Renderbuffer ||
747 !att[BUFFER_STENCIL].Renderbuffer) {
748 return GL_FALSE;
749 }
750 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
751 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
752 break;
753 default:
754 _mesa_problem(ctx,
Brian Paul590cd262006-03-24 22:53:00 +0000755 "Unexpected format 0x%x in _mesa_source_buffer_exists",
756 format);
Brian Paul7275d4d2006-03-20 15:25:18 +0000757 return GL_FALSE;
758 }
759
760 /* OK */
761 return GL_TRUE;
762}
763
764
765/**
766 * As above, but for drawing operations.
767 * XXX code do some code merging w/ above function.
768 */
769GLboolean
770_mesa_dest_buffer_exists(GLcontext *ctx, GLenum format)
771{
772 const struct gl_renderbuffer_attachment *att
773 = ctx->ReadBuffer->Attachment;
774
775 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
776 return GL_FALSE;
777 }
778
779 switch (format) {
780 case GL_COLOR:
Brian Paul590cd262006-03-24 22:53:00 +0000781 case GL_RED:
782 case GL_GREEN:
783 case GL_BLUE:
Brian Paul7275d4d2006-03-20 15:25:18 +0000784 case GL_ALPHA:
785 case GL_LUMINANCE:
786 case GL_LUMINANCE_ALPHA:
787 case GL_INTENSITY:
788 case GL_RGB:
Brian Paul590cd262006-03-24 22:53:00 +0000789 case GL_BGR:
Brian Paul7275d4d2006-03-20 15:25:18 +0000790 case GL_RGBA:
Brian Paul590cd262006-03-24 22:53:00 +0000791 case GL_BGRA:
792 case GL_ABGR_EXT:
Brian Paul7275d4d2006-03-20 15:25:18 +0000793 case GL_COLOR_INDEX:
794 /* nothing special */
Brian Paul84c5d0a2006-03-30 16:29:41 +0000795 /* Could assert that colorbuffer has RedBits > 0 */
Brian Paul7275d4d2006-03-20 15:25:18 +0000796 break;
797 case GL_DEPTH:
798 case GL_DEPTH_COMPONENT:
799 if (!att[BUFFER_DEPTH].Renderbuffer) {
800 return GL_FALSE;
801 }
802 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
803 break;
804 case GL_STENCIL:
805 case GL_STENCIL_INDEX:
806 if (!att[BUFFER_STENCIL].Renderbuffer) {
807 return GL_FALSE;
808 }
809 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
810 break;
811 case GL_DEPTH_STENCIL_EXT:
812 if (!att[BUFFER_DEPTH].Renderbuffer ||
813 !att[BUFFER_STENCIL].Renderbuffer) {
814 return GL_FALSE;
815 }
816 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
817 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
818 break;
819 default:
820 _mesa_problem(ctx,
Brian Paul590cd262006-03-24 22:53:00 +0000821 "Unexpected format 0x%x in _mesa_source_buffer_exists",
822 format);
Brian Paul7275d4d2006-03-20 15:25:18 +0000823 return GL_FALSE;
824 }
825
826 /* OK */
827 return GL_TRUE;
828}