cd4f594aa2915c9423a5096a227a6f57e4853e94
[mesa.git] / src / mesa / main / framebuffer.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.1
4 *
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 /**
27 * Functions for allocating/managing framebuffers and renderbuffers.
28 * Also, routines for reading/writing renderbuffer data as ubytes,
29 * ushorts, uints, etc.
30 */
31
32
33 #include "glheader.h"
34 #include "imports.h"
35 #include "context.h"
36 #include "depthstencil.h"
37 #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 */
48 static void
49 compute_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 /**
73 * Set the framebuffer's _DepthBuffer field, taking care of
74 * reference counts, etc.
75 */
76 static void
77 set_depth_renderbuffer(struct gl_framebuffer *fb,
78 struct gl_renderbuffer *rb)
79 {
80 if (fb->_DepthBuffer) {
81 _mesa_unreference_renderbuffer(&fb->_DepthBuffer);
82 }
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 */
94 static void
95 set_stencil_renderbuffer(struct gl_framebuffer *fb,
96 struct gl_renderbuffer *rb)
97 {
98 if (fb->_StencilBuffer) {
99 _mesa_unreference_renderbuffer(&fb->_StencilBuffer);
100 }
101 fb->_StencilBuffer = rb;
102 if (rb) {
103 rb->RefCount++;
104 }
105 }
106
107
108 /**
109 * 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 */
115 struct 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 */
134 struct gl_framebuffer *
135 _mesa_new_framebuffer(GLcontext *ctx, GLuint name)
136 {
137 struct gl_framebuffer *fb;
138 (void) ctx;
139 assert(name != 0);
140 fb = CALLOC_STRUCT(gl_framebuffer);
141 if (fb) {
142 fb->Name = name;
143 fb->RefCount = 1;
144 fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT;
145 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_COLOR0;
146 fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT;
147 fb->_ColorReadBufferIndex = BUFFER_COLOR0;
148 fb->Delete = _mesa_destroy_framebuffer;
149 }
150 return fb;
151 }
152
153
154 /**
155 * Initialize a gl_framebuffer object. Typically used to initialize
156 * window system-created framebuffers, not user-created framebuffers.
157 * \sa _mesa_create_framebuffer
158 */
159 void
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
167 _glthread_INIT_MUTEX(fb->Mutex);
168
169 fb->RefCount = 1;
170
171 /* 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;
179 fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT;
180 }
181 else {
182 fb->ColorDrawBuffer[0] = GL_FRONT;
183 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT;
184 fb->ColorReadBuffer = GL_FRONT;
185 fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT;
186 }
187
188 fb->Delete = _mesa_destroy_framebuffer;
189 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
190
191 compute_depth_max(fb);
192 }
193
194
195 /**
196 * Deallocate buffer and everything attached to it.
197 * Typically called via the gl_framebuffer->Delete() method.
198 */
199 void
200 _mesa_destroy_framebuffer(struct gl_framebuffer *fb)
201 {
202 if (fb) {
203 _mesa_free_framebuffer_data(fb);
204 _mesa_free(fb);
205 }
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 */
213 void
214 _mesa_free_framebuffer_data(struct gl_framebuffer *fb)
215 {
216 GLuint i;
217
218 assert(fb);
219 assert(fb->RefCount == 0);
220
221 _glthread_DESTROY_MUTEX(fb->Mutex);
222
223 for (i = 0; i < BUFFER_COUNT; i++) {
224 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
225 if (att->Renderbuffer) {
226 _mesa_unreference_renderbuffer(&att->Renderbuffer);
227 }
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 }
236 }
237 }
238 att->Type = GL_NONE;
239 att->Texture = NULL;
240 }
241
242 /* unbind depth/stencil to decr ref counts */
243 set_depth_renderbuffer(fb, NULL);
244 set_stencil_renderbuffer(fb, NULL);
245 }
246
247
248 /**
249 * Set *ptr to point to fb, with refcounting and locking.
250 */
251 void
252 _mesa_reference_framebuffer(struct gl_framebuffer **ptr,
253 struct gl_framebuffer *fb)
254 {
255 assert(ptr);
256 if (*ptr == fb) {
257 /* no change */
258 return;
259 }
260 if (*ptr) {
261 _mesa_unreference_framebuffer(ptr);
262 }
263 assert(!*ptr);
264 assert(fb);
265 _glthread_LOCK_MUTEX(fb->Mutex);
266 fb->RefCount++;
267 _glthread_UNLOCK_MUTEX(fb->Mutex);
268 *ptr = fb;
269 }
270
271
272 /**
273 * Undo/remove a reference to a framebuffer object.
274 * Decrement the framebuffer object's reference count and delete it when
275 * the refcount hits zero.
276 * Note: we pass the address of a pointer and set it to NULL.
277 */
278 void
279 _mesa_unreference_framebuffer(struct gl_framebuffer **fb)
280 {
281 assert(fb);
282 if (*fb) {
283 GLboolean deleteFlag = GL_FALSE;
284
285 _glthread_LOCK_MUTEX((*fb)->Mutex);
286 ASSERT((*fb)->RefCount > 0);
287 (*fb)->RefCount--;
288 deleteFlag = ((*fb)->RefCount == 0);
289 _glthread_UNLOCK_MUTEX((*fb)->Mutex);
290
291 if (deleteFlag)
292 (*fb)->Delete(*fb);
293
294 *fb = NULL;
295 }
296 }
297
298
299
300
301 /**
302 * Resize the given framebuffer's renderbuffers to the new width and height.
303 * This should only be used for window-system framebuffers, not
304 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object).
305 * This will typically be called via ctx->Driver.ResizeBuffers() or directly
306 * from a device driver.
307 *
308 * \note it's possible for ctx to be null since a window can be resized
309 * without a currently bound rendering context.
310 */
311 void
312 _mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
313 GLuint width, GLuint height)
314 {
315 GLuint i;
316
317 /* XXX I think we could check if the size is not changing
318 * and return early.
319 */
320
321 /* For window system framebuffers, Name is zero */
322 assert(fb->Name == 0);
323
324 for (i = 0; i < BUFFER_COUNT; i++) {
325 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
326 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
327 struct gl_renderbuffer *rb = att->Renderbuffer;
328 /* only resize if size is changing */
329 if (rb->Width != width || rb->Height != height) {
330 /* could just as well pass rb->_ActualFormat here */
331 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
332 ASSERT(rb->Width == width);
333 ASSERT(rb->Height == height);
334 }
335 else {
336 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
337 /* no return */
338 }
339 }
340 }
341 }
342
343 if (fb->_DepthBuffer) {
344 struct gl_renderbuffer *rb = fb->_DepthBuffer;
345 if (rb->Width != width || rb->Height != height) {
346 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
347 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
348 }
349 }
350 }
351
352 if (fb->_StencilBuffer) {
353 struct gl_renderbuffer *rb = fb->_StencilBuffer;
354 if (rb->Width != width || rb->Height != height) {
355 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
356 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
357 }
358 }
359 }
360
361 fb->Width = width;
362 fb->Height = height;
363
364 if (ctx) {
365 /* update scissor / window bounds */
366 _mesa_update_draw_buffer_bounds(ctx);
367 /* Signal new buffer state so that swrast will update its clipping
368 * info (the CLIP_BIT flag).
369 */
370 ctx->NewState |= _NEW_BUFFERS;
371 }
372 }
373
374
375 /**
376 * Examine all the framebuffer's renderbuffers to update the Width/Height
377 * fields of the framebuffer. If we have renderbuffers with different
378 * sizes, set the framebuffer's width and height to zero.
379 * Note: this is only intended for user-created framebuffers, not
380 * window-system framebuffes.
381 */
382 static void
383 update_framebuffer_size(struct gl_framebuffer *fb)
384 {
385 GLboolean haveSize = GL_FALSE;
386 GLuint i;
387
388 /* user-created framebuffers only */
389 assert(fb->Name);
390
391 for (i = 0; i < BUFFER_COUNT; i++) {
392 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
393 const struct gl_renderbuffer *rb = att->Renderbuffer;
394 if (rb) {
395 if (haveSize) {
396 if (rb->Width != fb->Width && rb->Height != fb->Height) {
397 /* size mismatch! */
398 fb->Width = 0;
399 fb->Height = 0;
400 return;
401 }
402 }
403 else {
404 fb->Width = rb->Width;
405 fb->Height = rb->Height;
406 haveSize = GL_TRUE;
407 }
408 }
409 }
410 }
411
412
413 /**
414 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
415 * These values are computed from the buffer's width and height and
416 * the scissor box, if it's enabled.
417 * \param ctx the GL context.
418 */
419 void
420 _mesa_update_draw_buffer_bounds(GLcontext *ctx)
421 {
422 struct gl_framebuffer *buffer = ctx->DrawBuffer;
423
424 if (!buffer)
425 return;
426
427 if (buffer->Name) {
428 /* user-created framebuffer size depends on the renderbuffers */
429 update_framebuffer_size(buffer);
430 }
431
432 buffer->_Xmin = 0;
433 buffer->_Ymin = 0;
434 buffer->_Xmax = buffer->Width;
435 buffer->_Ymax = buffer->Height;
436
437 if (ctx->Scissor.Enabled) {
438 if (ctx->Scissor.X > buffer->_Xmin) {
439 buffer->_Xmin = ctx->Scissor.X;
440 }
441 if (ctx->Scissor.Y > buffer->_Ymin) {
442 buffer->_Ymin = ctx->Scissor.Y;
443 }
444 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
445 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
446 }
447 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
448 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
449 }
450 /* finally, check for empty region */
451 if (buffer->_Xmin > buffer->_Xmax) {
452 buffer->_Xmin = buffer->_Xmax;
453 }
454 if (buffer->_Ymin > buffer->_Ymax) {
455 buffer->_Ymin = buffer->_Ymax;
456 }
457 }
458
459 ASSERT(buffer->_Xmin <= buffer->_Xmax);
460 ASSERT(buffer->_Ymin <= buffer->_Ymax);
461 }
462
463
464 /**
465 * The glGet queries of the framebuffer red/green/blue size, stencil size,
466 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can
467 * change depending on the renderbuffer bindings. This function updates
468 * the given framebuffer's Visual from the current renderbuffer bindings.
469 *
470 * This may apply to user-created framebuffers or window system framebuffers.
471 *
472 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal
473 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits.
474 * The former one is used to convert floating point depth values into
475 * integer Z values.
476 */
477 void
478 _mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
479 {
480 GLuint i;
481
482 _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
483 fb->Visual.rgbMode = GL_TRUE; /* assume this */
484
485 #if 0 /* this _might_ be needed */
486 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
487 /* leave visual fields zero'd */
488 return;
489 }
490 #endif
491
492 /* find first RGB or CI renderbuffer */
493 for (i = 0; i < BUFFER_COUNT; i++) {
494 if (fb->Attachment[i].Renderbuffer) {
495 const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
496 if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) {
497 fb->Visual.redBits = rb->RedBits;
498 fb->Visual.greenBits = rb->GreenBits;
499 fb->Visual.blueBits = rb->BlueBits;
500 fb->Visual.alphaBits = rb->AlphaBits;
501 fb->Visual.rgbBits = fb->Visual.redBits
502 + fb->Visual.greenBits + fb->Visual.blueBits;
503 fb->Visual.floatMode = GL_FALSE;
504 break;
505 }
506 else if (rb->_BaseFormat == GL_COLOR_INDEX) {
507 fb->Visual.indexBits = rb->IndexBits;
508 fb->Visual.rgbMode = GL_FALSE;
509 break;
510 }
511 }
512 }
513
514 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
515 fb->Visual.haveDepthBuffer = GL_TRUE;
516 fb->Visual.depthBits
517 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits;
518 }
519
520 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
521 fb->Visual.haveStencilBuffer = GL_TRUE;
522 fb->Visual.stencilBits
523 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits;
524 }
525
526 if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) {
527 fb->Visual.haveAccumBuffer = GL_TRUE;
528 fb->Visual.accumRedBits
529 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->RedBits;
530 fb->Visual.accumGreenBits
531 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->GreenBits;
532 fb->Visual.accumBlueBits
533 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->BlueBits;
534 fb->Visual.accumAlphaBits
535 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->AlphaBits;
536 }
537
538 compute_depth_max(fb);
539 }
540
541
542 /**
543 * Update the framebuffer's _DepthBuffer field using the renderbuffer
544 * found at the given attachment index.
545 *
546 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
547 * create and install a depth wrapper/adaptor.
548 *
549 * \param fb the framebuffer whose _DepthBuffer field to update
550 * \param attIndex indicates the renderbuffer to possibly wrap
551 */
552 void
553 _mesa_update_depth_buffer(GLcontext *ctx,
554 struct gl_framebuffer *fb,
555 GLuint attIndex)
556 {
557 struct gl_renderbuffer *depthRb;
558
559 /* only one possiblity for now */
560 ASSERT(attIndex == BUFFER_DEPTH);
561
562 depthRb = fb->Attachment[attIndex].Renderbuffer;
563
564 if (depthRb && depthRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
565 /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */
566 if (!fb->_DepthBuffer
567 || fb->_DepthBuffer->Wrapped != depthRb
568 || fb->_DepthBuffer->_BaseFormat != GL_DEPTH_COMPONENT) {
569 /* need to update wrapper */
570 struct gl_renderbuffer *wrapper
571 = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb);
572 set_depth_renderbuffer(fb, wrapper);
573 ASSERT(fb->_DepthBuffer->Wrapped == depthRb);
574 }
575 }
576 else {
577 /* depthRb may be null */
578 set_depth_renderbuffer(fb, depthRb);
579 }
580 }
581
582
583 /**
584 * Update the framebuffer's _StencilBuffer field using the renderbuffer
585 * found at the given attachment index.
586 *
587 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
588 * create and install a stencil wrapper/adaptor.
589 *
590 * \param fb the framebuffer whose _StencilBuffer field to update
591 * \param attIndex indicates the renderbuffer to possibly wrap
592 */
593 void
594 _mesa_update_stencil_buffer(GLcontext *ctx,
595 struct gl_framebuffer *fb,
596 GLuint attIndex)
597 {
598 struct gl_renderbuffer *stencilRb;
599
600 ASSERT(attIndex == BUFFER_DEPTH ||
601 attIndex == BUFFER_STENCIL);
602
603 stencilRb = fb->Attachment[attIndex].Renderbuffer;
604
605 if (stencilRb && stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
606 /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */
607 if (!fb->_StencilBuffer
608 || fb->_StencilBuffer->Wrapped != stencilRb
609 || fb->_StencilBuffer->_BaseFormat != GL_STENCIL_INDEX) {
610 /* need to update wrapper */
611 struct gl_renderbuffer *wrapper
612 = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb);
613 set_stencil_renderbuffer(fb, wrapper);
614 ASSERT(fb->_StencilBuffer->Wrapped == stencilRb);
615 }
616 }
617 else {
618 /* stencilRb may be null */
619 set_stencil_renderbuffer(fb, stencilRb);
620 }
621 }
622
623
624 /**
625 * Update the list of color drawing renderbuffer pointers.
626 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
627 * writing colors.
628 */
629 static void
630 update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb)
631 {
632 GLuint output;
633
634 /*
635 * Fragment programs can write to multiple colorbuffers with
636 * the GL_ARB_draw_buffers extension.
637 */
638 for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) {
639 GLbitfield bufferMask = fb->_ColorDrawBufferMask[output];
640 GLuint count = 0;
641 GLuint i;
642 if (!fb->DeletePending) {
643 /* We need the inner loop here because glDrawBuffer(GL_FRONT_AND_BACK)
644 * can specify writing to two or four color buffers (for example).
645 */
646 for (i = 0; bufferMask && i < BUFFER_COUNT; i++) {
647 const GLuint bufferBit = 1 << i;
648 if (bufferBit & bufferMask) {
649 struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
650 if (rb && rb->Width > 0 && rb->Height > 0) {
651 fb->_ColorDrawBuffers[output][count] = rb;
652 count++;
653 }
654 else {
655 /*
656 _mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");
657 */
658 }
659 bufferMask &= ~bufferBit;
660 }
661 }
662 }
663 fb->_NumColorDrawBuffers[output] = count;
664 }
665 }
666
667
668 /**
669 * Update the color read renderbuffer pointer.
670 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
671 */
672 static void
673 update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
674 {
675 (void) ctx;
676 if (fb->_ColorReadBufferIndex == -1 ||
677 fb->DeletePending ||
678 fb->Width == 0 ||
679 fb->Height == 0) {
680 fb->_ColorReadBuffer = NULL; /* legal! */
681 }
682 else {
683 ASSERT(fb->_ColorReadBufferIndex >= 0);
684 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT);
685 fb->_ColorReadBuffer
686 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
687 }
688 }
689
690
691 /**
692 * Update state related to the current draw/read framebuffers.
693 * Specifically, update these framebuffer fields:
694 * _ColorDrawBuffers
695 * _NumColorDrawBuffers
696 * _ColorReadBuffer
697 * _DepthBuffer
698 * _StencilBuffer
699 * If the current framebuffer is user-created, make sure it's complete.
700 * The following functions can effect this state: glReadBuffer,
701 * glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT,
702 * glRenderbufferStorageEXT.
703 */
704 void
705 _mesa_update_framebuffer(GLcontext *ctx)
706 {
707 struct gl_framebuffer *fb = ctx->DrawBuffer;
708
709 /* Completeness only matters for user-created framebuffers */
710 if (fb->Name != 0) {
711 _mesa_test_framebuffer_completeness(ctx, fb);
712 _mesa_update_framebuffer_visual(fb);
713 }
714
715 update_color_draw_buffers(ctx, fb);
716 update_color_read_buffer(ctx, fb);
717 _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH);
718 _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL);
719
720 compute_depth_max(fb);
721 }
722
723
724 /**
725 * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels,
726 * glCopyTex[Sub]Image, etc. exists.
727 * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA,
728 * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL.
729 * \return GL_TRUE if buffer exists, GL_FALSE otherwise
730 */
731 GLboolean
732 _mesa_source_buffer_exists(GLcontext *ctx, GLenum format)
733 {
734 const struct gl_renderbuffer_attachment *att
735 = ctx->ReadBuffer->Attachment;
736
737 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
738 return GL_FALSE;
739 }
740
741 switch (format) {
742 case GL_COLOR:
743 case GL_RED:
744 case GL_GREEN:
745 case GL_BLUE:
746 case GL_ALPHA:
747 case GL_LUMINANCE:
748 case GL_LUMINANCE_ALPHA:
749 case GL_INTENSITY:
750 case GL_RGB:
751 case GL_BGR:
752 case GL_RGBA:
753 case GL_BGRA:
754 case GL_ABGR_EXT:
755 case GL_COLOR_INDEX:
756 if (ctx->ReadBuffer->_ColorReadBuffer == NULL) {
757 return GL_FALSE;
758 }
759 /* XXX enable this post 6.5 release:
760 ASSERT(ctx->ReadBuffer->_ColorReadBuffer->RedBits > 0 ||
761 ctx->ReadBuffer->_ColorReadBuffer->IndexBits > 0);
762 */
763 break;
764 case GL_DEPTH:
765 case GL_DEPTH_COMPONENT:
766 if (!att[BUFFER_DEPTH].Renderbuffer) {
767 return GL_FALSE;
768 }
769 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
770 break;
771 case GL_STENCIL:
772 case GL_STENCIL_INDEX:
773 if (!att[BUFFER_STENCIL].Renderbuffer) {
774 return GL_FALSE;
775 }
776 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
777 break;
778 case GL_DEPTH_STENCIL_EXT:
779 if (!att[BUFFER_DEPTH].Renderbuffer ||
780 !att[BUFFER_STENCIL].Renderbuffer) {
781 return GL_FALSE;
782 }
783 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
784 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
785 break;
786 default:
787 _mesa_problem(ctx,
788 "Unexpected format 0x%x in _mesa_source_buffer_exists",
789 format);
790 return GL_FALSE;
791 }
792
793 /* OK */
794 return GL_TRUE;
795 }
796
797
798 /**
799 * As above, but for drawing operations.
800 * XXX code do some code merging w/ above function.
801 */
802 GLboolean
803 _mesa_dest_buffer_exists(GLcontext *ctx, GLenum format)
804 {
805 const struct gl_renderbuffer_attachment *att
806 = ctx->ReadBuffer->Attachment;
807
808 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
809 return GL_FALSE;
810 }
811
812 switch (format) {
813 case GL_COLOR:
814 case GL_RED:
815 case GL_GREEN:
816 case GL_BLUE:
817 case GL_ALPHA:
818 case GL_LUMINANCE:
819 case GL_LUMINANCE_ALPHA:
820 case GL_INTENSITY:
821 case GL_RGB:
822 case GL_BGR:
823 case GL_RGBA:
824 case GL_BGRA:
825 case GL_ABGR_EXT:
826 case GL_COLOR_INDEX:
827 /* nothing special */
828 /* Could assert that colorbuffer has RedBits > 0 */
829 break;
830 case GL_DEPTH:
831 case GL_DEPTH_COMPONENT:
832 if (!att[BUFFER_DEPTH].Renderbuffer) {
833 return GL_FALSE;
834 }
835 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
836 break;
837 case GL_STENCIL:
838 case GL_STENCIL_INDEX:
839 if (!att[BUFFER_STENCIL].Renderbuffer) {
840 return GL_FALSE;
841 }
842 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
843 break;
844 case GL_DEPTH_STENCIL_EXT:
845 if (!att[BUFFER_DEPTH].Renderbuffer ||
846 !att[BUFFER_STENCIL].Renderbuffer) {
847 return GL_FALSE;
848 }
849 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
850 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
851 break;
852 default:
853 _mesa_problem(ctx,
854 "Unexpected format 0x%x in _mesa_source_buffer_exists",
855 format);
856 return GL_FALSE;
857 }
858
859 /* OK */
860 return GL_TRUE;
861 }