some tentative code for _mesa_update_framebuffer_visual()
[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 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 */
97 static void
98 set_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 /**
115 * 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 */
121 struct 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 */
140 struct gl_framebuffer *
141 _mesa_new_framebuffer(GLcontext *ctx, GLuint name)
142 {
143 struct gl_framebuffer *fb;
144 (void) ctx;
145 assert(name != 0);
146 fb = CALLOC_STRUCT(gl_framebuffer);
147 if (fb) {
148 fb->Name = name;
149 fb->RefCount = 1;
150 fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT;
151 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_COLOR0;
152 fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT;
153 fb->_ColorReadBufferIndex = BUFFER_COLOR0;
154 fb->Delete = _mesa_destroy_framebuffer;
155 }
156 return fb;
157 }
158
159
160 /**
161 * Initialize a gl_framebuffer object. Typically used to initialize
162 * window system-created framebuffers, not user-created framebuffers.
163 * \sa _mesa_create_framebuffer
164 */
165 void
166 _mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual)
167 {
168 assert(fb);
169 assert(visual);
170
171 _mesa_bzero(fb, sizeof(struct gl_framebuffer));
172
173 _glthread_INIT_MUTEX(fb->Mutex);
174
175 /* save the visual */
176 fb->Visual = *visual;
177
178 /* Init glRead/DrawBuffer state */
179 if (visual->doubleBufferMode) {
180 fb->ColorDrawBuffer[0] = GL_BACK;
181 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_BACK_LEFT;
182 fb->ColorReadBuffer = GL_BACK;
183 fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT;
184 }
185 else {
186 fb->ColorDrawBuffer[0] = GL_FRONT;
187 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT;
188 fb->ColorReadBuffer = GL_FRONT;
189 fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT;
190 }
191
192 fb->Delete = _mesa_destroy_framebuffer;
193 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
194
195 compute_depth_max(fb);
196 }
197
198
199 /**
200 * Deallocate buffer and everything attached to it.
201 * Typically called via the gl_framebuffer->Delete() method.
202 */
203 void
204 _mesa_destroy_framebuffer(struct gl_framebuffer *fb)
205 {
206 if (fb) {
207 _glthread_DESTROY_MUTEX(fb->Mutex);
208 _mesa_free_framebuffer_data(fb);
209 _mesa_free(fb);
210 }
211 }
212
213
214 /**
215 * Free all the data hanging off the given gl_framebuffer, but don't free
216 * the gl_framebuffer object itself.
217 */
218 void
219 _mesa_free_framebuffer_data(struct gl_framebuffer *fb)
220 {
221 GLuint i;
222
223 assert(fb);
224
225 for (i = 0; i < BUFFER_COUNT; i++) {
226 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
227 if (att->Renderbuffer) {
228 struct gl_renderbuffer *rb = att->Renderbuffer;
229 _glthread_LOCK_MUTEX(rb->Mutex);
230 rb->RefCount--;
231 _glthread_UNLOCK_MUTEX(rb->Mutex);
232 if (rb->RefCount == 0) {
233 rb->Delete(rb);
234 }
235 }
236 att->Type = GL_NONE;
237 att->Renderbuffer = NULL;
238 }
239
240 /* unbind depth/stencil to decr ref counts */
241 set_depth_renderbuffer(fb, NULL);
242 set_stencil_renderbuffer(fb, NULL);
243 }
244
245
246 /**
247 * Resize the given framebuffer's renderbuffers to the new width and height.
248 * This should only be used for window-system framebuffers, not
249 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object).
250 * This will typically be called via ctx->Driver.ResizeBuffers() or directly
251 * from a device driver.
252 *
253 * \note it's possible for ctx to be null since a window can be resized
254 * without a currently bound rendering context.
255 */
256 void
257 _mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
258 GLuint width, GLuint height)
259 {
260 GLuint i;
261
262 /* XXX I think we could check if the size is not changing
263 * and return early.
264 */
265
266 /* For window system framebuffers, Name is zero */
267 assert(fb->Name == 0);
268
269 for (i = 0; i < BUFFER_COUNT; i++) {
270 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
271 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
272 struct gl_renderbuffer *rb = att->Renderbuffer;
273 /* only resize if size is changing */
274 if (rb->Width != width || rb->Height != height) {
275 /* could just as well pass rb->_ActualFormat here */
276 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
277 ASSERT(rb->Width == width);
278 ASSERT(rb->Height == height);
279 }
280 else {
281 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
282 /* no return */
283 }
284 }
285 }
286 }
287
288 if (fb->_DepthBuffer) {
289 struct gl_renderbuffer *rb = fb->_DepthBuffer;
290 if (rb->Width != width || rb->Height != height) {
291 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
292 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
293 }
294 }
295 }
296
297 if (fb->_StencilBuffer) {
298 struct gl_renderbuffer *rb = fb->_StencilBuffer;
299 if (rb->Width != width || rb->Height != height) {
300 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
301 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
302 }
303 }
304 }
305
306 fb->Width = width;
307 fb->Height = height;
308
309 /* to update scissor / window bounds */
310 _mesa_update_draw_buffer_bounds(ctx);
311 }
312
313
314 /**
315 * Examine all the framebuffer's renderbuffers to update the Width/Height
316 * fields of the framebuffer. If we have renderbuffers with different
317 * sizes, set the framebuffer's width and height to zero.
318 * Note: this is only intended for user-created framebuffers, not
319 * window-system framebuffes.
320 */
321 static void
322 update_framebuffer_size(struct gl_framebuffer *fb)
323 {
324 GLboolean haveSize = GL_FALSE;
325 GLuint i;
326
327 /* user-created framebuffers only */
328 assert(fb->Name);
329
330 for (i = 0; i < BUFFER_COUNT; i++) {
331 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
332 const struct gl_renderbuffer *rb = att->Renderbuffer;
333 if (rb) {
334 if (haveSize) {
335 if (rb->Width != fb->Width && rb->Height != fb->Height) {
336 /* size mismatch! */
337 fb->Width = 0;
338 fb->Height = 0;
339 return;
340 }
341 }
342 else {
343 fb->Width = rb->Width;
344 fb->Height = rb->Height;
345 haveSize = GL_TRUE;
346 }
347 }
348 }
349 }
350
351
352 /**
353 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
354 * These values are computed from the buffer's width and height and
355 * the scissor box, if it's enabled.
356 * \param ctx the GL context.
357 */
358 void
359 _mesa_update_draw_buffer_bounds(GLcontext *ctx)
360 {
361 struct gl_framebuffer *buffer = ctx->DrawBuffer;
362
363 if (buffer->Name) {
364 /* user-created framebuffer size depends on the renderbuffers */
365 update_framebuffer_size(buffer);
366 }
367
368 buffer->_Xmin = 0;
369 buffer->_Ymin = 0;
370 buffer->_Xmax = buffer->Width;
371 buffer->_Ymax = buffer->Height;
372
373 if (ctx->Scissor.Enabled) {
374 if (ctx->Scissor.X > buffer->_Xmin) {
375 buffer->_Xmin = ctx->Scissor.X;
376 }
377 if (ctx->Scissor.Y > buffer->_Ymin) {
378 buffer->_Ymin = ctx->Scissor.Y;
379 }
380 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
381 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
382 }
383 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
384 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
385 }
386 /* finally, check for empty region */
387 if (buffer->_Xmin > buffer->_Xmax) {
388 buffer->_Xmin = buffer->_Xmax;
389 }
390 if (buffer->_Ymin > buffer->_Ymax) {
391 buffer->_Ymin = buffer->_Ymax;
392 }
393 }
394
395 ASSERT(buffer->_Xmin <= buffer->_Xmax);
396 ASSERT(buffer->_Ymin <= buffer->_Ymax);
397 }
398
399
400 /**
401 * The glGet queries of the framebuffer red/green/blue size, stencil size,
402 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can
403 * change depending on the renderbuffer bindings. This function updates
404 * the given framebuffer's Visual from the current renderbuffer bindings.
405 * This is only intended for user-created framebuffers.
406 *
407 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal
408 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits.
409 * The former one is used to convert floating point depth values into
410 * integer Z values.
411 */
412 void
413 _mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
414 {
415 GLuint i;
416
417 assert(fb->Name != 0);
418
419 _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
420 fb->Visual.rgbMode = GL_TRUE; /* assume this */
421
422 #if 0 /* this _might_ be needed */
423 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
424 /* leave visual fields zero'd */
425 return;
426 }
427 #endif
428
429 /* find first RGB or CI renderbuffer */
430 for (i = 0; i < BUFFER_COUNT; i++) {
431 if (fb->Attachment[i].Renderbuffer) {
432 const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
433 if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) {
434 fb->Visual.redBits = rb->RedBits;
435 fb->Visual.greenBits = rb->GreenBits;
436 fb->Visual.blueBits = rb->BlueBits;
437 fb->Visual.alphaBits = rb->AlphaBits;
438 fb->Visual.rgbBits = fb->Visual.redBits
439 + fb->Visual.greenBits + fb->Visual.blueBits;
440 fb->Visual.floatMode = GL_FALSE;
441 break;
442 }
443 else if (rb->_BaseFormat == GL_COLOR_INDEX) {
444 fb->Visual.indexBits = rb->IndexBits;
445 fb->Visual.rgbMode = GL_FALSE;
446 break;
447 }
448 }
449 }
450
451 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
452 fb->Visual.haveDepthBuffer = GL_TRUE;
453 fb->Visual.depthBits
454 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits;
455 }
456
457 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
458 fb->Visual.haveStencilBuffer = GL_TRUE;
459 fb->Visual.stencilBits
460 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits;
461 }
462
463 compute_depth_max(fb);
464 }
465
466
467 /**
468 * Update the framebuffer's _DepthBuffer field using the renderbuffer
469 * found at the given attachment index.
470 *
471 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
472 * create and install a depth wrapper/adaptor.
473 *
474 * \param fb the framebuffer whose _DepthBuffer field to update
475 * \param attIndex indicates the renderbuffer to possibly wrap
476 */
477 void
478 _mesa_update_depth_buffer(GLcontext *ctx,
479 struct gl_framebuffer *fb,
480 GLuint attIndex)
481 {
482 struct gl_renderbuffer *depthRb;
483
484 /* only one possiblity for now */
485 ASSERT(attIndex == BUFFER_DEPTH);
486
487 depthRb = fb->Attachment[attIndex].Renderbuffer;
488
489 if (depthRb && depthRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
490 /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */
491 if (!fb->_DepthBuffer
492 || fb->_DepthBuffer->Wrapped != depthRb
493 || fb->_DepthBuffer->_BaseFormat != GL_DEPTH_COMPONENT) {
494 /* need to update wrapper */
495 struct gl_renderbuffer *wrapper
496 = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb);
497 set_depth_renderbuffer(fb, wrapper);
498 ASSERT(fb->_DepthBuffer->Wrapped == depthRb);
499 }
500 }
501 else {
502 /* depthRb may be null */
503 set_depth_renderbuffer(fb, depthRb);
504 }
505 }
506
507
508 /**
509 * Update the framebuffer's _StencilBuffer 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 stencil wrapper/adaptor.
514 *
515 * \param fb the framebuffer whose _StencilBuffer field to update
516 * \param attIndex indicates the renderbuffer to possibly wrap
517 */
518 void
519 _mesa_update_stencil_buffer(GLcontext *ctx,
520 struct gl_framebuffer *fb,
521 GLuint attIndex)
522 {
523 struct gl_renderbuffer *stencilRb;
524
525 ASSERT(attIndex == BUFFER_DEPTH ||
526 attIndex == BUFFER_STENCIL);
527
528 stencilRb = fb->Attachment[attIndex].Renderbuffer;
529
530 if (stencilRb && stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
531 /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */
532 if (!fb->_StencilBuffer
533 || fb->_StencilBuffer->Wrapped != stencilRb
534 || fb->_StencilBuffer->_BaseFormat != GL_STENCIL_INDEX) {
535 /* need to update wrapper */
536 struct gl_renderbuffer *wrapper
537 = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb);
538 set_stencil_renderbuffer(fb, wrapper);
539 ASSERT(fb->_StencilBuffer->Wrapped == stencilRb);
540 }
541 }
542 else {
543 /* stencilRb may be null */
544 set_stencil_renderbuffer(fb, stencilRb);
545 }
546 }
547
548
549 /**
550 * Update the list of color drawing renderbuffer pointers.
551 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
552 * writing colors.
553 */
554 static void
555 update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb)
556 {
557 GLuint output;
558
559 /*
560 * Fragment programs can write to multiple colorbuffers with
561 * the GL_ARB_draw_buffers extension.
562 */
563 for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) {
564 GLbitfield bufferMask = fb->_ColorDrawBufferMask[output];
565 GLuint count = 0;
566 GLuint i;
567 /* We need the inner loop here because glDrawBuffer(GL_FRONT_AND_BACK)
568 * can specify writing to two or four color buffers (for example).
569 */
570 for (i = 0; bufferMask && i < BUFFER_COUNT; i++) {
571 const GLuint bufferBit = 1 << i;
572 if (bufferBit & bufferMask) {
573 struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
574 if (rb) {
575 fb->_ColorDrawBuffers[output][count] = rb;
576 count++;
577 }
578 else {
579 /*_mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");*/
580 }
581 bufferMask &= ~bufferBit;
582 }
583 }
584 fb->_NumColorDrawBuffers[output] = count;
585 }
586 }
587
588
589 /**
590 * Update the color read renderbuffer pointer.
591 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
592 */
593 static void
594 update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
595 {
596 (void) ctx;
597 if (fb->_ColorReadBufferIndex == -1) {
598 fb->_ColorReadBuffer = NULL; /* legal! */
599 }
600 else {
601 ASSERT(fb->_ColorReadBufferIndex >= 0);
602 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT);
603 fb->_ColorReadBuffer
604 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
605 }
606 }
607
608
609 /**
610 * Update state related to the current draw/read framebuffers.
611 * Specifically, update these framebuffer fields:
612 * _ColorDrawBuffers
613 * _NumColorDrawBuffers
614 * _ColorReadBuffer
615 * _DepthBuffer
616 * _StencilBuffer
617 * If the current framebuffer is user-created, make sure it's complete.
618 * The following functions can effect this state: glReadBuffer,
619 * glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT,
620 * glRenderbufferStorageEXT.
621 */
622 void
623 _mesa_update_framebuffer(GLcontext *ctx)
624 {
625 struct gl_framebuffer *fb = ctx->DrawBuffer;
626
627 /* Completeness only matters for user-created framebuffers */
628 if (fb->Name != 0) {
629 _mesa_test_framebuffer_completeness(ctx, fb);
630 _mesa_update_framebuffer_visual(fb);
631 }
632
633 update_color_draw_buffers(ctx, fb);
634 update_color_read_buffer(ctx, fb);
635 _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH);
636 _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL);
637
638 compute_depth_max(fb);
639 }
640
641
642 /**
643 * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels,
644 * glCopyTex[Sub]Image, etc. exists.
645 * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA,
646 * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL.
647 * \return GL_TRUE if buffer exists, GL_FALSE otherwise
648 */
649 GLboolean
650 _mesa_source_buffer_exists(GLcontext *ctx, GLenum format)
651 {
652 const struct gl_renderbuffer_attachment *att
653 = ctx->ReadBuffer->Attachment;
654
655 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
656 return GL_FALSE;
657 }
658
659 switch (format) {
660 case GL_COLOR:
661 case GL_RED:
662 case GL_GREEN:
663 case GL_BLUE:
664 case GL_ALPHA:
665 case GL_LUMINANCE:
666 case GL_LUMINANCE_ALPHA:
667 case GL_INTENSITY:
668 case GL_RGB:
669 case GL_BGR:
670 case GL_RGBA:
671 case GL_BGRA:
672 case GL_ABGR_EXT:
673 case GL_COLOR_INDEX:
674 if (ctx->ReadBuffer->_ColorReadBuffer == NULL) {
675 return GL_FALSE;
676 }
677 /* XXX enable this post 6.5 release:
678 ASSERT(ctx->ReadBuffer->_ColorReadBuffer->RedBits > 0 ||
679 ctx->ReadBuffer->_ColorReadBuffer->IndexBits > 0);
680 */
681 break;
682 case GL_DEPTH:
683 case GL_DEPTH_COMPONENT:
684 if (!att[BUFFER_DEPTH].Renderbuffer) {
685 return GL_FALSE;
686 }
687 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
688 break;
689 case GL_STENCIL:
690 case GL_STENCIL_INDEX:
691 if (!att[BUFFER_STENCIL].Renderbuffer) {
692 return GL_FALSE;
693 }
694 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
695 break;
696 case GL_DEPTH_STENCIL_EXT:
697 if (!att[BUFFER_DEPTH].Renderbuffer ||
698 !att[BUFFER_STENCIL].Renderbuffer) {
699 return GL_FALSE;
700 }
701 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
702 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
703 break;
704 default:
705 _mesa_problem(ctx,
706 "Unexpected format 0x%x in _mesa_source_buffer_exists",
707 format);
708 return GL_FALSE;
709 }
710
711 /* OK */
712 return GL_TRUE;
713 }
714
715
716 /**
717 * As above, but for drawing operations.
718 * XXX code do some code merging w/ above function.
719 */
720 GLboolean
721 _mesa_dest_buffer_exists(GLcontext *ctx, GLenum format)
722 {
723 const struct gl_renderbuffer_attachment *att
724 = ctx->ReadBuffer->Attachment;
725
726 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
727 return GL_FALSE;
728 }
729
730 switch (format) {
731 case GL_COLOR:
732 case GL_RED:
733 case GL_GREEN:
734 case GL_BLUE:
735 case GL_ALPHA:
736 case GL_LUMINANCE:
737 case GL_LUMINANCE_ALPHA:
738 case GL_INTENSITY:
739 case GL_RGB:
740 case GL_BGR:
741 case GL_RGBA:
742 case GL_BGRA:
743 case GL_ABGR_EXT:
744 case GL_COLOR_INDEX:
745 /* nothing special */
746 /* Could assert that colorbuffer has RedBits > 0 */
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 }