blob: d0dbbbad02b2d06c2bb5089ed55e17a335cb63b0 [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
Brian Paule4b23562005-05-04 20:11:35 +0000169 /* save the visual */
170 fb->Visual = *visual;
171
172 /* Init glRead/DrawBuffer state */
173 if (visual->doubleBufferMode) {
174 fb->ColorDrawBuffer[0] = GL_BACK;
175 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_BACK_LEFT;
176 fb->ColorReadBuffer = GL_BACK;
Brian Paul048b13d2005-09-23 03:22:20 +0000177 fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT;
Brian Paule4b23562005-05-04 20:11:35 +0000178 }
179 else {
180 fb->ColorDrawBuffer[0] = GL_FRONT;
181 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT;
182 fb->ColorReadBuffer = GL_FRONT;
Brian Paul048b13d2005-09-23 03:22:20 +0000183 fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT;
Brian Paule4b23562005-05-04 20:11:35 +0000184 }
185
186 fb->Delete = _mesa_destroy_framebuffer;
Brian Pauld95000d2005-09-28 15:46:46 +0000187 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
Brian Paule4b23562005-05-04 20:11:35 +0000188
189 compute_depth_max(fb);
190}
191
192
193/**
Brian Paule4b23562005-05-04 20:11:35 +0000194 * Deallocate buffer and everything attached to it.
Brian Paulf084f602005-09-13 23:37:50 +0000195 * Typically called via the gl_framebuffer->Delete() method.
Brian Paule4b23562005-05-04 20:11:35 +0000196 */
197void
Brian Paulf084f602005-09-13 23:37:50 +0000198_mesa_destroy_framebuffer(struct gl_framebuffer *fb)
Brian Paule4b23562005-05-04 20:11:35 +0000199{
Brian Paulf084f602005-09-13 23:37:50 +0000200 if (fb) {
Brian Paulea4fe662006-03-26 05:22:17 +0000201 _glthread_DESTROY_MUTEX(fb->Mutex);
Brian Paulf084f602005-09-13 23:37:50 +0000202 _mesa_free_framebuffer_data(fb);
Brian Paul84716042005-11-16 04:05:54 +0000203 _mesa_free(fb);
Brian Paule4b23562005-05-04 20:11:35 +0000204 }
205}
206
207
208/**
209 * Free all the data hanging off the given gl_framebuffer, but don't free
210 * the gl_framebuffer object itself.
211 */
212void
213_mesa_free_framebuffer_data(struct gl_framebuffer *fb)
214{
215 GLuint i;
216
217 assert(fb);
218
219 for (i = 0; i < BUFFER_COUNT; i++) {
220 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
Brian Paul753af3a2006-03-25 17:57:52 +0000221 if (att->Renderbuffer) {
Brian Paule4b23562005-05-04 20:11:35 +0000222 struct gl_renderbuffer *rb = att->Renderbuffer;
Brian Paul2eb88c172006-05-20 15:06:35 +0000223 /* remove framebuffer's reference to renderbuffer */
224 _mesa_dereference_renderbuffer(&rb);
225 if (rb && rb->Name == 0) {
226 /* delete window system renderbuffer */
227 _mesa_dereference_renderbuffer(&rb);
Brian Paule4b23562005-05-04 20:11:35 +0000228 }
229 }
230 att->Type = GL_NONE;
231 att->Renderbuffer = NULL;
232 }
Brian Paul84716042005-11-16 04:05:54 +0000233
Brian Paulea4fe662006-03-26 05:22:17 +0000234 /* unbind depth/stencil to decr ref counts */
235 set_depth_renderbuffer(fb, NULL);
236 set_stencil_renderbuffer(fb, NULL);
Brian Paule4b23562005-05-04 20:11:35 +0000237}
238
239
240/**
Brian Paul2eb88c172006-05-20 15:06:35 +0000241 * Decrement the reference count on a framebuffer and delete it when
242 * the refcount hits zero.
243 * Note: we pass the address of a pointer and set it to NULL if we delete it.
244 */
245void
246_mesa_dereference_framebuffer(struct gl_framebuffer **fb)
247{
248 GLboolean deleteFlag = GL_FALSE;
249
250 _glthread_LOCK_MUTEX((*fb)->Mutex);
251 {
252 ASSERT((*fb)->RefCount > 0);
253 (*fb)->RefCount--;
254 deleteFlag = ((*fb)->RefCount == 0);
255 }
256 _glthread_UNLOCK_MUTEX((*fb)->Mutex);
257
258 if (deleteFlag) {
259 (*fb)->Delete(*fb);
260 *fb = NULL;
261 }
262}
263
264
265
266
267/**
Brian Paule4b23562005-05-04 20:11:35 +0000268 * Resize the given framebuffer's renderbuffers to the new width and height.
269 * This should only be used for window-system framebuffers, not
270 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object).
Brian Paul84716042005-11-16 04:05:54 +0000271 * This will typically be called via ctx->Driver.ResizeBuffers() or directly
272 * from a device driver.
273 *
274 * \note it's possible for ctx to be null since a window can be resized
275 * without a currently bound rendering context.
Brian Paule4b23562005-05-04 20:11:35 +0000276 */
277void
278_mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
279 GLuint width, GLuint height)
280{
281 GLuint i;
282
Brian Paulea4fe662006-03-26 05:22:17 +0000283 /* XXX I think we could check if the size is not changing
284 * and return early.
285 */
286
Brian Paule4b23562005-05-04 20:11:35 +0000287 /* For window system framebuffers, Name is zero */
288 assert(fb->Name == 0);
289
290 for (i = 0; i < BUFFER_COUNT; i++) {
291 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
292 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
293 struct gl_renderbuffer *rb = att->Renderbuffer;
294 /* only resize if size is changing */
295 if (rb->Width != width || rb->Height != height) {
Brian Paulea4fe662006-03-26 05:22:17 +0000296 /* could just as well pass rb->_ActualFormat here */
Brian Paule4b23562005-05-04 20:11:35 +0000297 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
Brian Paulea4fe662006-03-26 05:22:17 +0000298 ASSERT(rb->Width == width);
299 ASSERT(rb->Height == height);
Brian Paule4b23562005-05-04 20:11:35 +0000300 }
301 else {
302 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
Brian Paulea4fe662006-03-26 05:22:17 +0000303 /* no return */
Brian Paule4b23562005-05-04 20:11:35 +0000304 }
305 }
306 }
307 }
308
Brian Paulea4fe662006-03-26 05:22:17 +0000309 if (fb->_DepthBuffer) {
310 struct gl_renderbuffer *rb = fb->_DepthBuffer;
311 if (rb->Width != width || rb->Height != height) {
312 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
313 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
314 }
315 }
316 }
317
318 if (fb->_StencilBuffer) {
319 struct gl_renderbuffer *rb = fb->_StencilBuffer;
320 if (rb->Width != width || rb->Height != height) {
321 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
322 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
323 }
324 }
325 }
326
Brian Paule4b23562005-05-04 20:11:35 +0000327 fb->Width = width;
328 fb->Height = height;
Brian Paul52f686c2005-10-21 21:39:10 +0000329
330 /* to update scissor / window bounds */
Alan Hourihanefeb0ff12006-06-21 10:58:04 +0000331 if (ctx)
332 _mesa_update_draw_buffer_bounds(ctx);
Brian Paule4b23562005-05-04 20:11:35 +0000333}
334
335
336/**
337 * Examine all the framebuffer's renderbuffers to update the Width/Height
338 * fields of the framebuffer. If we have renderbuffers with different
339 * sizes, set the framebuffer's width and height to zero.
340 * Note: this is only intended for user-created framebuffers, not
341 * window-system framebuffes.
342 */
343static void
344update_framebuffer_size(struct gl_framebuffer *fb)
345{
346 GLboolean haveSize = GL_FALSE;
347 GLuint i;
348
349 /* user-created framebuffers only */
350 assert(fb->Name);
351
352 for (i = 0; i < BUFFER_COUNT; i++) {
353 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
354 const struct gl_renderbuffer *rb = att->Renderbuffer;
355 if (rb) {
356 if (haveSize) {
357 if (rb->Width != fb->Width && rb->Height != fb->Height) {
358 /* size mismatch! */
359 fb->Width = 0;
360 fb->Height = 0;
361 return;
362 }
363 }
364 else {
365 fb->Width = rb->Width;
366 fb->Height = rb->Height;
367 haveSize = GL_TRUE;
368 }
369 }
370 }
371}
372
373
374/**
375 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
376 * These values are computed from the buffer's width and height and
377 * the scissor box, if it's enabled.
378 * \param ctx the GL context.
379 */
380void
381_mesa_update_draw_buffer_bounds(GLcontext *ctx)
382{
383 struct gl_framebuffer *buffer = ctx->DrawBuffer;
384
Alan Hourihane161de102006-06-19 09:27:04 +0000385 if (!buffer)
386 return;
387
Brian Paule4b23562005-05-04 20:11:35 +0000388 if (buffer->Name) {
389 /* user-created framebuffer size depends on the renderbuffers */
390 update_framebuffer_size(buffer);
391 }
392
393 buffer->_Xmin = 0;
394 buffer->_Ymin = 0;
395 buffer->_Xmax = buffer->Width;
396 buffer->_Ymax = buffer->Height;
397
398 if (ctx->Scissor.Enabled) {
399 if (ctx->Scissor.X > buffer->_Xmin) {
400 buffer->_Xmin = ctx->Scissor.X;
401 }
402 if (ctx->Scissor.Y > buffer->_Ymin) {
403 buffer->_Ymin = ctx->Scissor.Y;
404 }
405 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
406 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
407 }
408 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
409 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
410 }
411 /* finally, check for empty region */
412 if (buffer->_Xmin > buffer->_Xmax) {
413 buffer->_Xmin = buffer->_Xmax;
414 }
415 if (buffer->_Ymin > buffer->_Ymax) {
416 buffer->_Ymin = buffer->_Ymax;
417 }
418 }
419
420 ASSERT(buffer->_Xmin <= buffer->_Xmax);
421 ASSERT(buffer->_Ymin <= buffer->_Ymax);
422}
423
424
425/**
426 * The glGet queries of the framebuffer red/green/blue size, stencil size,
427 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can
Brian Paulf084f602005-09-13 23:37:50 +0000428 * change depending on the renderbuffer bindings. This function updates
Brian Paule4b23562005-05-04 20:11:35 +0000429 * the given framebuffer's Visual from the current renderbuffer bindings.
Brian Paul02aa5fb2006-09-11 15:04:23 +0000430 *
431 * This may apply to user-created framebuffers or window system framebuffers.
Brian Pauleb063cf2005-10-04 14:48:24 +0000432 *
433 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal
434 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits.
435 * The former one is used to convert floating point depth values into
436 * integer Z values.
Brian Paule4b23562005-05-04 20:11:35 +0000437 */
438void
439_mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
440{
Brian Paul474f28e2005-10-08 14:41:17 +0000441 GLuint i;
442
Brian Paule4b23562005-05-04 20:11:35 +0000443 _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
Brian Paul474f28e2005-10-08 14:41:17 +0000444 fb->Visual.rgbMode = GL_TRUE; /* assume this */
Brian Paule4b23562005-05-04 20:11:35 +0000445
Brian Paul34b3b402006-04-20 00:45:08 +0000446#if 0 /* this _might_ be needed */
447 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
448 /* leave visual fields zero'd */
449 return;
450 }
451#endif
452
Brian Paul474f28e2005-10-08 14:41:17 +0000453 /* find first RGB or CI renderbuffer */
454 for (i = 0; i < BUFFER_COUNT; i++) {
455 if (fb->Attachment[i].Renderbuffer) {
456 const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
457 if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) {
458 fb->Visual.redBits = rb->RedBits;
459 fb->Visual.greenBits = rb->GreenBits;
460 fb->Visual.blueBits = rb->BlueBits;
461 fb->Visual.alphaBits = rb->AlphaBits;
462 fb->Visual.rgbBits = fb->Visual.redBits
463 + fb->Visual.greenBits + fb->Visual.blueBits;
464 fb->Visual.floatMode = GL_FALSE;
465 break;
466 }
467 else if (rb->_BaseFormat == GL_COLOR_INDEX) {
468 fb->Visual.indexBits = rb->IndexBits;
469 fb->Visual.rgbMode = GL_FALSE;
470 break;
471 }
472 }
Brian Paule4b23562005-05-04 20:11:35 +0000473 }
474
475 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
476 fb->Visual.haveDepthBuffer = GL_TRUE;
477 fb->Visual.depthBits
Brian Paul676d0ac2005-09-22 05:19:57 +0000478 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits;
Brian Paule4b23562005-05-04 20:11:35 +0000479 }
480
481 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
482 fb->Visual.haveStencilBuffer = GL_TRUE;
483 fb->Visual.stencilBits
Brian Paul676d0ac2005-09-22 05:19:57 +0000484 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits;
Brian Paule4b23562005-05-04 20:11:35 +0000485 }
486
Brian Paul02aa5fb2006-09-11 15:04:23 +0000487 if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) {
488 fb->Visual.haveAccumBuffer = GL_TRUE;
489 fb->Visual.accumRedBits
490 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->RedBits;
491 fb->Visual.accumGreenBits
492 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->GreenBits;
493 fb->Visual.accumBlueBits
494 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->BlueBits;
495 fb->Visual.accumAlphaBits
496 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->AlphaBits;
497 }
498
Brian Paule4b23562005-05-04 20:11:35 +0000499 compute_depth_max(fb);
500}
501
502
503/**
Brian Paulea4fe662006-03-26 05:22:17 +0000504 * Update the framebuffer's _DepthBuffer field using the renderbuffer
505 * found at the given attachment index.
506 *
507 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
508 * create and install a depth wrapper/adaptor.
509 *
510 * \param fb the framebuffer whose _DepthBuffer field to update
511 * \param attIndex indicates the renderbuffer to possibly wrap
Brian Paul84716042005-11-16 04:05:54 +0000512 */
Brian Paulea4fe662006-03-26 05:22:17 +0000513void
514_mesa_update_depth_buffer(GLcontext *ctx,
515 struct gl_framebuffer *fb,
516 GLuint attIndex)
Brian Paul84716042005-11-16 04:05:54 +0000517{
Brian Paulea4fe662006-03-26 05:22:17 +0000518 struct gl_renderbuffer *depthRb;
519
520 /* only one possiblity for now */
521 ASSERT(attIndex == BUFFER_DEPTH);
522
523 depthRb = fb->Attachment[attIndex].Renderbuffer;
524
525 if (depthRb && depthRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
526 /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */
Brian Paul57223382006-04-06 04:09:03 +0000527 if (!fb->_DepthBuffer
528 || fb->_DepthBuffer->Wrapped != depthRb
529 || fb->_DepthBuffer->_BaseFormat != GL_DEPTH_COMPONENT) {
Brian Paulea4fe662006-03-26 05:22:17 +0000530 /* need to update wrapper */
531 struct gl_renderbuffer *wrapper
532 = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb);
533 set_depth_renderbuffer(fb, wrapper);
534 ASSERT(fb->_DepthBuffer->Wrapped == depthRb);
Brian Paul84716042005-11-16 04:05:54 +0000535 }
536 }
Brian Paulea4fe662006-03-26 05:22:17 +0000537 else {
538 /* depthRb may be null */
539 set_depth_renderbuffer(fb, depthRb);
540 }
Brian Paul84716042005-11-16 04:05:54 +0000541}
542
Brian Paulea4fe662006-03-26 05:22:17 +0000543
Brian Paul84716042005-11-16 04:05:54 +0000544/**
Brian Paulea4fe662006-03-26 05:22:17 +0000545 * Update the framebuffer's _StencilBuffer field using the renderbuffer
546 * found at the given attachment index.
547 *
548 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
549 * create and install a stencil wrapper/adaptor.
550 *
551 * \param fb the framebuffer whose _StencilBuffer field to update
552 * \param attIndex indicates the renderbuffer to possibly wrap
Brian Paul84716042005-11-16 04:05:54 +0000553 */
Brian Paulea4fe662006-03-26 05:22:17 +0000554void
555_mesa_update_stencil_buffer(GLcontext *ctx,
556 struct gl_framebuffer *fb,
557 GLuint attIndex)
Brian Paul84716042005-11-16 04:05:54 +0000558{
Brian Paulea4fe662006-03-26 05:22:17 +0000559 struct gl_renderbuffer *stencilRb;
560
561 ASSERT(attIndex == BUFFER_DEPTH ||
562 attIndex == BUFFER_STENCIL);
563
564 stencilRb = fb->Attachment[attIndex].Renderbuffer;
565
566 if (stencilRb && stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
567 /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */
Brian Paul57223382006-04-06 04:09:03 +0000568 if (!fb->_StencilBuffer
569 || fb->_StencilBuffer->Wrapped != stencilRb
570 || fb->_StencilBuffer->_BaseFormat != GL_STENCIL_INDEX) {
Brian Paulea4fe662006-03-26 05:22:17 +0000571 /* need to update wrapper */
572 struct gl_renderbuffer *wrapper
573 = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb);
574 set_stencil_renderbuffer(fb, wrapper);
575 ASSERT(fb->_StencilBuffer->Wrapped == stencilRb);
Brian Paul84716042005-11-16 04:05:54 +0000576 }
577 }
Brian Paulea4fe662006-03-26 05:22:17 +0000578 else {
579 /* stencilRb may be null */
580 set_stencil_renderbuffer(fb, stencilRb);
581 }
582}
583
584
585/**
586 * Update the list of color drawing renderbuffer pointers.
587 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
588 * writing colors.
589 */
590static void
591update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb)
592{
593 GLuint output;
594
595 /*
596 * Fragment programs can write to multiple colorbuffers with
597 * the GL_ARB_draw_buffers extension.
598 */
599 for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) {
600 GLbitfield bufferMask = fb->_ColorDrawBufferMask[output];
601 GLuint count = 0;
602 GLuint i;
603 /* We need the inner loop here because glDrawBuffer(GL_FRONT_AND_BACK)
604 * can specify writing to two or four color buffers (for example).
605 */
606 for (i = 0; bufferMask && i < BUFFER_COUNT; i++) {
607 const GLuint bufferBit = 1 << i;
608 if (bufferBit & bufferMask) {
609 struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
610 if (rb) {
611 fb->_ColorDrawBuffers[output][count] = rb;
612 count++;
613 }
614 else {
615 /*_mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");*/
616 }
617 bufferMask &= ~bufferBit;
618 }
619 }
620 fb->_NumColorDrawBuffers[output] = count;
621 }
622}
623
624
625/**
626 * Update the color read renderbuffer pointer.
627 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
628 */
629static void
630update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
631{
Brian Paul28b014e2006-04-05 03:05:17 +0000632 (void) ctx;
Brian Paulea4fe662006-03-26 05:22:17 +0000633 if (fb->_ColorReadBufferIndex == -1) {
634 fb->_ColorReadBuffer = NULL; /* legal! */
635 }
636 else {
637 ASSERT(fb->_ColorReadBufferIndex >= 0);
638 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT);
639 fb->_ColorReadBuffer
640 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
641 }
Brian Paul84716042005-11-16 04:05:54 +0000642}
643
644
645/**
Brian Paule4b23562005-05-04 20:11:35 +0000646 * Update state related to the current draw/read framebuffers.
Brian Paul52783592005-08-31 21:38:53 +0000647 * Specifically, update these framebuffer fields:
648 * _ColorDrawBuffers
Brian Paul52783592005-08-31 21:38:53 +0000649 * _NumColorDrawBuffers
650 * _ColorReadBuffer
Brian Paul0f29ef62005-11-16 04:17:20 +0000651 * _DepthBuffer
652 * _StencilBuffer
Brian Paule4b23562005-05-04 20:11:35 +0000653 * If the current framebuffer is user-created, make sure it's complete.
Brian Paul52783592005-08-31 21:38:53 +0000654 * The following functions can effect this state: glReadBuffer,
Brian Paul0f29ef62005-11-16 04:17:20 +0000655 * glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT,
656 * glRenderbufferStorageEXT.
Brian Paule4b23562005-05-04 20:11:35 +0000657 */
658void
659_mesa_update_framebuffer(GLcontext *ctx)
660{
661 struct gl_framebuffer *fb = ctx->DrawBuffer;
Brian Paule4b23562005-05-04 20:11:35 +0000662
663 /* Completeness only matters for user-created framebuffers */
Brian Paul474f28e2005-10-08 14:41:17 +0000664 if (fb->Name != 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000665 _mesa_test_framebuffer_completeness(ctx, fb);
Brian Paul474f28e2005-10-08 14:41:17 +0000666 _mesa_update_framebuffer_visual(fb);
667 }
Brian Paule4b23562005-05-04 20:11:35 +0000668
Brian Paulea4fe662006-03-26 05:22:17 +0000669 update_color_draw_buffers(ctx, fb);
670 update_color_read_buffer(ctx, fb);
671 _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH);
672 _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL);
Brian Paul84716042005-11-16 04:05:54 +0000673
Brian Paule4b23562005-05-04 20:11:35 +0000674 compute_depth_max(fb);
675}
Brian Paul7275d4d2006-03-20 15:25:18 +0000676
677
678/**
679 * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels,
680 * glCopyTex[Sub]Image, etc. exists.
681 * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA,
682 * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL.
683 * \return GL_TRUE if buffer exists, GL_FALSE otherwise
684 */
685GLboolean
686_mesa_source_buffer_exists(GLcontext *ctx, GLenum format)
687{
688 const struct gl_renderbuffer_attachment *att
689 = ctx->ReadBuffer->Attachment;
690
691 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
692 return GL_FALSE;
693 }
694
695 switch (format) {
696 case GL_COLOR:
Brian Paul590cd262006-03-24 22:53:00 +0000697 case GL_RED:
698 case GL_GREEN:
699 case GL_BLUE:
Brian Paul7275d4d2006-03-20 15:25:18 +0000700 case GL_ALPHA:
701 case GL_LUMINANCE:
702 case GL_LUMINANCE_ALPHA:
703 case GL_INTENSITY:
704 case GL_RGB:
Brian Paul590cd262006-03-24 22:53:00 +0000705 case GL_BGR:
Brian Paul7275d4d2006-03-20 15:25:18 +0000706 case GL_RGBA:
Brian Paul590cd262006-03-24 22:53:00 +0000707 case GL_BGRA:
708 case GL_ABGR_EXT:
Brian Paul7275d4d2006-03-20 15:25:18 +0000709 case GL_COLOR_INDEX:
710 if (ctx->ReadBuffer->_ColorReadBuffer == NULL) {
711 return GL_FALSE;
712 }
Brian Paul84c5d0a2006-03-30 16:29:41 +0000713 /* XXX enable this post 6.5 release:
714 ASSERT(ctx->ReadBuffer->_ColorReadBuffer->RedBits > 0 ||
715 ctx->ReadBuffer->_ColorReadBuffer->IndexBits > 0);
716 */
Brian Paul7275d4d2006-03-20 15:25:18 +0000717 break;
718 case GL_DEPTH:
719 case GL_DEPTH_COMPONENT:
720 if (!att[BUFFER_DEPTH].Renderbuffer) {
721 return GL_FALSE;
722 }
723 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
724 break;
725 case GL_STENCIL:
726 case GL_STENCIL_INDEX:
727 if (!att[BUFFER_STENCIL].Renderbuffer) {
728 return GL_FALSE;
729 }
730 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
731 break;
732 case GL_DEPTH_STENCIL_EXT:
733 if (!att[BUFFER_DEPTH].Renderbuffer ||
734 !att[BUFFER_STENCIL].Renderbuffer) {
735 return GL_FALSE;
736 }
737 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
738 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
739 break;
740 default:
741 _mesa_problem(ctx,
Brian Paul590cd262006-03-24 22:53:00 +0000742 "Unexpected format 0x%x in _mesa_source_buffer_exists",
743 format);
Brian Paul7275d4d2006-03-20 15:25:18 +0000744 return GL_FALSE;
745 }
746
747 /* OK */
748 return GL_TRUE;
749}
750
751
752/**
753 * As above, but for drawing operations.
754 * XXX code do some code merging w/ above function.
755 */
756GLboolean
757_mesa_dest_buffer_exists(GLcontext *ctx, GLenum format)
758{
759 const struct gl_renderbuffer_attachment *att
760 = ctx->ReadBuffer->Attachment;
761
762 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
763 return GL_FALSE;
764 }
765
766 switch (format) {
767 case GL_COLOR:
Brian Paul590cd262006-03-24 22:53:00 +0000768 case GL_RED:
769 case GL_GREEN:
770 case GL_BLUE:
Brian Paul7275d4d2006-03-20 15:25:18 +0000771 case GL_ALPHA:
772 case GL_LUMINANCE:
773 case GL_LUMINANCE_ALPHA:
774 case GL_INTENSITY:
775 case GL_RGB:
Brian Paul590cd262006-03-24 22:53:00 +0000776 case GL_BGR:
Brian Paul7275d4d2006-03-20 15:25:18 +0000777 case GL_RGBA:
Brian Paul590cd262006-03-24 22:53:00 +0000778 case GL_BGRA:
779 case GL_ABGR_EXT:
Brian Paul7275d4d2006-03-20 15:25:18 +0000780 case GL_COLOR_INDEX:
781 /* nothing special */
Brian Paul84c5d0a2006-03-30 16:29:41 +0000782 /* Could assert that colorbuffer has RedBits > 0 */
Brian Paul7275d4d2006-03-20 15:25:18 +0000783 break;
784 case GL_DEPTH:
785 case GL_DEPTH_COMPONENT:
786 if (!att[BUFFER_DEPTH].Renderbuffer) {
787 return GL_FALSE;
788 }
789 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
790 break;
791 case GL_STENCIL:
792 case GL_STENCIL_INDEX:
793 if (!att[BUFFER_STENCIL].Renderbuffer) {
794 return GL_FALSE;
795 }
796 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
797 break;
798 case GL_DEPTH_STENCIL_EXT:
799 if (!att[BUFFER_DEPTH].Renderbuffer ||
800 !att[BUFFER_STENCIL].Renderbuffer) {
801 return GL_FALSE;
802 }
803 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
804 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
805 break;
806 default:
807 _mesa_problem(ctx,
Brian Paul590cd262006-03-24 22:53:00 +0000808 "Unexpected format 0x%x in _mesa_source_buffer_exists",
809 format);
Brian Paul7275d4d2006-03-20 15:25:18 +0000810 return GL_FALSE;
811 }
812
813 /* OK */
814 return GL_TRUE;
815}