1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the "Software"), 8848b8605Smrg * to deal in the Software without restriction, including without limitation 9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 11848b8605Smrg * Software is furnished to do so, subject to the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice shall be included 14848b8605Smrg * in all copies or substantial portions of the Software. 15848b8605Smrg * 16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 23848b8605Smrg */ 24848b8605Smrg 25848b8605Smrg#include "glheader.h" 26848b8605Smrg#include "accum.h" 27848b8605Smrg#include "condrender.h" 28848b8605Smrg#include "context.h" 29848b8605Smrg#include "format_unpack.h" 30848b8605Smrg#include "format_pack.h" 31b8e80941Smrg#include "framebuffer.h" 32848b8605Smrg#include "imports.h" 33848b8605Smrg#include "macros.h" 34848b8605Smrg#include "state.h" 35848b8605Smrg#include "mtypes.h" 36848b8605Smrg 37848b8605Smrg 38848b8605Smrgvoid GLAPIENTRY 39848b8605Smrg_mesa_ClearAccum( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ) 40848b8605Smrg{ 41848b8605Smrg GLfloat tmp[4]; 42848b8605Smrg GET_CURRENT_CONTEXT(ctx); 43848b8605Smrg 44848b8605Smrg tmp[0] = CLAMP( red, -1.0F, 1.0F ); 45848b8605Smrg tmp[1] = CLAMP( green, -1.0F, 1.0F ); 46848b8605Smrg tmp[2] = CLAMP( blue, -1.0F, 1.0F ); 47848b8605Smrg tmp[3] = CLAMP( alpha, -1.0F, 1.0F ); 48848b8605Smrg 49848b8605Smrg if (TEST_EQ_4V(tmp, ctx->Accum.ClearColor)) 50848b8605Smrg return; 51848b8605Smrg 52848b8605Smrg COPY_4FV( ctx->Accum.ClearColor, tmp ); 53848b8605Smrg} 54848b8605Smrg 55848b8605Smrg 56848b8605Smrg/** 57848b8605Smrg * Clear the accumulation buffer by mapping the renderbuffer and 58848b8605Smrg * writing the clear color to it. Called by the driver's implementation 59848b8605Smrg * of the glClear function. 60848b8605Smrg */ 61848b8605Smrgvoid 62848b8605Smrg_mesa_clear_accum_buffer(struct gl_context *ctx) 63848b8605Smrg{ 64848b8605Smrg GLuint x, y, width, height; 65848b8605Smrg GLubyte *accMap; 66848b8605Smrg GLint accRowStride; 67848b8605Smrg struct gl_renderbuffer *accRb; 68848b8605Smrg 69848b8605Smrg if (!ctx->DrawBuffer) 70848b8605Smrg return; 71848b8605Smrg 72848b8605Smrg accRb = ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer; 73848b8605Smrg if (!accRb) 74848b8605Smrg return; /* missing accum buffer, not an error */ 75848b8605Smrg 76b8e80941Smrg _mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer); 77b8e80941Smrg 78848b8605Smrg /* bounds, with scissor */ 79848b8605Smrg x = ctx->DrawBuffer->_Xmin; 80848b8605Smrg y = ctx->DrawBuffer->_Ymin; 81848b8605Smrg width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; 82848b8605Smrg height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; 83848b8605Smrg 84848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, accRb, x, y, width, height, 85b8e80941Smrg GL_MAP_WRITE_BIT, &accMap, &accRowStride, 86b8e80941Smrg ctx->DrawBuffer->FlipY); 87848b8605Smrg 88848b8605Smrg if (!accMap) { 89848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum"); 90848b8605Smrg return; 91848b8605Smrg } 92848b8605Smrg 93848b8605Smrg if (accRb->Format == MESA_FORMAT_RGBA_SNORM16) { 94848b8605Smrg const GLshort clearR = FLOAT_TO_SHORT(ctx->Accum.ClearColor[0]); 95848b8605Smrg const GLshort clearG = FLOAT_TO_SHORT(ctx->Accum.ClearColor[1]); 96848b8605Smrg const GLshort clearB = FLOAT_TO_SHORT(ctx->Accum.ClearColor[2]); 97848b8605Smrg const GLshort clearA = FLOAT_TO_SHORT(ctx->Accum.ClearColor[3]); 98848b8605Smrg GLuint i, j; 99848b8605Smrg 100848b8605Smrg for (j = 0; j < height; j++) { 101848b8605Smrg GLshort *row = (GLshort *) accMap; 102848b8605Smrg 103848b8605Smrg for (i = 0; i < width; i++) { 104848b8605Smrg row[i * 4 + 0] = clearR; 105848b8605Smrg row[i * 4 + 1] = clearG; 106848b8605Smrg row[i * 4 + 2] = clearB; 107848b8605Smrg row[i * 4 + 3] = clearA; 108848b8605Smrg } 109848b8605Smrg accMap += accRowStride; 110848b8605Smrg } 111848b8605Smrg } 112848b8605Smrg else { 113848b8605Smrg /* other types someday? */ 114848b8605Smrg _mesa_warning(ctx, "unexpected accum buffer type"); 115848b8605Smrg } 116848b8605Smrg 117848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, accRb); 118848b8605Smrg} 119848b8605Smrg 120848b8605Smrg 121848b8605Smrg/** 122848b8605Smrg * if (bias) 123848b8605Smrg * Accum += value 124848b8605Smrg * else 125848b8605Smrg * Accum *= value 126848b8605Smrg */ 127848b8605Smrgstatic void 128848b8605Smrgaccum_scale_or_bias(struct gl_context *ctx, GLfloat value, 129848b8605Smrg GLint xpos, GLint ypos, GLint width, GLint height, 130848b8605Smrg GLboolean bias) 131848b8605Smrg{ 132848b8605Smrg struct gl_renderbuffer *accRb = 133848b8605Smrg ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer; 134848b8605Smrg GLubyte *accMap; 135848b8605Smrg GLint accRowStride; 136848b8605Smrg 137848b8605Smrg assert(accRb); 138848b8605Smrg 139848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, accRb, xpos, ypos, width, height, 140848b8605Smrg GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, 141b8e80941Smrg &accMap, &accRowStride, 142b8e80941Smrg ctx->DrawBuffer->FlipY); 143848b8605Smrg 144848b8605Smrg if (!accMap) { 145848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum"); 146848b8605Smrg return; 147848b8605Smrg } 148848b8605Smrg 149848b8605Smrg if (accRb->Format == MESA_FORMAT_RGBA_SNORM16) { 150848b8605Smrg const GLshort incr = (GLshort) (value * 32767.0f); 151848b8605Smrg GLint i, j; 152848b8605Smrg if (bias) { 153848b8605Smrg for (j = 0; j < height; j++) { 154848b8605Smrg GLshort *acc = (GLshort *) accMap; 155848b8605Smrg for (i = 0; i < 4 * width; i++) { 156848b8605Smrg acc[i] += incr; 157848b8605Smrg } 158848b8605Smrg accMap += accRowStride; 159848b8605Smrg } 160848b8605Smrg } 161848b8605Smrg else { 162848b8605Smrg /* scale */ 163848b8605Smrg for (j = 0; j < height; j++) { 164848b8605Smrg GLshort *acc = (GLshort *) accMap; 165848b8605Smrg for (i = 0; i < 4 * width; i++) { 166848b8605Smrg acc[i] = (GLshort) (acc[i] * value); 167848b8605Smrg } 168848b8605Smrg accMap += accRowStride; 169848b8605Smrg } 170848b8605Smrg } 171848b8605Smrg } 172848b8605Smrg else { 173848b8605Smrg /* other types someday? */ 174848b8605Smrg } 175848b8605Smrg 176848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, accRb); 177848b8605Smrg} 178848b8605Smrg 179848b8605Smrg 180848b8605Smrg/** 181848b8605Smrg * if (load) 182848b8605Smrg * Accum = ColorBuf * value 183848b8605Smrg * else 184848b8605Smrg * Accum += ColorBuf * value 185848b8605Smrg */ 186848b8605Smrgstatic void 187848b8605Smrgaccum_or_load(struct gl_context *ctx, GLfloat value, 188848b8605Smrg GLint xpos, GLint ypos, GLint width, GLint height, 189848b8605Smrg GLboolean load) 190848b8605Smrg{ 191848b8605Smrg struct gl_renderbuffer *accRb = 192848b8605Smrg ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer; 193848b8605Smrg struct gl_renderbuffer *colorRb = ctx->ReadBuffer->_ColorReadBuffer; 194848b8605Smrg GLubyte *accMap, *colorMap; 195848b8605Smrg GLint accRowStride, colorRowStride; 196848b8605Smrg GLbitfield mappingFlags; 197848b8605Smrg 198848b8605Smrg if (!colorRb) { 199848b8605Smrg /* no read buffer - OK */ 200848b8605Smrg return; 201848b8605Smrg } 202848b8605Smrg 203848b8605Smrg assert(accRb); 204848b8605Smrg 205848b8605Smrg mappingFlags = GL_MAP_WRITE_BIT; 206848b8605Smrg if (!load) /* if we're accumulating */ 207848b8605Smrg mappingFlags |= GL_MAP_READ_BIT; 208848b8605Smrg 209848b8605Smrg /* Map accum buffer */ 210848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, accRb, xpos, ypos, width, height, 211b8e80941Smrg mappingFlags, &accMap, &accRowStride, 212b8e80941Smrg ctx->DrawBuffer->FlipY); 213848b8605Smrg if (!accMap) { 214848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum"); 215848b8605Smrg return; 216848b8605Smrg } 217848b8605Smrg 218848b8605Smrg /* Map color buffer */ 219848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, colorRb, xpos, ypos, width, height, 220848b8605Smrg GL_MAP_READ_BIT, 221b8e80941Smrg &colorMap, &colorRowStride, 222b8e80941Smrg ctx->DrawBuffer->FlipY); 223848b8605Smrg if (!colorMap) { 224848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, accRb); 225848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum"); 226848b8605Smrg return; 227848b8605Smrg } 228848b8605Smrg 229848b8605Smrg if (accRb->Format == MESA_FORMAT_RGBA_SNORM16) { 230848b8605Smrg const GLfloat scale = value * 32767.0f; 231848b8605Smrg GLint i, j; 232848b8605Smrg GLfloat (*rgba)[4]; 233848b8605Smrg 234848b8605Smrg rgba = malloc(width * 4 * sizeof(GLfloat)); 235848b8605Smrg if (rgba) { 236848b8605Smrg for (j = 0; j < height; j++) { 237848b8605Smrg GLshort *acc = (GLshort *) accMap; 238848b8605Smrg 239848b8605Smrg /* read colors from source color buffer */ 240848b8605Smrg _mesa_unpack_rgba_row(colorRb->Format, width, colorMap, rgba); 241848b8605Smrg 242848b8605Smrg if (load) { 243848b8605Smrg for (i = 0; i < width; i++) { 244848b8605Smrg acc[i * 4 + 0] = (GLshort) (rgba[i][RCOMP] * scale); 245848b8605Smrg acc[i * 4 + 1] = (GLshort) (rgba[i][GCOMP] * scale); 246848b8605Smrg acc[i * 4 + 2] = (GLshort) (rgba[i][BCOMP] * scale); 247848b8605Smrg acc[i * 4 + 3] = (GLshort) (rgba[i][ACOMP] * scale); 248848b8605Smrg } 249848b8605Smrg } 250848b8605Smrg else { 251848b8605Smrg /* accumulate */ 252848b8605Smrg for (i = 0; i < width; i++) { 253848b8605Smrg acc[i * 4 + 0] += (GLshort) (rgba[i][RCOMP] * scale); 254848b8605Smrg acc[i * 4 + 1] += (GLshort) (rgba[i][GCOMP] * scale); 255848b8605Smrg acc[i * 4 + 2] += (GLshort) (rgba[i][BCOMP] * scale); 256848b8605Smrg acc[i * 4 + 3] += (GLshort) (rgba[i][ACOMP] * scale); 257848b8605Smrg } 258848b8605Smrg } 259848b8605Smrg 260848b8605Smrg colorMap += colorRowStride; 261848b8605Smrg accMap += accRowStride; 262848b8605Smrg } 263848b8605Smrg 264848b8605Smrg free(rgba); 265848b8605Smrg } 266848b8605Smrg else { 267848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum"); 268848b8605Smrg } 269848b8605Smrg } 270848b8605Smrg else { 271848b8605Smrg /* other types someday? */ 272848b8605Smrg } 273848b8605Smrg 274848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, accRb); 275848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, colorRb); 276848b8605Smrg} 277848b8605Smrg 278848b8605Smrg 279848b8605Smrg/** 280848b8605Smrg * ColorBuffer = Accum * value 281848b8605Smrg */ 282848b8605Smrgstatic void 283848b8605Smrgaccum_return(struct gl_context *ctx, GLfloat value, 284848b8605Smrg GLint xpos, GLint ypos, GLint width, GLint height) 285848b8605Smrg{ 286848b8605Smrg struct gl_framebuffer *fb = ctx->DrawBuffer; 287848b8605Smrg struct gl_renderbuffer *accRb = fb->Attachment[BUFFER_ACCUM].Renderbuffer; 288848b8605Smrg GLubyte *accMap, *colorMap; 289848b8605Smrg GLint accRowStride, colorRowStride; 290848b8605Smrg GLuint buffer; 291848b8605Smrg 292848b8605Smrg /* Map accum buffer */ 293848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, accRb, xpos, ypos, width, height, 294848b8605Smrg GL_MAP_READ_BIT, 295b8e80941Smrg &accMap, &accRowStride, fb->FlipY); 296848b8605Smrg if (!accMap) { 297848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum"); 298848b8605Smrg return; 299848b8605Smrg } 300848b8605Smrg 301848b8605Smrg /* Loop over destination buffers */ 302848b8605Smrg for (buffer = 0; buffer < fb->_NumColorDrawBuffers; buffer++) { 303848b8605Smrg struct gl_renderbuffer *colorRb = fb->_ColorDrawBuffers[buffer]; 304b8e80941Smrg const GLboolean masking = (!GET_COLORMASK_BIT(ctx->Color.ColorMask, buffer, 0) || 305b8e80941Smrg !GET_COLORMASK_BIT(ctx->Color.ColorMask, buffer, 1) || 306b8e80941Smrg !GET_COLORMASK_BIT(ctx->Color.ColorMask, buffer, 2) || 307b8e80941Smrg !GET_COLORMASK_BIT(ctx->Color.ColorMask, buffer, 3)); 308848b8605Smrg GLbitfield mappingFlags = GL_MAP_WRITE_BIT; 309848b8605Smrg 310848b8605Smrg if (masking) 311848b8605Smrg mappingFlags |= GL_MAP_READ_BIT; 312848b8605Smrg 313848b8605Smrg /* Map color buffer */ 314848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, colorRb, xpos, ypos, width, height, 315b8e80941Smrg mappingFlags, &colorMap, &colorRowStride, 316b8e80941Smrg fb->FlipY); 317848b8605Smrg if (!colorMap) { 318848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum"); 319848b8605Smrg continue; 320848b8605Smrg } 321848b8605Smrg 322848b8605Smrg if (accRb->Format == MESA_FORMAT_RGBA_SNORM16) { 323848b8605Smrg const GLfloat scale = value / 32767.0f; 324848b8605Smrg GLint i, j; 325848b8605Smrg GLfloat (*rgba)[4], (*dest)[4]; 326848b8605Smrg 327848b8605Smrg rgba = malloc(width * 4 * sizeof(GLfloat)); 328848b8605Smrg dest = malloc(width * 4 * sizeof(GLfloat)); 329848b8605Smrg 330848b8605Smrg if (rgba && dest) { 331848b8605Smrg for (j = 0; j < height; j++) { 332848b8605Smrg GLshort *acc = (GLshort *) accMap; 333848b8605Smrg 334848b8605Smrg for (i = 0; i < width; i++) { 335848b8605Smrg rgba[i][0] = acc[i * 4 + 0] * scale; 336848b8605Smrg rgba[i][1] = acc[i * 4 + 1] * scale; 337848b8605Smrg rgba[i][2] = acc[i * 4 + 2] * scale; 338848b8605Smrg rgba[i][3] = acc[i * 4 + 3] * scale; 339848b8605Smrg } 340848b8605Smrg 341848b8605Smrg if (masking) { 342848b8605Smrg 343848b8605Smrg /* get existing colors from dest buffer */ 344848b8605Smrg _mesa_unpack_rgba_row(colorRb->Format, width, colorMap, dest); 345848b8605Smrg 346848b8605Smrg /* use the dest colors where mask[channel] = 0 */ 347b8e80941Smrg if (!GET_COLORMASK_BIT(ctx->Color.ColorMask, buffer, 0)) { 348848b8605Smrg for (i = 0; i < width; i++) 349848b8605Smrg rgba[i][RCOMP] = dest[i][RCOMP]; 350848b8605Smrg } 351b8e80941Smrg if (!GET_COLORMASK_BIT(ctx->Color.ColorMask, buffer, 1)) { 352848b8605Smrg for (i = 0; i < width; i++) 353848b8605Smrg rgba[i][GCOMP] = dest[i][GCOMP]; 354848b8605Smrg } 355b8e80941Smrg if (!GET_COLORMASK_BIT(ctx->Color.ColorMask, buffer, 2)) { 356848b8605Smrg for (i = 0; i < width; i++) 357848b8605Smrg rgba[i][BCOMP] = dest[i][BCOMP]; 358848b8605Smrg } 359b8e80941Smrg if (!GET_COLORMASK_BIT(ctx->Color.ColorMask, buffer, 3)) { 360848b8605Smrg for (i = 0; i < width; i++) 361848b8605Smrg rgba[i][ACOMP] = dest[i][ACOMP]; 362848b8605Smrg } 363848b8605Smrg } 364848b8605Smrg 365848b8605Smrg _mesa_pack_float_rgba_row(colorRb->Format, width, 366848b8605Smrg (const GLfloat (*)[4]) rgba, colorMap); 367848b8605Smrg 368848b8605Smrg accMap += accRowStride; 369848b8605Smrg colorMap += colorRowStride; 370848b8605Smrg } 371848b8605Smrg } 372848b8605Smrg else { 373848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum"); 374848b8605Smrg } 375848b8605Smrg free(rgba); 376848b8605Smrg free(dest); 377848b8605Smrg } 378848b8605Smrg else { 379848b8605Smrg /* other types someday? */ 380848b8605Smrg } 381848b8605Smrg 382848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, colorRb); 383848b8605Smrg } 384848b8605Smrg 385848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, accRb); 386848b8605Smrg} 387848b8605Smrg 388848b8605Smrg 389848b8605Smrg 390848b8605Smrg/** 391848b8605Smrg * Software fallback for glAccum. A hardware driver that supports 392848b8605Smrg * signed 16-bit color channels could implement hardware accumulation 393848b8605Smrg * operations, but no driver does so at this time. 394848b8605Smrg */ 395b8e80941Smrgstatic void 396b8e80941Smrgaccum(struct gl_context *ctx, GLenum op, GLfloat value) 397848b8605Smrg{ 398848b8605Smrg GLint xpos, ypos, width, height; 399848b8605Smrg 400848b8605Smrg if (!ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer) { 401848b8605Smrg _mesa_warning(ctx, "Calling glAccum() without an accumulation buffer"); 402848b8605Smrg return; 403848b8605Smrg } 404848b8605Smrg 405848b8605Smrg if (!_mesa_check_conditional_render(ctx)) 406848b8605Smrg return; 407848b8605Smrg 408b8e80941Smrg _mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer); 409b8e80941Smrg 410848b8605Smrg xpos = ctx->DrawBuffer->_Xmin; 411848b8605Smrg ypos = ctx->DrawBuffer->_Ymin; 412848b8605Smrg width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; 413848b8605Smrg height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; 414848b8605Smrg 415848b8605Smrg switch (op) { 416848b8605Smrg case GL_ADD: 417848b8605Smrg if (value != 0.0F) { 418848b8605Smrg accum_scale_or_bias(ctx, value, xpos, ypos, width, height, GL_TRUE); 419848b8605Smrg } 420848b8605Smrg break; 421848b8605Smrg case GL_MULT: 422848b8605Smrg if (value != 1.0F) { 423848b8605Smrg accum_scale_or_bias(ctx, value, xpos, ypos, width, height, GL_FALSE); 424848b8605Smrg } 425848b8605Smrg break; 426848b8605Smrg case GL_ACCUM: 427848b8605Smrg if (value != 0.0F) { 428848b8605Smrg accum_or_load(ctx, value, xpos, ypos, width, height, GL_FALSE); 429848b8605Smrg } 430848b8605Smrg break; 431848b8605Smrg case GL_LOAD: 432848b8605Smrg accum_or_load(ctx, value, xpos, ypos, width, height, GL_TRUE); 433848b8605Smrg break; 434848b8605Smrg case GL_RETURN: 435848b8605Smrg accum_return(ctx, value, xpos, ypos, width, height); 436848b8605Smrg break; 437848b8605Smrg default: 438b8e80941Smrg unreachable("invalid mode in _mesa_Accum()"); 439848b8605Smrg break; 440848b8605Smrg } 441848b8605Smrg} 442848b8605Smrg 443848b8605Smrg 444848b8605Smrgvoid 445848b8605Smrg_mesa_init_accum( struct gl_context *ctx ) 446848b8605Smrg{ 447848b8605Smrg /* Accumulate buffer group */ 448848b8605Smrg ASSIGN_4V( ctx->Accum.ClearColor, 0.0, 0.0, 0.0, 0.0 ); 449848b8605Smrg} 450b8e80941Smrg 451b8e80941Smrg 452b8e80941Smrgvoid GLAPIENTRY 453b8e80941Smrg_mesa_Accum( GLenum op, GLfloat value ) 454b8e80941Smrg{ 455b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 456b8e80941Smrg FLUSH_VERTICES(ctx, 0); 457b8e80941Smrg 458b8e80941Smrg switch (op) { 459b8e80941Smrg case GL_ADD: 460b8e80941Smrg case GL_MULT: 461b8e80941Smrg case GL_ACCUM: 462b8e80941Smrg case GL_LOAD: 463b8e80941Smrg case GL_RETURN: 464b8e80941Smrg /* OK */ 465b8e80941Smrg break; 466b8e80941Smrg default: 467b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glAccum(op)"); 468b8e80941Smrg return; 469b8e80941Smrg } 470b8e80941Smrg 471b8e80941Smrg if (ctx->DrawBuffer->Visual.haveAccumBuffer == 0) { 472b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glAccum(no accum buffer)"); 473b8e80941Smrg return; 474b8e80941Smrg } 475b8e80941Smrg 476b8e80941Smrg if (ctx->DrawBuffer != ctx->ReadBuffer) { 477b8e80941Smrg /* See GLX_SGI_make_current_read or WGL_ARB_make_current_read, 478b8e80941Smrg * or GL_EXT_framebuffer_blit. 479b8e80941Smrg */ 480b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 481b8e80941Smrg "glAccum(different read/draw buffers)"); 482b8e80941Smrg return; 483b8e80941Smrg } 484b8e80941Smrg 485b8e80941Smrg if (ctx->NewState) 486b8e80941Smrg _mesa_update_state(ctx); 487b8e80941Smrg 488b8e80941Smrg if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 489b8e80941Smrg _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 490b8e80941Smrg "glAccum(incomplete framebuffer)"); 491b8e80941Smrg return; 492b8e80941Smrg } 493b8e80941Smrg 494b8e80941Smrg if (ctx->RasterDiscard) 495b8e80941Smrg return; 496b8e80941Smrg 497b8e80941Smrg if (ctx->RenderMode == GL_RENDER) { 498b8e80941Smrg accum(ctx, op, value); 499b8e80941Smrg } 500b8e80941Smrg} 501