72d85f6f892f357fc672106c6d87d280fbb89447
[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 #include "texobj.h"
42
43
44
45 /**
46 * Compute/set the _DepthMax field for the given framebuffer.
47 * This value depends on the Z buffer resolution.
48 */
49 static void
50 compute_depth_max(struct gl_framebuffer *fb)
51 {
52 if (fb->Visual.depthBits == 0) {
53 /* Special case. Even if we don't have a depth buffer we need
54 * good values for DepthMax for Z vertex transformation purposes
55 * and for per-fragment fog computation.
56 */
57 fb->_DepthMax = (1 << 16) - 1;
58 }
59 else if (fb->Visual.depthBits < 32) {
60 fb->_DepthMax = (1 << fb->Visual.depthBits) - 1;
61 }
62 else {
63 /* Special case since shift values greater than or equal to the
64 * number of bits in the left hand expression's type are undefined.
65 */
66 fb->_DepthMax = 0xffffffff;
67 }
68 fb->_DepthMaxF = (GLfloat) fb->_DepthMax;
69
70 /* Minimum resolvable depth value, for polygon offset */
71 fb->_MRD = 1.0 / fb->_DepthMaxF;
72 }
73
74
75 /**
76 * Create and initialize a gl_framebuffer object.
77 * This is intended for creating _window_system_ framebuffers, not generic
78 * framebuffer objects ala GL_EXT_framebuffer_object.
79 *
80 * \sa _mesa_new_framebuffer
81 */
82 struct gl_framebuffer *
83 _mesa_create_framebuffer(const GLvisual *visual)
84 {
85 struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer);
86 assert(visual);
87 if (fb) {
88 _mesa_initialize_framebuffer(fb, visual);
89 }
90 return fb;
91 }
92
93
94 /**
95 * Allocate a new gl_framebuffer object.
96 * This is the default function for ctx->Driver.NewFramebuffer().
97 * This is for allocating user-created framebuffers, not window-system
98 * framebuffers!
99 * \sa _mesa_create_framebuffer
100 */
101 struct gl_framebuffer *
102 _mesa_new_framebuffer(GLcontext *ctx, GLuint name)
103 {
104 struct gl_framebuffer *fb;
105 (void) ctx;
106 assert(name != 0);
107 fb = CALLOC_STRUCT(gl_framebuffer);
108 if (fb) {
109 fb->Name = name;
110 fb->RefCount = 1;
111 fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT;
112 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_COLOR0;
113 fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT;
114 fb->_ColorReadBufferIndex = BUFFER_COLOR0;
115 fb->Delete = _mesa_destroy_framebuffer;
116 }
117 return fb;
118 }
119
120
121 /**
122 * Initialize a gl_framebuffer object. Typically used to initialize
123 * window system-created framebuffers, not user-created framebuffers.
124 * \sa _mesa_create_framebuffer
125 */
126 void
127 _mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual)
128 {
129 assert(fb);
130 assert(visual);
131
132 _mesa_bzero(fb, sizeof(struct gl_framebuffer));
133
134 _glthread_INIT_MUTEX(fb->Mutex);
135
136 fb->RefCount = 1;
137
138 /* save the visual */
139 fb->Visual = *visual;
140
141 /* Init read/draw renderbuffer state */
142 if (visual->doubleBufferMode) {
143 fb->ColorDrawBuffer[0] = GL_BACK;
144 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_BACK_LEFT;
145 fb->ColorReadBuffer = GL_BACK;
146 fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT;
147 }
148 else {
149 fb->ColorDrawBuffer[0] = GL_FRONT;
150 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT;
151 fb->ColorReadBuffer = GL_FRONT;
152 fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT;
153 }
154
155 fb->Delete = _mesa_destroy_framebuffer;
156 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
157
158 compute_depth_max(fb);
159 }
160
161
162 /**
163 * Deallocate buffer and everything attached to it.
164 * Typically called via the gl_framebuffer->Delete() method.
165 */
166 void
167 _mesa_destroy_framebuffer(struct gl_framebuffer *fb)
168 {
169 if (fb) {
170 _mesa_free_framebuffer_data(fb);
171 _mesa_free(fb);
172 }
173 }
174
175
176 /**
177 * Free all the data hanging off the given gl_framebuffer, but don't free
178 * the gl_framebuffer object itself.
179 */
180 void
181 _mesa_free_framebuffer_data(struct gl_framebuffer *fb)
182 {
183 GLuint i;
184
185 assert(fb);
186 assert(fb->RefCount == 0);
187
188 _glthread_DESTROY_MUTEX(fb->Mutex);
189
190 for (i = 0; i < BUFFER_COUNT; i++) {
191 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
192 if (att->Renderbuffer) {
193 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
194 }
195 if (att->Texture) {
196 _mesa_reference_texobj(&att->Texture, NULL);
197 }
198 ASSERT(!att->Renderbuffer);
199 ASSERT(!att->Texture);
200 att->Type = GL_NONE;
201 }
202
203 /* unbind _Depth/_StencilBuffer to decr ref counts */
204 _mesa_reference_renderbuffer(&fb->_DepthBuffer, NULL);
205 _mesa_reference_renderbuffer(&fb->_StencilBuffer, NULL);
206 }
207
208
209 /**
210 * Set *ptr to point to fb, with refcounting and locking.
211 */
212 void
213 _mesa_reference_framebuffer(struct gl_framebuffer **ptr,
214 struct gl_framebuffer *fb)
215 {
216 assert(ptr);
217 if (*ptr == fb) {
218 /* no change */
219 return;
220 }
221 if (*ptr) {
222 _mesa_unreference_framebuffer(ptr);
223 }
224 assert(!*ptr);
225 assert(fb);
226 _glthread_LOCK_MUTEX(fb->Mutex);
227 fb->RefCount++;
228 _glthread_UNLOCK_MUTEX(fb->Mutex);
229 *ptr = fb;
230 }
231
232
233 /**
234 * Undo/remove a reference to a framebuffer object.
235 * Decrement the framebuffer object's reference count and delete it when
236 * the refcount hits zero.
237 * Note: we pass the address of a pointer and set it to NULL.
238 */
239 void
240 _mesa_unreference_framebuffer(struct gl_framebuffer **fb)
241 {
242 assert(fb);
243 if (*fb) {
244 GLboolean deleteFlag = GL_FALSE;
245
246 _glthread_LOCK_MUTEX((*fb)->Mutex);
247 ASSERT((*fb)->RefCount > 0);
248 (*fb)->RefCount--;
249 deleteFlag = ((*fb)->RefCount == 0);
250 _glthread_UNLOCK_MUTEX((*fb)->Mutex);
251
252 if (deleteFlag)
253 (*fb)->Delete(*fb);
254
255 *fb = NULL;
256 }
257 }
258
259
260
261
262 /**
263 * Resize the given framebuffer's renderbuffers to the new width and height.
264 * This should only be used for window-system framebuffers, not
265 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object).
266 * This will typically be called via ctx->Driver.ResizeBuffers() or directly
267 * from a device driver.
268 *
269 * \note it's possible for ctx to be null since a window can be resized
270 * without a currently bound rendering context.
271 */
272 void
273 _mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
274 GLuint width, GLuint height)
275 {
276 GLuint i;
277
278 /* XXX I think we could check if the size is not changing
279 * and return early.
280 */
281
282 /* For window system framebuffers, Name is zero */
283 assert(fb->Name == 0);
284
285 for (i = 0; i < BUFFER_COUNT; i++) {
286 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
287 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
288 struct gl_renderbuffer *rb = att->Renderbuffer;
289 /* only resize if size is changing */
290 if (rb->Width != width || rb->Height != height) {
291 /* could just as well pass rb->_ActualFormat here */
292 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
293 ASSERT(rb->Width == width);
294 ASSERT(rb->Height == height);
295 }
296 else {
297 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
298 /* no return */
299 }
300 }
301 }
302 }
303
304 if (fb->_DepthBuffer) {
305 struct gl_renderbuffer *rb = fb->_DepthBuffer;
306 if (rb->Width != width || rb->Height != height) {
307 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
308 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
309 }
310 }
311 }
312
313 if (fb->_StencilBuffer) {
314 struct gl_renderbuffer *rb = fb->_StencilBuffer;
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 fb->Width = width;
323 fb->Height = height;
324
325 if (ctx) {
326 /* update scissor / window bounds */
327 _mesa_update_draw_buffer_bounds(ctx);
328 /* Signal new buffer state so that swrast will update its clipping
329 * info (the CLIP_BIT flag).
330 */
331 ctx->NewState |= _NEW_BUFFERS;
332 }
333 }
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 */
343 static void
344 update_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 */
380 void
381 _mesa_update_draw_buffer_bounds(GLcontext *ctx)
382 {
383 struct gl_framebuffer *buffer = ctx->DrawBuffer;
384
385 if (!buffer)
386 return;
387
388 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
428 * change depending on the renderbuffer bindings. This function updates
429 * the given framebuffer's Visual from the current renderbuffer bindings.
430 *
431 * This may apply to user-created framebuffers or window system framebuffers.
432 *
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.
437 */
438 void
439 _mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
440 {
441 GLuint i;
442
443 _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
444 fb->Visual.rgbMode = GL_TRUE; /* assume this */
445
446 #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
453 /* 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 }
473 }
474
475 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
476 fb->Visual.haveDepthBuffer = GL_TRUE;
477 fb->Visual.depthBits
478 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits;
479 }
480
481 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
482 fb->Visual.haveStencilBuffer = GL_TRUE;
483 fb->Visual.stencilBits
484 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits;
485 }
486
487 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
499 compute_depth_max(fb);
500 }
501
502
503 /**
504 * 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
512 */
513 void
514 _mesa_update_depth_buffer(GLcontext *ctx,
515 struct gl_framebuffer *fb,
516 GLuint attIndex)
517 {
518 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 */
527 if (!fb->_DepthBuffer
528 || fb->_DepthBuffer->Wrapped != depthRb
529 || fb->_DepthBuffer->_BaseFormat != GL_DEPTH_COMPONENT) {
530 /* need to update wrapper */
531 struct gl_renderbuffer *wrapper
532 = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb);
533 _mesa_reference_renderbuffer(&fb->_DepthBuffer, wrapper);
534 ASSERT(fb->_DepthBuffer->Wrapped == depthRb);
535 }
536 }
537 else {
538 /* depthRb may be null */
539 _mesa_reference_renderbuffer(&fb->_DepthBuffer, depthRb);
540 }
541 }
542
543
544 /**
545 * 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
553 */
554 void
555 _mesa_update_stencil_buffer(GLcontext *ctx,
556 struct gl_framebuffer *fb,
557 GLuint attIndex)
558 {
559 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 */
568 if (!fb->_StencilBuffer
569 || fb->_StencilBuffer->Wrapped != stencilRb
570 || fb->_StencilBuffer->_BaseFormat != GL_STENCIL_INDEX) {
571 /* need to update wrapper */
572 struct gl_renderbuffer *wrapper
573 = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb);
574 _mesa_reference_renderbuffer(&fb->_StencilBuffer, wrapper);
575 ASSERT(fb->_StencilBuffer->Wrapped == stencilRb);
576 }
577 }
578 else {
579 /* stencilRb may be null */
580 _mesa_reference_renderbuffer(&fb->_StencilBuffer, 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 */
590 static void
591 update_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 if (!fb->DeletePending) {
604 /* We need the inner loop here because glDrawBuffer(GL_FRONT_AND_BACK)
605 * can specify writing to two or four color buffers (for example).
606 */
607 for (i = 0; bufferMask && i < BUFFER_COUNT; i++) {
608 const GLuint bufferBit = 1 << i;
609 if (bufferBit & bufferMask) {
610 struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
611 if (rb && rb->Width > 0 && rb->Height > 0) {
612 fb->_ColorDrawBuffers[output][count] = rb;
613 count++;
614 }
615 else {
616 /*
617 _mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");
618 */
619 }
620 bufferMask &= ~bufferBit;
621 }
622 }
623 }
624 fb->_NumColorDrawBuffers[output] = count;
625 }
626 }
627
628
629 /**
630 * Update the color read renderbuffer pointer.
631 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
632 */
633 static void
634 update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
635 {
636 (void) ctx;
637 if (fb->_ColorReadBufferIndex == -1 ||
638 fb->DeletePending ||
639 fb->Width == 0 ||
640 fb->Height == 0) {
641 fb->_ColorReadBuffer = NULL; /* legal! */
642 }
643 else {
644 ASSERT(fb->_ColorReadBufferIndex >= 0);
645 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT);
646 fb->_ColorReadBuffer
647 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
648 }
649 }
650
651
652 /**
653 * Update a gl_framebuffer's derived state.
654 *
655 * Specifically, update these framebuffer fields:
656 * _ColorDrawBuffers
657 * _NumColorDrawBuffers
658 * _ColorReadBuffer
659 * _DepthBuffer
660 * _StencilBuffer
661 *
662 * If the framebuffer is user-created, make sure it's complete.
663 *
664 * The following functions (at least) can effect framebuffer state:
665 * glReadBuffer, glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT,
666 * glRenderbufferStorageEXT.
667 */
668 static void
669 update_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb)
670 {
671 /* Completeness only matters for user-created framebuffers */
672 if (fb->Name != 0) {
673 /* XXX: EXT_framebuffer_blit:
674 framebuffer must still be complete wrt read/draw? */
675 _mesa_test_framebuffer_completeness(ctx, fb);
676 _mesa_update_framebuffer_visual(fb);
677 }
678
679 /* Strictly speaking, we don't need to update the draw-state
680 * if this FB is bound as ctx->ReadBuffer (and conversely, the
681 * read-state if this FB is bound as ctx->DrawBuffer), but no
682 * harm.
683 */
684 update_color_draw_buffers(ctx, fb);
685 update_color_read_buffer(ctx, fb);
686 _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH);
687 _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL);
688
689 compute_depth_max(fb);
690 }
691
692
693 /**
694 * Update state related to the current draw/read framebuffers.
695 */
696 void
697 _mesa_update_framebuffer(GLcontext *ctx)
698 {
699 struct gl_framebuffer *drawFb = ctx->DrawBuffer;
700 struct gl_framebuffer *readFb = ctx->ReadBuffer;
701
702 update_framebuffer(ctx, drawFb);
703 if (readFb != drawFb)
704 update_framebuffer(ctx, readFb);
705 }
706
707
708 /**
709 * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels,
710 * glCopyTex[Sub]Image, etc. exists.
711 * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA,
712 * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL.
713 * \return GL_TRUE if buffer exists, GL_FALSE otherwise
714 */
715 GLboolean
716 _mesa_source_buffer_exists(GLcontext *ctx, GLenum format)
717 {
718 const struct gl_renderbuffer_attachment *att
719 = ctx->ReadBuffer->Attachment;
720
721 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
722 return GL_FALSE;
723 }
724
725 switch (format) {
726 case GL_COLOR:
727 case GL_RED:
728 case GL_GREEN:
729 case GL_BLUE:
730 case GL_ALPHA:
731 case GL_LUMINANCE:
732 case GL_LUMINANCE_ALPHA:
733 case GL_INTENSITY:
734 case GL_RGB:
735 case GL_BGR:
736 case GL_RGBA:
737 case GL_BGRA:
738 case GL_ABGR_EXT:
739 case GL_COLOR_INDEX:
740 if (ctx->ReadBuffer->_ColorReadBuffer == NULL) {
741 return GL_FALSE;
742 }
743 /* XXX enable this post 6.5 release:
744 ASSERT(ctx->ReadBuffer->_ColorReadBuffer->RedBits > 0 ||
745 ctx->ReadBuffer->_ColorReadBuffer->IndexBits > 0);
746 */
747 break;
748 case GL_DEPTH:
749 case GL_DEPTH_COMPONENT:
750 if (!att[BUFFER_DEPTH].Renderbuffer) {
751 return GL_FALSE;
752 }
753 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
754 break;
755 case GL_STENCIL:
756 case GL_STENCIL_INDEX:
757 if (!att[BUFFER_STENCIL].Renderbuffer) {
758 return GL_FALSE;
759 }
760 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
761 break;
762 case GL_DEPTH_STENCIL_EXT:
763 if (!att[BUFFER_DEPTH].Renderbuffer ||
764 !att[BUFFER_STENCIL].Renderbuffer) {
765 return GL_FALSE;
766 }
767 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
768 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
769 break;
770 default:
771 _mesa_problem(ctx,
772 "Unexpected format 0x%x in _mesa_source_buffer_exists",
773 format);
774 return GL_FALSE;
775 }
776
777 /* OK */
778 return GL_TRUE;
779 }
780
781
782 /**
783 * As above, but for drawing operations.
784 * XXX code do some code merging w/ above function.
785 */
786 GLboolean
787 _mesa_dest_buffer_exists(GLcontext *ctx, GLenum format)
788 {
789 const struct gl_renderbuffer_attachment *att
790 = ctx->ReadBuffer->Attachment;
791
792 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
793 return GL_FALSE;
794 }
795
796 switch (format) {
797 case GL_COLOR:
798 case GL_RED:
799 case GL_GREEN:
800 case GL_BLUE:
801 case GL_ALPHA:
802 case GL_LUMINANCE:
803 case GL_LUMINANCE_ALPHA:
804 case GL_INTENSITY:
805 case GL_RGB:
806 case GL_BGR:
807 case GL_RGBA:
808 case GL_BGRA:
809 case GL_ABGR_EXT:
810 case GL_COLOR_INDEX:
811 /* nothing special */
812 /* Could assert that colorbuffer has RedBits > 0 */
813 break;
814 case GL_DEPTH:
815 case GL_DEPTH_COMPONENT:
816 if (!att[BUFFER_DEPTH].Renderbuffer) {
817 return GL_FALSE;
818 }
819 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
820 break;
821 case GL_STENCIL:
822 case GL_STENCIL_INDEX:
823 if (!att[BUFFER_STENCIL].Renderbuffer) {
824 return GL_FALSE;
825 }
826 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
827 break;
828 case GL_DEPTH_STENCIL_EXT:
829 if (!att[BUFFER_DEPTH].Renderbuffer ||
830 !att[BUFFER_STENCIL].Renderbuffer) {
831 return GL_FALSE;
832 }
833 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
834 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
835 break;
836 default:
837 _mesa_problem(ctx,
838 "Unexpected format 0x%x in _mesa_source_buffer_exists",
839 format);
840 return GL_FALSE;
841 }
842
843 /* OK */
844 return GL_TRUE;
845 }