Merge commit 'origin/master' into gallium-0.2
[mesa.git] / src / mesa / main / framebuffer.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.2
4 *
5 * Copyright (C) 1999-2008 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 = (GLfloat)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 /**
342 * XXX THIS IS OBSOLETE - drivers should take care of detecting window
343 * size changes and act accordingly, likely calling _mesa_resize_framebuffer().
344 *
345 * GL_MESA_resize_buffers extension.
346 *
347 * When this function is called, we'll ask the window system how large
348 * the current window is. If it's a new size, we'll call the driver's
349 * ResizeBuffers function. The driver will then resize its color buffers
350 * as needed, and maybe call the swrast's routine for reallocating
351 * swrast-managed depth/stencil/accum/etc buffers.
352 * \note This function should only be called through the GL API, not
353 * from device drivers (as was done in the past).
354 */
355 void
356 _mesa_resizebuffers( GLcontext *ctx )
357 {
358 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx );
359
360 if (MESA_VERBOSE & VERBOSE_API)
361 _mesa_debug(ctx, "glResizeBuffersMESA\n");
362
363 if (!ctx->Driver.GetBufferSize) {
364 return;
365 }
366
367 if (ctx->WinSysDrawBuffer) {
368 GLuint newWidth, newHeight;
369 GLframebuffer *buffer = ctx->WinSysDrawBuffer;
370
371 assert(buffer->Name == 0);
372
373 /* ask device driver for size of output buffer */
374 ctx->Driver.GetBufferSize( buffer, &newWidth, &newHeight );
375
376 /* see if size of device driver's color buffer (window) has changed */
377 if (buffer->Width != newWidth || buffer->Height != newHeight) {
378 if (ctx->Driver.ResizeBuffers)
379 ctx->Driver.ResizeBuffers(ctx, buffer, newWidth, newHeight );
380 }
381 }
382
383 if (ctx->WinSysReadBuffer
384 && ctx->WinSysReadBuffer != ctx->WinSysDrawBuffer) {
385 GLuint newWidth, newHeight;
386 GLframebuffer *buffer = ctx->WinSysReadBuffer;
387
388 assert(buffer->Name == 0);
389
390 /* ask device driver for size of read buffer */
391 ctx->Driver.GetBufferSize( buffer, &newWidth, &newHeight );
392
393 /* see if size of device driver's color buffer (window) has changed */
394 if (buffer->Width != newWidth || buffer->Height != newHeight) {
395 if (ctx->Driver.ResizeBuffers)
396 ctx->Driver.ResizeBuffers(ctx, buffer, newWidth, newHeight );
397 }
398 }
399
400 ctx->NewState |= _NEW_BUFFERS; /* to update scissor / window bounds */
401 }
402
403
404 /*
405 * XXX THIS IS OBSOLETE
406 */
407 void GLAPIENTRY
408 _mesa_ResizeBuffersMESA( void )
409 {
410 GET_CURRENT_CONTEXT(ctx);
411
412 if (ctx->Extensions.MESA_resize_buffers)
413 _mesa_resizebuffers( ctx );
414 }
415
416
417
418 /**
419 * Examine all the framebuffer's renderbuffers to update the Width/Height
420 * fields of the framebuffer. If we have renderbuffers with different
421 * sizes, set the framebuffer's width and height to zero.
422 * Note: this is only intended for user-created framebuffers, not
423 * window-system framebuffes.
424 */
425 static void
426 update_framebuffer_size(struct gl_framebuffer *fb)
427 {
428 GLboolean haveSize = GL_FALSE;
429 GLuint i;
430
431 /* user-created framebuffers only */
432 assert(fb->Name);
433
434 for (i = 0; i < BUFFER_COUNT; i++) {
435 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
436 const struct gl_renderbuffer *rb = att->Renderbuffer;
437 if (rb) {
438 if (haveSize) {
439 if (rb->Width != fb->Width && rb->Height != fb->Height) {
440 /* size mismatch! */
441 fb->Width = 0;
442 fb->Height = 0;
443 return;
444 }
445 }
446 else {
447 fb->Width = rb->Width;
448 fb->Height = rb->Height;
449 haveSize = GL_TRUE;
450 }
451 }
452 }
453 }
454
455
456 /**
457 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
458 * These values are computed from the buffer's width and height and
459 * the scissor box, if it's enabled.
460 * \param ctx the GL context.
461 */
462 void
463 _mesa_update_draw_buffer_bounds(GLcontext *ctx)
464 {
465 struct gl_framebuffer *buffer = ctx->DrawBuffer;
466
467 if (!buffer)
468 return;
469
470 if (buffer->Name) {
471 /* user-created framebuffer size depends on the renderbuffers */
472 update_framebuffer_size(buffer);
473 }
474
475 buffer->_Xmin = 0;
476 buffer->_Ymin = 0;
477 buffer->_Xmax = buffer->Width;
478 buffer->_Ymax = buffer->Height;
479
480 if (ctx->Scissor.Enabled) {
481 if (ctx->Scissor.X > buffer->_Xmin) {
482 buffer->_Xmin = ctx->Scissor.X;
483 }
484 if (ctx->Scissor.Y > buffer->_Ymin) {
485 buffer->_Ymin = ctx->Scissor.Y;
486 }
487 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
488 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
489 }
490 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
491 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
492 }
493 /* finally, check for empty region */
494 if (buffer->_Xmin > buffer->_Xmax) {
495 buffer->_Xmin = buffer->_Xmax;
496 }
497 if (buffer->_Ymin > buffer->_Ymax) {
498 buffer->_Ymin = buffer->_Ymax;
499 }
500 }
501
502 ASSERT(buffer->_Xmin <= buffer->_Xmax);
503 ASSERT(buffer->_Ymin <= buffer->_Ymax);
504 }
505
506
507 /**
508 * The glGet queries of the framebuffer red/green/blue size, stencil size,
509 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can
510 * change depending on the renderbuffer bindings. This function updates
511 * the given framebuffer's Visual from the current renderbuffer bindings.
512 *
513 * This may apply to user-created framebuffers or window system framebuffers.
514 *
515 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal
516 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits.
517 * The former one is used to convert floating point depth values into
518 * integer Z values.
519 */
520 void
521 _mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
522 {
523 GLuint i;
524
525 _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
526 fb->Visual.rgbMode = GL_TRUE; /* assume this */
527
528 #if 0 /* this _might_ be needed */
529 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
530 /* leave visual fields zero'd */
531 return;
532 }
533 #endif
534
535 /* find first RGB or CI renderbuffer */
536 for (i = 0; i < BUFFER_COUNT; i++) {
537 if (fb->Attachment[i].Renderbuffer) {
538 const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
539 if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) {
540 fb->Visual.redBits = rb->RedBits;
541 fb->Visual.greenBits = rb->GreenBits;
542 fb->Visual.blueBits = rb->BlueBits;
543 fb->Visual.alphaBits = rb->AlphaBits;
544 fb->Visual.rgbBits = fb->Visual.redBits
545 + fb->Visual.greenBits + fb->Visual.blueBits;
546 fb->Visual.floatMode = GL_FALSE;
547 break;
548 }
549 else if (rb->_BaseFormat == GL_COLOR_INDEX) {
550 fb->Visual.indexBits = rb->IndexBits;
551 fb->Visual.rgbMode = GL_FALSE;
552 break;
553 }
554 }
555 }
556
557 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
558 fb->Visual.haveDepthBuffer = GL_TRUE;
559 fb->Visual.depthBits
560 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits;
561 }
562
563 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
564 fb->Visual.haveStencilBuffer = GL_TRUE;
565 fb->Visual.stencilBits
566 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits;
567 }
568
569 if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) {
570 fb->Visual.haveAccumBuffer = GL_TRUE;
571 fb->Visual.accumRedBits
572 = fb->Attachment[BUFFER_ACCUM].Renderbuffer->RedBits;
573 fb->Visual.accumGreenBits
574 = fb->Attachment[BUFFER_ACCUM].Renderbuffer->GreenBits;
575 fb->Visual.accumBlueBits
576 = fb->Attachment[BUFFER_ACCUM].Renderbuffer->BlueBits;
577 fb->Visual.accumAlphaBits
578 = fb->Attachment[BUFFER_ACCUM].Renderbuffer->AlphaBits;
579 }
580
581 compute_depth_max(fb);
582 }
583
584
585 /**
586 * Update the framebuffer's _DepthBuffer field using the renderbuffer
587 * found at the given attachment index.
588 *
589 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
590 * create and install a depth wrapper/adaptor.
591 *
592 * \param fb the framebuffer whose _DepthBuffer field to update
593 * \param attIndex indicates the renderbuffer to possibly wrap
594 */
595 void
596 _mesa_update_depth_buffer(GLcontext *ctx,
597 struct gl_framebuffer *fb,
598 GLuint attIndex)
599 {
600 struct gl_renderbuffer *depthRb;
601
602 /* only one possiblity for now */
603 ASSERT(attIndex == BUFFER_DEPTH);
604
605 depthRb = fb->Attachment[attIndex].Renderbuffer;
606
607 if (depthRb && depthRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
608 /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */
609 if (!fb->_DepthBuffer
610 || fb->_DepthBuffer->Wrapped != depthRb
611 || fb->_DepthBuffer->_BaseFormat != GL_DEPTH_COMPONENT) {
612 /* need to update wrapper */
613 struct gl_renderbuffer *wrapper
614 = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb);
615 _mesa_reference_renderbuffer(&fb->_DepthBuffer, wrapper);
616 ASSERT(fb->_DepthBuffer->Wrapped == depthRb);
617 }
618 }
619 else {
620 /* depthRb may be null */
621 _mesa_reference_renderbuffer(&fb->_DepthBuffer, depthRb);
622 }
623 }
624
625
626 /**
627 * Update the framebuffer's _StencilBuffer field using the renderbuffer
628 * found at the given attachment index.
629 *
630 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
631 * create and install a stencil wrapper/adaptor.
632 *
633 * \param fb the framebuffer whose _StencilBuffer field to update
634 * \param attIndex indicates the renderbuffer to possibly wrap
635 */
636 void
637 _mesa_update_stencil_buffer(GLcontext *ctx,
638 struct gl_framebuffer *fb,
639 GLuint attIndex)
640 {
641 struct gl_renderbuffer *stencilRb;
642
643 ASSERT(attIndex == BUFFER_DEPTH ||
644 attIndex == BUFFER_STENCIL);
645
646 stencilRb = fb->Attachment[attIndex].Renderbuffer;
647
648 if (stencilRb && stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
649 /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */
650 if (!fb->_StencilBuffer
651 || fb->_StencilBuffer->Wrapped != stencilRb
652 || fb->_StencilBuffer->_BaseFormat != GL_STENCIL_INDEX) {
653 /* need to update wrapper */
654 struct gl_renderbuffer *wrapper
655 = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb);
656 _mesa_reference_renderbuffer(&fb->_StencilBuffer, wrapper);
657 ASSERT(fb->_StencilBuffer->Wrapped == stencilRb);
658 }
659 }
660 else {
661 /* stencilRb may be null */
662 _mesa_reference_renderbuffer(&fb->_StencilBuffer, stencilRb);
663 }
664 }
665
666
667 /*
668 * Example DrawBuffers scenarios:
669 *
670 * 1. glDrawBuffer(GL_FRONT_AND_BACK), fixed-func or shader writes to
671 * "gl_FragColor" or program writes to the "result.color" register:
672 *
673 * fragment color output renderbuffer
674 * --------------------- ---------------
675 * color[0] Front, Back
676 *
677 *
678 * 2. glDrawBuffers(3, [GL_FRONT, GL_AUX0, GL_AUX1]), shader writes to
679 * gl_FragData[i] or program writes to result.color[i] registers:
680 *
681 * fragment color output renderbuffer
682 * --------------------- ---------------
683 * color[0] Front
684 * color[1] Aux0
685 * color[3] Aux1
686 *
687 *
688 * 3. glDrawBuffers(3, [GL_FRONT, GL_AUX0, GL_AUX1]) and shader writes to
689 * gl_FragColor, or fixed function:
690 *
691 * fragment color output renderbuffer
692 * --------------------- ---------------
693 * color[0] Front, Aux0, Aux1
694 *
695 *
696 * In either case, the list of renderbuffers is stored in the
697 * framebuffer->_ColorDrawBuffers[] array and
698 * framebuffer->_NumColorDrawBuffers indicates the number of buffers.
699 * The renderer (like swrast) has to look at the current fragment shader
700 * to see if it writes to gl_FragColor vs. gl_FragData[i] to determine
701 * how to map color outputs to renderbuffers.
702 *
703 * Note that these two calls are equivalent (for fixed function fragment
704 * shading anyway):
705 * a) glDrawBuffer(GL_FRONT_AND_BACK); (assuming non-stereo framebuffer)
706 * b) glDrawBuffers(2, [GL_FRONT_LEFT, GL_BACK_LEFT]);
707 */
708
709
710
711
712 /**
713 * Update the (derived) list of color drawing renderbuffer pointers.
714 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
715 * writing colors.
716 */
717 static void
718 update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb)
719 {
720 GLuint output;
721
722 /* set 0th buffer to NULL now in case _NumColorDrawBuffers is zero */
723 fb->_ColorDrawBuffers[0] = NULL;
724
725 for (output = 0; output < fb->_NumColorDrawBuffers; output++) {
726 GLint buf = fb->_ColorDrawBufferIndexes[output];
727 if (buf >= 0) {
728 fb->_ColorDrawBuffers[output] = fb->Attachment[buf].Renderbuffer;
729 }
730 else {
731 fb->_ColorDrawBuffers[output] = NULL;
732 }
733 }
734 }
735
736
737 /**
738 * Update the (derived) color read renderbuffer pointer.
739 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
740 */
741 static void
742 update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
743 {
744 (void) ctx;
745 if (fb->_ColorReadBufferIndex == -1 ||
746 fb->DeletePending ||
747 fb->Width == 0 ||
748 fb->Height == 0) {
749 fb->_ColorReadBuffer = NULL; /* legal! */
750 }
751 else {
752 ASSERT(fb->_ColorReadBufferIndex >= 0);
753 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT);
754 fb->_ColorReadBuffer
755 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
756 }
757 }
758
759
760 /**
761 * Update a gl_framebuffer's derived state.
762 *
763 * Specifically, update these framebuffer fields:
764 * _ColorDrawBuffers
765 * _NumColorDrawBuffers
766 * _ColorReadBuffer
767 * _DepthBuffer
768 * _StencilBuffer
769 *
770 * If the framebuffer is user-created, make sure it's complete.
771 *
772 * The following functions (at least) can effect framebuffer state:
773 * glReadBuffer, glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT,
774 * glRenderbufferStorageEXT.
775 */
776 static void
777 update_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb)
778 {
779 if (fb->Name == 0) {
780 /* This is a window-system framebuffer */
781 /* Need to update the FB's GL_DRAW_BUFFER state to match the
782 * context state (GL_READ_BUFFER too).
783 */
784 if (fb->ColorDrawBuffer[0] != ctx->Color.DrawBuffer[0]) {
785 _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers,
786 ctx->Color.DrawBuffer, NULL);
787 }
788 if (fb->ColorReadBuffer != ctx->Pixel.ReadBuffer) {
789
790 }
791 }
792 else {
793 /* This is a user-created framebuffer.
794 * Completeness only matters for user-created framebuffers.
795 */
796 _mesa_test_framebuffer_completeness(ctx, fb);
797 _mesa_update_framebuffer_visual(fb);
798 }
799
800 /* Strictly speaking, we don't need to update the draw-state
801 * if this FB is bound as ctx->ReadBuffer (and conversely, the
802 * read-state if this FB is bound as ctx->DrawBuffer), but no
803 * harm.
804 */
805 update_color_draw_buffers(ctx, fb);
806 update_color_read_buffer(ctx, fb);
807 _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH);
808 _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL);
809
810 compute_depth_max(fb);
811 }
812
813
814 /**
815 * Update state related to the current draw/read framebuffers.
816 */
817 void
818 _mesa_update_framebuffer(GLcontext *ctx)
819 {
820 struct gl_framebuffer *drawFb = ctx->DrawBuffer;
821 struct gl_framebuffer *readFb = ctx->ReadBuffer;
822
823 update_framebuffer(ctx, drawFb);
824 if (readFb != drawFb)
825 update_framebuffer(ctx, readFb);
826 }
827
828
829 /**
830 * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels,
831 * glCopyTex[Sub]Image, etc. exists.
832 * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA,
833 * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL.
834 * \return GL_TRUE if buffer exists, GL_FALSE otherwise
835 */
836 GLboolean
837 _mesa_source_buffer_exists(GLcontext *ctx, GLenum format)
838 {
839 const struct gl_renderbuffer_attachment *att
840 = ctx->ReadBuffer->Attachment;
841
842 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
843 return GL_FALSE;
844 }
845
846 switch (format) {
847 case GL_COLOR:
848 case GL_RED:
849 case GL_GREEN:
850 case GL_BLUE:
851 case GL_ALPHA:
852 case GL_LUMINANCE:
853 case GL_LUMINANCE_ALPHA:
854 case GL_INTENSITY:
855 case GL_RGB:
856 case GL_BGR:
857 case GL_RGBA:
858 case GL_BGRA:
859 case GL_ABGR_EXT:
860 case GL_COLOR_INDEX:
861 if (ctx->ReadBuffer->_ColorReadBuffer == NULL) {
862 return GL_FALSE;
863 }
864 /* XXX enable this post 6.5 release:
865 ASSERT(ctx->ReadBuffer->_ColorReadBuffer->RedBits > 0 ||
866 ctx->ReadBuffer->_ColorReadBuffer->IndexBits > 0);
867 */
868 break;
869 case GL_DEPTH:
870 case GL_DEPTH_COMPONENT:
871 if (!att[BUFFER_DEPTH].Renderbuffer) {
872 return GL_FALSE;
873 }
874 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
875 break;
876 case GL_STENCIL:
877 case GL_STENCIL_INDEX:
878 if (!att[BUFFER_STENCIL].Renderbuffer) {
879 return GL_FALSE;
880 }
881 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
882 break;
883 case GL_DEPTH_STENCIL_EXT:
884 if (!att[BUFFER_DEPTH].Renderbuffer ||
885 !att[BUFFER_STENCIL].Renderbuffer) {
886 return GL_FALSE;
887 }
888 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
889 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
890 break;
891 default:
892 _mesa_problem(ctx,
893 "Unexpected format 0x%x in _mesa_source_buffer_exists",
894 format);
895 return GL_FALSE;
896 }
897
898 /* OK */
899 return GL_TRUE;
900 }
901
902
903 /**
904 * As above, but for drawing operations.
905 * XXX code do some code merging w/ above function.
906 */
907 GLboolean
908 _mesa_dest_buffer_exists(GLcontext *ctx, GLenum format)
909 {
910 const struct gl_renderbuffer_attachment *att
911 = ctx->ReadBuffer->Attachment;
912
913 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
914 return GL_FALSE;
915 }
916
917 switch (format) {
918 case GL_COLOR:
919 case GL_RED:
920 case GL_GREEN:
921 case GL_BLUE:
922 case GL_ALPHA:
923 case GL_LUMINANCE:
924 case GL_LUMINANCE_ALPHA:
925 case GL_INTENSITY:
926 case GL_RGB:
927 case GL_BGR:
928 case GL_RGBA:
929 case GL_BGRA:
930 case GL_ABGR_EXT:
931 case GL_COLOR_INDEX:
932 /* nothing special */
933 /* Could assert that colorbuffer has RedBits > 0 */
934 break;
935 case GL_DEPTH:
936 case GL_DEPTH_COMPONENT:
937 if (!att[BUFFER_DEPTH].Renderbuffer) {
938 return GL_FALSE;
939 }
940 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
941 break;
942 case GL_STENCIL:
943 case GL_STENCIL_INDEX:
944 if (!att[BUFFER_STENCIL].Renderbuffer) {
945 return GL_FALSE;
946 }
947 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
948 break;
949 case GL_DEPTH_STENCIL_EXT:
950 if (!att[BUFFER_DEPTH].Renderbuffer ||
951 !att[BUFFER_STENCIL].Renderbuffer) {
952 return GL_FALSE;
953 }
954 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
955 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
956 break;
957 default:
958 _mesa_problem(ctx,
959 "Unexpected format 0x%x in _mesa_source_buffer_exists",
960 format);
961 return GL_FALSE;
962 }
963
964 /* OK */
965 return GL_TRUE;
966 }