source: trunk/src/opengl/mesa/accum.c@ 2938

Last change on this file since 2938 was 2938, checked in by sandervl, 25 years ago

created

File size: 17.3 KB
Line 
1/* $Id: accum.c,v 1.1 2000-02-29 00:49:57 sandervl Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version: 3.1
6 *
7 * Copyright (C) 1999 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28/* $XFree86: xc/lib/GL/mesa/src/accum.c,v 1.3 1999/04/04 00:20:17 dawes Exp $ */
29
30#ifdef PC_HEADER
31#include "all.h"
32#else
33#ifndef XFree86Server
34#include <assert.h>
35#include <limits.h>
36#include <stdlib.h>
37#include <string.h>
38#else
39#include "GL/xf86glx.h"
40#endif
41#include "accum.h"
42#include "context.h"
43#include "macros.h"
44#include "masking.h"
45#include "span.h"
46#include "types.h"
47#endif
48
49
50/*
51 * Accumulation buffer notes
52 *
53 * Normally, accumulation buffer values are GLshorts with values in
54 * [-32767, 32767] which represent floating point colors in [-1, 1],
55 * as suggested by the OpenGL specification.
56 *
57 * We optimize for the common case used for full-scene antialiasing:
58 * // start with accum buffer cleared to zero
59 * glAccum(GL_LOAD, w); // or GL_ACCUM the first image
60 * glAccum(GL_ACCUM, w);
61 * ...
62 * glAccum(GL_ACCUM, w);
63 * glAccum(GL_RETURN, 1.0);
64 * That is, we start with an empty accumulation buffer and accumulate
65 * n images, each with weight w = 1/n.
66 * In this scenario, we can simply store unscaled integer values in
67 * the accum buffer instead of scaled integers. We'll also keep track
68 * of the w value so when we do GL_RETURN we simply divide the accumulated
69 * values by n (=1/w).
70 * This lets us avoid _many_ int->float->int conversions.
71 */
72
73
74#define USE_OPTIMIZED_ACCUM /* enable the optimization */
75
76
77
78void gl_alloc_accum_buffer( GLcontext *ctx )
79{
80 GLint n;
81
82 if (ctx->Buffer->Accum) {
83 FREE( ctx->Buffer->Accum );
84 ctx->Buffer->Accum = NULL;
85 }
86
87 /* allocate accumulation buffer if not already present */
88 n = ctx->Buffer->Width * ctx->Buffer->Height * 4 * sizeof(GLaccum);
89 ctx->Buffer->Accum = (GLaccum *) MALLOC( n );
90 if (!ctx->Buffer->Accum) {
91 /* unable to setup accumulation buffer */
92 gl_error( ctx, GL_OUT_OF_MEMORY, "glAccum" );
93 }
94#ifdef USE_OPTIMIZED_ACCUM
95 ctx->IntegerAccumMode = GL_TRUE;
96#else
97 ctx->IntegerAccumMode = GL_FALSE;
98#endif
99 ctx->IntegerAccumScaler = 0.0;
100}
101
102
103
104void gl_ClearAccum( GLcontext *ctx,
105 GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha )
106{
107 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glAccum");
108
109 ctx->Accum.ClearColor[0] = CLAMP( red, -1.0, 1.0 );
110 ctx->Accum.ClearColor[1] = CLAMP( green, -1.0, 1.0 );
111 ctx->Accum.ClearColor[2] = CLAMP( blue, -1.0, 1.0 );
112 ctx->Accum.ClearColor[3] = CLAMP( alpha, -1.0, 1.0 );
113}
114
115
116
117/*
118 * This is called when we fall out of optimized/unscaled accum buffer mode.
119 * That is, we convert each unscaled accum buffer value into a scaled value
120 * representing the range[-1, 1].
121 */
122static void rescale_accum( GLcontext *ctx )
123{
124 const GLuint n = ctx->Buffer->Width * ctx->Buffer->Height * 4;
125 const GLfloat fChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
126 const GLfloat s = ctx->IntegerAccumScaler * (32767.0 / fChanMax);
127 GLaccum *accum = ctx->Buffer->Accum;
128 GLuint i;
129
130 assert(ctx->IntegerAccumMode);
131 assert(accum);
132
133 for (i = 0; i < n; i++) {
134 accum[i] = (GLaccum) (accum[i] * s);
135 }
136
137 ctx->IntegerAccumMode = GL_FALSE;
138}
139
140
141
142void gl_Accum( GLcontext *ctx, GLenum op, GLfloat value )
143{
144 GLuint xpos, ypos, width, height, width4;
145 GLfloat acc_scale;
146 GLubyte rgba[MAX_WIDTH][4];
147 const GLint iChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
148 const GLfloat fChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
149
150 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glAccum");
151
152 if (ctx->Visual->AccumBits==0 || !ctx->Buffer->Accum) {
153 /* No accumulation buffer! */
154 gl_warning(ctx, "Calling glAccum() without an accumulation buffer");
155 return;
156 }
157
158 switch(sizeof(GLaccum))
159 {
160 case 1:
161 acc_scale=127.0;
162 break;
163
164 case 2:
165 acc_scale=32767.0;
166 break;
167
168 default: /* Cray*/
169 acc_scale = (float) SHRT_MAX;
170 break;
171 }
172/*
173 if (sizeof(GLaccum)==1) {
174 acc_scale = 127.0;
175 }
176 else if (sizeof(GLaccum)==2) {
177 acc_scale = 32767.0;
178 }
179 else {
180 acc_scale = (float) SHRT_MAX;
181 }
182*/
183 if (ctx->NewState)
184 gl_update_state( ctx );
185
186 /* Determine region to operate upon. */
187 if (ctx->Scissor.Enabled) {
188 xpos = ctx->Scissor.X;
189 ypos = ctx->Scissor.Y;
190 width = ctx->Scissor.Width;
191 height = ctx->Scissor.Height;
192 }
193 else {
194 /* whole window */
195 xpos = 0;
196 ypos = 0;
197 width = ctx->Buffer->Width;
198 height = ctx->Buffer->Height;
199 }
200
201 width4 = 4 * width;
202
203 switch (op) {
204 case GL_ADD:
205 {
206 const GLaccum intVal = (GLaccum) (value * acc_scale);
207 GLuint j;
208 /* Leave optimized accum buffer mode */
209 if (ctx->IntegerAccumMode)
210 rescale_accum(ctx);
211 for (j = 0; j < height; j++) {
212 GLaccum * acc = ctx->Buffer->Accum + ypos * width4 + 4 * xpos;
213 GLuint i;
214 for (i = 0; i < width4; i++) {
215 acc[i] += intVal;
216 }
217 ypos++;
218 }
219 }
220 break;
221
222 case GL_MULT:
223 {
224 GLuint j;
225 /* Leave optimized accum buffer mode */
226 if (ctx->IntegerAccumMode)
227 rescale_accum(ctx);
228 for (j = 0; j < height; j++) {
229 GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + 4 * xpos;
230 GLuint i;
231 for (i = 0; i < width4; i++) {
232 acc[i] = (GLaccum) ( (GLfloat) acc[i] * value );
233 }
234 ypos++;
235 }
236 }
237 break;
238
239 case GL_ACCUM:
240 (void) (*ctx->Driver.SetBuffer)( ctx, ctx->Pixel.DriverReadBuffer );
241
242 /* May have to leave optimized accum buffer mode */
243 if (ctx->IntegerAccumScaler == 0.0 && value > 0.0 && value <= 1.0)
244 ctx->IntegerAccumScaler = value;
245 if (ctx->IntegerAccumMode && value != ctx->IntegerAccumScaler)
246 rescale_accum(ctx);
247
248 if (ctx->IntegerAccumMode) {
249 /* simply add integer color values into accum buffer */
250 GLuint j;
251 GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos * 4;
252 assert(ctx->IntegerAccumScaler > 0.0);
253 assert(ctx->IntegerAccumScaler <= 1.0);
254 for (j = 0; j < height; j++) {
255
256 GLuint i, i4;
257 gl_read_rgba_span(ctx, width, xpos, ypos, rgba);
258 for (i = i4 = 0; i < width; i++, i4+=4) {
259 acc[i4+0] += rgba[i][RCOMP];
260 acc[i4+1] += rgba[i][GCOMP];
261 acc[i4+2] += rgba[i][BCOMP];
262 acc[i4+3] += rgba[i][ACOMP];
263 }
264 acc += width4;
265 ypos++;
266 }
267 }
268 else {
269 /* scaled integer accum buffer */
270 const GLfloat rscale = value * acc_scale / fChanMax;
271 const GLfloat gscale = value * acc_scale / fChanMax;
272 const GLfloat bscale = value * acc_scale / fChanMax;
273 const GLfloat ascale = value * acc_scale / fChanMax;
274 GLuint j;
275 for (j=0;j<height;j++) {
276 GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos * 4;
277 GLuint i;
278 gl_read_rgba_span(ctx, width, xpos, ypos, rgba);
279 for (i=0;i<width;i++) {
280 *acc += (GLaccum) ( (GLfloat) rgba[i][RCOMP] * rscale ); acc++;
281 *acc += (GLaccum) ( (GLfloat) rgba[i][GCOMP] * gscale ); acc++;
282 *acc += (GLaccum) ( (GLfloat) rgba[i][BCOMP] * bscale ); acc++;
283 *acc += (GLaccum) ( (GLfloat) rgba[i][ACOMP] * ascale ); acc++;
284 }
285 ypos++;
286 }
287 }
288 (void) (*ctx->Driver.SetBuffer)( ctx, ctx->Color.DriverDrawBuffer );
289 break;
290
291 case GL_LOAD:
292 (void) (*ctx->Driver.SetBuffer)( ctx, ctx->Pixel.DriverReadBuffer );
293
294 /* This is a change to go into optimized accum buffer mode */
295 if (value > 0.0 && value <= 1.0) {
296#ifdef USE_OPTIMIZED_ACCUM
297 ctx->IntegerAccumMode = GL_TRUE;
298#else
299 ctx->IntegerAccumMode = GL_FALSE;
300#endif
301 ctx->IntegerAccumScaler = value;
302 }
303 else {
304 ctx->IntegerAccumMode = GL_FALSE;
305 ctx->IntegerAccumScaler = 0.0;
306 }
307
308 if (ctx->IntegerAccumMode) {
309 /* just copy values into accum buffer */
310 GLuint j;
311 GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos * 4;
312 assert(ctx->IntegerAccumScaler > 0.0);
313 assert(ctx->IntegerAccumScaler <= 1.0);
314 for (j = 0; j < height; j++) {
315 GLuint i, i4;
316 gl_read_rgba_span(ctx, width, xpos, ypos, rgba);
317 for (i = i4 = 0; i < width; i++, i4 += 4) {
318 acc[i4+0] = rgba[i][RCOMP];
319 acc[i4+1] = rgba[i][GCOMP];
320 acc[i4+2] = rgba[i][BCOMP];
321 acc[i4+3] = rgba[i][ACOMP];
322 }
323 acc += width4;
324 ypos++;
325 }
326 }
327 else {
328 /* scaled integer accum buffer */
329 const GLfloat rscale = value * acc_scale / fChanMax;
330 const GLfloat gscale = value * acc_scale / fChanMax;
331 const GLfloat bscale = value * acc_scale / fChanMax;
332 const GLfloat ascale = value * acc_scale / fChanMax;
333 const GLfloat d = 3.0 / acc_scale;
334 GLuint i, j;
335 for (j = 0; j < height; j++) {
336 GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos * 4;
337 gl_read_rgba_span(ctx, width, xpos, ypos, rgba);
338 for (i=0;i<width;i++) {
339 *acc++ = (GLaccum) ((GLfloat) rgba[i][RCOMP] * rscale + d);
340 *acc++ = (GLaccum) ((GLfloat) rgba[i][GCOMP] * gscale + d);
341 *acc++ = (GLaccum) ((GLfloat) rgba[i][BCOMP] * bscale + d);
342 *acc++ = (GLaccum) ((GLfloat) rgba[i][ACOMP] * ascale + d);
343 }
344 ypos++;
345 }
346 }
347 (void) (*ctx->Driver.SetBuffer)( ctx, ctx->Color.DriverDrawBuffer );
348 break;
349
350 case GL_RETURN:
351 /* May have to leave optimized accum buffer mode */
352 if (ctx->IntegerAccumMode && value != 1.0)
353 rescale_accum(ctx);
354
355 if (ctx->IntegerAccumMode) {
356 /* build lookup table to avoid many floating point multiplies */
357 const GLfloat mult = ctx->IntegerAccumScaler;
358 static GLchan multTable[32768];
359 static GLfloat prevMult = 0.0;
360 GLuint j;
361 const GLint max = (GLint) (256 / mult);
362 if (mult != prevMult) {
363 assert(max <= 32768);
364 for (j = 0; j < max; j++)
365 multTable[j] = (GLint) ((GLfloat) j * mult + 0.5F);
366 prevMult = mult;
367 }
368
369 assert(ctx->IntegerAccumScaler > 0.0);
370 assert(ctx->IntegerAccumScaler <= 1.0);
371 for (j = 0; j < height; j++) {
372 const GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos*4;
373 GLuint i, i4;
374 for (i = i4 = 0; i < width; i++, i4 += 4) {
375 ASSERT(acc[i4+0] < max);
376 ASSERT(acc[i4+1] < max);
377 ASSERT(acc[i4+2] < max);
378 ASSERT(acc[i4+3] < max);
379 rgba[i][RCOMP] = multTable[acc[i4+0]];
380 rgba[i][GCOMP] = multTable[acc[i4+1]];
381 rgba[i][BCOMP] = multTable[acc[i4+2]];
382 rgba[i][ACOMP] = multTable[acc[i4+3]];
383 }
384 if (ctx->Color.SWmasking) {
385 gl_mask_rgba_span( ctx, width, xpos, ypos, rgba );
386 }
387 (*ctx->Driver.WriteRGBASpan)( ctx, width, xpos, ypos,
388 (const GLubyte (*)[4])rgba, NULL );
389 ypos++;
390 }
391 }
392 else {
393 const GLfloat rscale = value / acc_scale * fChanMax;
394 const GLfloat gscale = value / acc_scale * fChanMax;
395 const GLfloat bscale = value / acc_scale * fChanMax;
396 const GLfloat ascale = value / acc_scale * fChanMax;
397 GLuint i, j;
398 for (j=0;j<height;j++) {
399 const GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos*4;
400 for (i=0;i<width;i++) {
401 GLint r, g, b, a;
402 r = (GLint) ( (GLfloat) (*acc++) * rscale + 0.5F );
403 g = (GLint) ( (GLfloat) (*acc++) * gscale + 0.5F );
404 b = (GLint) ( (GLfloat) (*acc++) * bscale + 0.5F );
405 a = (GLint) ( (GLfloat) (*acc++) * ascale + 0.5F );
406 rgba[i][RCOMP] = CLAMP( r, 0, iChanMax );
407 rgba[i][GCOMP] = CLAMP( g, 0, iChanMax );
408 rgba[i][BCOMP] = CLAMP( b, 0, iChanMax );
409 rgba[i][ACOMP] = CLAMP( a, 0, iChanMax );
410 }
411 if (ctx->Color.SWmasking) {
412 gl_mask_rgba_span( ctx, width, xpos, ypos, rgba );
413 }
414 (*ctx->Driver.WriteRGBASpan)( ctx, width, xpos, ypos,
415 (const GLubyte (*)[4])rgba, NULL );
416 ypos++;
417 }
418 }
419 break;
420
421 default:
422 gl_error( ctx, GL_INVALID_ENUM, "glAccum" );
423 }
424}
425
426
427
428/*
429 * Clear the accumulation Buffer.
430 */
431void gl_clear_accum_buffer( GLcontext *ctx )
432{
433 GLuint buffersize;
434 GLfloat acc_scale;
435
436 if (ctx->Visual->AccumBits==0) {
437 /* No accumulation buffer! */
438 return;
439 }
440
441 switch(sizeof(GLaccum))
442 {
443 case 1:
444 acc_scale=127.0;
445 break;
446
447 case 2:
448 acc_scale=32767.0;
449 break;
450
451 default: /* Cray*/
452 acc_scale = (float) SHRT_MAX;
453 break;
454 }
455/*
456 if (sizeof(GLaccum)==1) {
457 acc_scale = 127.0;
458 }
459 else if (sizeof(GLaccum)==2) {
460 acc_scale = 32767.0;
461 }
462 else {
463 acc_scale = (float) SHRT_MAX;
464 }
465*/
466 /* number of pixels */
467 buffersize = ctx->Buffer->Width * ctx->Buffer->Height;
468
469 if (!ctx->Buffer->Accum) {
470 /* try to alloc accumulation buffer */
471 ctx->Buffer->Accum = (GLaccum *)
472 MALLOC( buffersize * 4 * sizeof(GLaccum) );
473 }
474
475 if (ctx->Buffer->Accum) {
476 if (ctx->Scissor.Enabled) {
477 /* Limit clear to scissor box */
478 GLaccum r, g, b, a;
479 GLint i, j;
480 GLint width, height;
481 GLaccum *row;
482 r = (GLaccum) (ctx->Accum.ClearColor[0] * acc_scale);
483 g = (GLaccum) (ctx->Accum.ClearColor[1] * acc_scale);
484 b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale);
485 a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale);
486 /* size of region to clear */
487 width = 4 * (ctx->Buffer->Xmax - ctx->Buffer->Xmin + 1);
488 height = ctx->Buffer->Ymax - ctx->Buffer->Ymin + 1;
489 /* ptr to first element to clear */
490 row = ctx->Buffer->Accum
491 + 4 * (ctx->Buffer->Ymin * ctx->Buffer->Width
492 + ctx->Buffer->Xmin);
493 for (j=0;j<height;j++) {
494 for (i=0;i<width;i+=4) {
495 row[i+0] = r;
496 row[i+1] = g;
497 row[i+2] = b;
498 row[i+3] = a;
499 }
500 row += 4 * ctx->Buffer->Width;
501 }
502 }
503 else {
504 /* clear whole buffer */
505 if (ctx->Accum.ClearColor[0]==0.0 &&
506 ctx->Accum.ClearColor[1]==0.0 &&
507 ctx->Accum.ClearColor[2]==0.0 &&
508 ctx->Accum.ClearColor[3]==0.0) {
509 /* Black */
510 MEMSET( ctx->Buffer->Accum, 0, buffersize * 4 * sizeof(GLaccum) );
511 }
512 else {
513 /* Not black */
514 GLaccum *acc, r, g, b, a;
515 GLuint i;
516
517 acc = ctx->Buffer->Accum;
518 r = (GLaccum) (ctx->Accum.ClearColor[0] * acc_scale);
519 g = (GLaccum) (ctx->Accum.ClearColor[1] * acc_scale);
520 b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale);
521 a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale);
522 for (i=0;i<buffersize;i++) {
523 *acc++ = r;
524 *acc++ = g;
525 *acc++ = b;
526 *acc++ = a;
527 }
528 }
529 }
530
531 /* update optimized accum state vars */
532 if (ctx->Accum.ClearColor[0] == 0.0 && ctx->Accum.ClearColor[1] == 0.0 &&
533 ctx->Accum.ClearColor[2] == 0.0 && ctx->Accum.ClearColor[3] == 0.0) {
534#ifdef USE_OPTIMIZED_ACCUM
535 ctx->IntegerAccumMode = GL_TRUE;
536#else
537 ctx->IntegerAccumMode = GL_FALSE;
538#endif
539 ctx->IntegerAccumScaler = 0.0; /* denotes empty accum buffer */
540 }
541 else {
542 ctx->IntegerAccumMode = GL_FALSE;
543 }
544 }
545}
Note: See TracBrowser for help on using the repository browser.