blob: 55e9bbc79d681ae6a35e3a33c98b9fdb376a5adf [file] [log] [blame]
Brian Paule4b23562005-05-04 20:11:35 +00001/*
2 * Mesa 3-D graphics library
Brian Paulf084f602005-09-13 23:37:50 +00003 * Version: 6.5
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) {
81 fb->_DepthBuffer->RefCount--;
82 if (fb->_DepthBuffer->RefCount <= 0) {
83 fb->_DepthBuffer->Delete(fb->_DepthBuffer);
84 }
85 }
86 fb->_DepthBuffer = rb;
87 if (rb) {
88 rb->RefCount++;
89 }
90}
91
92
93/**
94 * Set the framebuffer's _StencilBuffer field, taking care of
95 * reference counts, etc.
96 */
97static void
98set_stencil_renderbuffer(struct gl_framebuffer *fb,
99 struct gl_renderbuffer *rb)
100{
101 if (fb->_StencilBuffer) {
102 fb->_StencilBuffer->RefCount--;
103 if (fb->_StencilBuffer->RefCount <= 0) {
104 fb->_StencilBuffer->Delete(fb->_StencilBuffer);
105 }
106 }
107 fb->_StencilBuffer = rb;
108 if (rb) {
109 rb->RefCount++;
110 }
111}
112
113
114/**
Brian Paule4b23562005-05-04 20:11:35 +0000115 * Create and initialize a gl_framebuffer object.
116 * This is intended for creating _window_system_ framebuffers, not generic
117 * framebuffer objects ala GL_EXT_framebuffer_object.
118 *
119 * \sa _mesa_new_framebuffer
120 */
121struct gl_framebuffer *
122_mesa_create_framebuffer(const GLvisual *visual)
123{
124 struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer);
125 assert(visual);
126 if (fb) {
127 _mesa_initialize_framebuffer(fb, visual);
128 }
129 return fb;
130}
131
132
133/**
134 * Allocate a new gl_framebuffer object.
135 * This is the default function for ctx->Driver.NewFramebuffer().
136 * This is for allocating user-created framebuffers, not window-system
137 * framebuffers!
138 * \sa _mesa_create_framebuffer
139 */
140struct gl_framebuffer *
141_mesa_new_framebuffer(GLcontext *ctx, GLuint name)
142{
143 struct gl_framebuffer *fb;
144 assert(name != 0);
145 fb = CALLOC_STRUCT(gl_framebuffer);
146 if (fb) {
147 fb->Name = name;
148 fb->RefCount = 1;
Brian Paule4b23562005-05-04 20:11:35 +0000149 fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT;
150 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_COLOR0;
151 fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT;
Brian Paul048b13d2005-09-23 03:22:20 +0000152 fb->_ColorReadBufferIndex = BUFFER_COLOR0;
Brian Paule4b23562005-05-04 20:11:35 +0000153 fb->Delete = _mesa_destroy_framebuffer;
154 }
155 return fb;
156}
157
158
159/**
Brian Paulf084f602005-09-13 23:37:50 +0000160 * Initialize a gl_framebuffer object. Typically used to initialize
161 * window system-created framebuffers, not user-created framebuffers.
Brian Paule4b23562005-05-04 20:11:35 +0000162 * \sa _mesa_create_framebuffer
163 */
164void
165_mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual)
166{
167 assert(fb);
168 assert(visual);
169
170 _mesa_bzero(fb, sizeof(struct gl_framebuffer));
171
Brian Paulea4fe662006-03-26 05:22:17 +0000172 _glthread_INIT_MUTEX(fb->Mutex);
173
Brian Paule4b23562005-05-04 20:11:35 +0000174 /* save the visual */
175 fb->Visual = *visual;
176
177 /* Init glRead/DrawBuffer state */
178 if (visual->doubleBufferMode) {
179 fb->ColorDrawBuffer[0] = GL_BACK;
180 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_BACK_LEFT;
181 fb->ColorReadBuffer = GL_BACK;
Brian Paul048b13d2005-09-23 03:22:20 +0000182 fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT;
Brian Paule4b23562005-05-04 20:11:35 +0000183 }
184 else {
185 fb->ColorDrawBuffer[0] = GL_FRONT;
186 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT;
187 fb->ColorReadBuffer = GL_FRONT;
Brian Paul048b13d2005-09-23 03:22:20 +0000188 fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT;
Brian Paule4b23562005-05-04 20:11:35 +0000189 }
190
191 fb->Delete = _mesa_destroy_framebuffer;
Brian Pauld95000d2005-09-28 15:46:46 +0000192 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
Brian Paule4b23562005-05-04 20:11:35 +0000193
194 compute_depth_max(fb);
195}
196
197
198/**
Brian Paule4b23562005-05-04 20:11:35 +0000199 * Deallocate buffer and everything attached to it.
Brian Paulf084f602005-09-13 23:37:50 +0000200 * Typically called via the gl_framebuffer->Delete() method.
Brian Paule4b23562005-05-04 20:11:35 +0000201 */
202void
Brian Paulf084f602005-09-13 23:37:50 +0000203_mesa_destroy_framebuffer(struct gl_framebuffer *fb)
Brian Paule4b23562005-05-04 20:11:35 +0000204{
Brian Paulf084f602005-09-13 23:37:50 +0000205 if (fb) {
Brian Paulea4fe662006-03-26 05:22:17 +0000206 _glthread_DESTROY_MUTEX(fb->Mutex);
Brian Paulf084f602005-09-13 23:37:50 +0000207 _mesa_free_framebuffer_data(fb);
Brian Paul84716042005-11-16 04:05:54 +0000208 _mesa_free(fb);
Brian Paule4b23562005-05-04 20:11:35 +0000209 }
210}
211
212
213/**
214 * Free all the data hanging off the given gl_framebuffer, but don't free
215 * the gl_framebuffer object itself.
216 */
217void
218_mesa_free_framebuffer_data(struct gl_framebuffer *fb)
219{
220 GLuint i;
221
222 assert(fb);
223
224 for (i = 0; i < BUFFER_COUNT; i++) {
225 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
Brian Paul753af3a2006-03-25 17:57:52 +0000226 if (att->Renderbuffer) {
Brian Paule4b23562005-05-04 20:11:35 +0000227 struct gl_renderbuffer *rb = att->Renderbuffer;
Brian Paulea4fe662006-03-26 05:22:17 +0000228 _glthread_LOCK_MUTEX(rb->Mutex);
Brian Paule4b23562005-05-04 20:11:35 +0000229 rb->RefCount--;
Brian Paulea4fe662006-03-26 05:22:17 +0000230 _glthread_UNLOCK_MUTEX(rb->Mutex);
Brian Paule4b23562005-05-04 20:11:35 +0000231 if (rb->RefCount == 0) {
232 rb->Delete(rb);
233 }
234 }
235 att->Type = GL_NONE;
236 att->Renderbuffer = NULL;
237 }
Brian Paul84716042005-11-16 04:05:54 +0000238
Brian Paulea4fe662006-03-26 05:22:17 +0000239 /* unbind depth/stencil to decr ref counts */
240 set_depth_renderbuffer(fb, NULL);
241 set_stencil_renderbuffer(fb, NULL);
Brian Paule4b23562005-05-04 20:11:35 +0000242}
243
244
245/**
246 * Resize the given framebuffer's renderbuffers to the new width and height.
247 * This should only be used for window-system framebuffers, not
248 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object).
Brian Paul84716042005-11-16 04:05:54 +0000249 * This will typically be called via ctx->Driver.ResizeBuffers() or directly
250 * from a device driver.
251 *
252 * \note it's possible for ctx to be null since a window can be resized
253 * without a currently bound rendering context.
Brian Paule4b23562005-05-04 20:11:35 +0000254 */
255void
256_mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
257 GLuint width, GLuint height)
258{
259 GLuint i;
260
Brian Paulea4fe662006-03-26 05:22:17 +0000261 /* XXX I think we could check if the size is not changing
262 * and return early.
263 */
264
Brian Paule4b23562005-05-04 20:11:35 +0000265 /* For window system framebuffers, Name is zero */
266 assert(fb->Name == 0);
267
268 for (i = 0; i < BUFFER_COUNT; i++) {
269 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
270 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
271 struct gl_renderbuffer *rb = att->Renderbuffer;
272 /* only resize if size is changing */
273 if (rb->Width != width || rb->Height != height) {
Brian Paulea4fe662006-03-26 05:22:17 +0000274 /* could just as well pass rb->_ActualFormat here */
Brian Paule4b23562005-05-04 20:11:35 +0000275 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
Brian Paulea4fe662006-03-26 05:22:17 +0000276 ASSERT(rb->Width == width);
277 ASSERT(rb->Height == height);
Brian Paule4b23562005-05-04 20:11:35 +0000278 }
279 else {
280 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
Brian Paulea4fe662006-03-26 05:22:17 +0000281 /* no return */
Brian Paule4b23562005-05-04 20:11:35 +0000282 }
283 }
284 }
285 }
286
Brian Paulea4fe662006-03-26 05:22:17 +0000287 if (fb->_DepthBuffer) {
288 struct gl_renderbuffer *rb = fb->_DepthBuffer;
289 if (rb->Width != width || rb->Height != height) {
290 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
291 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
292 }
293 }
294 }
295
296 if (fb->_StencilBuffer) {
297 struct gl_renderbuffer *rb = fb->_StencilBuffer;
298 if (rb->Width != width || rb->Height != height) {
299 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
300 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
301 }
302 }
303 }
304
Brian Paule4b23562005-05-04 20:11:35 +0000305 fb->Width = width;
306 fb->Height = height;
Brian Paul52f686c2005-10-21 21:39:10 +0000307
308 /* to update scissor / window bounds */
Brian Paulea4fe662006-03-26 05:22:17 +0000309 _mesa_update_draw_buffer_bounds(ctx);
Brian Paule4b23562005-05-04 20:11:35 +0000310}
311
312
313/**
314 * Examine all the framebuffer's renderbuffers to update the Width/Height
315 * fields of the framebuffer. If we have renderbuffers with different
316 * sizes, set the framebuffer's width and height to zero.
317 * Note: this is only intended for user-created framebuffers, not
318 * window-system framebuffes.
319 */
320static void
321update_framebuffer_size(struct gl_framebuffer *fb)
322{
323 GLboolean haveSize = GL_FALSE;
324 GLuint i;
325
326 /* user-created framebuffers only */
327 assert(fb->Name);
328
329 for (i = 0; i < BUFFER_COUNT; i++) {
330 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
331 const struct gl_renderbuffer *rb = att->Renderbuffer;
332 if (rb) {
333 if (haveSize) {
334 if (rb->Width != fb->Width && rb->Height != fb->Height) {
335 /* size mismatch! */
336 fb->Width = 0;
337 fb->Height = 0;
338 return;
339 }
340 }
341 else {
342 fb->Width = rb->Width;
343 fb->Height = rb->Height;
344 haveSize = GL_TRUE;
345 }
346 }
347 }
348}
349
350
351/**
352 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
353 * These values are computed from the buffer's width and height and
354 * the scissor box, if it's enabled.
355 * \param ctx the GL context.
356 */
357void
358_mesa_update_draw_buffer_bounds(GLcontext *ctx)
359{
360 struct gl_framebuffer *buffer = ctx->DrawBuffer;
361
362 if (buffer->Name) {
363 /* user-created framebuffer size depends on the renderbuffers */
364 update_framebuffer_size(buffer);
365 }
366
367 buffer->_Xmin = 0;
368 buffer->_Ymin = 0;
369 buffer->_Xmax = buffer->Width;
370 buffer->_Ymax = buffer->Height;
371
372 if (ctx->Scissor.Enabled) {
373 if (ctx->Scissor.X > buffer->_Xmin) {
374 buffer->_Xmin = ctx->Scissor.X;
375 }
376 if (ctx->Scissor.Y > buffer->_Ymin) {
377 buffer->_Ymin = ctx->Scissor.Y;
378 }
379 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
380 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
381 }
382 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
383 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
384 }
385 /* finally, check for empty region */
386 if (buffer->_Xmin > buffer->_Xmax) {
387 buffer->_Xmin = buffer->_Xmax;
388 }
389 if (buffer->_Ymin > buffer->_Ymax) {
390 buffer->_Ymin = buffer->_Ymax;
391 }
392 }
393
394 ASSERT(buffer->_Xmin <= buffer->_Xmax);
395 ASSERT(buffer->_Ymin <= buffer->_Ymax);
396}
397
398
399/**
400 * The glGet queries of the framebuffer red/green/blue size, stencil size,
401 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can
Brian Paulf084f602005-09-13 23:37:50 +0000402 * change depending on the renderbuffer bindings. This function updates
Brian Paule4b23562005-05-04 20:11:35 +0000403 * the given framebuffer's Visual from the current renderbuffer bindings.
404 * This is only intended for user-created framebuffers.
Brian Pauleb063cf2005-10-04 14:48:24 +0000405 *
406 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal
407 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits.
408 * The former one is used to convert floating point depth values into
409 * integer Z values.
Brian Paule4b23562005-05-04 20:11:35 +0000410 */
411void
412_mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
413{
Brian Paul474f28e2005-10-08 14:41:17 +0000414 GLuint i;
415
Brian Paule4b23562005-05-04 20:11:35 +0000416 assert(fb->Name != 0);
417
418 _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
Brian Paul474f28e2005-10-08 14:41:17 +0000419 fb->Visual.rgbMode = GL_TRUE; /* assume this */
Brian Paule4b23562005-05-04 20:11:35 +0000420
Brian Paul474f28e2005-10-08 14:41:17 +0000421 /* find first RGB or CI renderbuffer */
422 for (i = 0; i < BUFFER_COUNT; i++) {
423 if (fb->Attachment[i].Renderbuffer) {
424 const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
425 if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) {
426 fb->Visual.redBits = rb->RedBits;
427 fb->Visual.greenBits = rb->GreenBits;
428 fb->Visual.blueBits = rb->BlueBits;
429 fb->Visual.alphaBits = rb->AlphaBits;
430 fb->Visual.rgbBits = fb->Visual.redBits
431 + fb->Visual.greenBits + fb->Visual.blueBits;
432 fb->Visual.floatMode = GL_FALSE;
433 break;
434 }
435 else if (rb->_BaseFormat == GL_COLOR_INDEX) {
436 fb->Visual.indexBits = rb->IndexBits;
437 fb->Visual.rgbMode = GL_FALSE;
438 break;
439 }
440 }
Brian Paule4b23562005-05-04 20:11:35 +0000441 }
442
443 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
444 fb->Visual.haveDepthBuffer = GL_TRUE;
445 fb->Visual.depthBits
Brian Paul676d0ac2005-09-22 05:19:57 +0000446 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits;
Brian Paule4b23562005-05-04 20:11:35 +0000447 }
448
449 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
450 fb->Visual.haveStencilBuffer = GL_TRUE;
451 fb->Visual.stencilBits
Brian Paul676d0ac2005-09-22 05:19:57 +0000452 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits;
Brian Paule4b23562005-05-04 20:11:35 +0000453 }
454
455 compute_depth_max(fb);
456}
457
458
459/**
Brian Paulea4fe662006-03-26 05:22:17 +0000460 * Update the framebuffer's _DepthBuffer field using the renderbuffer
461 * found at the given attachment index.
462 *
463 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
464 * create and install a depth wrapper/adaptor.
465 *
466 * \param fb the framebuffer whose _DepthBuffer field to update
467 * \param attIndex indicates the renderbuffer to possibly wrap
Brian Paul84716042005-11-16 04:05:54 +0000468 */
Brian Paulea4fe662006-03-26 05:22:17 +0000469void
470_mesa_update_depth_buffer(GLcontext *ctx,
471 struct gl_framebuffer *fb,
472 GLuint attIndex)
Brian Paul84716042005-11-16 04:05:54 +0000473{
Brian Paulea4fe662006-03-26 05:22:17 +0000474 struct gl_renderbuffer *depthRb;
475
476 /* only one possiblity for now */
477 ASSERT(attIndex == BUFFER_DEPTH);
478
479 depthRb = fb->Attachment[attIndex].Renderbuffer;
480
481 if (depthRb && depthRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
482 /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */
483 if (!fb->_DepthBuffer || fb->_DepthBuffer->Wrapped != depthRb) {
484 /* need to update wrapper */
485 struct gl_renderbuffer *wrapper
486 = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb);
487 set_depth_renderbuffer(fb, wrapper);
488 ASSERT(fb->_DepthBuffer->Wrapped == depthRb);
Brian Paul84716042005-11-16 04:05:54 +0000489 }
490 }
Brian Paulea4fe662006-03-26 05:22:17 +0000491 else {
492 /* depthRb may be null */
493 set_depth_renderbuffer(fb, depthRb);
494 }
Brian Paul84716042005-11-16 04:05:54 +0000495}
496
Brian Paulea4fe662006-03-26 05:22:17 +0000497
Brian Paul84716042005-11-16 04:05:54 +0000498/**
Brian Paulea4fe662006-03-26 05:22:17 +0000499 * Update the framebuffer's _StencilBuffer field using the renderbuffer
500 * found at the given attachment index.
501 *
502 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
503 * create and install a stencil wrapper/adaptor.
504 *
505 * \param fb the framebuffer whose _StencilBuffer field to update
506 * \param attIndex indicates the renderbuffer to possibly wrap
Brian Paul84716042005-11-16 04:05:54 +0000507 */
Brian Paulea4fe662006-03-26 05:22:17 +0000508void
509_mesa_update_stencil_buffer(GLcontext *ctx,
510 struct gl_framebuffer *fb,
511 GLuint attIndex)
Brian Paul84716042005-11-16 04:05:54 +0000512{
Brian Paulea4fe662006-03-26 05:22:17 +0000513 struct gl_renderbuffer *stencilRb;
514
515 ASSERT(attIndex == BUFFER_DEPTH ||
516 attIndex == BUFFER_STENCIL);
517
518 stencilRb = fb->Attachment[attIndex].Renderbuffer;
519
520 if (stencilRb && stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
521 /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */
522 if (!fb->_StencilBuffer || fb->_StencilBuffer->Wrapped != stencilRb) {
523 /* need to update wrapper */
524 struct gl_renderbuffer *wrapper
525 = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb);
526 set_stencil_renderbuffer(fb, wrapper);
527 ASSERT(fb->_StencilBuffer->Wrapped == stencilRb);
Brian Paul84716042005-11-16 04:05:54 +0000528 }
529 }
Brian Paulea4fe662006-03-26 05:22:17 +0000530 else {
531 /* stencilRb may be null */
532 set_stencil_renderbuffer(fb, stencilRb);
533 }
534}
535
536
537/**
538 * Update the list of color drawing renderbuffer pointers.
539 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
540 * writing colors.
541 */
542static void
543update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb)
544{
545 GLuint output;
546
547 /*
548 * Fragment programs can write to multiple colorbuffers with
549 * the GL_ARB_draw_buffers extension.
550 */
551 for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) {
552 GLbitfield bufferMask = fb->_ColorDrawBufferMask[output];
553 GLuint count = 0;
554 GLuint i;
555 /* We need the inner loop here because glDrawBuffer(GL_FRONT_AND_BACK)
556 * can specify writing to two or four color buffers (for example).
557 */
558 for (i = 0; bufferMask && i < BUFFER_COUNT; i++) {
559 const GLuint bufferBit = 1 << i;
560 if (bufferBit & bufferMask) {
561 struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
562 if (rb) {
563 fb->_ColorDrawBuffers[output][count] = rb;
564 count++;
565 }
566 else {
567 /*_mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");*/
568 }
569 bufferMask &= ~bufferBit;
570 }
571 }
572 fb->_NumColorDrawBuffers[output] = count;
573 }
574}
575
576
577/**
578 * Update the color read renderbuffer pointer.
579 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
580 */
581static void
582update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
583{
584 if (fb->_ColorReadBufferIndex == -1) {
585 fb->_ColorReadBuffer = NULL; /* legal! */
586 }
587 else {
588 ASSERT(fb->_ColorReadBufferIndex >= 0);
589 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT);
590 fb->_ColorReadBuffer
591 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
592 }
Brian Paul84716042005-11-16 04:05:54 +0000593}
594
595
596/**
Brian Paule4b23562005-05-04 20:11:35 +0000597 * Update state related to the current draw/read framebuffers.
Brian Paul52783592005-08-31 21:38:53 +0000598 * Specifically, update these framebuffer fields:
599 * _ColorDrawBuffers
Brian Paul52783592005-08-31 21:38:53 +0000600 * _NumColorDrawBuffers
601 * _ColorReadBuffer
Brian Paul0f29ef62005-11-16 04:17:20 +0000602 * _DepthBuffer
603 * _StencilBuffer
Brian Paule4b23562005-05-04 20:11:35 +0000604 * If the current framebuffer is user-created, make sure it's complete.
Brian Paul52783592005-08-31 21:38:53 +0000605 * The following functions can effect this state: glReadBuffer,
Brian Paul0f29ef62005-11-16 04:17:20 +0000606 * glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT,
607 * glRenderbufferStorageEXT.
Brian Paule4b23562005-05-04 20:11:35 +0000608 */
609void
610_mesa_update_framebuffer(GLcontext *ctx)
611{
612 struct gl_framebuffer *fb = ctx->DrawBuffer;
Brian Paule4b23562005-05-04 20:11:35 +0000613
614 /* Completeness only matters for user-created framebuffers */
Brian Paul474f28e2005-10-08 14:41:17 +0000615 if (fb->Name != 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000616 _mesa_test_framebuffer_completeness(ctx, fb);
Brian Paul474f28e2005-10-08 14:41:17 +0000617 _mesa_update_framebuffer_visual(fb);
618 }
Brian Paule4b23562005-05-04 20:11:35 +0000619
Brian Paulea4fe662006-03-26 05:22:17 +0000620 update_color_draw_buffers(ctx, fb);
621 update_color_read_buffer(ctx, fb);
622 _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH);
623 _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL);
Brian Paul84716042005-11-16 04:05:54 +0000624
Brian Paule4b23562005-05-04 20:11:35 +0000625 compute_depth_max(fb);
626}
Brian Paul7275d4d2006-03-20 15:25:18 +0000627
628
629/**
630 * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels,
631 * glCopyTex[Sub]Image, etc. exists.
632 * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA,
633 * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL.
634 * \return GL_TRUE if buffer exists, GL_FALSE otherwise
635 */
636GLboolean
637_mesa_source_buffer_exists(GLcontext *ctx, GLenum format)
638{
639 const struct gl_renderbuffer_attachment *att
640 = ctx->ReadBuffer->Attachment;
641
642 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
643 return GL_FALSE;
644 }
645
646 switch (format) {
647 case GL_COLOR:
Brian Paul590cd262006-03-24 22:53:00 +0000648 case GL_RED:
649 case GL_GREEN:
650 case GL_BLUE:
Brian Paul7275d4d2006-03-20 15:25:18 +0000651 case GL_ALPHA:
652 case GL_LUMINANCE:
653 case GL_LUMINANCE_ALPHA:
654 case GL_INTENSITY:
655 case GL_RGB:
Brian Paul590cd262006-03-24 22:53:00 +0000656 case GL_BGR:
Brian Paul7275d4d2006-03-20 15:25:18 +0000657 case GL_RGBA:
Brian Paul590cd262006-03-24 22:53:00 +0000658 case GL_BGRA:
659 case GL_ABGR_EXT:
Brian Paul7275d4d2006-03-20 15:25:18 +0000660 case GL_COLOR_INDEX:
661 if (ctx->ReadBuffer->_ColorReadBuffer == NULL) {
662 return GL_FALSE;
663 }
664 break;
665 case GL_DEPTH:
666 case GL_DEPTH_COMPONENT:
667 if (!att[BUFFER_DEPTH].Renderbuffer) {
668 return GL_FALSE;
669 }
670 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
671 break;
672 case GL_STENCIL:
673 case GL_STENCIL_INDEX:
674 if (!att[BUFFER_STENCIL].Renderbuffer) {
675 return GL_FALSE;
676 }
677 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
678 break;
679 case GL_DEPTH_STENCIL_EXT:
680 if (!att[BUFFER_DEPTH].Renderbuffer ||
681 !att[BUFFER_STENCIL].Renderbuffer) {
682 return GL_FALSE;
683 }
684 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
685 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
686 break;
687 default:
688 _mesa_problem(ctx,
Brian Paul590cd262006-03-24 22:53:00 +0000689 "Unexpected format 0x%x in _mesa_source_buffer_exists",
690 format);
Brian Paul7275d4d2006-03-20 15:25:18 +0000691 return GL_FALSE;
692 }
693
694 /* OK */
695 return GL_TRUE;
696}
697
698
699/**
700 * As above, but for drawing operations.
701 * XXX code do some code merging w/ above function.
702 */
703GLboolean
704_mesa_dest_buffer_exists(GLcontext *ctx, GLenum format)
705{
706 const struct gl_renderbuffer_attachment *att
707 = ctx->ReadBuffer->Attachment;
708
709 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
710 return GL_FALSE;
711 }
712
713 switch (format) {
714 case GL_COLOR:
Brian Paul590cd262006-03-24 22:53:00 +0000715 case GL_RED:
716 case GL_GREEN:
717 case GL_BLUE:
Brian Paul7275d4d2006-03-20 15:25:18 +0000718 case GL_ALPHA:
719 case GL_LUMINANCE:
720 case GL_LUMINANCE_ALPHA:
721 case GL_INTENSITY:
722 case GL_RGB:
Brian Paul590cd262006-03-24 22:53:00 +0000723 case GL_BGR:
Brian Paul7275d4d2006-03-20 15:25:18 +0000724 case GL_RGBA:
Brian Paul590cd262006-03-24 22:53:00 +0000725 case GL_BGRA:
726 case GL_ABGR_EXT:
Brian Paul7275d4d2006-03-20 15:25:18 +0000727 case GL_COLOR_INDEX:
728 /* nothing special */
729 break;
730 case GL_DEPTH:
731 case GL_DEPTH_COMPONENT:
732 if (!att[BUFFER_DEPTH].Renderbuffer) {
733 return GL_FALSE;
734 }
735 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
736 break;
737 case GL_STENCIL:
738 case GL_STENCIL_INDEX:
739 if (!att[BUFFER_STENCIL].Renderbuffer) {
740 return GL_FALSE;
741 }
742 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
743 break;
744 case GL_DEPTH_STENCIL_EXT:
745 if (!att[BUFFER_DEPTH].Renderbuffer ||
746 !att[BUFFER_STENCIL].Renderbuffer) {
747 return GL_FALSE;
748 }
749 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
750 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
751 break;
752 default:
753 _mesa_problem(ctx,
Brian Paul590cd262006-03-24 22:53:00 +0000754 "Unexpected format 0x%x in _mesa_source_buffer_exists",
755 format);
Brian Paul7275d4d2006-03-20 15:25:18 +0000756 return GL_FALSE;
757 }
758
759 /* OK */
760 return GL_TRUE;
761}