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