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