OSDN Git Service

mesa/swrast: Respect mfeatures.h.
[android-x86/external-mesa.git] / src / mesa / swrast / s_accum.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  6.5.2
4  *
5  * Copyright (C) 1999-2006  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 #include "main/glheader.h"
27 #include "main/context.h"
28 #include "main/macros.h"
29 #include "main/imports.h"
30 #include "main/fbobject.h"
31
32 #include "s_accum.h"
33 #include "s_context.h"
34 #include "s_masking.h"
35 #include "s_span.h"
36
37
38 /* XXX this would have to change for accum buffers with more or less
39  * than 16 bits per color channel.
40  */
41 #define ACCUM_SCALE16 32767.0
42
43
44 /*
45  * Accumulation buffer notes
46  *
47  * Normally, accumulation buffer values are GLshorts with values in
48  * [-32767, 32767] which represent floating point colors in [-1, 1],
49  * as defined by the OpenGL specification.
50  *
51  * We optimize for the common case used for full-scene antialiasing:
52  *    // start with accum buffer cleared to zero
53  *    glAccum(GL_LOAD, w);   // or GL_ACCUM the first image
54  *    glAccum(GL_ACCUM, w);
55  *    ...
56  *    glAccum(GL_ACCUM, w);
57  *    glAccum(GL_RETURN, 1.0);
58  * That is, we start with an empty accumulation buffer and accumulate
59  * n images, each with weight w = 1/n.
60  * In this scenario, we can simply store unscaled integer values in
61  * the accum buffer instead of scaled integers.  We'll also keep track
62  * of the w value so when we do GL_RETURN we simply divide the accumulated
63  * values by n (n=1/w).
64  * This lets us avoid _many_ int->float->int conversions.
65  */
66
67
68 #if CHAN_BITS == 8
69 /* enable the optimization */
70 #define USE_OPTIMIZED_ACCUM  1
71 #else
72 #define USE_OPTIMIZED_ACCUM  0
73 #endif
74
75
76 #if FEATURE_accum
77
78
79 /**
80  * This is called when we fall out of optimized/unscaled accum buffer mode.
81  * That is, we convert each unscaled accum buffer value into a scaled value
82  * representing the range[-1, 1].
83  */
84 static void
85 rescale_accum( GLcontext *ctx )
86 {
87    SWcontext *swrast = SWRAST_CONTEXT(ctx);
88    struct gl_renderbuffer *rb
89       = ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer;
90    const GLfloat s = swrast->_IntegerAccumScaler * (32767.0F / CHAN_MAXF);
91
92    assert(rb);
93    assert(rb->_BaseFormat == GL_RGBA);
94    /* add other types in future? */
95    assert(rb->DataType == GL_SHORT || rb->DataType == GL_UNSIGNED_SHORT);
96    assert(swrast->_IntegerAccumMode);
97
98    if (rb->GetPointer(ctx, rb, 0, 0)) {
99       /* directly-addressable memory */
100       GLuint y;
101       for (y = 0; y < rb->Height; y++) {
102          GLuint i;
103          GLshort *acc = (GLshort *) rb->GetPointer(ctx, rb, 0, y);
104          for (i = 0; i < 4 * rb->Width; i++) {
105             acc[i] = (GLshort) (acc[i] * s);
106          }
107       }
108    }
109    else {
110       /* use get/put row funcs */
111       GLuint y;
112       for (y = 0; y < rb->Height; y++) {
113          GLshort accRow[MAX_WIDTH * 4];
114          GLuint i;
115          rb->GetRow(ctx, rb, rb->Width, 0, y, accRow);
116          for (i = 0; i < 4 * rb->Width; i++) {
117             accRow[i] = (GLshort) (accRow[i] * s);
118          }
119          rb->PutRow(ctx, rb, rb->Width, 0, y, accRow, NULL);
120       }
121    }
122
123    swrast->_IntegerAccumMode = GL_FALSE;
124 }
125
126
127
128 /**
129  * Clear the accumulation Buffer.
130  */
131 void
132 _swrast_clear_accum_buffer( GLcontext *ctx, struct gl_renderbuffer *rb )
133 {
134    SWcontext *swrast = SWRAST_CONTEXT(ctx);
135    GLuint x, y, width, height;
136
137    if (ctx->Visual.accumRedBits == 0) {
138       /* No accumulation buffer! Not an error. */
139       return;
140    }
141
142    if (!rb || !rb->Data)
143       return;
144
145    assert(rb->_BaseFormat == GL_RGBA);
146    /* add other types in future? */
147    assert(rb->DataType == GL_SHORT || rb->DataType == GL_UNSIGNED_SHORT);
148
149    /* bounds, with scissor */
150    x = ctx->DrawBuffer->_Xmin;
151    y = ctx->DrawBuffer->_Ymin;
152    width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
153    height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
154
155    if (rb->DataType == GL_SHORT || rb->DataType == GL_UNSIGNED_SHORT) {
156       const GLfloat accScale = 32767.0;
157       GLshort clearVal[4];
158       GLuint i;
159
160       clearVal[0] = (GLshort) (ctx->Accum.ClearColor[0] * accScale);
161       clearVal[1] = (GLshort) (ctx->Accum.ClearColor[1] * accScale);
162       clearVal[2] = (GLshort) (ctx->Accum.ClearColor[2] * accScale);
163       clearVal[3] = (GLshort) (ctx->Accum.ClearColor[3] * accScale);
164
165       for (i = 0; i < height; i++) {
166          rb->PutMonoRow(ctx, rb, width, x, y + i, clearVal, NULL);
167       }
168    }
169    else {
170       /* someday support other sizes */
171    }
172
173    /* update optimized accum state vars */
174    if (ctx->Accum.ClearColor[0] == 0.0 && ctx->Accum.ClearColor[1] == 0.0 &&
175        ctx->Accum.ClearColor[2] == 0.0 && ctx->Accum.ClearColor[3] == 0.0) {
176 #if USE_OPTIMIZED_ACCUM
177       swrast->_IntegerAccumMode = GL_TRUE;
178 #else
179       swrast->_IntegerAccumMode = GL_FALSE;
180 #endif
181       swrast->_IntegerAccumScaler = 0.0;  /* denotes empty accum buffer */
182    }
183    else {
184       swrast->_IntegerAccumMode = GL_FALSE;
185    }
186 }
187
188
189 static void
190 accum_add(GLcontext *ctx, GLfloat value,
191           GLint xpos, GLint ypos, GLint width, GLint height )
192 {
193    SWcontext *swrast = SWRAST_CONTEXT(ctx);
194    struct gl_renderbuffer *rb
195       = ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer;
196
197    assert(rb);
198
199    /* Leave optimized accum buffer mode */
200    if (swrast->_IntegerAccumMode)
201       rescale_accum(ctx);
202
203    if (rb->DataType == GL_SHORT || rb->DataType == GL_UNSIGNED_SHORT) {
204       const GLshort incr = (GLshort) (value * ACCUM_SCALE16);
205       if (rb->GetPointer(ctx, rb, 0, 0)) {
206          GLint i, j;
207          for (i = 0; i < height; i++) {
208             GLshort *acc = (GLshort *) rb->GetPointer(ctx, rb, xpos, ypos + i);
209             for (j = 0; j < 4 * width; j++) {
210                acc[j] += incr;
211             }
212          }
213       }
214       else {
215          GLint i, j;
216          for (i = 0; i < height; i++) {
217             GLshort accRow[4 * MAX_WIDTH];
218             rb->GetRow(ctx, rb, width, xpos, ypos + i, accRow);
219             for (j = 0; j < 4 * width; j++) {
220                accRow[j] += incr;
221             }
222             rb->PutRow(ctx, rb, width, xpos, ypos + i, accRow, NULL);
223          }
224       }
225    }
226    else {
227       /* other types someday */
228    }
229 }
230
231
232 static void
233 accum_mult(GLcontext *ctx, GLfloat mult,
234            GLint xpos, GLint ypos, GLint width, GLint height )
235 {
236    SWcontext *swrast = SWRAST_CONTEXT(ctx);
237    struct gl_renderbuffer *rb
238       = ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer;
239
240    assert(rb);
241
242    /* Leave optimized accum buffer mode */
243    if (swrast->_IntegerAccumMode)
244       rescale_accum(ctx);
245
246    if (rb->DataType == GL_SHORT || rb->DataType == GL_UNSIGNED_SHORT) {
247       if (rb->GetPointer(ctx, rb, 0, 0)) {
248          GLint i, j;
249          for (i = 0; i < height; i++) {
250             GLshort *acc = (GLshort *) rb->GetPointer(ctx, rb, xpos, ypos + i);
251             for (j = 0; j < 4 * width; j++) {
252                acc[j] = (GLshort) (acc[j] * mult);
253             }
254          }
255       }
256       else {
257          GLint i, j;
258          for (i = 0; i < height; i++) {
259             GLshort accRow[4 * MAX_WIDTH];
260             rb->GetRow(ctx, rb, width, xpos, ypos + i, accRow);
261             for (j = 0; j < 4 * width; j++) {
262                accRow[j] = (GLshort) (accRow[j] * mult);
263             }
264             rb->PutRow(ctx, rb, width, xpos, ypos + i, accRow, NULL);
265          }
266       }
267    }
268    else {
269       /* other types someday */
270    }
271 }
272
273
274
275 static void
276 accum_accum(GLcontext *ctx, GLfloat value,
277             GLint xpos, GLint ypos, GLint width, GLint height )
278 {
279    SWcontext *swrast = SWRAST_CONTEXT(ctx);
280    struct gl_renderbuffer *rb
281       = ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer;
282    const GLboolean directAccess = (rb->GetPointer(ctx, rb, 0, 0) != NULL);
283
284    assert(rb);
285
286    if (!ctx->ReadBuffer->_ColorReadBuffer) {
287       /* no read buffer - OK */
288       return;
289    }
290
291    /* May have to leave optimized accum buffer mode */
292    if (swrast->_IntegerAccumScaler == 0.0 && value > 0.0 && value <= 1.0)
293       swrast->_IntegerAccumScaler = value;
294    if (swrast->_IntegerAccumMode && value != swrast->_IntegerAccumScaler)
295       rescale_accum(ctx);
296
297    if (rb->DataType == GL_SHORT || rb->DataType == GL_UNSIGNED_SHORT) {
298       const GLfloat scale = value * ACCUM_SCALE16 / CHAN_MAXF;
299       GLshort accumRow[4 * MAX_WIDTH];
300       GLchan rgba[MAX_WIDTH][4];
301       GLint i;
302
303       for (i = 0; i < height; i++) {
304          GLshort *acc;
305          if (directAccess) {
306             acc = (GLshort *) rb->GetPointer(ctx, rb, xpos, ypos + i);
307          }
308          else {
309             rb->GetRow(ctx, rb, width, xpos, ypos + i, accumRow);
310             acc = accumRow;
311          }
312
313          /* read colors from color buffer */
314          _swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer, width,
315                                 xpos, ypos + i, CHAN_TYPE, rgba);
316
317          /* do accumulation */
318          if (swrast->_IntegerAccumMode) {
319             /* simply add integer color values into accum buffer */
320             GLint j;
321             for (j = 0; j < width; j++) {
322                acc[j * 4 + 0] += rgba[j][RCOMP];
323                acc[j * 4 + 1] += rgba[j][GCOMP];
324                acc[j * 4 + 2] += rgba[j][BCOMP];
325                acc[j * 4 + 3] += rgba[j][ACOMP];
326             }
327          }
328          else {
329             /* scaled integer (or float) accum buffer */
330             GLint j;
331             for (j = 0; j < width; j++) {
332                acc[j * 4 + 0] += (GLshort) ((GLfloat) rgba[j][RCOMP] * scale);
333                acc[j * 4 + 1] += (GLshort) ((GLfloat) rgba[j][GCOMP] * scale);
334                acc[j * 4 + 2] += (GLshort) ((GLfloat) rgba[j][BCOMP] * scale);
335                acc[j * 4 + 3] += (GLshort) ((GLfloat) rgba[j][ACOMP] * scale);
336             }
337          }
338
339          if (!directAccess) {
340             rb->PutRow(ctx, rb, width, xpos, ypos + i, accumRow, NULL);
341          }
342       }
343    }
344    else {
345       /* other types someday */
346    }
347 }
348
349
350
351 static void
352 accum_load(GLcontext *ctx, GLfloat value,
353            GLint xpos, GLint ypos, GLint width, GLint height )
354 {
355    SWcontext *swrast = SWRAST_CONTEXT(ctx);
356    struct gl_renderbuffer *rb
357       = ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer;
358    const GLboolean directAccess = (rb->GetPointer(ctx, rb, 0, 0) != NULL);
359
360    assert(rb);
361
362    if (!ctx->ReadBuffer->_ColorReadBuffer) {
363       /* no read buffer - OK */
364       return;
365    }
366
367    /* This is a change to go into optimized accum buffer mode */
368    if (value > 0.0 && value <= 1.0) {
369 #if USE_OPTIMIZED_ACCUM
370       swrast->_IntegerAccumMode = GL_TRUE;
371 #else
372       swrast->_IntegerAccumMode = GL_FALSE;
373 #endif
374       swrast->_IntegerAccumScaler = value;
375    }
376    else {
377       swrast->_IntegerAccumMode = GL_FALSE;
378       swrast->_IntegerAccumScaler = 0.0;
379    }
380
381    if (rb->DataType == GL_SHORT || rb->DataType == GL_UNSIGNED_SHORT) {
382       const GLfloat scale = value * ACCUM_SCALE16 / CHAN_MAXF;
383       GLshort accumRow[4 * MAX_WIDTH];
384       GLchan rgba[MAX_WIDTH][4];
385       GLint i;
386
387       for (i = 0; i < height; i++) {
388          GLshort *acc;
389          if (directAccess) {
390             acc = (GLshort *) rb->GetPointer(ctx, rb, xpos, ypos + i);
391          }
392          else {
393             rb->GetRow(ctx, rb, width, xpos, ypos + i, accumRow);
394             acc = accumRow;
395          }
396
397          /* read colors from color buffer */
398          _swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer, width,
399                                 xpos, ypos + i, CHAN_TYPE, rgba);
400
401          /* do load */
402          if (swrast->_IntegerAccumMode) {
403             /* just copy values in */
404             GLint j;
405             assert(swrast->_IntegerAccumScaler > 0.0);
406             assert(swrast->_IntegerAccumScaler <= 1.0);
407             for (j = 0; j < width; j++) {
408                acc[j * 4 + 0] = rgba[j][RCOMP];
409                acc[j * 4 + 1] = rgba[j][GCOMP];
410                acc[j * 4 + 2] = rgba[j][BCOMP];
411                acc[j * 4 + 3] = rgba[j][ACOMP];
412             }
413          }
414          else {
415             /* scaled integer (or float) accum buffer */
416             GLint j;
417             for (j = 0; j < width; j++) {
418                acc[j * 4 + 0] = (GLshort) ((GLfloat) rgba[j][RCOMP] * scale);
419                acc[j * 4 + 1] = (GLshort) ((GLfloat) rgba[j][GCOMP] * scale);
420                acc[j * 4 + 2] = (GLshort) ((GLfloat) rgba[j][BCOMP] * scale);
421                acc[j * 4 + 3] = (GLshort) ((GLfloat) rgba[j][ACOMP] * scale);
422             }
423          }
424
425          if (!directAccess) {
426             rb->PutRow(ctx, rb, width, xpos, ypos + i, accumRow, NULL);
427          }
428       }
429    }
430 }
431
432
433 static void
434 accum_return(GLcontext *ctx, GLfloat value,
435              GLint xpos, GLint ypos, GLint width, GLint height )
436 {
437    SWcontext *swrast = SWRAST_CONTEXT(ctx);
438    struct gl_framebuffer *fb = ctx->DrawBuffer;
439    struct gl_renderbuffer *accumRb = fb->Attachment[BUFFER_ACCUM].Renderbuffer;
440    const GLboolean directAccess
441       = (accumRb->GetPointer(ctx, accumRb, 0, 0) != NULL);
442    const GLboolean masking = (!ctx->Color.ColorMask[RCOMP] ||
443                               !ctx->Color.ColorMask[GCOMP] ||
444                               !ctx->Color.ColorMask[BCOMP] ||
445                               !ctx->Color.ColorMask[ACOMP]);
446
447    static GLchan multTable[32768];
448    static GLfloat prevMult = 0.0;
449    const GLfloat mult = swrast->_IntegerAccumScaler;
450    const GLint max = MIN2((GLint) (256 / mult), 32767);
451
452    /* May have to leave optimized accum buffer mode */
453    if (swrast->_IntegerAccumMode && value != 1.0)
454       rescale_accum(ctx);
455
456    if (swrast->_IntegerAccumMode && swrast->_IntegerAccumScaler > 0) {
457       /* build lookup table to avoid many floating point multiplies */
458       GLint j;
459       assert(swrast->_IntegerAccumScaler <= 1.0);
460       if (mult != prevMult) {
461          for (j = 0; j < max; j++)
462             multTable[j] = IROUND((GLfloat) j * mult);
463          prevMult = mult;
464       }
465    }
466
467    if (accumRb->DataType == GL_SHORT ||
468        accumRb->DataType == GL_UNSIGNED_SHORT) {
469       const GLfloat scale = value * CHAN_MAXF / ACCUM_SCALE16;
470       GLuint buffer;
471       GLint i;
472
473       /* XXX maybe transpose the 'i' and 'buffer' loops??? */
474       for (i = 0; i < height; i++) {
475          GLshort accumRow[4 * MAX_WIDTH];
476          GLshort *acc;
477          SWspan span;
478
479          /* init color span */
480          INIT_SPAN(span, GL_BITMAP);
481          span.end = width;
482          span.arrayMask = SPAN_RGBA;
483          span.x = xpos;
484          span.y = ypos + i;
485
486          if (directAccess) {
487             acc = (GLshort *) accumRb->GetPointer(ctx, accumRb, xpos, ypos +i);
488          }
489          else {
490             accumRb->GetRow(ctx, accumRb, width, xpos, ypos + i, accumRow);
491             acc = accumRow;
492          }
493
494          /* get the colors to return */
495          if (swrast->_IntegerAccumMode) {
496             GLint j;
497             for (j = 0; j < width; j++) {
498                ASSERT(acc[j * 4 + 0] < max);
499                ASSERT(acc[j * 4 + 1] < max);
500                ASSERT(acc[j * 4 + 2] < max);
501                ASSERT(acc[j * 4 + 3] < max);
502                span.array->rgba[j][RCOMP] = multTable[acc[j * 4 + 0]];
503                span.array->rgba[j][GCOMP] = multTable[acc[j * 4 + 1]];
504                span.array->rgba[j][BCOMP] = multTable[acc[j * 4 + 2]];
505                span.array->rgba[j][ACOMP] = multTable[acc[j * 4 + 3]];
506             }
507          }
508          else {
509             /* scaled integer (or float) accum buffer */
510             GLint j;
511             for (j = 0; j < width; j++) {
512 #if CHAN_BITS==32
513                GLchan r = acc[j * 4 + 0] * scale;
514                GLchan g = acc[j * 4 + 1] * scale;
515                GLchan b = acc[j * 4 + 2] * scale;
516                GLchan a = acc[j * 4 + 3] * scale;
517 #else
518                GLint r = IROUND( (GLfloat) (acc[j * 4 + 0]) * scale );
519                GLint g = IROUND( (GLfloat) (acc[j * 4 + 1]) * scale );
520                GLint b = IROUND( (GLfloat) (acc[j * 4 + 2]) * scale );
521                GLint a = IROUND( (GLfloat) (acc[j * 4 + 3]) * scale );
522 #endif
523                span.array->rgba[j][RCOMP] = CLAMP( r, 0, CHAN_MAX );
524                span.array->rgba[j][GCOMP] = CLAMP( g, 0, CHAN_MAX );
525                span.array->rgba[j][BCOMP] = CLAMP( b, 0, CHAN_MAX );
526                span.array->rgba[j][ACOMP] = CLAMP( a, 0, CHAN_MAX );
527             }
528          }
529
530          /* store colors */
531          for (buffer = 0; buffer < fb->_NumColorDrawBuffers; buffer++) {
532             struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[buffer];
533             if (masking) {
534                _swrast_mask_rgba_span(ctx, rb, &span);
535             }
536             rb->PutRow(ctx, rb, width, xpos, ypos + i, span.array->rgba, NULL);
537          }
538       }
539    }
540    else {
541       /* other types someday */
542    }
543 }
544
545
546
547 /**
548  * Software fallback for glAccum.
549  */
550 void
551 _swrast_Accum(GLcontext *ctx, GLenum op, GLfloat value)
552 {
553    SWcontext *swrast = SWRAST_CONTEXT(ctx);
554    GLint xpos, ypos, width, height;
555
556    if (swrast->NewState)
557       _swrast_validate_derived( ctx );
558
559    if (!ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer) {
560       _mesa_warning(ctx, "Calling glAccum() without an accumulation buffer");
561       return;
562    }
563
564    swrast_render_start(ctx);
565
566    /* Compute region after calling swrast_render_start() so that we know the
567     * drawbuffer's size/bounds are up to date.
568     */
569    xpos = ctx->DrawBuffer->_Xmin;
570    ypos = ctx->DrawBuffer->_Ymin;
571    width =  ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
572    height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
573
574    switch (op) {
575       case GL_ADD:
576          if (value != 0.0F) {
577             accum_add(ctx, value, xpos, ypos, width, height);
578          }
579          break;
580       case GL_MULT:
581          if (value != 1.0F) {
582             accum_mult(ctx, value, xpos, ypos, width, height);
583          }
584          break;
585       case GL_ACCUM:
586          if (value != 0.0F) {
587             accum_accum(ctx, value, xpos, ypos, width, height);
588          }
589          break;
590       case GL_LOAD:
591          accum_load(ctx, value, xpos, ypos, width, height);
592          break;
593       case GL_RETURN:
594          accum_return(ctx, value, xpos, ypos, width, height);
595          break;
596       default:
597          _mesa_problem(ctx, "invalid mode in _swrast_Accum()");
598          break;
599    }
600
601    swrast_render_finish(ctx);
602 }
603
604
605 #endif /* FEATURE_accum */