2
* Mesa 3-D graphics library
5
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
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:
14
* The above copyright notice and this permission notice shall be included
15
* in all copies or substantial portions of the Software.
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.
33
#include "s_context.h"
34
#include "s_masking.h"
38
/* XXX this would have to change for accum buffers with more or less
39
* than 16 bits per color channel.
41
#define ACCUM_SCALE16 32767.0
45
* Accumulation buffer notes
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.
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);
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.
69
/* enable the optimization */
70
#define USE_OPTIMIZED_ACCUM 1
72
#define USE_OPTIMIZED_ACCUM 0
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].
82
rescale_accum( GLcontext *ctx )
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);
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);
95
if (rb->GetPointer(ctx, rb, 0, 0)) {
96
/* directly-addressable memory */
98
for (y = 0; y < rb->Height; y++) {
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);
107
/* use get/put row funcs */
109
for (y = 0; y < rb->Height; y++) {
110
GLshort accRow[MAX_WIDTH * 4];
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);
116
rb->PutRow(ctx, rb, rb->Width, 0, y, accRow, NULL);
120
swrast->_IntegerAccumMode = GL_FALSE;
126
* Clear the accumulation Buffer.
129
_swrast_clear_accum_buffer( GLcontext *ctx, struct gl_renderbuffer *rb )
131
SWcontext *swrast = SWRAST_CONTEXT(ctx);
132
GLuint x, y, width, height;
134
if (ctx->Visual.accumRedBits == 0) {
135
/* No accumulation buffer! Not an error. */
139
if (!rb || !rb->Data)
142
assert(rb->_BaseFormat == GL_RGBA);
143
/* add other types in future? */
144
assert(rb->DataType == GL_SHORT || rb->DataType == GL_UNSIGNED_SHORT);
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;
152
if (rb->DataType == GL_SHORT || rb->DataType == GL_UNSIGNED_SHORT) {
153
const GLfloat accScale = 32767.0;
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);
162
for (i = 0; i < height; i++) {
163
rb->PutMonoRow(ctx, rb, width, x, y + i, clearVal, NULL);
167
/* someday support other sizes */
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;
176
swrast->_IntegerAccumMode = GL_FALSE;
178
swrast->_IntegerAccumScaler = 0.0; /* denotes empty accum buffer */
181
swrast->_IntegerAccumMode = GL_FALSE;
187
accum_add(GLcontext *ctx, GLfloat value,
188
GLint xpos, GLint ypos, GLint width, GLint height )
190
SWcontext *swrast = SWRAST_CONTEXT(ctx);
191
struct gl_renderbuffer *rb
192
= ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer;
196
/* Leave optimized accum buffer mode */
197
if (swrast->_IntegerAccumMode)
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)) {
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++) {
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++) {
219
rb->PutRow(ctx, rb, width, xpos, ypos + i, accRow, NULL);
224
/* other types someday */
230
accum_mult(GLcontext *ctx, GLfloat mult,
231
GLint xpos, GLint ypos, GLint width, GLint height )
233
SWcontext *swrast = SWRAST_CONTEXT(ctx);
234
struct gl_renderbuffer *rb
235
= ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer;
239
/* Leave optimized accum buffer mode */
240
if (swrast->_IntegerAccumMode)
243
if (rb->DataType == GL_SHORT || rb->DataType == GL_UNSIGNED_SHORT) {
244
if (rb->GetPointer(ctx, rb, 0, 0)) {
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);
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);
261
rb->PutRow(ctx, rb, width, xpos, ypos + i, accRow, NULL);
266
/* other types someday */
273
accum_accum(GLcontext *ctx, GLfloat value,
274
GLint xpos, GLint ypos, GLint width, GLint height )
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);
283
if (!ctx->ReadBuffer->_ColorReadBuffer) {
284
/* no read buffer - OK */
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)
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];
300
for (i = 0; i < height; i++) {
303
acc = (GLshort *) rb->GetPointer(ctx, rb, xpos, ypos + i);
306
rb->GetRow(ctx, rb, width, xpos, ypos + i, accumRow);
310
/* read colors from color buffer */
311
_swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer, width,
312
xpos, ypos + i, CHAN_TYPE, rgba);
314
/* do accumulation */
315
if (swrast->_IntegerAccumMode) {
316
/* simply add integer color values into accum buffer */
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];
326
/* scaled integer (or float) accum buffer */
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);
337
rb->PutRow(ctx, rb, width, xpos, ypos + i, accumRow, NULL);
342
/* other types someday */
349
accum_load(GLcontext *ctx, GLfloat value,
350
GLint xpos, GLint ypos, GLint width, GLint height )
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);
359
if (!ctx->ReadBuffer->_ColorReadBuffer) {
360
/* no read buffer - OK */
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;
369
swrast->_IntegerAccumMode = GL_FALSE;
371
swrast->_IntegerAccumScaler = value;
374
swrast->_IntegerAccumMode = GL_FALSE;
375
swrast->_IntegerAccumScaler = 0.0;
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];
384
for (i = 0; i < height; i++) {
387
acc = (GLshort *) rb->GetPointer(ctx, rb, xpos, ypos + i);
390
rb->GetRow(ctx, rb, width, xpos, ypos + i, accumRow);
394
/* read colors from color buffer */
395
_swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer, width,
396
xpos, ypos + i, CHAN_TYPE, rgba);
399
if (swrast->_IntegerAccumMode) {
400
/* just copy values in */
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];
412
/* scaled integer (or float) accum buffer */
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);
423
rb->PutRow(ctx, rb, width, xpos, ypos + i, accumRow, NULL);
431
accum_return(GLcontext *ctx, GLfloat value,
432
GLint xpos, GLint ypos, GLint width, GLint height )
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]);
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);
449
/* May have to leave optimized accum buffer mode */
450
if (swrast->_IntegerAccumMode && value != 1.0)
453
if (swrast->_IntegerAccumMode && swrast->_IntegerAccumScaler > 0) {
454
/* build lookup table to avoid many floating point multiplies */
456
assert(swrast->_IntegerAccumScaler <= 1.0);
457
if (mult != prevMult) {
458
for (j = 0; j < max; j++)
459
multTable[j] = IROUND((GLfloat) j * mult);
464
if (accumRb->DataType == GL_SHORT ||
465
accumRb->DataType == GL_UNSIGNED_SHORT) {
466
const GLfloat scale = value * CHAN_MAXF / ACCUM_SCALE16;
470
/* XXX maybe transpose the 'i' and 'buffer' loops??? */
471
for (i = 0; i < height; i++) {
472
GLshort accumRow[4 * MAX_WIDTH];
476
/* init color span */
477
INIT_SPAN(span, GL_BITMAP, width, 0, SPAN_RGBA);
482
acc = (GLshort *) accumRb->GetPointer(ctx, accumRb, xpos, ypos +i);
485
accumRb->GetRow(ctx, accumRb, width, xpos, ypos + i, accumRow);
489
/* get the colors to return */
490
if (swrast->_IntegerAccumMode) {
492
for (j = 0; j < width; j++) {
493
ASSERT(acc[j * 4 + 0] < max);
494
ASSERT(acc[j * 4 + 1] < max);
495
ASSERT(acc[j * 4 + 2] < max);
496
ASSERT(acc[j * 4 + 3] < max);
497
span.array->rgba[j][RCOMP] = multTable[acc[j * 4 + 0]];
498
span.array->rgba[j][GCOMP] = multTable[acc[j * 4 + 1]];
499
span.array->rgba[j][BCOMP] = multTable[acc[j * 4 + 2]];
500
span.array->rgba[j][ACOMP] = multTable[acc[j * 4 + 3]];
504
/* scaled integer (or float) accum buffer */
506
for (j = 0; j < width; j++) {
508
GLchan r = acc[j * 4 + 0] * scale;
509
GLchan g = acc[j * 4 + 1] * scale;
510
GLchan b = acc[j * 4 + 2] * scale;
511
GLchan a = acc[j * 4 + 3] * scale;
513
GLint r = IROUND( (GLfloat) (acc[j * 4 + 0]) * scale );
514
GLint g = IROUND( (GLfloat) (acc[j * 4 + 1]) * scale );
515
GLint b = IROUND( (GLfloat) (acc[j * 4 + 2]) * scale );
516
GLint a = IROUND( (GLfloat) (acc[j * 4 + 3]) * scale );
518
span.array->rgba[j][RCOMP] = CLAMP( r, 0, CHAN_MAX );
519
span.array->rgba[j][GCOMP] = CLAMP( g, 0, CHAN_MAX );
520
span.array->rgba[j][BCOMP] = CLAMP( b, 0, CHAN_MAX );
521
span.array->rgba[j][ACOMP] = CLAMP( a, 0, CHAN_MAX );
526
for (buffer = 0; buffer < fb->_NumColorDrawBuffers[0]; buffer++) {
527
struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[0][buffer];
529
_swrast_mask_rgba_span(ctx, rb, &span);
531
rb->PutRow(ctx, rb, width, xpos, ypos + i, span.array->rgba, NULL);
536
/* other types someday */
543
* Software fallback for glAccum.
546
_swrast_Accum(GLcontext *ctx, GLenum op, GLfloat value)
548
SWcontext *swrast = SWRAST_CONTEXT(ctx);
549
GLint xpos, ypos, width, height;
551
if (SWRAST_CONTEXT(ctx)->NewState)
552
_swrast_validate_derived( ctx );
554
if (!ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer) {
555
_mesa_warning(ctx, "Calling glAccum() without an accumulation buffer");
559
RENDER_START(swrast, ctx);
561
/* Compute region after calling RENDER_START so that we know the
562
* drawbuffer's size/bounds are up to date.
564
xpos = ctx->DrawBuffer->_Xmin;
565
ypos = ctx->DrawBuffer->_Ymin;
566
width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
567
height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
572
accum_add(ctx, value, xpos, ypos, width, height);
577
accum_mult(ctx, value, xpos, ypos, width, height);
582
accum_accum(ctx, value, xpos, ypos, width, height);
586
accum_load(ctx, value, xpos, ypos, width, height);
589
accum_return(ctx, value, xpos, ypos, width, height);
592
_mesa_problem(ctx, "invalid mode in _swrast_Accum()");
596
RENDER_FINISH(swrast, ctx);