• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Mesa 3-D graphics library
3   * Version:  6.5
4   *
5   * Copyright (C) 1999-2005  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  #include "glheader.h"
26  #include "accum.h"
27  #include "condrender.h"
28  #include "context.h"
29  #include "format_unpack.h"
30  #include "format_pack.h"
31  #include "imports.h"
32  #include "macros.h"
33  #include "mfeatures.h"
34  #include "state.h"
35  #include "mtypes.h"
36  #include "main/dispatch.h"
37  
38  
39  #if FEATURE_accum
40  
41  
42  void GLAPIENTRY
_mesa_ClearAccum(GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha)43  _mesa_ClearAccum( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha )
44  {
45     GLfloat tmp[4];
46     GET_CURRENT_CONTEXT(ctx);
47     ASSERT_OUTSIDE_BEGIN_END(ctx);
48  
49     tmp[0] = CLAMP( red,   -1.0F, 1.0F );
50     tmp[1] = CLAMP( green, -1.0F, 1.0F );
51     tmp[2] = CLAMP( blue,  -1.0F, 1.0F );
52     tmp[3] = CLAMP( alpha, -1.0F, 1.0F );
53  
54     if (TEST_EQ_4V(tmp, ctx->Accum.ClearColor))
55        return;
56  
57     COPY_4FV( ctx->Accum.ClearColor, tmp );
58  }
59  
60  
61  static void GLAPIENTRY
_mesa_Accum(GLenum op,GLfloat value)62  _mesa_Accum( GLenum op, GLfloat value )
63  {
64     GET_CURRENT_CONTEXT(ctx);
65     ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
66  
67     switch (op) {
68     case GL_ADD:
69     case GL_MULT:
70     case GL_ACCUM:
71     case GL_LOAD:
72     case GL_RETURN:
73        /* OK */
74        break;
75     default:
76        _mesa_error(ctx, GL_INVALID_ENUM, "glAccum(op)");
77        return;
78     }
79  
80     if (ctx->DrawBuffer->Visual.haveAccumBuffer == 0) {
81        _mesa_error(ctx, GL_INVALID_OPERATION, "glAccum(no accum buffer)");
82        return;
83     }
84  
85     if (ctx->DrawBuffer != ctx->ReadBuffer) {
86        /* See GLX_SGI_make_current_read or WGL_ARB_make_current_read,
87         * or GL_EXT_framebuffer_blit.
88         */
89        _mesa_error(ctx, GL_INVALID_OPERATION,
90                    "glAccum(different read/draw buffers)");
91        return;
92     }
93  
94     if (ctx->NewState)
95        _mesa_update_state(ctx);
96  
97     if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
98        _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
99                    "glAccum(incomplete framebuffer)");
100        return;
101     }
102  
103     if (ctx->RasterDiscard)
104        return;
105  
106     if (ctx->RenderMode == GL_RENDER) {
107        _mesa_accum(ctx, op, value);
108     }
109  }
110  
111  
112  void
_mesa_init_accum_dispatch(struct _glapi_table * disp)113  _mesa_init_accum_dispatch(struct _glapi_table *disp)
114  {
115     SET_Accum(disp, _mesa_Accum);
116     SET_ClearAccum(disp, _mesa_ClearAccum);
117  }
118  
119  
120  /**
121   * Clear the accumulation buffer by mapping the renderbuffer and
122   * writing the clear color to it.  Called by the driver's implementation
123   * of the glClear function.
124   */
125  void
_mesa_clear_accum_buffer(struct gl_context * ctx)126  _mesa_clear_accum_buffer(struct gl_context *ctx)
127  {
128     GLuint x, y, width, height;
129     GLubyte *accMap;
130     GLint accRowStride;
131     struct gl_renderbuffer *accRb;
132  
133     if (!ctx->DrawBuffer)
134        return;
135  
136     accRb = ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer;
137     if (!accRb)
138        return;   /* missing accum buffer, not an error */
139  
140     /* bounds, with scissor */
141     x = ctx->DrawBuffer->_Xmin;
142     y = ctx->DrawBuffer->_Ymin;
143     width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
144     height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
145  
146     ctx->Driver.MapRenderbuffer(ctx, accRb, x, y, width, height,
147                                 GL_MAP_WRITE_BIT, &accMap, &accRowStride);
148  
149     if (!accMap) {
150        _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
151        return;
152     }
153  
154     if (accRb->Format == MESA_FORMAT_SIGNED_RGBA_16) {
155        const GLshort clearR = FLOAT_TO_SHORT(ctx->Accum.ClearColor[0]);
156        const GLshort clearG = FLOAT_TO_SHORT(ctx->Accum.ClearColor[1]);
157        const GLshort clearB = FLOAT_TO_SHORT(ctx->Accum.ClearColor[2]);
158        const GLshort clearA = FLOAT_TO_SHORT(ctx->Accum.ClearColor[3]);
159        GLuint i, j;
160  
161        for (j = 0; j < height; j++) {
162           GLshort *row = (GLshort *) accMap;
163  
164           for (i = 0; i < width; i++) {
165              row[i * 4 + 0] = clearR;
166              row[i * 4 + 1] = clearG;
167              row[i * 4 + 2] = clearB;
168              row[i * 4 + 3] = clearA;
169           }
170           accMap += accRowStride;
171        }
172     }
173     else {
174        /* other types someday? */
175        _mesa_warning(ctx, "unexpected accum buffer type");
176     }
177  
178     ctx->Driver.UnmapRenderbuffer(ctx, accRb);
179  }
180  
181  
182  /**
183   * if (bias)
184   *    Accum += value
185   * else
186   *    Accum *= value
187   */
188  static void
accum_scale_or_bias(struct gl_context * ctx,GLfloat value,GLint xpos,GLint ypos,GLint width,GLint height,GLboolean bias)189  accum_scale_or_bias(struct gl_context *ctx, GLfloat value,
190                      GLint xpos, GLint ypos, GLint width, GLint height,
191                      GLboolean bias)
192  {
193     struct gl_renderbuffer *accRb =
194        ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer;
195     GLubyte *accMap;
196     GLint accRowStride;
197  
198     assert(accRb);
199  
200     ctx->Driver.MapRenderbuffer(ctx, accRb, xpos, ypos, width, height,
201                                 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
202                                 &accMap, &accRowStride);
203  
204     if (!accMap) {
205        _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
206        return;
207     }
208  
209     if (accRb->Format == MESA_FORMAT_SIGNED_RGBA_16) {
210        const GLshort incr = (GLshort) (value * 32767.0f);
211        GLuint i, j;
212        if (bias) {
213           for (j = 0; j < height; j++) {
214              GLshort *acc = (GLshort *) accMap;
215              for (i = 0; i < 4 * width; i++) {
216                 acc[i] += incr;
217              }
218              accMap += accRowStride;
219           }
220        }
221        else {
222           /* scale */
223           for (j = 0; j < height; j++) {
224              GLshort *acc = (GLshort *) accMap;
225              for (i = 0; i < 4 * width; i++) {
226                 acc[i] = (GLshort) (acc[i] * value);
227              }
228              accMap += accRowStride;
229           }
230        }
231     }
232     else {
233        /* other types someday? */
234     }
235  
236     ctx->Driver.UnmapRenderbuffer(ctx, accRb);
237  }
238  
239  
240  /**
241   * if (load)
242   *    Accum = ColorBuf * value
243   * else
244   *    Accum += ColorBuf * value
245   */
246  static void
accum_or_load(struct gl_context * ctx,GLfloat value,GLint xpos,GLint ypos,GLint width,GLint height,GLboolean load)247  accum_or_load(struct gl_context *ctx, GLfloat value,
248                GLint xpos, GLint ypos, GLint width, GLint height,
249                GLboolean load)
250  {
251     struct gl_renderbuffer *accRb =
252        ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer;
253     struct gl_renderbuffer *colorRb = ctx->ReadBuffer->_ColorReadBuffer;
254     GLubyte *accMap, *colorMap;
255     GLint accRowStride, colorRowStride;
256     GLbitfield mappingFlags;
257  
258     if (!colorRb) {
259        /* no read buffer - OK */
260        return;
261     }
262  
263     assert(accRb);
264  
265     mappingFlags = GL_MAP_WRITE_BIT;
266     if (!load) /* if we're accumulating */
267        mappingFlags |= GL_MAP_READ_BIT;
268  
269     /* Map accum buffer */
270     ctx->Driver.MapRenderbuffer(ctx, accRb, xpos, ypos, width, height,
271                                 mappingFlags, &accMap, &accRowStride);
272     if (!accMap) {
273        _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
274        return;
275     }
276  
277     /* Map color buffer */
278     ctx->Driver.MapRenderbuffer(ctx, colorRb, xpos, ypos, width, height,
279                                 GL_MAP_READ_BIT,
280                                 &colorMap, &colorRowStride);
281     if (!colorMap) {
282        ctx->Driver.UnmapRenderbuffer(ctx, accRb);
283        _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
284        return;
285     }
286  
287     if (accRb->Format == MESA_FORMAT_SIGNED_RGBA_16) {
288        const GLfloat scale = value * 32767.0f;
289        GLuint i, j;
290        GLfloat (*rgba)[4];
291  
292        rgba = (GLfloat (*)[4]) malloc(width * 4 * sizeof(GLfloat));
293        if (rgba) {
294           for (j = 0; j < height; j++) {
295              GLshort *acc = (GLshort *) accMap;
296  
297              /* read colors from source color buffer */
298              _mesa_unpack_rgba_row(colorRb->Format, width, colorMap, rgba);
299  
300              if (load) {
301                 for (i = 0; i < width; i++) {
302                    acc[i * 4 + 0] = (GLshort) (rgba[i][RCOMP] * scale);
303                    acc[i * 4 + 1] = (GLshort) (rgba[i][GCOMP] * scale);
304                    acc[i * 4 + 2] = (GLshort) (rgba[i][BCOMP] * scale);
305                    acc[i * 4 + 3] = (GLshort) (rgba[i][ACOMP] * scale);
306                 }
307              }
308              else {
309                 /* accumulate */
310                 for (i = 0; i < width; i++) {
311                    acc[i * 4 + 0] += (GLshort) (rgba[i][RCOMP] * scale);
312                    acc[i * 4 + 1] += (GLshort) (rgba[i][GCOMP] * scale);
313                    acc[i * 4 + 2] += (GLshort) (rgba[i][BCOMP] * scale);
314                    acc[i * 4 + 3] += (GLshort) (rgba[i][ACOMP] * scale);
315                 }
316              }
317  
318              colorMap += colorRowStride;
319              accMap += accRowStride;
320           }
321  
322           free(rgba);
323        }
324        else {
325           _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
326        }
327     }
328     else {
329        /* other types someday? */
330     }
331  
332     ctx->Driver.UnmapRenderbuffer(ctx, accRb);
333     ctx->Driver.UnmapRenderbuffer(ctx, colorRb);
334  }
335  
336  
337  /**
338   * ColorBuffer = Accum * value
339   */
340  static void
accum_return(struct gl_context * ctx,GLfloat value,GLint xpos,GLint ypos,GLint width,GLint height)341  accum_return(struct gl_context *ctx, GLfloat value,
342               GLint xpos, GLint ypos, GLint width, GLint height)
343  {
344     struct gl_framebuffer *fb = ctx->DrawBuffer;
345     struct gl_renderbuffer *accRb = fb->Attachment[BUFFER_ACCUM].Renderbuffer;
346     GLubyte *accMap, *colorMap;
347     GLint accRowStride, colorRowStride;
348     GLuint buffer;
349  
350     /* Map accum buffer */
351     ctx->Driver.MapRenderbuffer(ctx, accRb, xpos, ypos, width, height,
352                                 GL_MAP_READ_BIT,
353                                 &accMap, &accRowStride);
354     if (!accMap) {
355        _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
356        return;
357     }
358  
359     /* Loop over destination buffers */
360     for (buffer = 0; buffer < fb->_NumColorDrawBuffers; buffer++) {
361        struct gl_renderbuffer *colorRb = fb->_ColorDrawBuffers[buffer];
362        const GLboolean masking = (!ctx->Color.ColorMask[buffer][RCOMP] ||
363                                   !ctx->Color.ColorMask[buffer][GCOMP] ||
364                                   !ctx->Color.ColorMask[buffer][BCOMP] ||
365                                   !ctx->Color.ColorMask[buffer][ACOMP]);
366        GLbitfield mappingFlags = GL_MAP_WRITE_BIT;
367  
368        if (masking)
369           mappingFlags |= GL_MAP_READ_BIT;
370  
371        /* Map color buffer */
372        ctx->Driver.MapRenderbuffer(ctx, colorRb, xpos, ypos, width, height,
373                                    mappingFlags, &colorMap, &colorRowStride);
374        if (!colorMap) {
375           _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
376           continue;
377        }
378  
379        if (accRb->Format == MESA_FORMAT_SIGNED_RGBA_16) {
380           const GLfloat scale = value / 32767.0f;
381           GLint i, j;
382           GLfloat (*rgba)[4], (*dest)[4];
383  
384           rgba = (GLfloat (*)[4]) malloc(width * 4 * sizeof(GLfloat));
385           dest = (GLfloat (*)[4]) malloc(width * 4 * sizeof(GLfloat));
386  
387           if (rgba && dest) {
388              for (j = 0; j < height; j++) {
389                 GLshort *acc = (GLshort *) accMap;
390  
391                 for (i = 0; i < width; i++) {
392                    rgba[i][0] = acc[i * 4 + 0] * scale;
393                    rgba[i][1] = acc[i * 4 + 1] * scale;
394                    rgba[i][2] = acc[i * 4 + 2] * scale;
395                    rgba[i][3] = acc[i * 4 + 3] * scale;
396                 }
397  
398                 if (masking) {
399  
400                    /* get existing colors from dest buffer */
401                    _mesa_unpack_rgba_row(colorRb->Format, width, colorMap, dest);
402  
403                    /* use the dest colors where mask[channel] = 0 */
404                    if (ctx->Color.ColorMask[buffer][RCOMP] == 0) {
405                       for (i = 0; i < width; i++)
406                          rgba[i][RCOMP] = dest[i][RCOMP];
407                    }
408                    if (ctx->Color.ColorMask[buffer][GCOMP] == 0) {
409                       for (i = 0; i < width; i++)
410                          rgba[i][GCOMP] = dest[i][GCOMP];
411                    }
412                    if (ctx->Color.ColorMask[buffer][BCOMP] == 0) {
413                       for (i = 0; i < width; i++)
414                          rgba[i][BCOMP] = dest[i][BCOMP];
415                    }
416                    if (ctx->Color.ColorMask[buffer][ACOMP] == 0) {
417                       for (i = 0; i < width; i++)
418                          rgba[i][ACOMP] = dest[i][ACOMP];
419                    }
420                 }
421  
422                 _mesa_pack_float_rgba_row(colorRb->Format, width,
423                                           (const GLfloat (*)[4]) rgba, colorMap);
424  
425                 accMap += accRowStride;
426                 colorMap += colorRowStride;
427              }
428           }
429           else {
430              _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
431           }
432           free(rgba);
433           free(dest);
434        }
435        else {
436           /* other types someday? */
437        }
438  
439        ctx->Driver.UnmapRenderbuffer(ctx, colorRb);
440     }
441  
442     ctx->Driver.UnmapRenderbuffer(ctx, accRb);
443  }
444  
445  
446  
447  /**
448   * Software fallback for glAccum.  A hardware driver that supports
449   * signed 16-bit color channels could implement hardware accumulation
450   * operations, but no driver does so at this time.
451   */
452  void
_mesa_accum(struct gl_context * ctx,GLenum op,GLfloat value)453  _mesa_accum(struct gl_context *ctx, GLenum op, GLfloat value)
454  {
455     GLint xpos, ypos, width, height;
456  
457     if (!ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer) {
458        _mesa_warning(ctx, "Calling glAccum() without an accumulation buffer");
459        return;
460     }
461  
462     if (!_mesa_check_conditional_render(ctx))
463        return;
464  
465     xpos = ctx->DrawBuffer->_Xmin;
466     ypos = ctx->DrawBuffer->_Ymin;
467     width =  ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
468     height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
469  
470     switch (op) {
471     case GL_ADD:
472        if (value != 0.0F) {
473           accum_scale_or_bias(ctx, value, xpos, ypos, width, height, GL_TRUE);
474        }
475        break;
476     case GL_MULT:
477        if (value != 1.0F) {
478           accum_scale_or_bias(ctx, value, xpos, ypos, width, height, GL_FALSE);
479        }
480        break;
481     case GL_ACCUM:
482        if (value != 0.0F) {
483           accum_or_load(ctx, value, xpos, ypos, width, height, GL_FALSE);
484        }
485        break;
486     case GL_LOAD:
487        accum_or_load(ctx, value, xpos, ypos, width, height, GL_TRUE);
488        break;
489     case GL_RETURN:
490        accum_return(ctx, value, xpos, ypos, width, height);
491        break;
492     default:
493        _mesa_problem(ctx, "invalid mode in _mesa_accum()");
494        break;
495     }
496  }
497  
498  
499  #endif /* FEATURE_accum */
500  
501  
502  void
_mesa_init_accum(struct gl_context * ctx)503  _mesa_init_accum( struct gl_context *ctx )
504  {
505     /* Accumulate buffer group */
506     ASSIGN_4V( ctx->Accum.ClearColor, 0.0, 0.0, 0.0, 0.0 );
507  }
508