blob: 894d99afd238c21154d2fe7372bdf04ae7d0ef5d [file] [log] [blame]
Brian Paule4b23562005-05-04 20:11:35 +00001/*
2 * Mesa 3-D graphics library
Brian Paul57223382006-04-06 04:09:03 +00003 * Version: 6.5.1
Brian Paule4b23562005-05-04 20:11:35 +00004 *
Brian Paul7275d4d2006-03-20 15:25:18 +00005 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
Brian Paule4b23562005-05-04 20:11:35 +00006 *
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"
Brian Paul84716042005-11-16 04:05:54 +000036#include "depthstencil.h"
Brian Paule4b23562005-05-04 20:11:35 +000037#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 */
48static void
49compute_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;
Brianb755a2d2007-07-11 16:19:51 -060068
69 /* Minimum resolvable depth value, for polygon offset */
José Fonseca53174af2008-05-31 18:14:09 +090070 fb->_MRD = (GLfloat)1.0 / fb->_DepthMaxF;
Brian Paule4b23562005-05-04 20:11:35 +000071}
72
73
74/**
75 * Create and initialize a gl_framebuffer object.
76 * This is intended for creating _window_system_ framebuffers, not generic
77 * framebuffer objects ala GL_EXT_framebuffer_object.
78 *
79 * \sa _mesa_new_framebuffer
80 */
81struct gl_framebuffer *
82_mesa_create_framebuffer(const GLvisual *visual)
83{
84 struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer);
85 assert(visual);
86 if (fb) {
87 _mesa_initialize_framebuffer(fb, visual);
88 }
89 return fb;
90}
91
92
93/**
94 * Allocate a new gl_framebuffer object.
95 * This is the default function for ctx->Driver.NewFramebuffer().
96 * This is for allocating user-created framebuffers, not window-system
97 * framebuffers!
98 * \sa _mesa_create_framebuffer
99 */
100struct gl_framebuffer *
101_mesa_new_framebuffer(GLcontext *ctx, GLuint name)
102{
103 struct gl_framebuffer *fb;
Brian Paul28b014e2006-04-05 03:05:17 +0000104 (void) ctx;
Brian Paule4b23562005-05-04 20:11:35 +0000105 assert(name != 0);
106 fb = CALLOC_STRUCT(gl_framebuffer);
107 if (fb) {
108 fb->Name = name;
109 fb->RefCount = 1;
Brian Paule4b23562005-05-04 20:11:35 +0000110 fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT;
111 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_COLOR0;
112 fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT;
Brian Paul048b13d2005-09-23 03:22:20 +0000113 fb->_ColorReadBufferIndex = BUFFER_COLOR0;
Brian Paule4b23562005-05-04 20:11:35 +0000114 fb->Delete = _mesa_destroy_framebuffer;
115 }
116 return fb;
117}
118
119
120/**
Brian Paulf084f602005-09-13 23:37:50 +0000121 * Initialize a gl_framebuffer object. Typically used to initialize
122 * window system-created framebuffers, not user-created framebuffers.
Brian Paule4b23562005-05-04 20:11:35 +0000123 * \sa _mesa_create_framebuffer
124 */
125void
126_mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual)
127{
128 assert(fb);
129 assert(visual);
130
131 _mesa_bzero(fb, sizeof(struct gl_framebuffer));
132
Brian Paulea4fe662006-03-26 05:22:17 +0000133 _glthread_INIT_MUTEX(fb->Mutex);
134
Briane6a93812007-02-26 11:37:37 -0700135 fb->RefCount = 1;
136
Brian Paule4b23562005-05-04 20:11:35 +0000137 /* save the visual */
138 fb->Visual = *visual;
139
140 /* Init glRead/DrawBuffer state */
141 if (visual->doubleBufferMode) {
142 fb->ColorDrawBuffer[0] = GL_BACK;
143 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_BACK_LEFT;
144 fb->ColorReadBuffer = GL_BACK;
Brian Paul048b13d2005-09-23 03:22:20 +0000145 fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT;
Brian Paule4b23562005-05-04 20:11:35 +0000146 }
147 else {
148 fb->ColorDrawBuffer[0] = GL_FRONT;
149 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT;
150 fb->ColorReadBuffer = GL_FRONT;
Brian Paul048b13d2005-09-23 03:22:20 +0000151 fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT;
Brian Paule4b23562005-05-04 20:11:35 +0000152 }
153
154 fb->Delete = _mesa_destroy_framebuffer;
Brian Pauld95000d2005-09-28 15:46:46 +0000155 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
Brian Paule4b23562005-05-04 20:11:35 +0000156
157 compute_depth_max(fb);
158}
159
160
161/**
Brian Paule4b23562005-05-04 20:11:35 +0000162 * Deallocate buffer and everything attached to it.
Brian Paulf084f602005-09-13 23:37:50 +0000163 * Typically called via the gl_framebuffer->Delete() method.
Brian Paule4b23562005-05-04 20:11:35 +0000164 */
165void
Brian Paulf084f602005-09-13 23:37:50 +0000166_mesa_destroy_framebuffer(struct gl_framebuffer *fb)
Brian Paule4b23562005-05-04 20:11:35 +0000167{
Brian Paulf084f602005-09-13 23:37:50 +0000168 if (fb) {
169 _mesa_free_framebuffer_data(fb);
Brian Paul84716042005-11-16 04:05:54 +0000170 _mesa_free(fb);
Brian Paule4b23562005-05-04 20:11:35 +0000171 }
172}
173
174
175/**
176 * Free all the data hanging off the given gl_framebuffer, but don't free
177 * the gl_framebuffer object itself.
178 */
179void
180_mesa_free_framebuffer_data(struct gl_framebuffer *fb)
181{
182 GLuint i;
183
184 assert(fb);
Brianf30e3122007-02-27 11:09:28 -0700185 assert(fb->RefCount == 0);
Brian Paule4b23562005-05-04 20:11:35 +0000186
Briane6a93812007-02-26 11:37:37 -0700187 _glthread_DESTROY_MUTEX(fb->Mutex);
188
Brian Paule4b23562005-05-04 20:11:35 +0000189 for (i = 0; i < BUFFER_COUNT; i++) {
190 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
Brian Paul753af3a2006-03-25 17:57:52 +0000191 if (att->Renderbuffer) {
Brian42aaa542007-03-25 10:39:36 -0600192 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
Brian593802c2007-03-06 09:49:15 -0700193 }
194 if (att->Texture) {
195 /* render to texture */
196 att->Texture->RefCount--;
197 if (att->Texture->RefCount == 0) {
198 GET_CURRENT_CONTEXT(ctx);
199 if (ctx) {
200 ctx->Driver.DeleteTexture(ctx, att->Texture);
201 }
Brian Paule4b23562005-05-04 20:11:35 +0000202 }
203 }
204 att->Type = GL_NONE;
Brian593802c2007-03-06 09:49:15 -0700205 att->Texture = NULL;
Brian Paule4b23562005-05-04 20:11:35 +0000206 }
Brian Paul84716042005-11-16 04:05:54 +0000207
Brian42aaa542007-03-25 10:39:36 -0600208 /* unbind _Depth/_StencilBuffer to decr ref counts */
209 _mesa_reference_renderbuffer(&fb->_DepthBuffer, NULL);
210 _mesa_reference_renderbuffer(&fb->_StencilBuffer, NULL);
Brian Paule4b23562005-05-04 20:11:35 +0000211}
212
213
214/**
Briana510bc32007-03-06 10:07:59 -0700215 * Set *ptr to point to fb, with refcounting and locking.
Brian Paul2eb88c172006-05-20 15:06:35 +0000216 */
217void
Briana510bc32007-03-06 10:07:59 -0700218_mesa_reference_framebuffer(struct gl_framebuffer **ptr,
219 struct gl_framebuffer *fb)
Brian Paul2eb88c172006-05-20 15:06:35 +0000220{
Briana510bc32007-03-06 10:07:59 -0700221 assert(ptr);
Brian1a6baf02007-03-06 16:26:02 -0700222 if (*ptr == fb) {
223 /* no change */
224 return;
225 }
226 if (*ptr) {
227 _mesa_unreference_framebuffer(ptr);
228 }
Briana510bc32007-03-06 10:07:59 -0700229 assert(!*ptr);
230 assert(fb);
231 _glthread_LOCK_MUTEX(fb->Mutex);
232 fb->RefCount++;
233 _glthread_UNLOCK_MUTEX(fb->Mutex);
234 *ptr = fb;
235}
Brian Paul2eb88c172006-05-20 15:06:35 +0000236
Briana510bc32007-03-06 10:07:59 -0700237
238/**
239 * Undo/remove a reference to a framebuffer object.
240 * Decrement the framebuffer object's reference count and delete it when
241 * the refcount hits zero.
242 * Note: we pass the address of a pointer and set it to NULL.
243 */
244void
245_mesa_unreference_framebuffer(struct gl_framebuffer **fb)
246{
247 assert(fb);
248 if (*fb) {
249 GLboolean deleteFlag = GL_FALSE;
250
251 _glthread_LOCK_MUTEX((*fb)->Mutex);
Brian Paul2eb88c172006-05-20 15:06:35 +0000252 ASSERT((*fb)->RefCount > 0);
253 (*fb)->RefCount--;
254 deleteFlag = ((*fb)->RefCount == 0);
Briana510bc32007-03-06 10:07:59 -0700255 _glthread_UNLOCK_MUTEX((*fb)->Mutex);
256
257 if (deleteFlag)
258 (*fb)->Delete(*fb);
Brian Paul2eb88c172006-05-20 15:06:35 +0000259
Brian Paul2eb88c172006-05-20 15:06:35 +0000260 *fb = NULL;
261 }
262}
263
264
265
266
267/**
Brian Paule4b23562005-05-04 20:11:35 +0000268 * Resize the given framebuffer's renderbuffers to the new width and height.
269 * This should only be used for window-system framebuffers, not
270 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object).
Brian Paul84716042005-11-16 04:05:54 +0000271 * This will typically be called via ctx->Driver.ResizeBuffers() or directly
272 * from a device driver.
273 *
274 * \note it's possible for ctx to be null since a window can be resized
275 * without a currently bound rendering context.
Brian Paule4b23562005-05-04 20:11:35 +0000276 */
277void
278_mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
279 GLuint width, GLuint height)
280{
281 GLuint i;
282
Brian Paulea4fe662006-03-26 05:22:17 +0000283 /* XXX I think we could check if the size is not changing
284 * and return early.
285 */
286
Brian Paule4b23562005-05-04 20:11:35 +0000287 /* For window system framebuffers, Name is zero */
288 assert(fb->Name == 0);
289
290 for (i = 0; i < BUFFER_COUNT; i++) {
291 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
292 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
293 struct gl_renderbuffer *rb = att->Renderbuffer;
294 /* only resize if size is changing */
295 if (rb->Width != width || rb->Height != height) {
Brian Paulea4fe662006-03-26 05:22:17 +0000296 /* could just as well pass rb->_ActualFormat here */
Brian Paule4b23562005-05-04 20:11:35 +0000297 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
Brian Paulea4fe662006-03-26 05:22:17 +0000298 ASSERT(rb->Width == width);
299 ASSERT(rb->Height == height);
Brian Paule4b23562005-05-04 20:11:35 +0000300 }
301 else {
302 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
Brian Paulea4fe662006-03-26 05:22:17 +0000303 /* no return */
Brian Paule4b23562005-05-04 20:11:35 +0000304 }
305 }
306 }
307 }
308
Brian Paulea4fe662006-03-26 05:22:17 +0000309 if (fb->_DepthBuffer) {
310 struct gl_renderbuffer *rb = fb->_DepthBuffer;
311 if (rb->Width != width || rb->Height != height) {
312 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
313 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
314 }
315 }
316 }
317
318 if (fb->_StencilBuffer) {
319 struct gl_renderbuffer *rb = fb->_StencilBuffer;
320 if (rb->Width != width || rb->Height != height) {
321 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
322 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
323 }
324 }
325 }
326
Brian Paule4b23562005-05-04 20:11:35 +0000327 fb->Width = width;
328 fb->Height = height;
Brian Paul52f686c2005-10-21 21:39:10 +0000329
Brian Paul041d6482006-10-16 17:26:30 +0000330 if (ctx) {
331 /* update scissor / window bounds */
Alan Hourihanefeb0ff12006-06-21 10:58:04 +0000332 _mesa_update_draw_buffer_bounds(ctx);
Brian Paul041d6482006-10-16 17:26:30 +0000333 /* Signal new buffer state so that swrast will update its clipping
334 * info (the CLIP_BIT flag).
335 */
336 ctx->NewState |= _NEW_BUFFERS;
337 }
Brian Paule4b23562005-05-04 20:11:35 +0000338}
339
340
341/**
342 * Examine all the framebuffer's renderbuffers to update the Width/Height
343 * fields of the framebuffer. If we have renderbuffers with different
344 * sizes, set the framebuffer's width and height to zero.
345 * Note: this is only intended for user-created framebuffers, not
346 * window-system framebuffes.
347 */
348static void
349update_framebuffer_size(struct gl_framebuffer *fb)
350{
351 GLboolean haveSize = GL_FALSE;
352 GLuint i;
353
354 /* user-created framebuffers only */
355 assert(fb->Name);
356
357 for (i = 0; i < BUFFER_COUNT; i++) {
358 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
359 const struct gl_renderbuffer *rb = att->Renderbuffer;
360 if (rb) {
361 if (haveSize) {
362 if (rb->Width != fb->Width && rb->Height != fb->Height) {
363 /* size mismatch! */
364 fb->Width = 0;
365 fb->Height = 0;
366 return;
367 }
368 }
369 else {
370 fb->Width = rb->Width;
371 fb->Height = rb->Height;
372 haveSize = GL_TRUE;
373 }
374 }
375 }
376}
377
378
379/**
380 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
381 * These values are computed from the buffer's width and height and
382 * the scissor box, if it's enabled.
383 * \param ctx the GL context.
384 */
385void
386_mesa_update_draw_buffer_bounds(GLcontext *ctx)
387{
388 struct gl_framebuffer *buffer = ctx->DrawBuffer;
389
Alan Hourihane161de102006-06-19 09:27:04 +0000390 if (!buffer)
391 return;
392
Brian Paule4b23562005-05-04 20:11:35 +0000393 if (buffer->Name) {
394 /* user-created framebuffer size depends on the renderbuffers */
395 update_framebuffer_size(buffer);
396 }
397
398 buffer->_Xmin = 0;
399 buffer->_Ymin = 0;
400 buffer->_Xmax = buffer->Width;
401 buffer->_Ymax = buffer->Height;
402
403 if (ctx->Scissor.Enabled) {
404 if (ctx->Scissor.X > buffer->_Xmin) {
405 buffer->_Xmin = ctx->Scissor.X;
406 }
407 if (ctx->Scissor.Y > buffer->_Ymin) {
408 buffer->_Ymin = ctx->Scissor.Y;
409 }
410 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
411 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
412 }
413 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
414 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
415 }
416 /* finally, check for empty region */
417 if (buffer->_Xmin > buffer->_Xmax) {
418 buffer->_Xmin = buffer->_Xmax;
419 }
420 if (buffer->_Ymin > buffer->_Ymax) {
421 buffer->_Ymin = buffer->_Ymax;
422 }
423 }
424
425 ASSERT(buffer->_Xmin <= buffer->_Xmax);
426 ASSERT(buffer->_Ymin <= buffer->_Ymax);
427}
428
429
430/**
431 * The glGet queries of the framebuffer red/green/blue size, stencil size,
432 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can
Brian Paulf084f602005-09-13 23:37:50 +0000433 * change depending on the renderbuffer bindings. This function updates
Brian Paule4b23562005-05-04 20:11:35 +0000434 * the given framebuffer's Visual from the current renderbuffer bindings.
Brian Paul02aa5fb2006-09-11 15:04:23 +0000435 *
436 * This may apply to user-created framebuffers or window system framebuffers.
Brian Pauleb063cf2005-10-04 14:48:24 +0000437 *
438 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal
439 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits.
440 * The former one is used to convert floating point depth values into
441 * integer Z values.
Brian Paule4b23562005-05-04 20:11:35 +0000442 */
443void
444_mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
445{
Brian Paul474f28e2005-10-08 14:41:17 +0000446 GLuint i;
447
Brian Paule4b23562005-05-04 20:11:35 +0000448 _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
Brian Paul474f28e2005-10-08 14:41:17 +0000449 fb->Visual.rgbMode = GL_TRUE; /* assume this */
Brian Paule4b23562005-05-04 20:11:35 +0000450
Brian Paul34b3b402006-04-20 00:45:08 +0000451#if 0 /* this _might_ be needed */
452 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
453 /* leave visual fields zero'd */
454 return;
455 }
456#endif
457
Brian Paul474f28e2005-10-08 14:41:17 +0000458 /* find first RGB or CI renderbuffer */
459 for (i = 0; i < BUFFER_COUNT; i++) {
460 if (fb->Attachment[i].Renderbuffer) {
461 const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
462 if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) {
463 fb->Visual.redBits = rb->RedBits;
464 fb->Visual.greenBits = rb->GreenBits;
465 fb->Visual.blueBits = rb->BlueBits;
466 fb->Visual.alphaBits = rb->AlphaBits;
467 fb->Visual.rgbBits = fb->Visual.redBits
468 + fb->Visual.greenBits + fb->Visual.blueBits;
469 fb->Visual.floatMode = GL_FALSE;
470 break;
471 }
472 else if (rb->_BaseFormat == GL_COLOR_INDEX) {
473 fb->Visual.indexBits = rb->IndexBits;
474 fb->Visual.rgbMode = GL_FALSE;
475 break;
476 }
477 }
Brian Paule4b23562005-05-04 20:11:35 +0000478 }
479
480 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
481 fb->Visual.haveDepthBuffer = GL_TRUE;
482 fb->Visual.depthBits
Brian Paul676d0ac2005-09-22 05:19:57 +0000483 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits;
Brian Paule4b23562005-05-04 20:11:35 +0000484 }
485
486 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
487 fb->Visual.haveStencilBuffer = GL_TRUE;
488 fb->Visual.stencilBits
Brian Paul676d0ac2005-09-22 05:19:57 +0000489 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits;
Brian Paule4b23562005-05-04 20:11:35 +0000490 }
491
Brian Paul02aa5fb2006-09-11 15:04:23 +0000492 if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) {
493 fb->Visual.haveAccumBuffer = GL_TRUE;
494 fb->Visual.accumRedBits
495 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->RedBits;
496 fb->Visual.accumGreenBits
497 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->GreenBits;
498 fb->Visual.accumBlueBits
499 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->BlueBits;
500 fb->Visual.accumAlphaBits
501 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->AlphaBits;
502 }
503
Brian Paule4b23562005-05-04 20:11:35 +0000504 compute_depth_max(fb);
505}
506
507
508/**
Brian Paulea4fe662006-03-26 05:22:17 +0000509 * Update the framebuffer's _DepthBuffer field using the renderbuffer
510 * found at the given attachment index.
511 *
512 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
513 * create and install a depth wrapper/adaptor.
514 *
515 * \param fb the framebuffer whose _DepthBuffer field to update
516 * \param attIndex indicates the renderbuffer to possibly wrap
Brian Paul84716042005-11-16 04:05:54 +0000517 */
Brian Paulea4fe662006-03-26 05:22:17 +0000518void
519_mesa_update_depth_buffer(GLcontext *ctx,
520 struct gl_framebuffer *fb,
521 GLuint attIndex)
Brian Paul84716042005-11-16 04:05:54 +0000522{
Brian Paulea4fe662006-03-26 05:22:17 +0000523 struct gl_renderbuffer *depthRb;
524
525 /* only one possiblity for now */
526 ASSERT(attIndex == BUFFER_DEPTH);
527
528 depthRb = fb->Attachment[attIndex].Renderbuffer;
529
530 if (depthRb && depthRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
531 /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */
Brian Paul57223382006-04-06 04:09:03 +0000532 if (!fb->_DepthBuffer
533 || fb->_DepthBuffer->Wrapped != depthRb
534 || fb->_DepthBuffer->_BaseFormat != GL_DEPTH_COMPONENT) {
Brian Paulea4fe662006-03-26 05:22:17 +0000535 /* need to update wrapper */
536 struct gl_renderbuffer *wrapper
537 = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb);
Brian42aaa542007-03-25 10:39:36 -0600538 _mesa_reference_renderbuffer(&fb->_DepthBuffer, wrapper);
Brian Paulea4fe662006-03-26 05:22:17 +0000539 ASSERT(fb->_DepthBuffer->Wrapped == depthRb);
Brian Paul84716042005-11-16 04:05:54 +0000540 }
541 }
Brian Paulea4fe662006-03-26 05:22:17 +0000542 else {
543 /* depthRb may be null */
Brian42aaa542007-03-25 10:39:36 -0600544 _mesa_reference_renderbuffer(&fb->_DepthBuffer, depthRb);
Brian Paulea4fe662006-03-26 05:22:17 +0000545 }
Brian Paul84716042005-11-16 04:05:54 +0000546}
547
Brian Paulea4fe662006-03-26 05:22:17 +0000548
Brian Paul84716042005-11-16 04:05:54 +0000549/**
Brian Paulea4fe662006-03-26 05:22:17 +0000550 * Update the framebuffer's _StencilBuffer field using the renderbuffer
551 * found at the given attachment index.
552 *
553 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
554 * create and install a stencil wrapper/adaptor.
555 *
556 * \param fb the framebuffer whose _StencilBuffer field to update
557 * \param attIndex indicates the renderbuffer to possibly wrap
Brian Paul84716042005-11-16 04:05:54 +0000558 */
Brian Paulea4fe662006-03-26 05:22:17 +0000559void
560_mesa_update_stencil_buffer(GLcontext *ctx,
561 struct gl_framebuffer *fb,
562 GLuint attIndex)
Brian Paul84716042005-11-16 04:05:54 +0000563{
Brian Paulea4fe662006-03-26 05:22:17 +0000564 struct gl_renderbuffer *stencilRb;
565
566 ASSERT(attIndex == BUFFER_DEPTH ||
567 attIndex == BUFFER_STENCIL);
568
569 stencilRb = fb->Attachment[attIndex].Renderbuffer;
570
571 if (stencilRb && stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
572 /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */
Brian Paul57223382006-04-06 04:09:03 +0000573 if (!fb->_StencilBuffer
574 || fb->_StencilBuffer->Wrapped != stencilRb
575 || fb->_StencilBuffer->_BaseFormat != GL_STENCIL_INDEX) {
Brian Paulea4fe662006-03-26 05:22:17 +0000576 /* need to update wrapper */
577 struct gl_renderbuffer *wrapper
578 = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb);
Brian42aaa542007-03-25 10:39:36 -0600579 _mesa_reference_renderbuffer(&fb->_StencilBuffer, wrapper);
Brian Paulea4fe662006-03-26 05:22:17 +0000580 ASSERT(fb->_StencilBuffer->Wrapped == stencilRb);
Brian Paul84716042005-11-16 04:05:54 +0000581 }
582 }
Brian Paulea4fe662006-03-26 05:22:17 +0000583 else {
584 /* stencilRb may be null */
Brian42aaa542007-03-25 10:39:36 -0600585 _mesa_reference_renderbuffer(&fb->_StencilBuffer, stencilRb);
Brian Paulea4fe662006-03-26 05:22:17 +0000586 }
587}
588
589
590/**
591 * Update the list of color drawing renderbuffer pointers.
592 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
593 * writing colors.
594 */
595static void
596update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb)
597{
598 GLuint output;
599
600 /*
601 * Fragment programs can write to multiple colorbuffers with
602 * the GL_ARB_draw_buffers extension.
603 */
604 for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) {
605 GLbitfield bufferMask = fb->_ColorDrawBufferMask[output];
606 GLuint count = 0;
607 GLuint i;
Briane6a93812007-02-26 11:37:37 -0700608 if (!fb->DeletePending) {
609 /* We need the inner loop here because glDrawBuffer(GL_FRONT_AND_BACK)
610 * can specify writing to two or four color buffers (for example).
611 */
612 for (i = 0; bufferMask && i < BUFFER_COUNT; i++) {
613 const GLuint bufferBit = 1 << i;
614 if (bufferBit & bufferMask) {
615 struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
Briane5070bc2007-03-16 11:00:07 -0600616 if (rb && rb->Width > 0 && rb->Height > 0) {
Briane6a93812007-02-26 11:37:37 -0700617 fb->_ColorDrawBuffers[output][count] = rb;
618 count++;
619 }
620 else {
621 /*
622 _mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");
623 */
624 }
625 bufferMask &= ~bufferBit;
Brian Paulea4fe662006-03-26 05:22:17 +0000626 }
Brian Paulea4fe662006-03-26 05:22:17 +0000627 }
628 }
629 fb->_NumColorDrawBuffers[output] = count;
630 }
631}
632
633
634/**
635 * Update the color read renderbuffer pointer.
636 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
637 */
638static void
639update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
640{
Brian Paul28b014e2006-04-05 03:05:17 +0000641 (void) ctx;
Briane5070bc2007-03-16 11:00:07 -0600642 if (fb->_ColorReadBufferIndex == -1 ||
643 fb->DeletePending ||
644 fb->Width == 0 ||
645 fb->Height == 0) {
Brian Paulea4fe662006-03-26 05:22:17 +0000646 fb->_ColorReadBuffer = NULL; /* legal! */
647 }
648 else {
649 ASSERT(fb->_ColorReadBufferIndex >= 0);
650 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT);
651 fb->_ColorReadBuffer
652 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
653 }
Brian Paul84716042005-11-16 04:05:54 +0000654}
655
656
Roland Scheideggerf9ac01e2007-07-19 17:58:21 +0200657static void
658update_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb)
659{
660 /* Completeness only matters for user-created framebuffers */
661 if (fb->Name != 0) {
662 /* XXX: EXT_framebuffer_blit:
663 framebuffer must still be complete wrt read/draw? */
664 _mesa_test_framebuffer_completeness(ctx, fb);
665 _mesa_update_framebuffer_visual(fb);
666 }
667
668 /* update_color_draw/read_buffers not needed for
669 read/draw only fb, but shouldn't hurt ??? */
670 update_color_draw_buffers(ctx, fb);
671 update_color_read_buffer(ctx, fb);
672 _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH);
673 _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL);
674
675 compute_depth_max(fb);
676}
677
Brian Paul84716042005-11-16 04:05:54 +0000678/**
Brian Paule4b23562005-05-04 20:11:35 +0000679 * Update state related to the current draw/read framebuffers.
Brian Paul52783592005-08-31 21:38:53 +0000680 * Specifically, update these framebuffer fields:
681 * _ColorDrawBuffers
Brian Paul52783592005-08-31 21:38:53 +0000682 * _NumColorDrawBuffers
683 * _ColorReadBuffer
Brian Paul0f29ef62005-11-16 04:17:20 +0000684 * _DepthBuffer
685 * _StencilBuffer
Brian Paule4b23562005-05-04 20:11:35 +0000686 * If the current framebuffer is user-created, make sure it's complete.
Brian Paul52783592005-08-31 21:38:53 +0000687 * The following functions can effect this state: glReadBuffer,
Brian Paul0f29ef62005-11-16 04:17:20 +0000688 * glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT,
689 * glRenderbufferStorageEXT.
Brian Paule4b23562005-05-04 20:11:35 +0000690 */
691void
692_mesa_update_framebuffer(GLcontext *ctx)
693{
694 struct gl_framebuffer *fb = ctx->DrawBuffer;
Roland Scheideggerf9ac01e2007-07-19 17:58:21 +0200695 struct gl_framebuffer *fbread = ctx->ReadBuffer;
Brian Paule4b23562005-05-04 20:11:35 +0000696
Roland Scheideggerf9ac01e2007-07-19 17:58:21 +0200697 update_framebuffer(ctx, fb);
Roland Scheideggera1bc0d02007-07-18 20:17:14 +0200698 if (fbread != fb)
Roland Scheideggerf9ac01e2007-07-19 17:58:21 +0200699 update_framebuffer(ctx, fbread);
Brian Paule4b23562005-05-04 20:11:35 +0000700}
Brian Paul7275d4d2006-03-20 15:25:18 +0000701
702
703/**
704 * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels,
705 * glCopyTex[Sub]Image, etc. exists.
706 * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA,
707 * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL.
708 * \return GL_TRUE if buffer exists, GL_FALSE otherwise
709 */
710GLboolean
711_mesa_source_buffer_exists(GLcontext *ctx, GLenum format)
712{
713 const struct gl_renderbuffer_attachment *att
714 = ctx->ReadBuffer->Attachment;
715
716 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
717 return GL_FALSE;
718 }
719
720 switch (format) {
721 case GL_COLOR:
Brian Paul590cd262006-03-24 22:53:00 +0000722 case GL_RED:
723 case GL_GREEN:
724 case GL_BLUE:
Brian Paul7275d4d2006-03-20 15:25:18 +0000725 case GL_ALPHA:
726 case GL_LUMINANCE:
727 case GL_LUMINANCE_ALPHA:
728 case GL_INTENSITY:
729 case GL_RGB:
Brian Paul590cd262006-03-24 22:53:00 +0000730 case GL_BGR:
Brian Paul7275d4d2006-03-20 15:25:18 +0000731 case GL_RGBA:
Brian Paul590cd262006-03-24 22:53:00 +0000732 case GL_BGRA:
733 case GL_ABGR_EXT:
Brian Paul7275d4d2006-03-20 15:25:18 +0000734 case GL_COLOR_INDEX:
735 if (ctx->ReadBuffer->_ColorReadBuffer == NULL) {
736 return GL_FALSE;
737 }
Brian Paul84c5d0a2006-03-30 16:29:41 +0000738 /* XXX enable this post 6.5 release:
739 ASSERT(ctx->ReadBuffer->_ColorReadBuffer->RedBits > 0 ||
740 ctx->ReadBuffer->_ColorReadBuffer->IndexBits > 0);
741 */
Brian Paul7275d4d2006-03-20 15:25:18 +0000742 break;
743 case GL_DEPTH:
744 case GL_DEPTH_COMPONENT:
745 if (!att[BUFFER_DEPTH].Renderbuffer) {
746 return GL_FALSE;
747 }
748 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
749 break;
750 case GL_STENCIL:
751 case GL_STENCIL_INDEX:
752 if (!att[BUFFER_STENCIL].Renderbuffer) {
753 return GL_FALSE;
754 }
755 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
756 break;
757 case GL_DEPTH_STENCIL_EXT:
758 if (!att[BUFFER_DEPTH].Renderbuffer ||
759 !att[BUFFER_STENCIL].Renderbuffer) {
760 return GL_FALSE;
761 }
762 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
763 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
764 break;
765 default:
766 _mesa_problem(ctx,
Brian Paul590cd262006-03-24 22:53:00 +0000767 "Unexpected format 0x%x in _mesa_source_buffer_exists",
768 format);
Brian Paul7275d4d2006-03-20 15:25:18 +0000769 return GL_FALSE;
770 }
771
772 /* OK */
773 return GL_TRUE;
774}
775
776
777/**
778 * As above, but for drawing operations.
779 * XXX code do some code merging w/ above function.
780 */
781GLboolean
782_mesa_dest_buffer_exists(GLcontext *ctx, GLenum format)
783{
784 const struct gl_renderbuffer_attachment *att
785 = ctx->ReadBuffer->Attachment;
786
787 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
788 return GL_FALSE;
789 }
790
791 switch (format) {
792 case GL_COLOR:
Brian Paul590cd262006-03-24 22:53:00 +0000793 case GL_RED:
794 case GL_GREEN:
795 case GL_BLUE:
Brian Paul7275d4d2006-03-20 15:25:18 +0000796 case GL_ALPHA:
797 case GL_LUMINANCE:
798 case GL_LUMINANCE_ALPHA:
799 case GL_INTENSITY:
800 case GL_RGB:
Brian Paul590cd262006-03-24 22:53:00 +0000801 case GL_BGR:
Brian Paul7275d4d2006-03-20 15:25:18 +0000802 case GL_RGBA:
Brian Paul590cd262006-03-24 22:53:00 +0000803 case GL_BGRA:
804 case GL_ABGR_EXT:
Brian Paul7275d4d2006-03-20 15:25:18 +0000805 case GL_COLOR_INDEX:
806 /* nothing special */
Brian Paul84c5d0a2006-03-30 16:29:41 +0000807 /* Could assert that colorbuffer has RedBits > 0 */
Brian Paul7275d4d2006-03-20 15:25:18 +0000808 break;
809 case GL_DEPTH:
810 case GL_DEPTH_COMPONENT:
811 if (!att[BUFFER_DEPTH].Renderbuffer) {
812 return GL_FALSE;
813 }
814 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
815 break;
816 case GL_STENCIL:
817 case GL_STENCIL_INDEX:
818 if (!att[BUFFER_STENCIL].Renderbuffer) {
819 return GL_FALSE;
820 }
821 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
822 break;
823 case GL_DEPTH_STENCIL_EXT:
824 if (!att[BUFFER_DEPTH].Renderbuffer ||
825 !att[BUFFER_STENCIL].Renderbuffer) {
826 return GL_FALSE;
827 }
828 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
829 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
830 break;
831 default:
832 _mesa_problem(ctx,
Brian Paul590cd262006-03-24 22:53:00 +0000833 "Unexpected format 0x%x in _mesa_source_buffer_exists",
834 format);
Brian Paul7275d4d2006-03-20 15:25:18 +0000835 return GL_FALSE;
836 }
837
838 /* OK */
839 return GL_TRUE;
840}