diff options
author | Bernie Innocenti <bernie@codewiz.org> | 2010-05-03 21:53:47 (GMT) |
---|---|---|
committer | Bernie Innocenti <bernie@codewiz.org> | 2010-05-03 21:53:47 (GMT) |
commit | 1030dc837b10a03a02a85d5504cbeec168ce49e2 (patch) | |
tree | 698eefa87ac437deaf36a4141b326f8ce7986692 /src/engine/docalc.c |
Import XaoS r489 (trunk after version 3.5)
Diffstat (limited to 'src/engine/docalc.c')
-rw-r--r-- | src/engine/docalc.c | 790 |
1 files changed, 790 insertions, 0 deletions
diff --git a/src/engine/docalc.c b/src/engine/docalc.c new file mode 100644 index 0000000..9cacf27 --- /dev/null +++ b/src/engine/docalc.c @@ -0,0 +1,790 @@ + +/* Hello reader! + + * Are you sure you want read this? Its very cryptic and strange code. YOU + * HAVE BEEN WARNED! Its purpose is to genereate as fast as possible + * calculation loops for various formulas/algorithms. It uses lots of + * coprocesor magic. It is included from formulas.c + */ + +#ifndef VARIABLES /*supply defaultd values */ +#define VARIABLES +#endif +#ifndef PRETEST +#define PRETEST 0 +#endif +#ifndef INIT +#define INIT +#endif +#ifndef POSTCALC +#define POSTCALC +#endif +#ifndef PRESMOOTH +#define PRESMOOTH zre=rp+ip +#endif +#ifndef UFORMULA +#define UFORMULA FORMULA +#endif +#ifndef UEND +#define UEND +#endif +#ifndef SAVE +#define SAVE +#endif +#ifndef SAVEVARIABLES +#define SAVEVARIABLES +#endif +#ifndef RESTORE +#define RESTORE +#endif +#ifndef RANGE +#define RANGE 2 +#endif +#ifndef __GNUC__ +#undef USEHACKS +#endif +#ifndef __i386__ +#undef USEHACKS +#endif +#ifdef NOASSEMBLY +#undef USEHACKS +#endif + +/* Prepare main loop */ +#ifndef NSFORMULALOOP +#define NSFORMULALOOP(iter) \ + do \ + { /*try first 8 iterations */ \ + FORMULA; \ + iter--; \ + } \ + while (BTEST && iter) +#endif +#ifndef SFORMULALOOP +#define SFORMULALOOP(iter) \ + do \ + { /*try first 8 iterations */ \ + SAVEZMAG; \ + FORMULA; \ + iter--; \ + } \ + while (BTEST && iter) +#endif +#ifndef FORMULALOOP +#ifdef SMOOTHMODE +#define FORMULALOOP SFORMULALOOP +#else +#define FORMULALOOP NSFORMULALOOP +#endif +#endif + +#ifdef USEHACKS +#ifdef RPIP +#define I386HACK1 __asm__ ("#HACK1" : \ + : \ + "m" (szre), \ + "m" (szim) \ + ); +#define I386HACK __asm__ ("#HACK" : \ + : \ + "f" (zre), \ + "f" (zim) \ + ); +#else +#define I386HACK __asm__ ("#HACK" : \ + : \ + "f" (zre), \ + "f" (zim) \ + ); +#endif +#else +#define I386HACK +#define I386HACK1 +#endif + +#ifdef SMOOTHMODE +#ifdef CUSTOMSAVEZMAG +#define SAVEZMAG CUSTOMSAVEZMAG; +#else +#define SAVEZMAG szmag=rp+ip; +#endif +#else +#define SAVEZMAG +#endif + +#ifdef UNCOMPRESS +/*uncompressed version of loop */ +#ifdef SMOOTHMODE +static unsigned int FUNCTYPE +SCALC(register number_t zre, register number_t zim, register number_t pre, + register number_t pim) +CONSTF REGISTERS(3); +REGISTERS(3) +static unsigned int FUNCTYPE +SCALC(register number_t zre, register number_t zim, + register number_t pre, register number_t pim) +#else +static unsigned int FUNCTYPE +CALC(register number_t zre, register number_t zim, register number_t pre, + register number_t pim) +CONSTF REGISTERS(3); +REGISTERS(3) +static unsigned +CALC(register number_t zre, register number_t zim, + register number_t pre, register number_t pim) +#endif +{ + register unsigned int iter = cfractalc.maxiter; + number_t szre = 0, szim = 0; +#ifdef RPIP + register number_t rp = 0, ip; +#endif +#ifdef SMOOTHMODE + number_t szmag = 0; +#endif + SAVEVARIABLES VARIABLES; + INIT; + if (PRETEST) + iter = 0; + else { +#ifdef RPIP + rp = zre * zre; + ip = zim * zim; +#endif + if (iter < 16) { + I386HACK1; + I386HACK; + + /*try first 8 iterations */ + if (BTEST && iter) { + FORMULALOOP(iter); + } + /* + while (BTEST && iter) + { + SAVEZMAG; + FORMULA; + iter--; + } */ + } else { + iter = 8 + (cfractalc.maxiter & 7); + I386HACK1; + I386HACK; + + /*try first 8 iterations */ + if (BTEST && iter) { + FORMULALOOP(iter); + } + /* + while (BTEST && iter) + { + SAVEZMAG; + FORMULA; + iter--; + } */ + if (BTEST) { + iter = (cfractalc.maxiter - 8) & (~7); + iter >>= 3; + I386HACK1; + I386HACK; /*do next 8 iteration w/o out of bounds checking */ + do { + /*hmm..we are probably in some deep area. */ + szre = zre; /*save current possition */ + szim = zim; + SAVE; + UFORMULA; + UFORMULA; + UFORMULA; + UFORMULA; + UFORMULA; + UFORMULA; + UFORMULA; + UFORMULA; + UEND; + iter--; + } + while (BTEST && iter); + if (!(BTEST)) { /*we got out of bounds */ + iter <<= 3; + iter += 8; /*restore saved possition */ + RESTORE; + zre = szre; + zim = szim; +#ifdef RPIP + rp = zre * zre; + ip = zim * zim; +#endif + I386HACK1; + I386HACK; + FORMULALOOP(iter); + /* + do + { + SAVEZMAG + FORMULA; + iter--; + } + while (BTEST && iter); */ + } + } else + iter += cfractalc.maxiter - 8 - (cfractalc.maxiter & 7); + } + } +#ifdef SMOOTHMODE + if (iter) + SMOOTHOUTPUT(); + POSTCALC; + iter = cfractalc.maxiter - iter; + INOUTPUT(); +#else + POSTCALC; + iter = cfractalc.maxiter - iter; + OUTPUT(); +#endif +} +#else +#ifdef SMOOTHMODE +static unsigned int FUNCTYPE +SCALC(register number_t zre, register number_t zim, register number_t pre, + register number_t pim) +CONSTF REGISTERS(3); +REGISTERS(3) +static unsigned int FUNCTYPE +SCALC(register number_t zre, register number_t zim, + register number_t pre, register number_t pim) +#else +static unsigned int FUNCTYPE +CALC(register number_t zre, register number_t zim, register number_t pre, + register number_t pim) +CONSTF REGISTERS(3); +REGISTERS(3) +static unsigned int FUNCTYPE +CALC(register number_t zre, register number_t zim, + register number_t pre, register number_t pim) +#endif +{ + register unsigned int iter = cfractalc.maxiter /*& (~(int) 3) */ ; +#ifdef RPIP + register number_t rp, ip; +#endif +#ifdef SMOOTHMODE + number_t szmag = 0; +#endif + VARIABLES; + INIT; + if (PRETEST) + iter = 0; + else { +#ifdef RPIP + rp = zre * zre; + ip = zim * zim; +#endif + if (BTEST && iter) { + FORMULALOOP(iter); + } + /* + while (BTEST && iter) + { + I386HACK; + SAVEZMAG + FORMULA; + iter--; + + } */ + } +#ifdef SMOOTHMODE + if (iter) + SMOOTHOUTPUT(); + POSTCALC; + iter = cfractalc.maxiter - iter; + INOUTPUT(); +#else + POSTCALC; + iter = cfractalc.maxiter - iter; + OUTPUT(); +#endif +} +#endif + + +/*F. : Periodicity checking rountines. (16-02-97) + All comments preceded by F. are mine (Fabrice Premel premelfa@etu.utc.fr). + Tried to make code as efficient as possible. + Next to do is convert lim in a variable that would be updated sometimes + I'll try to make here a short explanation on periodicity checking : + first, we'll define 2 variables : whentosave and whenincsave, which are, respectively, + a measure of when we have to update saved values to be checked, and when to increase + interval between 2 updates, as if they're too close, we'll miss large periods. + We save Z at the beginning, and then we compare each new iteration with this Z, and if naerly + equal, we declare the suite to be periodic. + When ( iter mod whentosave ) == 0, we store a new value, and we repeat. + + UNCOMPRESSed form is just an extension, with careful that if we only check whentosave + all 8 iterations, number of iterations must be well set at the begining.This is + done by adding a (iter&7) in the while statement preceeding then uncompressed + calculation. */ + +/*F. : This is from then lim factor that depends all periodicity check spped : the bigger it is, the faster we + can detect periodicity, but the bigger it is, the more we can introduce errors. + I suggest a value of (maxx-minx)/(double)getmaxx for a classic Mandelbrot Set, + and maybe a lesser value for an extra power Mandelbrot. + But this should be calculated outter from here (ie each frame, for example), to avoid + new calculs */ +#ifdef PERI +#define PCHECK (abs_less_than(r1 - zre, cfractalc.periodicity_limit) && abs_less_than(s1 - zim, cfractalc.periodicity_limit)) + +#ifndef UNCOMPRESS + +#ifdef SMOOTHMODE +static unsigned int FUNCTYPE +SPERI(register number_t zre, register number_t zim, register number_t pre, + register number_t pim) +CONSTF REGISTERS(3); +REGISTERS(3) +static unsigned int FUNCTYPE +SPERI(register number_t zre, register number_t zim, + register number_t pre, register number_t pim) +#else +static unsigned int FUNCTYPE +PERI(register number_t zre, register number_t zim, register number_t pre, + register number_t pim) +CONSTF REGISTERS(3); +REGISTERS(3) +static unsigned int FUNCTYPE +PERI(register number_t zre, register number_t zim, + register number_t pre, register number_t pim) +#endif +{ + register unsigned int iter = + cfractalc.maxiter /*& (~(int) 3) */ , iter1 = + 8; + register number_t r1, s1; + int whensavenew, whenincsave; +#ifdef RPIP + register number_t rp, ip; +#endif +#ifdef SMOOTHMODE + number_t szmag = 0; +#endif + VARIABLES; + INIT; + if (PRETEST) + iter = 0; + else { +#ifdef RPIP + rp = zre * zre; + ip = zim * zim; +#endif + I386HACK; + if (iter < iter1) + iter1 = iter, iter = 8; + + /*H. : do first few iterations w/o checking */ + if (BTEST && iter1) { + FORMULALOOP(iter1); + } + /* + while (BTEST && iter1) + { + SAVEZMAG; + FORMULA; + iter1--; + } */ + if (iter1) { + if (iter >= 8) + iter -= 8 - iter1; + goto end; + } + if (iter <= 8) { + iter = iter1; + } else { + iter -= 8; + r1 = zre; + s1 = zim; + whensavenew = 3; /*You should adapt theese values */ + /*F. : We should always define whensavenew as 2^N-1, so we could use a AND instead of % */ + + whenincsave = 10; + /*F. : problem is that after deep zooming, peiodicity is never detected early, cause is is + quite slow before going in a periodic loop. + So, we should start checking periodicity only after some times */ + while (BTEST && iter) { + SAVEZMAG; + FORMULA; + if ((iter & whensavenew) == 0) { /*F. : changed % to & */ + r1 = zre; + s1 = zim; + whenincsave--; + if (!whenincsave) { + whensavenew = ((whensavenew + 1) << 1) - 1; /*F. : Changed to define a new AND mask */ + whenincsave = 10; + } + } else { + if (PCHECK) { + PERIINOUTPUT(); + } + } + iter--; + + } + } + } + end: +#ifdef SMOOTHMODE + if (iter) + SMOOTHOUTPUT(); + POSTCALC; + iter = cfractalc.maxiter - iter; + INOUTPUT(); +#else + POSTCALC; + iter = cfractalc.maxiter - iter; + OUTPUT(); +#endif +} + +#else + +/*F. : UNCOMPRESSed version. Note that whensavenew+1 should be a multiple of 8, else periodicity won't be able + to detect anything. */ +/*F. : this macros definitions are really strange, but after a while, it's good */ + +#ifdef SMOOTHMODE +static unsigned int FUNCTYPE +SPERI(register number_t zre, register number_t zim, register number_t pre, + register number_t pim) +CONSTF REGISTERS(3); +REGISTERS(3) +static unsigned int FUNCTYPE +SPERI(register number_t zre, register number_t zim, + register number_t pre, register number_t pim) +#else +static unsigned int FUNCTYPE +PERI(register number_t zre, register number_t zim, register number_t pre, + register number_t pim) +CONSTF REGISTERS(3); +REGISTERS(3) +static unsigned int FUNCTYPE +PERI(register number_t zre, register number_t zim, + register number_t pre, register number_t pim) +#endif +{ + register unsigned int iter = cfractalc.maxiter /*& (~(int) 3) */ ; + register number_t r1 = zre, s1 = zim; + number_t szre = 0, szim = 0; /*F. : Didn't declared register, cause they are few used */ + unsigned int whensavenew, whenincsave; +#ifdef RPIP + register number_t rp = 0, ip; +#endif +#ifdef SMOOTHMODE + number_t szmag = 0; +#endif + SAVEVARIABLES VARIABLES; + INIT; + if (PRETEST) + iter = 0; + else { + if (cfractalc.maxiter <= 16) { + I386HACK1; + /*I386HACK; */ +#ifdef RPIP + rp = zre * zre; + ip = zim * zim; +#endif + /*F. : Added iter&7 to be sure we'll be on a 8 multiple */ + if (BTEST && iter) { + FORMULALOOP(iter); + } + /* + while (BTEST && iter) + { + SAVEZMAG + FORMULA; + iter--; + } */ + } else { + whensavenew = 7; /*You should adapt theese values */ + /*F. : We should always define whensavenew as 2^N-1, so we could use a AND instead of % */ + + whenincsave = 10; +#ifdef RPIP + rp = zre * zre; + ip = zim * zim; +#endif + /*F. : problem is that after deep zooming, peiodicity is never detected early, cause is is + quite slow before going in a periodic loop. + So, we should start checking periodicity only after some times */ + I386HACK1; + /*I386HACK; */ + iter = 8 + (cfractalc.maxiter & 7); + while (BTEST && iter) { /*F. : Added iter&7 to be sure we'll be on a 8 multiple */ + SAVEZMAG FORMULA; + iter--; + } + if (BTEST) { /*F. : BTEST is calculed two times here, isn't it ? */ + /*H. : No gcc is clever and adds test to the end :) */ + iter = (cfractalc.maxiter - 8) & (~7); + do { + szre = zre, szim = zim; + SAVE; + SAVEZMAG + /*I386HACK; */ + I386HACK1; + FORMULA; /*F. : Calculate one time */ + if (PCHECK) + goto periodicity; + FORMULA; + if (PCHECK) + goto periodicity; + FORMULA; + if (PCHECK) + goto periodicity; + FORMULA; + if (PCHECK) + goto periodicity; + FORMULA; + if (PCHECK) + goto periodicity; + FORMULA; + if (PCHECK) + goto periodicity; + FORMULA; + if (PCHECK) + goto periodicity; + FORMULA; + if (PCHECK) + goto periodicity; + iter -= 8; + /*F. : We only test this now, as it can't be true before */ + if ((iter & whensavenew) == 0) { /*F. : changed % to & */ + r1 = zre, s1 = zim; /*F. : Save new values */ + whenincsave--; + if (!whenincsave) { + whensavenew = ((whensavenew + 1) << 1) - 1; /*F. : Changed to define a new AND mask */ + whenincsave = 10; /*F. : Start back */ + } + } + } + while (BTEST && iter); + if (!BTEST) { /*we got out of bounds */ + iter += 8; /*restore saved possition */ + RESTORE; + zre = szre; + zim = szim; +#ifdef RPIP + rp = zre * zre; + ip = zim * zim; +#endif + I386HACK1; + /*I386HACK; */ + FORMULALOOP(iter); + /* + do + { + SAVEZMAG + FORMULA; + iter--; + } + while (BTEST && iter); */ + } + } else + iter += cfractalc.maxiter - 8 - (cfractalc.maxiter & 7); + } + } +#ifdef SMOOTHMODE + if (iter) + SMOOTHOUTPUT(); + POSTCALC; + iter = cfractalc.maxiter - iter; + INOUTPUT(); +#else + POSTCALC; + iter = cfractalc.maxiter - iter; + OUTPUT(); +#endif + periodicity: + PERIINOUTPUT(); +} + +/*else uncompress */ +#endif + +/*endif PERI */ +#undef PCHECK +#endif + +#ifndef SMOOTHMODE +#ifdef JULIA +static void +JULIA(struct image *image, register number_t pre, register number_t pim) +{ + int i, i1, i2, j, x, y; + unsigned char iter, itmp2, itmp; + number_t rp = 0, ip = 0; + register number_t zre, zim, im, xdelta, ydelta, range, rangep; + number_t xstep, ystep; + unsigned char *queue[QMAX]; + unsigned char **qptr; + unsigned char *addr, **addr1 = image->currlines; +#ifdef STATISTICS + int guessed = 0, unguessed = 0, iters = 0; +#endif + VARIABLES; + range = (number_t) RANGE; + rangep = range * range; + + xdelta = image->width / (RMAX - RMIN); + ydelta = image->height / (IMAX - IMIN); + xstep = (RMAX - RMIN) / image->width; + ystep = (IMAX - IMIN) / image->height; + init_julia(image, rangep, range, xdelta, ystep); + for (i2 = 0; i2 < 2; i2++) + for (i1 = 0; i1 < image->height; i1++) { + if (i1 % 2) + i = image->height / 2 - i1 / 2; + else + i = image->height / 2 + i1 / 2 + 1; + if (i >= image->height) + continue; + im = IMIN + (i + 0.5) * ystep; + for (j = (i + i2) & 1; j < image->width; j += 2) { + STAT(total2++); + addr = addr1[i] + j; + if (*addr != NOT_CALCULATED) + continue; + x = j; + y = i; + if (y > 0 && y < image->height - 1 && *(addr + 1) && + x > 0 && x < image->width - 1) { + if ((iter = *(addr + 1)) != NOT_CALCULATED + && iter == *(addr - 1) && iter == addr1[y - 1][x] + && iter == addr1[y + 1][x]) { + *addr = *(addr + 1); + continue; + } + } + zim = im; + zre = RMIN + (j + 0.5) * xstep; + iter = (unsigned char) 0; + qptr = queue; + ip = (zim * zim); + rp = (zre * zre); + INIT; + while (1) { + if (*addr != NOT_CALCULATED +#ifdef SAG + && (*addr == INPROCESS + || (*addr != (unsigned char) 1 + && (itmp2 = *(addr + 1)) != NOT_CALCULATED + && ((itmp2 != (itmp = *(addr - 1)) + && itmp != NOT_CALCULATED) + || (itmp2 != + (itmp = *((addr1[y + 1]) + x)) + && itmp != NOT_CALCULATED) + || (itmp2 != + (itmp = *((addr1[y - 1]) + x)) + && itmp != NOT_CALCULATED)))) +#endif + ) { + if (*addr == INPROCESS || *addr == INSET) { + *qptr = addr; + qptr++; + STAT(guessed++); + goto inset; + } + STAT(guessed++); + iter = *addr; + goto outset; + } +#ifdef STATISTICS + if (*addr != NOT_CALCULATED) + unguessed++; +#endif + if (*addr != INPROCESS) { + *qptr = addr; + qptr++; + *addr = INPROCESS; + if (qptr >= queue + QMAX) + goto inset; + } + STAT(iters++); + FORMULA; + ip = (zim * zim); + rp = (zre * zre); + if (greater_than(rp + ip, RANGE) || !(BTEST)) + goto outset; + x = (int) ((zre - RMIN) * xdelta); + y = (int) ((zim - IMIN) * ydelta); + addr = addr1[y] + x; + if ((itmp = *(addr + 1)) != NOT_CALCULATED + && itmp == *(addr - 1) && itmp == addr1[y - 1][x] + && itmp == addr1[y + 1][x]) { + *addr = *(addr + 1); + } + } + inset: + while (qptr > queue) { + qptr--; + **qptr = INSET; + } + continue; + outset: + y = image->palette->size; + while (qptr > queue) { + qptr--; + iter++; + if ((int) iter >= y) + iter = (unsigned char) 1; + **qptr = iter; + } + } + } +#ifdef STATISTICS + printf("guessed %i, unguessed %i, iterations %i\n", guessed, unguessed, + iters); + guessed2 += guessed; + unguessed2 += unguessed; + iters2 += iters; +#endif +} +#endif +#endif + +#undef FORMULALOOP +#undef PCHECK +#undef I386HACK +#undef I386HACK1 +#undef SAVEZMAG +#ifndef SMOOTHMODE +#ifdef SMOOTH +#define SMOOTHMODE +#include "docalc.c" +#endif +#endif + +/*cleanup for next formula */ +#undef NSFORMULALOOP +#undef SFORMULALOOP +#undef PRESMOOTH +#undef SMOOTH +#undef SMOOTHMODE +#undef RANGE +#undef JULIA +#undef PERI +#undef SPERI +#undef INIT +#undef VARIABLES +#undef PRETEST +#undef BTEST +#undef FORMULA +#undef CALC +#undef SCALC +#undef RPIP +#undef POSTCALC +#undef UNCOMPRESS +#undef SAVE +#undef SAVEVARIABLES +#undef RESTORE +#undef USEHACKS +#undef UFORMULA +#undef UEND |