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