Clone of mesa.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

accum.c 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. /* $Id: accum.c,v 1.26 2000/09/26 20:53:53 brianp Exp $ */
  2. /*
  3. * Mesa 3-D graphics library
  4. * Version: 3.5
  5. *
  6. * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a
  9. * copy of this software and associated documentation files (the "Software"),
  10. * to deal in the Software without restriction, including without limitation
  11. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12. * and/or sell copies of the Software, and to permit persons to whom the
  13. * Software is furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included
  16. * in all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  21. * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  22. * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  23. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24. */
  25. #ifdef PC_HEADER
  26. #include "all.h"
  27. #else
  28. #include "glheader.h"
  29. #include "accum.h"
  30. #include "context.h"
  31. #include "mem.h"
  32. #include "masking.h"
  33. #include "span.h"
  34. #include "state.h"
  35. #include "types.h"
  36. #endif
  37. /*
  38. * Accumulation buffer notes
  39. *
  40. * Normally, accumulation buffer values are GLshorts with values in
  41. * [-32767, 32767] which represent floating point colors in [-1, 1],
  42. * as suggested by the OpenGL specification.
  43. *
  44. * We optimize for the common case used for full-scene antialiasing:
  45. * // start with accum buffer cleared to zero
  46. * glAccum(GL_LOAD, w); // or GL_ACCUM the first image
  47. * glAccum(GL_ACCUM, w);
  48. * ...
  49. * glAccum(GL_ACCUM, w);
  50. * glAccum(GL_RETURN, 1.0);
  51. * That is, we start with an empty accumulation buffer and accumulate
  52. * n images, each with weight w = 1/n.
  53. * In this scenario, we can simply store unscaled integer values in
  54. * the accum buffer instead of scaled integers. We'll also keep track
  55. * of the w value so when we do GL_RETURN we simply divide the accumulated
  56. * values by n (=1/w).
  57. * This lets us avoid _many_ int->float->int conversions.
  58. */
  59. #define USE_OPTIMIZED_ACCUM /* enable the optimization */
  60. void
  61. _mesa_alloc_accum_buffer( GLcontext *ctx )
  62. {
  63. GLint n;
  64. if (ctx->DrawBuffer->Accum) {
  65. FREE( ctx->DrawBuffer->Accum );
  66. ctx->DrawBuffer->Accum = NULL;
  67. }
  68. /* allocate accumulation buffer if not already present */
  69. n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height * 4 * sizeof(GLaccum);
  70. ctx->DrawBuffer->Accum = (GLaccum *) MALLOC( n );
  71. if (!ctx->DrawBuffer->Accum) {
  72. /* unable to setup accumulation buffer */
  73. gl_error( ctx, GL_OUT_OF_MEMORY, "glAccum" );
  74. }
  75. #ifdef USE_OPTIMIZED_ACCUM
  76. ctx->IntegerAccumMode = GL_TRUE;
  77. #else
  78. ctx->IntegerAccumMode = GL_FALSE;
  79. #endif
  80. ctx->IntegerAccumScaler = 0.0;
  81. }
  82. void
  83. _mesa_ClearAccum( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha )
  84. {
  85. GET_CURRENT_CONTEXT(ctx);
  86. ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glAccum");
  87. ctx->Accum.ClearColor[0] = CLAMP( red, -1.0, 1.0 );
  88. ctx->Accum.ClearColor[1] = CLAMP( green, -1.0, 1.0 );
  89. ctx->Accum.ClearColor[2] = CLAMP( blue, -1.0, 1.0 );
  90. ctx->Accum.ClearColor[3] = CLAMP( alpha, -1.0, 1.0 );
  91. }
  92. /*
  93. * This is called when we fall out of optimized/unscaled accum buffer mode.
  94. * That is, we convert each unscaled accum buffer value into a scaled value
  95. * representing the range[-1, 1].
  96. */
  97. static void rescale_accum( GLcontext *ctx )
  98. {
  99. const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height * 4;
  100. const GLfloat fChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
  101. const GLfloat s = ctx->IntegerAccumScaler * (32767.0 / fChanMax);
  102. GLaccum *accum = ctx->DrawBuffer->Accum;
  103. GLuint i;
  104. assert(ctx->IntegerAccumMode);
  105. assert(accum);
  106. for (i = 0; i < n; i++) {
  107. accum[i] = (GLaccum) (accum[i] * s);
  108. }
  109. ctx->IntegerAccumMode = GL_FALSE;
  110. }
  111. void
  112. _mesa_Accum( GLenum op, GLfloat value )
  113. {
  114. GET_CURRENT_CONTEXT(ctx);
  115. GLuint xpos, ypos, width, height, width4;
  116. GLfloat acc_scale;
  117. GLubyte rgba[MAX_WIDTH][4];
  118. const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask);
  119. const GLint iChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
  120. const GLfloat fChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
  121. ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glAccum");
  122. if (ctx->Visual.AccumRedBits == 0 || ctx->DrawBuffer != ctx->ReadBuffer) {
  123. gl_error(ctx, GL_INVALID_OPERATION, "glAccum");
  124. return;
  125. }
  126. if (!ctx->DrawBuffer->Accum) {
  127. _mesa_warning(ctx, "Calling glAccum() without an accumulation buffer (low memory?)");
  128. return;
  129. }
  130. if (sizeof(GLaccum)==1) {
  131. acc_scale = 127.0;
  132. }
  133. else if (sizeof(GLaccum)==2) {
  134. acc_scale = 32767.0;
  135. }
  136. else {
  137. /* sizeof(GLaccum) > 2 (Cray) */
  138. acc_scale = (float) SHRT_MAX;
  139. }
  140. if (ctx->NewState)
  141. gl_update_state( ctx );
  142. /* Determine region to operate upon. */
  143. if (ctx->Scissor.Enabled) {
  144. xpos = ctx->Scissor.X;
  145. ypos = ctx->Scissor.Y;
  146. width = ctx->Scissor.Width;
  147. height = ctx->Scissor.Height;
  148. }
  149. else {
  150. /* whole window */
  151. xpos = 0;
  152. ypos = 0;
  153. width = ctx->DrawBuffer->Width;
  154. height = ctx->DrawBuffer->Height;
  155. }
  156. width4 = 4 * width;
  157. switch (op) {
  158. case GL_ADD:
  159. if (value != 0.0F) {
  160. const GLaccum intVal = (GLaccum) (value * acc_scale);
  161. GLuint j;
  162. /* Leave optimized accum buffer mode */
  163. if (ctx->IntegerAccumMode)
  164. rescale_accum(ctx);
  165. for (j = 0; j < height; j++) {
  166. GLaccum * acc = ctx->DrawBuffer->Accum + ypos * width4 + 4 * xpos;
  167. GLuint i;
  168. for (i = 0; i < width4; i++) {
  169. acc[i] += intVal;
  170. }
  171. ypos++;
  172. }
  173. }
  174. break;
  175. case GL_MULT:
  176. if (value != 1.0F) {
  177. GLuint j;
  178. /* Leave optimized accum buffer mode */
  179. if (ctx->IntegerAccumMode)
  180. rescale_accum(ctx);
  181. for (j = 0; j < height; j++) {
  182. GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + 4 * xpos;
  183. GLuint i;
  184. for (i = 0; i < width4; i++) {
  185. acc[i] = (GLaccum) ( (GLfloat) acc[i] * value );
  186. }
  187. ypos++;
  188. }
  189. }
  190. break;
  191. case GL_ACCUM:
  192. if (value == 0.0F)
  193. return;
  194. (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
  195. ctx->Pixel.DriverReadBuffer );
  196. /* May have to leave optimized accum buffer mode */
  197. if (ctx->IntegerAccumScaler == 0.0 && value > 0.0 && value <= 1.0)
  198. ctx->IntegerAccumScaler = value;
  199. if (ctx->IntegerAccumMode && value != ctx->IntegerAccumScaler)
  200. rescale_accum(ctx);
  201. if (ctx->IntegerAccumMode) {
  202. /* simply add integer color values into accum buffer */
  203. GLuint j;
  204. GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
  205. assert(ctx->IntegerAccumScaler > 0.0);
  206. assert(ctx->IntegerAccumScaler <= 1.0);
  207. for (j = 0; j < height; j++) {
  208. GLuint i, i4;
  209. gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
  210. for (i = i4 = 0; i < width; i++, i4+=4) {
  211. acc[i4+0] += rgba[i][RCOMP];
  212. acc[i4+1] += rgba[i][GCOMP];
  213. acc[i4+2] += rgba[i][BCOMP];
  214. acc[i4+3] += rgba[i][ACOMP];
  215. }
  216. acc += width4;
  217. ypos++;
  218. }
  219. }
  220. else {
  221. /* scaled integer accum buffer */
  222. const GLfloat rscale = value * acc_scale / fChanMax;
  223. const GLfloat gscale = value * acc_scale / fChanMax;
  224. const GLfloat bscale = value * acc_scale / fChanMax;
  225. const GLfloat ascale = value * acc_scale / fChanMax;
  226. GLuint j;
  227. for (j=0;j<height;j++) {
  228. GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
  229. GLuint i;
  230. gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
  231. for (i=0;i<width;i++) {
  232. *acc += (GLaccum) ( (GLfloat) rgba[i][RCOMP] * rscale ); acc++;
  233. *acc += (GLaccum) ( (GLfloat) rgba[i][GCOMP] * gscale ); acc++;
  234. *acc += (GLaccum) ( (GLfloat) rgba[i][BCOMP] * bscale ); acc++;
  235. *acc += (GLaccum) ( (GLfloat) rgba[i][ACOMP] * ascale ); acc++;
  236. }
  237. ypos++;
  238. }
  239. }
  240. /* restore read buffer = draw buffer (the default) */
  241. (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
  242. ctx->Color.DriverDrawBuffer );
  243. break;
  244. case GL_LOAD:
  245. (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
  246. ctx->Pixel.DriverReadBuffer );
  247. /* This is a change to go into optimized accum buffer mode */
  248. if (value > 0.0 && value <= 1.0) {
  249. #ifdef USE_OPTIMIZED_ACCUM
  250. ctx->IntegerAccumMode = GL_TRUE;
  251. #else
  252. ctx->IntegerAccumMode = GL_FALSE;
  253. #endif
  254. ctx->IntegerAccumScaler = value;
  255. }
  256. else {
  257. ctx->IntegerAccumMode = GL_FALSE;
  258. ctx->IntegerAccumScaler = 0.0;
  259. }
  260. if (ctx->IntegerAccumMode) {
  261. /* just copy values into accum buffer */
  262. GLuint j;
  263. GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
  264. assert(ctx->IntegerAccumScaler > 0.0);
  265. assert(ctx->IntegerAccumScaler <= 1.0);
  266. for (j = 0; j < height; j++) {
  267. GLuint i, i4;
  268. gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
  269. for (i = i4 = 0; i < width; i++, i4 += 4) {
  270. acc[i4+0] = rgba[i][RCOMP];
  271. acc[i4+1] = rgba[i][GCOMP];
  272. acc[i4+2] = rgba[i][BCOMP];
  273. acc[i4+3] = rgba[i][ACOMP];
  274. }
  275. acc += width4;
  276. ypos++;
  277. }
  278. }
  279. else {
  280. /* scaled integer accum buffer */
  281. const GLfloat rscale = value * acc_scale / fChanMax;
  282. const GLfloat gscale = value * acc_scale / fChanMax;
  283. const GLfloat bscale = value * acc_scale / fChanMax;
  284. const GLfloat ascale = value * acc_scale / fChanMax;
  285. const GLfloat d = 3.0 / acc_scale;
  286. GLuint i, j;
  287. for (j = 0; j < height; j++) {
  288. GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
  289. gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
  290. for (i=0;i<width;i++) {
  291. *acc++ = (GLaccum) ((GLfloat) rgba[i][RCOMP] * rscale + d);
  292. *acc++ = (GLaccum) ((GLfloat) rgba[i][GCOMP] * gscale + d);
  293. *acc++ = (GLaccum) ((GLfloat) rgba[i][BCOMP] * bscale + d);
  294. *acc++ = (GLaccum) ((GLfloat) rgba[i][ACOMP] * ascale + d);
  295. }
  296. ypos++;
  297. }
  298. }
  299. /* restore read buffer = draw buffer (the default) */
  300. (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
  301. ctx->Color.DriverDrawBuffer );
  302. break;
  303. case GL_RETURN:
  304. /* May have to leave optimized accum buffer mode */
  305. if (ctx->IntegerAccumMode && value != 1.0)
  306. rescale_accum(ctx);
  307. if (ctx->IntegerAccumMode && ctx->IntegerAccumScaler > 0) {
  308. /* build lookup table to avoid many floating point multiplies */
  309. static GLchan multTable[32768];
  310. static GLfloat prevMult = 0.0;
  311. const GLfloat mult = ctx->IntegerAccumScaler;
  312. const GLint max = MIN2((GLint) (256 / mult), 32767);
  313. GLuint j;
  314. if (mult != prevMult) {
  315. for (j = 0; j < max; j++)
  316. multTable[j] = (GLint) ((GLfloat) j * mult + 0.5F);
  317. prevMult = mult;
  318. }
  319. assert(ctx->IntegerAccumScaler > 0.0);
  320. assert(ctx->IntegerAccumScaler <= 1.0);
  321. for (j = 0; j < height; j++) {
  322. const GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos*4;
  323. GLuint i, i4;
  324. for (i = i4 = 0; i < width; i++, i4 += 4) {
  325. ASSERT(acc[i4+0] < max);
  326. ASSERT(acc[i4+1] < max);
  327. ASSERT(acc[i4+2] < max);
  328. ASSERT(acc[i4+3] < max);
  329. rgba[i][RCOMP] = multTable[acc[i4+0]];
  330. rgba[i][GCOMP] = multTable[acc[i4+1]];
  331. rgba[i][BCOMP] = multTable[acc[i4+2]];
  332. rgba[i][ACOMP] = multTable[acc[i4+3]];
  333. }
  334. if (colorMask != 0xffffffff) {
  335. _mesa_mask_rgba_span( ctx, width, xpos, ypos, rgba );
  336. }
  337. (*ctx->Driver.WriteRGBASpan)( ctx, width, xpos, ypos,
  338. (const GLubyte (*)[4])rgba, NULL );
  339. ypos++;
  340. }
  341. }
  342. else {
  343. const GLfloat rscale = value / acc_scale * fChanMax;
  344. const GLfloat gscale = value / acc_scale * fChanMax;
  345. const GLfloat bscale = value / acc_scale * fChanMax;
  346. const GLfloat ascale = value / acc_scale * fChanMax;
  347. GLuint i, j;
  348. for (j=0;j<height;j++) {
  349. const GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos*4;
  350. for (i=0;i<width;i++) {
  351. GLint r, g, b, a;
  352. r = (GLint) ( (GLfloat) (*acc++) * rscale + 0.5F );
  353. g = (GLint) ( (GLfloat) (*acc++) * gscale + 0.5F );
  354. b = (GLint) ( (GLfloat) (*acc++) * bscale + 0.5F );
  355. a = (GLint) ( (GLfloat) (*acc++) * ascale + 0.5F );
  356. rgba[i][RCOMP] = CLAMP( r, 0, iChanMax );
  357. rgba[i][GCOMP] = CLAMP( g, 0, iChanMax );
  358. rgba[i][BCOMP] = CLAMP( b, 0, iChanMax );
  359. rgba[i][ACOMP] = CLAMP( a, 0, iChanMax );
  360. }
  361. if (colorMask != 0xffffffff) {
  362. _mesa_mask_rgba_span( ctx, width, xpos, ypos, rgba );
  363. }
  364. (*ctx->Driver.WriteRGBASpan)( ctx, width, xpos, ypos,
  365. (const GLubyte (*)[4])rgba, NULL );
  366. ypos++;
  367. }
  368. }
  369. break;
  370. default:
  371. gl_error( ctx, GL_INVALID_ENUM, "glAccum" );
  372. }
  373. }
  374. /*
  375. * Clear the accumulation Buffer.
  376. */
  377. void
  378. _mesa_clear_accum_buffer( GLcontext *ctx )
  379. {
  380. GLuint buffersize;
  381. GLfloat acc_scale;
  382. if (ctx->Visual.AccumRedBits==0) {
  383. /* No accumulation buffer! */
  384. return;
  385. }
  386. if (sizeof(GLaccum)==1) {
  387. acc_scale = 127.0;
  388. }
  389. else if (sizeof(GLaccum)==2) {
  390. acc_scale = 32767.0;
  391. }
  392. else {
  393. /* sizeof(GLaccum) > 2 (Cray) */
  394. acc_scale = (float) SHRT_MAX;
  395. }
  396. /* number of pixels */
  397. buffersize = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
  398. if (!ctx->DrawBuffer->Accum) {
  399. /* try to alloc accumulation buffer */
  400. ctx->DrawBuffer->Accum = (GLaccum *)
  401. MALLOC( buffersize * 4 * sizeof(GLaccum) );
  402. }
  403. if (ctx->DrawBuffer->Accum) {
  404. if (ctx->Scissor.Enabled) {
  405. /* Limit clear to scissor box */
  406. GLaccum r, g, b, a;
  407. GLint i, j;
  408. GLint width, height;
  409. GLaccum *row;
  410. r = (GLaccum) (ctx->Accum.ClearColor[0] * acc_scale);
  411. g = (GLaccum) (ctx->Accum.ClearColor[1] * acc_scale);
  412. b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale);
  413. a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale);
  414. /* size of region to clear */
  415. width = 4 * (ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin);
  416. height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin;
  417. /* ptr to first element to clear */
  418. row = ctx->DrawBuffer->Accum
  419. + 4 * (ctx->DrawBuffer->Ymin * ctx->DrawBuffer->Width
  420. + ctx->DrawBuffer->Xmin);
  421. for (j=0;j<height;j++) {
  422. for (i=0;i<width;i+=4) {
  423. row[i+0] = r;
  424. row[i+1] = g;
  425. row[i+2] = b;
  426. row[i+3] = a;
  427. }
  428. row += 4 * ctx->DrawBuffer->Width;
  429. }
  430. }
  431. else {
  432. /* clear whole buffer */
  433. if (ctx->Accum.ClearColor[0]==0.0 &&
  434. ctx->Accum.ClearColor[1]==0.0 &&
  435. ctx->Accum.ClearColor[2]==0.0 &&
  436. ctx->Accum.ClearColor[3]==0.0) {
  437. /* Black */
  438. BZERO( ctx->DrawBuffer->Accum, buffersize * 4 * sizeof(GLaccum) );
  439. }
  440. else {
  441. /* Not black */
  442. GLaccum *acc, r, g, b, a;
  443. GLuint i;
  444. acc = ctx->DrawBuffer->Accum;
  445. r = (GLaccum) (ctx->Accum.ClearColor[0] * acc_scale);
  446. g = (GLaccum) (ctx->Accum.ClearColor[1] * acc_scale);
  447. b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale);
  448. a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale);
  449. for (i=0;i<buffersize;i++) {
  450. *acc++ = r;
  451. *acc++ = g;
  452. *acc++ = b;
  453. *acc++ = a;
  454. }
  455. }
  456. }
  457. /* update optimized accum state vars */
  458. if (ctx->Accum.ClearColor[0] == 0.0 && ctx->Accum.ClearColor[1] == 0.0 &&
  459. ctx->Accum.ClearColor[2] == 0.0 && ctx->Accum.ClearColor[3] == 0.0) {
  460. #ifdef USE_OPTIMIZED_ACCUM
  461. ctx->IntegerAccumMode = GL_TRUE;
  462. #else
  463. ctx->IntegerAccumMode = GL_FALSE;
  464. #endif
  465. ctx->IntegerAccumScaler = 0.0; /* denotes empty accum buffer */
  466. }
  467. else {
  468. ctx->IntegerAccumMode = GL_FALSE;
  469. }
  470. }
  471. }