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