mesa: whitespace, 80-column wrapping in buffers.c
[mesa.git] / src / mesa / main / buffers.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.1
4 *
5 * Copyright (C) 1999-2007 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 * \file buffers.c
28 * glReadBuffer, DrawBuffer functions.
29 */
30
31
32
33 #include "glheader.h"
34 #include "buffers.h"
35 #include "colormac.h"
36 #include "context.h"
37 #include "enums.h"
38 #include "mtypes.h"
39
40
41 #define BAD_MASK ~0u
42
43
44 /**
45 * Return bitmask of BUFFER_BIT_* flags indicating which color buffers are
46 * available to the rendering context (for drawing or reading).
47 * This depends on the type of framebuffer. For window system framebuffers
48 * we look at the framebuffer's visual. But for user-create framebuffers we
49 * look at the number of supported color attachments.
50 * \param fb the framebuffer to draw to, or read from
51 * \return bitmask of BUFFER_BIT_* flags
52 */
53 static GLbitfield
54 supported_buffer_bitmask(const struct gl_context *ctx,
55 const struct gl_framebuffer *fb)
56 {
57 GLbitfield mask = 0x0;
58
59 if (fb->Name > 0) {
60 /* A user-created renderbuffer */
61 GLuint i;
62 ASSERT(ctx->Extensions.EXT_framebuffer_object);
63 for (i = 0; i < ctx->Const.MaxColorAttachments; i++) {
64 mask |= (BUFFER_BIT_COLOR0 << i);
65 }
66 }
67 else {
68 /* A window system framebuffer */
69 GLint i;
70 mask = BUFFER_BIT_FRONT_LEFT; /* always have this */
71 if (fb->Visual.stereoMode) {
72 mask |= BUFFER_BIT_FRONT_RIGHT;
73 if (fb->Visual.doubleBufferMode) {
74 mask |= BUFFER_BIT_BACK_LEFT | BUFFER_BIT_BACK_RIGHT;
75 }
76 }
77 else if (fb->Visual.doubleBufferMode) {
78 mask |= BUFFER_BIT_BACK_LEFT;
79 }
80
81 for (i = 0; i < fb->Visual.numAuxBuffers; i++) {
82 mask |= (BUFFER_BIT_AUX0 << i);
83 }
84 }
85
86 return mask;
87 }
88
89
90 /**
91 * Helper routine used by glDrawBuffer and glDrawBuffersARB.
92 * Given a GLenum naming one or more color buffers (such as
93 * GL_FRONT_AND_BACK), return the corresponding bitmask of BUFFER_BIT_* flags.
94 */
95 static GLbitfield
96 draw_buffer_enum_to_bitmask(GLenum buffer)
97 {
98 switch (buffer) {
99 case GL_NONE:
100 return 0;
101 case GL_FRONT:
102 return BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_FRONT_RIGHT;
103 case GL_BACK:
104 return BUFFER_BIT_BACK_LEFT | BUFFER_BIT_BACK_RIGHT;
105 case GL_RIGHT:
106 return BUFFER_BIT_FRONT_RIGHT | BUFFER_BIT_BACK_RIGHT;
107 case GL_FRONT_RIGHT:
108 return BUFFER_BIT_FRONT_RIGHT;
109 case GL_BACK_RIGHT:
110 return BUFFER_BIT_BACK_RIGHT;
111 case GL_BACK_LEFT:
112 return BUFFER_BIT_BACK_LEFT;
113 case GL_FRONT_AND_BACK:
114 return BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT
115 | BUFFER_BIT_FRONT_RIGHT | BUFFER_BIT_BACK_RIGHT;
116 case GL_LEFT:
117 return BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT;
118 case GL_FRONT_LEFT:
119 return BUFFER_BIT_FRONT_LEFT;
120 case GL_AUX0:
121 return BUFFER_BIT_AUX0;
122 case GL_AUX1:
123 case GL_AUX2:
124 case GL_AUX3:
125 return 1 << BUFFER_COUNT; /* invalid, but not BAD_MASK */
126 case GL_COLOR_ATTACHMENT0_EXT:
127 return BUFFER_BIT_COLOR0;
128 case GL_COLOR_ATTACHMENT1_EXT:
129 return BUFFER_BIT_COLOR1;
130 case GL_COLOR_ATTACHMENT2_EXT:
131 return BUFFER_BIT_COLOR2;
132 case GL_COLOR_ATTACHMENT3_EXT:
133 return BUFFER_BIT_COLOR3;
134 case GL_COLOR_ATTACHMENT4_EXT:
135 return BUFFER_BIT_COLOR4;
136 case GL_COLOR_ATTACHMENT5_EXT:
137 return BUFFER_BIT_COLOR5;
138 case GL_COLOR_ATTACHMENT6_EXT:
139 return BUFFER_BIT_COLOR6;
140 case GL_COLOR_ATTACHMENT7_EXT:
141 return BUFFER_BIT_COLOR7;
142 default:
143 /* error */
144 return BAD_MASK;
145 }
146 }
147
148
149 /**
150 * Helper routine used by glReadBuffer.
151 * Given a GLenum naming a color buffer, return the index of the corresponding
152 * renderbuffer (a BUFFER_* value).
153 * return -1 for an invalid buffer.
154 */
155 static GLint
156 read_buffer_enum_to_index(GLenum buffer)
157 {
158 switch (buffer) {
159 case GL_FRONT:
160 return BUFFER_FRONT_LEFT;
161 case GL_BACK:
162 return BUFFER_BACK_LEFT;
163 case GL_RIGHT:
164 return BUFFER_FRONT_RIGHT;
165 case GL_FRONT_RIGHT:
166 return BUFFER_FRONT_RIGHT;
167 case GL_BACK_RIGHT:
168 return BUFFER_BACK_RIGHT;
169 case GL_BACK_LEFT:
170 return BUFFER_BACK_LEFT;
171 case GL_LEFT:
172 return BUFFER_FRONT_LEFT;
173 case GL_FRONT_LEFT:
174 return BUFFER_FRONT_LEFT;
175 case GL_AUX0:
176 return BUFFER_AUX0;
177 case GL_AUX1:
178 case GL_AUX2:
179 case GL_AUX3:
180 return BUFFER_COUNT; /* invalid, but not -1 */
181 case GL_COLOR_ATTACHMENT0_EXT:
182 return BUFFER_COLOR0;
183 case GL_COLOR_ATTACHMENT1_EXT:
184 return BUFFER_COLOR1;
185 case GL_COLOR_ATTACHMENT2_EXT:
186 return BUFFER_COLOR2;
187 case GL_COLOR_ATTACHMENT3_EXT:
188 return BUFFER_COLOR3;
189 case GL_COLOR_ATTACHMENT4_EXT:
190 return BUFFER_COLOR4;
191 case GL_COLOR_ATTACHMENT5_EXT:
192 return BUFFER_COLOR5;
193 case GL_COLOR_ATTACHMENT6_EXT:
194 return BUFFER_COLOR6;
195 case GL_COLOR_ATTACHMENT7_EXT:
196 return BUFFER_COLOR7;
197 default:
198 /* error */
199 return -1;
200 }
201 }
202
203
204 /**
205 * Called by glDrawBuffer().
206 * Specify which renderbuffer(s) to draw into for the first color output.
207 * <buffer> can name zero, one, two or four renderbuffers!
208 * \sa _mesa_DrawBuffersARB
209 *
210 * \param buffer buffer token such as GL_LEFT or GL_FRONT_AND_BACK, etc.
211 *
212 * Note that the behaviour of this function depends on whether the
213 * current ctx->DrawBuffer is a window-system framebuffer (Name=0) or
214 * a user-created framebuffer object (Name!=0).
215 * In the former case, we update the per-context ctx->Color.DrawBuffer
216 * state var _and_ the FB's ColorDrawBuffer state.
217 * In the later case, we update the FB's ColorDrawBuffer state only.
218 *
219 * Furthermore, upon a MakeCurrent() or BindFramebuffer() call, if the
220 * new FB is a window system FB, we need to re-update the FB's
221 * ColorDrawBuffer state to match the context. This is handled in
222 * _mesa_update_framebuffer().
223 *
224 * See the GL_EXT_framebuffer_object spec for more info.
225 */
226 void GLAPIENTRY
227 _mesa_DrawBuffer(GLenum buffer)
228 {
229 GLbitfield destMask;
230 GET_CURRENT_CONTEXT(ctx);
231 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex... */
232
233 if (MESA_VERBOSE & VERBOSE_API) {
234 _mesa_debug(ctx, "glDrawBuffer %s\n", _mesa_lookup_enum_by_nr(buffer));
235 }
236
237 if (buffer == GL_NONE) {
238 destMask = 0x0;
239 }
240 else {
241 const GLbitfield supportedMask
242 = supported_buffer_bitmask(ctx, ctx->DrawBuffer);
243 destMask = draw_buffer_enum_to_bitmask(buffer);
244 if (destMask == BAD_MASK) {
245 /* totally bogus buffer */
246 _mesa_error(ctx, GL_INVALID_ENUM,
247 "glDrawBuffer(buffer=0x%x)", buffer);
248 return;
249 }
250 destMask &= supportedMask;
251 if (destMask == 0x0) {
252 /* none of the named color buffers exist! */
253 _mesa_error(ctx, GL_INVALID_OPERATION,
254 "glDrawBuffer(buffer=0x%x)", buffer);
255 return;
256 }
257 }
258
259 /* if we get here, there's no error so set new state */
260 _mesa_drawbuffers(ctx, 1, &buffer, &destMask);
261
262 /*
263 * Call device driver function.
264 */
265 if (ctx->Driver.DrawBuffers)
266 ctx->Driver.DrawBuffers(ctx, 1, &buffer);
267 else if (ctx->Driver.DrawBuffer)
268 ctx->Driver.DrawBuffer(ctx, buffer);
269 }
270
271
272 /**
273 * Called by glDrawBuffersARB; specifies the destination color renderbuffers
274 * for N fragment program color outputs.
275 * \sa _mesa_DrawBuffer
276 * \param n number of outputs
277 * \param buffers array [n] of renderbuffer names. Unlike glDrawBuffer, the
278 * names cannot specify more than one buffer. For example,
279 * GL_FRONT_AND_BACK is illegal.
280 */
281 void GLAPIENTRY
282 _mesa_DrawBuffersARB(GLsizei n, const GLenum *buffers)
283 {
284 GLint output;
285 GLbitfield usedBufferMask, supportedMask;
286 GLbitfield destMask[MAX_DRAW_BUFFERS];
287 GET_CURRENT_CONTEXT(ctx);
288 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
289
290 /* Turns out n==0 is a valid input that should not produce an error.
291 * The remaining code below correctly handles the n==0 case.
292 */
293 if (n < 0 || n > (GLsizei) ctx->Const.MaxDrawBuffers) {
294 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawBuffersARB(n)");
295 return;
296 }
297
298 supportedMask = supported_buffer_bitmask(ctx, ctx->DrawBuffer);
299 usedBufferMask = 0x0;
300
301 /* complicated error checking... */
302 for (output = 0; output < n; output++) {
303 if (buffers[output] == GL_NONE) {
304 destMask[output] = 0x0;
305 }
306 else {
307 destMask[output] = draw_buffer_enum_to_bitmask(buffers[output]);
308 if (destMask[output] == BAD_MASK
309 || _mesa_bitcount(destMask[output]) > 1) {
310 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawBuffersARB(buffer)");
311 return;
312 }
313 destMask[output] &= supportedMask;
314 if (destMask[output] == 0) {
315 _mesa_error(ctx, GL_INVALID_OPERATION,
316 "glDrawBuffersARB(unsupported buffer)");
317 return;
318 }
319 if (destMask[output] & usedBufferMask) {
320 /* can't specify a dest buffer more than once! */
321 _mesa_error(ctx, GL_INVALID_OPERATION,
322 "glDrawBuffersARB(duplicated buffer)");
323 return;
324 }
325
326 /* update bitmask */
327 usedBufferMask |= destMask[output];
328 }
329 }
330
331 /* OK, if we get here, there were no errors so set the new state */
332 _mesa_drawbuffers(ctx, n, buffers, destMask);
333
334 /*
335 * Call device driver function. Note that n can be equal to 0,
336 * in which case we don't want to reference buffers[0], which
337 * may not be valid.
338 */
339 if (ctx->Driver.DrawBuffers)
340 ctx->Driver.DrawBuffers(ctx, n, buffers);
341 else if (ctx->Driver.DrawBuffer)
342 ctx->Driver.DrawBuffer(ctx, n > 0 ? buffers[0] : GL_NONE);
343 }
344
345
346 /**
347 * Performs necessary state updates when _mesa_drawbuffers makes an
348 * actual change.
349 */
350 static void
351 updated_drawbuffers(struct gl_context *ctx)
352 {
353 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
354
355 #if FEATURE_GL
356 if (ctx->API == API_OPENGL && !ctx->Extensions.ARB_ES2_compatibility) {
357 struct gl_framebuffer *fb = ctx->DrawBuffer;
358
359 /* Flag the FBO as requiring validation. */
360 if (fb->Name != 0) {
361 fb->_Status = 0;
362 }
363 }
364 #endif
365 }
366
367
368 /**
369 * Helper function to set the GL_DRAW_BUFFER state in the context and
370 * current FBO. Called via glDrawBuffer(), glDrawBuffersARB()
371 *
372 * All error checking will have been done prior to calling this function
373 * so nothing should go wrong at this point.
374 *
375 * \param ctx current context
376 * \param n number of color outputs to set
377 * \param buffers array[n] of colorbuffer names, like GL_LEFT.
378 * \param destMask array[n] of BUFFER_BIT_* bitmasks which correspond to the
379 * colorbuffer names. (i.e. GL_FRONT_AND_BACK =>
380 * BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT).
381 */
382 void
383 _mesa_drawbuffers(struct gl_context *ctx, GLuint n, const GLenum *buffers,
384 const GLbitfield *destMask)
385 {
386 struct gl_framebuffer *fb = ctx->DrawBuffer;
387 GLbitfield mask[MAX_DRAW_BUFFERS];
388 GLuint buf;
389
390 if (!destMask) {
391 /* compute destMask values now */
392 const GLbitfield supportedMask = supported_buffer_bitmask(ctx, fb);
393 GLuint output;
394 for (output = 0; output < n; output++) {
395 mask[output] = draw_buffer_enum_to_bitmask(buffers[output]);
396 ASSERT(mask[output] != BAD_MASK);
397 mask[output] &= supportedMask;
398 }
399 destMask = mask;
400 }
401
402 /*
403 * If n==1, destMask[0] may have up to four bits set.
404 * Otherwise, destMask[x] can only have one bit set.
405 */
406 if (n == 1) {
407 GLuint count = 0, destMask0 = destMask[0];
408 while (destMask0) {
409 GLint bufIndex = ffs(destMask0) - 1;
410 if (fb->_ColorDrawBufferIndexes[count] != bufIndex) {
411 updated_drawbuffers(ctx);
412 fb->_ColorDrawBufferIndexes[count] = bufIndex;
413 }
414 count++;
415 destMask0 &= ~(1 << bufIndex);
416 }
417 fb->ColorDrawBuffer[0] = buffers[0];
418 fb->_NumColorDrawBuffers = count;
419 }
420 else {
421 GLuint count = 0;
422 for (buf = 0; buf < n; buf++ ) {
423 if (destMask[buf]) {
424 GLint bufIndex = ffs(destMask[buf]) - 1;
425 /* only one bit should be set in the destMask[buf] field */
426 ASSERT(_mesa_bitcount(destMask[buf]) == 1);
427 if (fb->_ColorDrawBufferIndexes[buf] != bufIndex) {
428 updated_drawbuffers(ctx);
429 fb->_ColorDrawBufferIndexes[buf] = bufIndex;
430 }
431 count = buf + 1;
432 }
433 else {
434 if (fb->_ColorDrawBufferIndexes[buf] != -1) {
435 updated_drawbuffers(ctx);
436 fb->_ColorDrawBufferIndexes[buf] = -1;
437 }
438 }
439 fb->ColorDrawBuffer[buf] = buffers[buf];
440 }
441 fb->_NumColorDrawBuffers = count;
442 }
443
444 /* set remaining outputs to -1 (GL_NONE) */
445 for (buf = fb->_NumColorDrawBuffers; buf < ctx->Const.MaxDrawBuffers; buf++) {
446 if (fb->_ColorDrawBufferIndexes[buf] != -1) {
447 updated_drawbuffers(ctx);
448 fb->_ColorDrawBufferIndexes[buf] = -1;
449 }
450 }
451 for (buf = n; buf < ctx->Const.MaxDrawBuffers; buf++) {
452 fb->ColorDrawBuffer[buf] = GL_NONE;
453 }
454
455 if (fb->Name == 0) {
456 /* also set context drawbuffer state */
457 for (buf = 0; buf < ctx->Const.MaxDrawBuffers; buf++) {
458 if (ctx->Color.DrawBuffer[buf] != fb->ColorDrawBuffer[buf]) {
459 updated_drawbuffers(ctx);
460 ctx->Color.DrawBuffer[buf] = fb->ColorDrawBuffer[buf];
461 }
462 }
463 }
464 }
465
466
467 /**
468 * Update the current drawbuffer's _ColorDrawBufferIndex[] list, etc.
469 * from the context's Color.DrawBuffer[] state.
470 * Use when changing contexts.
471 */
472 void
473 _mesa_update_draw_buffers(struct gl_context *ctx)
474 {
475 GLenum buffers[MAX_DRAW_BUFFERS];
476 GLuint i;
477
478 /* should be a window system FBO */
479 assert(ctx->DrawBuffer->Name == 0);
480
481 for (i = 0; i < ctx->Const.MaxDrawBuffers; i++)
482 buffers[i] = ctx->Color.DrawBuffer[i];
483
484 _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers, buffers, NULL);
485 }
486
487
488 /**
489 * Like \sa _mesa_drawbuffers(), this is a helper function for setting
490 * GL_READ_BUFFER state in the context and current FBO.
491 * \param ctx the rendering context
492 * \param buffer GL_FRONT, GL_BACK, GL_COLOR_ATTACHMENT0, etc.
493 * \param bufferIndex the numerical index corresponding to 'buffer'
494 */
495 void
496 _mesa_readbuffer(struct gl_context *ctx, GLenum buffer, GLint bufferIndex)
497 {
498 struct gl_framebuffer *fb = ctx->ReadBuffer;
499
500 if (fb->Name == 0) {
501 /* Only update the per-context READ_BUFFER state if we're bound to
502 * a window-system framebuffer.
503 */
504 ctx->Pixel.ReadBuffer = buffer;
505 }
506
507 fb->ColorReadBuffer = buffer;
508 fb->_ColorReadBufferIndex = bufferIndex;
509
510 ctx->NewState |= _NEW_BUFFERS;
511 }
512
513
514
515 /**
516 * Called by glReadBuffer to set the source renderbuffer for reading pixels.
517 * \param mode color buffer such as GL_FRONT, GL_BACK, etc.
518 */
519 void GLAPIENTRY
520 _mesa_ReadBuffer(GLenum buffer)
521 {
522 struct gl_framebuffer *fb;
523 GLbitfield supportedMask;
524 GLint srcBuffer;
525 GET_CURRENT_CONTEXT(ctx);
526 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
527
528 if (MESA_VERBOSE & VERBOSE_API)
529 _mesa_debug(ctx, "glReadBuffer %s\n", _mesa_lookup_enum_by_nr(buffer));
530
531 fb = ctx->ReadBuffer;
532
533 if (MESA_VERBOSE & VERBOSE_API)
534 _mesa_debug(ctx, "glReadBuffer %s\n", _mesa_lookup_enum_by_nr(buffer));
535
536 if (fb->Name > 0 && buffer == GL_NONE) {
537 /* This is legal for user-created framebuffer objects */
538 srcBuffer = -1;
539 }
540 else {
541 /* general case / window-system framebuffer */
542 srcBuffer = read_buffer_enum_to_index(buffer);
543 if (srcBuffer == -1) {
544 _mesa_error(ctx, GL_INVALID_ENUM,
545 "glReadBuffer(buffer=0x%x)", buffer);
546 return;
547 }
548 supportedMask = supported_buffer_bitmask(ctx, fb);
549 if (((1 << srcBuffer) & supportedMask) == 0) {
550 _mesa_error(ctx, GL_INVALID_OPERATION,
551 "glReadBuffer(buffer=0x%x)", buffer);
552 return;
553 }
554 }
555
556 /* OK, all error checking has been completed now */
557
558 _mesa_readbuffer(ctx, buffer, srcBuffer);
559 ctx->NewState |= _NEW_BUFFERS;
560
561 /*
562 * Call device driver function.
563 */
564 if (ctx->Driver.ReadBuffer)
565 (*ctx->Driver.ReadBuffer)(ctx, buffer);
566 }