OSDN Git Service

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