Major check-in of changes for GL_EXT_framebuffer_object extension.
[mesa.git] / src / mesa / main / framebuffer.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.3
4 *
5 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 /**
27 * Functions for allocating/managing framebuffers and renderbuffers.
28 * Also, routines for reading/writing renderbuffer data as ubytes,
29 * ushorts, uints, etc.
30 */
31
32
33 #include "glheader.h"
34 #include "imports.h"
35 #include "context.h"
36 #include "mtypes.h"
37 #include "fbobject.h"
38 #include "framebuffer.h"
39 #include "renderbuffer.h"
40
41
42
43 /**
44 * Compute/set the _DepthMax field for the given framebuffer.
45 * This value depends on the Z buffer resolution.
46 */
47 static void
48 compute_depth_max(struct gl_framebuffer *fb)
49 {
50 if (fb->Visual.depthBits == 0) {
51 /* Special case. Even if we don't have a depth buffer we need
52 * good values for DepthMax for Z vertex transformation purposes
53 * and for per-fragment fog computation.
54 */
55 fb->_DepthMax = (1 << 16) - 1;
56 }
57 else if (fb->Visual.depthBits < 32) {
58 fb->_DepthMax = (1 << fb->Visual.depthBits) - 1;
59 }
60 else {
61 /* Special case since shift values greater than or equal to the
62 * number of bits in the left hand expression's type are undefined.
63 */
64 fb->_DepthMax = 0xffffffff;
65 }
66 fb->_DepthMaxF = (GLfloat) fb->_DepthMax;
67 fb->_MRD = 1.0; /* Minimum resolvable depth value, for polygon offset */
68 }
69
70
71 /**
72 * Create and initialize a gl_framebuffer object.
73 * This is intended for creating _window_system_ framebuffers, not generic
74 * framebuffer objects ala GL_EXT_framebuffer_object.
75 *
76 * \sa _mesa_new_framebuffer
77 */
78 struct gl_framebuffer *
79 _mesa_create_framebuffer(const GLvisual *visual)
80 {
81 struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer);
82 assert(visual);
83 if (fb) {
84 _mesa_initialize_framebuffer(fb, visual);
85 }
86 return fb;
87 }
88
89
90 /**
91 * Allocate a new gl_framebuffer object.
92 * This is the default function for ctx->Driver.NewFramebuffer().
93 * This is for allocating user-created framebuffers, not window-system
94 * framebuffers!
95 * \sa _mesa_create_framebuffer
96 */
97 struct gl_framebuffer *
98 _mesa_new_framebuffer(GLcontext *ctx, GLuint name)
99 {
100 struct gl_framebuffer *fb;
101 assert(name != 0);
102 fb = CALLOC_STRUCT(gl_framebuffer);
103 if (fb) {
104 fb->Name = name;
105 fb->RefCount = 1;
106 fb->Delete = _mesa_destroy_framebuffer;
107 fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT;
108 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_COLOR0;
109 fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT;
110 fb->_ColorReadBufferMask = BUFFER_BIT_COLOR0;
111 fb->Delete = _mesa_destroy_framebuffer;
112 }
113 return fb;
114 }
115
116
117 /**
118 * Initialize a gl_framebuffer object.
119 * \sa _mesa_create_framebuffer
120 */
121 void
122 _mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual)
123 {
124 assert(fb);
125 assert(visual);
126
127 _mesa_bzero(fb, sizeof(struct gl_framebuffer));
128
129 /* save the visual */
130 fb->Visual = *visual;
131
132 /* Init glRead/DrawBuffer state */
133 if (visual->doubleBufferMode) {
134 fb->ColorDrawBuffer[0] = GL_BACK;
135 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_BACK_LEFT;
136 fb->ColorReadBuffer = GL_BACK;
137 fb->_ColorReadBufferMask = BUFFER_BIT_BACK_LEFT;
138 }
139 else {
140 fb->ColorDrawBuffer[0] = GL_FRONT;
141 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT;
142 fb->ColorReadBuffer = GL_FRONT;
143 fb->_ColorReadBufferMask = BUFFER_BIT_FRONT_LEFT;
144 }
145
146 fb->Delete = _mesa_destroy_framebuffer;
147
148 compute_depth_max(fb);
149 }
150
151
152 /**
153 * Create/attach software-based renderbuffers to the given framebuffer.
154 * This is a helper routine for device drivers. Drivers can just as well
155 * call the individual _mesa_add_*_renderbuffer() routines directly.
156 */
157 void
158 _mesa_add_soft_renderbuffers(struct gl_framebuffer *fb,
159 GLboolean color,
160 GLboolean depth,
161 GLboolean stencil,
162 GLboolean accum,
163 GLboolean alpha,
164 GLboolean aux)
165 {
166 GLboolean frontLeft = GL_TRUE;
167 GLboolean backLeft = fb->Visual.doubleBufferMode;
168 GLboolean frontRight = fb->Visual.stereoMode;
169 GLboolean backRight = fb->Visual.stereoMode && fb->Visual.doubleBufferMode;
170
171 if (color) {
172 if (fb->Visual.rgbMode) {
173 assert(fb->Visual.redBits == fb->Visual.greenBits);
174 assert(fb->Visual.redBits == fb->Visual.blueBits);
175 _mesa_add_color_renderbuffers(NULL, fb,
176 fb->Visual.redBits,
177 fb->Visual.alphaBits,
178 frontLeft, backLeft,
179 frontRight, backRight);
180 }
181 else {
182 _mesa_add_color_index_renderbuffers(NULL, fb,
183 fb->Visual.indexBits,
184 frontLeft, backLeft,
185 frontRight, backRight);
186 }
187 }
188
189 if (depth) {
190 assert(fb->Visual.depthBits > 0);
191 _mesa_add_depth_renderbuffer(NULL, fb, fb->Visual.depthBits);
192 }
193
194 if (stencil) {
195 assert(fb->Visual.stencilBits > 0);
196 _mesa_add_stencil_renderbuffer(NULL, fb, fb->Visual.stencilBits);
197 }
198
199 if (accum) {
200 assert(fb->Visual.rgbMode);
201 assert(fb->Visual.accumRedBits > 0);
202 assert(fb->Visual.accumGreenBits > 0);
203 assert(fb->Visual.accumBlueBits > 0);
204 _mesa_add_accum_renderbuffer(NULL, fb,
205 fb->Visual.accumRedBits,
206 fb->Visual.accumGreenBits,
207 fb->Visual.accumBlueBits,
208 fb->Visual.accumAlphaBits);
209 }
210
211 if (aux) {
212 assert(fb->Visual.rgbMode);
213 assert(fb->Visual.numAuxBuffers > 0);
214 _mesa_add_aux_renderbuffers(NULL, fb, fb->Visual.redBits,
215 fb->Visual.numAuxBuffers);
216 }
217
218 #if 1
219 if (alpha) {
220 assert(fb->Visual.rgbMode);
221 assert(fb->Visual.alphaBits > 0);
222 _mesa_add_alpha_renderbuffers(NULL, fb, fb->Visual.alphaBits,
223 frontLeft, backLeft,
224 frontRight, backRight);
225 }
226 #endif
227
228 #if 0
229 if (multisample) {
230 /* maybe someday */
231 }
232 #endif
233 }
234
235
236 /**
237 * Deallocate buffer and everything attached to it.
238 */
239 void
240 _mesa_destroy_framebuffer(struct gl_framebuffer *buffer)
241 {
242 if (buffer) {
243 _mesa_free_framebuffer_data(buffer);
244 FREE(buffer);
245 }
246 }
247
248
249 /**
250 * Free all the data hanging off the given gl_framebuffer, but don't free
251 * the gl_framebuffer object itself.
252 */
253 void
254 _mesa_free_framebuffer_data(struct gl_framebuffer *fb)
255 {
256 GLuint i;
257
258 assert(fb);
259
260 for (i = 0; i < BUFFER_COUNT; i++) {
261 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
262 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
263 struct gl_renderbuffer *rb = att->Renderbuffer;
264 rb->RefCount--;
265 if (rb->RefCount == 0) {
266 rb->Delete(rb);
267 }
268 }
269 att->Type = GL_NONE;
270 att->Renderbuffer = NULL;
271 }
272 }
273
274
275 /**
276 * Resize the given framebuffer's renderbuffers to the new width and height.
277 * This should only be used for window-system framebuffers, not
278 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object).
279 * This will typically be called via ctx->Driver.ResizeBuffers()
280 */
281 void
282 _mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
283 GLuint width, GLuint height)
284 {
285 GLuint i;
286
287 /* 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) {
296 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
297 rb->Width = width;
298 rb->Height = height;
299 }
300 else {
301 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
302 }
303 }
304 }
305 }
306
307 fb->Width = width;
308 fb->Height = height;
309 }
310
311
312 /**
313 * Examine all the framebuffer's renderbuffers to update the Width/Height
314 * fields of the framebuffer. If we have renderbuffers with different
315 * sizes, set the framebuffer's width and height to zero.
316 * Note: this is only intended for user-created framebuffers, not
317 * window-system framebuffes.
318 */
319 static void
320 update_framebuffer_size(struct gl_framebuffer *fb)
321 {
322 GLboolean haveSize = GL_FALSE;
323 GLuint i;
324
325 /* user-created framebuffers only */
326 assert(fb->Name);
327
328 for (i = 0; i < BUFFER_COUNT; i++) {
329 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
330 const struct gl_renderbuffer *rb = att->Renderbuffer;
331 if (rb) {
332 if (haveSize) {
333 if (rb->Width != fb->Width && rb->Height != fb->Height) {
334 /* size mismatch! */
335 fb->Width = 0;
336 fb->Height = 0;
337 return;
338 }
339 }
340 else {
341 fb->Width = rb->Width;
342 fb->Height = rb->Height;
343 haveSize = GL_TRUE;
344 }
345 }
346 }
347 }
348
349
350 /**
351 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
352 * These values are computed from the buffer's width and height and
353 * the scissor box, if it's enabled.
354 * \param ctx the GL context.
355 */
356 void
357 _mesa_update_draw_buffer_bounds(GLcontext *ctx)
358 {
359 struct gl_framebuffer *buffer = ctx->DrawBuffer;
360
361 if (buffer->Name) {
362 /* user-created framebuffer size depends on the renderbuffers */
363 update_framebuffer_size(buffer);
364 }
365
366 buffer->_Xmin = 0;
367 buffer->_Ymin = 0;
368 buffer->_Xmax = buffer->Width;
369 buffer->_Ymax = buffer->Height;
370
371 if (ctx->Scissor.Enabled) {
372 if (ctx->Scissor.X > buffer->_Xmin) {
373 buffer->_Xmin = ctx->Scissor.X;
374 }
375 if (ctx->Scissor.Y > buffer->_Ymin) {
376 buffer->_Ymin = ctx->Scissor.Y;
377 }
378 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
379 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
380 }
381 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
382 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
383 }
384 /* finally, check for empty region */
385 if (buffer->_Xmin > buffer->_Xmax) {
386 buffer->_Xmin = buffer->_Xmax;
387 }
388 if (buffer->_Ymin > buffer->_Ymax) {
389 buffer->_Ymin = buffer->_Ymax;
390 }
391 }
392
393 ASSERT(buffer->_Xmin <= buffer->_Xmax);
394 ASSERT(buffer->_Ymin <= buffer->_Ymax);
395 }
396
397
398 /**
399 * The glGet queries of the framebuffer red/green/blue size, stencil size,
400 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can
401 * change depending on the renderbuffer bindings. This function update's
402 * the given framebuffer's Visual from the current renderbuffer bindings.
403 * This is only intended for user-created framebuffers.
404 */
405 void
406 _mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
407 {
408 assert(fb->Name != 0);
409
410 _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
411 fb->Visual.rgbMode = GL_TRUE;
412
413 if (fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer) {
414 fb->Visual.redBits
415 = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer->ComponentSizes[0];
416 fb->Visual.greenBits
417 = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer->ComponentSizes[1];
418 fb->Visual.blueBits
419 = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer->ComponentSizes[2];
420 fb->Visual.alphaBits
421 = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer->ComponentSizes[3];
422 fb->Visual.rgbBits
423 = fb->Visual.redBits + fb->Visual.greenBits + fb->Visual.blueBits;
424 fb->Visual.floatMode = GL_FALSE;
425 }
426
427 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
428 fb->Visual.haveDepthBuffer = GL_TRUE;
429 fb->Visual.depthBits
430 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->ComponentSizes[0];
431 }
432
433 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
434 fb->Visual.haveStencilBuffer = GL_TRUE;
435 fb->Visual.stencilBits
436 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->ComponentSizes[0];
437 }
438
439 compute_depth_max(fb);
440 }
441
442
443 /**
444 * Given a framebuffer and a buffer bit (like BUFFER_BIT_FRONT_LEFT), return
445 * the corresponding renderbuffer.
446 */
447 static struct gl_renderbuffer *
448 get_renderbuffer(struct gl_framebuffer *fb, GLuint bufferBit)
449 {
450 GLuint index;
451 for (index = 0; index < BUFFER_COUNT; index++) {
452 if ((1 << index) == bufferBit) {
453 return fb->Attachment[index].Renderbuffer;
454 }
455 }
456 _mesa_problem(NULL, "Bad bufferBit in get_renderbuffer");
457 return NULL;
458 }
459
460
461 /**
462 * Update state related to the current draw/read framebuffers.
463 * If the current framebuffer is user-created, make sure it's complete.
464 */
465 void
466 _mesa_update_framebuffer(GLcontext *ctx)
467 {
468 struct gl_framebuffer *fb = ctx->DrawBuffer;
469 GLuint output;
470
471 /* Completeness only matters for user-created framebuffers */
472 if (fb->Name != 0)
473 _mesa_test_framebuffer_completeness(ctx, fb);
474
475 /*
476 * Update the list of drawing renderbuffer pointers.
477 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
478 * writing colors. We have a loop because glDrawBuffer(GL_FRONT_AND_BACK)
479 * can specify writing to two or four color buffers.
480 */
481 for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) {
482 GLuint bufferMask = fb->_ColorDrawBufferMask[output];
483 GLuint count = 0;
484 GLuint bufferBit;
485 /* for each bit that's set in the bufferMask... */
486 for (bufferBit = 1; bufferMask; bufferBit <<= 1) {
487 if (bufferBit & bufferMask) {
488 struct gl_renderbuffer *rb = get_renderbuffer(fb, bufferBit);
489 if (rb) {
490 fb->_ColorDrawBuffers[output][count] = rb;
491 fb->_ColorDrawBit[output][count] = bufferBit;
492 count++;
493 }
494 else {
495 _mesa_warning(ctx, "DrawBuffer names a missing buffer!");
496 }
497 bufferMask &= ~bufferBit;
498 }
499 }
500 fb->_NumColorDrawBuffers[output] = count;
501 }
502
503 /*
504 * Update the read renderbuffer pointer.
505 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
506 */
507 if (fb->_ColorReadBufferMask == 0x0)
508 fb->_ColorReadBuffer = NULL; /* legal! */
509 else
510 fb->_ColorReadBuffer = get_renderbuffer(fb, fb->_ColorReadBufferMask);
511
512 compute_depth_max(fb);
513 }