465197401b7b8ab0b99f852890a07505863916b7
[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_dereference_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_dereference_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 /* 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;
177 fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT;
178 }
179 else {
180 fb->ColorDrawBuffer[0] = GL_FRONT;
181 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT;
182 fb->ColorReadBuffer = GL_FRONT;
183 fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT;
184 }
185
186 fb->Delete = _mesa_destroy_framebuffer;
187 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
188
189 compute_depth_max(fb);
190 }
191
192
193 /**
194 * Deallocate buffer and everything attached to it.
195 * Typically called via the gl_framebuffer->Delete() method.
196 */
197 void
198 _mesa_destroy_framebuffer(struct gl_framebuffer *fb)
199 {
200 if (fb) {
201 _glthread_DESTROY_MUTEX(fb->Mutex);
202 _mesa_free_framebuffer_data(fb);
203 _mesa_free(fb);
204 }
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 */
212 void
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];
221 if (att->Renderbuffer) {
222 struct gl_renderbuffer *rb = att->Renderbuffer;
223 /* 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);
228 }
229 }
230 att->Type = GL_NONE;
231 att->Renderbuffer = NULL;
232 }
233
234 /* unbind depth/stencil to decr ref counts */
235 set_depth_renderbuffer(fb, NULL);
236 set_stencil_renderbuffer(fb, NULL);
237 }
238
239
240 /**
241 * 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 */
245 void
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 /**
268 * 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).
271 * 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.
276 */
277 void
278 _mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
279 GLuint width, GLuint height)
280 {
281 GLuint i;
282
283 /* XXX I think we could check if the size is not changing
284 * and return early.
285 */
286
287 /* 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) {
296 /* could just as well pass rb->_ActualFormat here */
297 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
298 ASSERT(rb->Width == width);
299 ASSERT(rb->Height == height);
300 }
301 else {
302 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
303 /* no return */
304 }
305 }
306 }
307 }
308
309 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
327 fb->Width = width;
328 fb->Height = height;
329
330 if (ctx) {
331 /* update scissor / window bounds */
332 _mesa_update_draw_buffer_bounds(ctx);
333 /* Signal new buffer state so that swrast will update its clipping
334 * info (the CLIP_BIT flag).
335 */
336 ctx->NewState |= _NEW_BUFFERS;
337 }
338 }
339
340
341 /**
342 * Examine all the framebuffer's renderbuffers to update the Width/Height
343 * fields of the framebuffer. If we have renderbuffers with different
344 * sizes, set the framebuffer's width and height to zero.
345 * Note: this is only intended for user-created framebuffers, not
346 * window-system framebuffes.
347 */
348 static void
349 update_framebuffer_size(struct gl_framebuffer *fb)
350 {
351 GLboolean haveSize = GL_FALSE;
352 GLuint i;
353
354 /* user-created framebuffers only */
355 assert(fb->Name);
356
357 for (i = 0; i < BUFFER_COUNT; i++) {
358 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
359 const struct gl_renderbuffer *rb = att->Renderbuffer;
360 if (rb) {
361 if (haveSize) {
362 if (rb->Width != fb->Width && rb->Height != fb->Height) {
363 /* size mismatch! */
364 fb->Width = 0;
365 fb->Height = 0;
366 return;
367 }
368 }
369 else {
370 fb->Width = rb->Width;
371 fb->Height = rb->Height;
372 haveSize = GL_TRUE;
373 }
374 }
375 }
376 }
377
378
379 /**
380 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
381 * These values are computed from the buffer's width and height and
382 * the scissor box, if it's enabled.
383 * \param ctx the GL context.
384 */
385 void
386 _mesa_update_draw_buffer_bounds(GLcontext *ctx)
387 {
388 struct gl_framebuffer *buffer = ctx->DrawBuffer;
389
390 if (!buffer)
391 return;
392
393 if (buffer->Name) {
394 /* user-created framebuffer size depends on the renderbuffers */
395 update_framebuffer_size(buffer);
396 }
397
398 buffer->_Xmin = 0;
399 buffer->_Ymin = 0;
400 buffer->_Xmax = buffer->Width;
401 buffer->_Ymax = buffer->Height;
402
403 if (ctx->Scissor.Enabled) {
404 if (ctx->Scissor.X > buffer->_Xmin) {
405 buffer->_Xmin = ctx->Scissor.X;
406 }
407 if (ctx->Scissor.Y > buffer->_Ymin) {
408 buffer->_Ymin = ctx->Scissor.Y;
409 }
410 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
411 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
412 }
413 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
414 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
415 }
416 /* finally, check for empty region */
417 if (buffer->_Xmin > buffer->_Xmax) {
418 buffer->_Xmin = buffer->_Xmax;
419 }
420 if (buffer->_Ymin > buffer->_Ymax) {
421 buffer->_Ymin = buffer->_Ymax;
422 }
423 }
424
425 ASSERT(buffer->_Xmin <= buffer->_Xmax);
426 ASSERT(buffer->_Ymin <= buffer->_Ymax);
427 }
428
429
430 /**
431 * The glGet queries of the framebuffer red/green/blue size, stencil size,
432 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can
433 * change depending on the renderbuffer bindings. This function updates
434 * the given framebuffer's Visual from the current renderbuffer bindings.
435 *
436 * This may apply to user-created framebuffers or window system framebuffers.
437 *
438 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal
439 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits.
440 * The former one is used to convert floating point depth values into
441 * integer Z values.
442 */
443 void
444 _mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
445 {
446 GLuint i;
447
448 _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
449 fb->Visual.rgbMode = GL_TRUE; /* assume this */
450
451 #if 0 /* this _might_ be needed */
452 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
453 /* leave visual fields zero'd */
454 return;
455 }
456 #endif
457
458 /* find first RGB or CI renderbuffer */
459 for (i = 0; i < BUFFER_COUNT; i++) {
460 if (fb->Attachment[i].Renderbuffer) {
461 const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
462 if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) {
463 fb->Visual.redBits = rb->RedBits;
464 fb->Visual.greenBits = rb->GreenBits;
465 fb->Visual.blueBits = rb->BlueBits;
466 fb->Visual.alphaBits = rb->AlphaBits;
467 fb->Visual.rgbBits = fb->Visual.redBits
468 + fb->Visual.greenBits + fb->Visual.blueBits;
469 fb->Visual.floatMode = GL_FALSE;
470 break;
471 }
472 else if (rb->_BaseFormat == GL_COLOR_INDEX) {
473 fb->Visual.indexBits = rb->IndexBits;
474 fb->Visual.rgbMode = GL_FALSE;
475 break;
476 }
477 }
478 }
479
480 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
481 fb->Visual.haveDepthBuffer = GL_TRUE;
482 fb->Visual.depthBits
483 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits;
484 }
485
486 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
487 fb->Visual.haveStencilBuffer = GL_TRUE;
488 fb->Visual.stencilBits
489 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits;
490 }
491
492 if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) {
493 fb->Visual.haveAccumBuffer = GL_TRUE;
494 fb->Visual.accumRedBits
495 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->RedBits;
496 fb->Visual.accumGreenBits
497 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->GreenBits;
498 fb->Visual.accumBlueBits
499 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->BlueBits;
500 fb->Visual.accumAlphaBits
501 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->AlphaBits;
502 }
503
504 compute_depth_max(fb);
505 }
506
507
508 /**
509 * Update the framebuffer's _DepthBuffer field using the renderbuffer
510 * found at the given attachment index.
511 *
512 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
513 * create and install a depth wrapper/adaptor.
514 *
515 * \param fb the framebuffer whose _DepthBuffer field to update
516 * \param attIndex indicates the renderbuffer to possibly wrap
517 */
518 void
519 _mesa_update_depth_buffer(GLcontext *ctx,
520 struct gl_framebuffer *fb,
521 GLuint attIndex)
522 {
523 struct gl_renderbuffer *depthRb;
524
525 /* only one possiblity for now */
526 ASSERT(attIndex == BUFFER_DEPTH);
527
528 depthRb = fb->Attachment[attIndex].Renderbuffer;
529
530 if (depthRb && depthRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
531 /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */
532 if (!fb->_DepthBuffer
533 || fb->_DepthBuffer->Wrapped != depthRb
534 || fb->_DepthBuffer->_BaseFormat != GL_DEPTH_COMPONENT) {
535 /* need to update wrapper */
536 struct gl_renderbuffer *wrapper
537 = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb);
538 set_depth_renderbuffer(fb, wrapper);
539 ASSERT(fb->_DepthBuffer->Wrapped == depthRb);
540 }
541 }
542 else {
543 /* depthRb may be null */
544 set_depth_renderbuffer(fb, depthRb);
545 }
546 }
547
548
549 /**
550 * Update the framebuffer's _StencilBuffer field using the renderbuffer
551 * found at the given attachment index.
552 *
553 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
554 * create and install a stencil wrapper/adaptor.
555 *
556 * \param fb the framebuffer whose _StencilBuffer field to update
557 * \param attIndex indicates the renderbuffer to possibly wrap
558 */
559 void
560 _mesa_update_stencil_buffer(GLcontext *ctx,
561 struct gl_framebuffer *fb,
562 GLuint attIndex)
563 {
564 struct gl_renderbuffer *stencilRb;
565
566 ASSERT(attIndex == BUFFER_DEPTH ||
567 attIndex == BUFFER_STENCIL);
568
569 stencilRb = fb->Attachment[attIndex].Renderbuffer;
570
571 if (stencilRb && stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
572 /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */
573 if (!fb->_StencilBuffer
574 || fb->_StencilBuffer->Wrapped != stencilRb
575 || fb->_StencilBuffer->_BaseFormat != GL_STENCIL_INDEX) {
576 /* need to update wrapper */
577 struct gl_renderbuffer *wrapper
578 = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb);
579 set_stencil_renderbuffer(fb, wrapper);
580 ASSERT(fb->_StencilBuffer->Wrapped == stencilRb);
581 }
582 }
583 else {
584 /* stencilRb may be null */
585 set_stencil_renderbuffer(fb, stencilRb);
586 }
587 }
588
589
590 /**
591 * Update the list of color drawing renderbuffer pointers.
592 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
593 * writing colors.
594 */
595 static void
596 update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb)
597 {
598 GLuint output;
599
600 /*
601 * Fragment programs can write to multiple colorbuffers with
602 * the GL_ARB_draw_buffers extension.
603 */
604 for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) {
605 GLbitfield bufferMask = fb->_ColorDrawBufferMask[output];
606 GLuint count = 0;
607 GLuint i;
608 /* We need the inner loop here because glDrawBuffer(GL_FRONT_AND_BACK)
609 * can specify writing to two or four color buffers (for example).
610 */
611 for (i = 0; bufferMask && i < BUFFER_COUNT; i++) {
612 const GLuint bufferBit = 1 << i;
613 if (bufferBit & bufferMask) {
614 struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
615 if (rb) {
616 fb->_ColorDrawBuffers[output][count] = rb;
617 count++;
618 }
619 else {
620 /*_mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");*/
621 }
622 bufferMask &= ~bufferBit;
623 }
624 }
625 fb->_NumColorDrawBuffers[output] = count;
626 }
627 }
628
629
630 /**
631 * Update the color read renderbuffer pointer.
632 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
633 */
634 static void
635 update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
636 {
637 (void) ctx;
638 if (fb->_ColorReadBufferIndex == -1) {
639 fb->_ColorReadBuffer = NULL; /* legal! */
640 }
641 else {
642 ASSERT(fb->_ColorReadBufferIndex >= 0);
643 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT);
644 fb->_ColorReadBuffer
645 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
646 }
647 }
648
649
650 /**
651 * Update state related to the current draw/read framebuffers.
652 * Specifically, update these framebuffer fields:
653 * _ColorDrawBuffers
654 * _NumColorDrawBuffers
655 * _ColorReadBuffer
656 * _DepthBuffer
657 * _StencilBuffer
658 * If the current framebuffer is user-created, make sure it's complete.
659 * The following functions can effect this state: glReadBuffer,
660 * glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT,
661 * glRenderbufferStorageEXT.
662 */
663 void
664 _mesa_update_framebuffer(GLcontext *ctx)
665 {
666 struct gl_framebuffer *fb = ctx->DrawBuffer;
667
668 /* Completeness only matters for user-created framebuffers */
669 if (fb->Name != 0) {
670 _mesa_test_framebuffer_completeness(ctx, fb);
671 _mesa_update_framebuffer_visual(fb);
672 }
673
674 update_color_draw_buffers(ctx, fb);
675 update_color_read_buffer(ctx, fb);
676 _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH);
677 _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL);
678
679 compute_depth_max(fb);
680 }
681
682
683 /**
684 * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels,
685 * glCopyTex[Sub]Image, etc. exists.
686 * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA,
687 * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL.
688 * \return GL_TRUE if buffer exists, GL_FALSE otherwise
689 */
690 GLboolean
691 _mesa_source_buffer_exists(GLcontext *ctx, GLenum format)
692 {
693 const struct gl_renderbuffer_attachment *att
694 = ctx->ReadBuffer->Attachment;
695
696 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
697 return GL_FALSE;
698 }
699
700 switch (format) {
701 case GL_COLOR:
702 case GL_RED:
703 case GL_GREEN:
704 case GL_BLUE:
705 case GL_ALPHA:
706 case GL_LUMINANCE:
707 case GL_LUMINANCE_ALPHA:
708 case GL_INTENSITY:
709 case GL_RGB:
710 case GL_BGR:
711 case GL_RGBA:
712 case GL_BGRA:
713 case GL_ABGR_EXT:
714 case GL_COLOR_INDEX:
715 if (ctx->ReadBuffer->_ColorReadBuffer == NULL) {
716 return GL_FALSE;
717 }
718 /* XXX enable this post 6.5 release:
719 ASSERT(ctx->ReadBuffer->_ColorReadBuffer->RedBits > 0 ||
720 ctx->ReadBuffer->_ColorReadBuffer->IndexBits > 0);
721 */
722 break;
723 case GL_DEPTH:
724 case GL_DEPTH_COMPONENT:
725 if (!att[BUFFER_DEPTH].Renderbuffer) {
726 return GL_FALSE;
727 }
728 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
729 break;
730 case GL_STENCIL:
731 case GL_STENCIL_INDEX:
732 if (!att[BUFFER_STENCIL].Renderbuffer) {
733 return GL_FALSE;
734 }
735 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
736 break;
737 case GL_DEPTH_STENCIL_EXT:
738 if (!att[BUFFER_DEPTH].Renderbuffer ||
739 !att[BUFFER_STENCIL].Renderbuffer) {
740 return GL_FALSE;
741 }
742 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
743 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
744 break;
745 default:
746 _mesa_problem(ctx,
747 "Unexpected format 0x%x in _mesa_source_buffer_exists",
748 format);
749 return GL_FALSE;
750 }
751
752 /* OK */
753 return GL_TRUE;
754 }
755
756
757 /**
758 * As above, but for drawing operations.
759 * XXX code do some code merging w/ above function.
760 */
761 GLboolean
762 _mesa_dest_buffer_exists(GLcontext *ctx, GLenum format)
763 {
764 const struct gl_renderbuffer_attachment *att
765 = ctx->ReadBuffer->Attachment;
766
767 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
768 return GL_FALSE;
769 }
770
771 switch (format) {
772 case GL_COLOR:
773 case GL_RED:
774 case GL_GREEN:
775 case GL_BLUE:
776 case GL_ALPHA:
777 case GL_LUMINANCE:
778 case GL_LUMINANCE_ALPHA:
779 case GL_INTENSITY:
780 case GL_RGB:
781 case GL_BGR:
782 case GL_RGBA:
783 case GL_BGRA:
784 case GL_ABGR_EXT:
785 case GL_COLOR_INDEX:
786 /* nothing special */
787 /* Could assert that colorbuffer has RedBits > 0 */
788 break;
789 case GL_DEPTH:
790 case GL_DEPTH_COMPONENT:
791 if (!att[BUFFER_DEPTH].Renderbuffer) {
792 return GL_FALSE;
793 }
794 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
795 break;
796 case GL_STENCIL:
797 case GL_STENCIL_INDEX:
798 if (!att[BUFFER_STENCIL].Renderbuffer) {
799 return GL_FALSE;
800 }
801 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
802 break;
803 case GL_DEPTH_STENCIL_EXT:
804 if (!att[BUFFER_DEPTH].Renderbuffer ||
805 !att[BUFFER_STENCIL].Renderbuffer) {
806 return GL_FALSE;
807 }
808 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
809 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
810 break;
811 default:
812 _mesa_problem(ctx,
813 "Unexpected format 0x%x in _mesa_source_buffer_exists",
814 format);
815 return GL_FALSE;
816 }
817
818 /* OK */
819 return GL_TRUE;
820 }