--- uae/src/gfxutil.c 2018/04/24 16:38:39 1.1.1.1 +++ uae/src/gfxutil.c 2018/04/24 17:16:18 1.1.1.10 @@ -1,22 +1,20 @@ - /* + /* * UAE - The Un*x Amiga Emulator - * + * * Common code needed by all the various graphics systems. - * + * * (c) 1996 Bernd Schmidt, Ed Hanway, Samuel Devulder */ #include "sysconfig.h" #include "sysdeps.h" -#include "config.h" #include "options.h" +#include "threaddep/thread.h" #include "memory.h" #include "custom.h" -#include "newcpu.h" #include "keyboard.h" #include "xwin.h" -#include "keybuf.h" #define RED 0 #define GRN 1 @@ -25,15 +23,15 @@ /* * dither matrix */ -static UBYTE dither[4][4] = +static uae_u8 dither[4][4] = { - {0,8,2,10}, - {12,4,14,6}, - {3,11,1,9}, - {14 /* 15 */,7,13,5} + { 0, 8, 2, 10 }, + { 12, 4, 14, 6 }, + { 3, 11, 1, 9 }, + { 14 /* 15 */, 7, 13, 5 } }; -unsigned long doMask(int p, int bits, int shift) +unsigned long doMask (int p, int bits, int shift) { /* p is a value from 0 to 15 (Amiga color value) * scale to 0..255, shift to align msb with mask, and apply mask */ @@ -45,34 +43,89 @@ unsigned long doMask(int p, int bits, in return val; } -void alloc_colors64k(int rw, int gw, int bw, int rs, int gs, int bs) +int bits_in_mask (unsigned long mask) +{ + int n = 0; + while (mask) { + n += mask & 1; + mask >>= 1; + } + return n; +} + +int mask_shift (unsigned long mask) +{ + int n = 0; + while (!(mask & 1)) { + n++; + mask >>= 1; + } + return n; +} + +unsigned long doMask256 (int p, int bits, int shift) +{ + /* p is a value from 0 to 255 (Amiga color value) + * shift to align msb with mask, and apply mask */ + + unsigned long val = p * 0x01010101UL; + val >>= (32 - bits); + val <<= shift; + + return val; +} + +static unsigned int doColor (int i, int bits, int shift) +{ + int shift2; + if(bits >= 8) shift2 = 0; else shift2 = 8 - bits; + return (i >> shift2) << shift; +} + +void alloc_colors64k (int rw, int gw, int bw, int rs, int gs, int bs) { int i; - for(i=0; i<4096; i++) { + for (i = 0; i < 4096; i++) { int r = i >> 8; int g = (i >> 4) & 0xF; int b = i & 0xF; xcolors[i] = doMask(r, rw, rs) | doMask(g, gw, gs) | doMask(b, bw, bs); } + /* create AGA color tables */ + for(i = 0; i < 256; i++) { + xredcolors[i] = doColor(i, rw, rs); + xgreencolors[i] = doColor(i, gw, gs); + xbluecolors[i] = doColor(i, bw, bs); + } } static int allocated[4096]; +static int color_diff[4096]; +static int newmaxcol = 0; + +void setup_maxcol (int max) +{ + newmaxcol = max; +} -void alloc_colors256(allocfunc_type allocfunc) +void alloc_colors256 (allocfunc_type allocfunc) { int nb_cols[3]; /* r,g,b */ - int maxcol = 256; - int i,j,k,l,t; - int diff[4096]; + int maxcol = newmaxcol == 0 ? 256 : newmaxcol; + int i,j,k,l; xcolnr *map; - - map = (xcolnr *)malloc(sizeof(xcolnr) * maxcol); - + + map = (xcolnr *)malloc (sizeof(xcolnr) * maxcol); + if (!map) { + write_log ("Not enough mem for colormap!\n"); + abort (); + } + /* * compute #cols per components */ - for(i = 1; i*i*i <= maxcol; ++i) + for (i = 1; i*i*i <= maxcol; ++i) ; --i; @@ -83,15 +136,15 @@ void alloc_colors256(allocfunc_type allo /* * set the colormap */ - l=0; - for(i = 0; i < nb_cols[RED]; ++i) { - int r = (i * 15 + (nb_cols[RED] - 1)/2) / (nb_cols[RED] - 1); - for(j = 0; j < nb_cols[GRN]; ++j) { - int g = (j * 15 + (nb_cols[GRN] - 1)/2) / (nb_cols[GRN] - 1); - for(k = 0; k < nb_cols[BLU]; ++k) { - int b = (k * 15 + (nb_cols[BLU] - 1)/2) / (nb_cols[BLU] - 1); + l = 0; + for (i = 0; i < nb_cols[RED]; ++i) { + int r = (i * 15) / (nb_cols[RED] - 1); + for (j = 0; j < nb_cols[GRN]; ++j) { + int g = (j * 15) / (nb_cols[GRN] - 1); + for (k = 0; k < nb_cols[BLU]; ++k) { + int b = (k * 15) / (nb_cols[BLU] - 1); int result; - result = allocfunc(r, g, b, map + l); + result = allocfunc (r, g, b, map + l); l++; } } @@ -104,62 +157,62 @@ void alloc_colors256(allocfunc_type allo { int diffr, diffg, diffb, maxdiff = 0, won = 0, lost; int r, d = 8; - for(r=0; r<16; ++r) { + for (r = 0; r < 16; ++r) { int cr, g, q; - - k = nb_cols[RED]-1; + + k = nb_cols[RED]-1; cr = (r * k) / 15; - q = (r * k) % 15; - if(q > d && cr < k) ++cr; - diffr = abs(cr*k-r); - for(g=0; g<16; ++g) { + q = (r * k) % 15; + if (q > d && cr < k) ++cr; + diffr = abs (cr*k - r); + for (g = 0; g < 16; ++g) { int cg, b; - - k = nb_cols[GRN]-1; + + k = nb_cols[GRN]-1; cg = (g * k) / 15; q = (g * k) % 15; - if(q > d && cg < k) ++cg; - diffg = abs(cg*k-g); - for(b=0; b<16; ++b) { - int cb, rgb = (r<<8) | (g<<4) | b; + if (q > d && cg < k) ++cg; + diffg = abs (cg*k - g); + for (b = 0; b < 16; ++b) { + int cb, rgb = (r << 8) | (g << 4) | b; - k = nb_cols[BLU]-1; + k = nb_cols[BLU]-1; cb = (b * k) / 15; - q = (b * k) % 15; - if(q > d && cb < k) ++cb; - diffb = abs(cb*k-b); - xcolors[rgb] = map[(cr*nb_cols[GRN]+cg)*nb_cols[BLU]+cb]; - diff[rgb] = diffr+diffg+diffb; - if (diff[rgb] > maxdiff) - maxdiff = diff[rgb]; + q = (b * k) % 15; + if (q > d && cb < k) ++cb; + diffb = abs (cb*k - b); + xcolors[rgb] = map[(cr * nb_cols[GRN] + cg) * nb_cols[BLU] + cb]; + color_diff[rgb] = diffr + diffg + diffb; + if (color_diff[rgb] > maxdiff) + maxdiff = color_diff[rgb]; } } } while (maxdiff > 0 && l < maxcol) { int newmaxdiff = 0; lost = 0; won++; - for(r = 15; r >= 0; r--) { - int cr, g, q; - - for(g = 15; g >= 0; g--) { - int cg, b; - - for(b = 15; b >= 0; b--) { - int cb, rgb = (r<<8) | (g<<4) | b; + for (r = 15; r >= 0; r--) { + int g; + + for (g = 15; g >= 0; g--) { + int b; + + for (b = 15; b >= 0; b--) { + int rgb = (r << 8) | (g << 4) | b; - if (diff[rgb] == maxdiff) { + if (color_diff[rgb] == maxdiff) { int result; - + if (l >= maxcol) lost++; else { - result = allocfunc(r, g, b, xcolors + rgb); + result = allocfunc (r, g, b, xcolors + rgb); l++; } - diff[rgb] = 0; - } else if (diff[rgb] > newmaxdiff) - newmaxdiff = diff[rgb]; - + color_diff[rgb] = 0; + } else if (color_diff[rgb] > newmaxdiff) + newmaxdiff = color_diff[rgb]; + } } } @@ -174,62 +227,67 @@ void alloc_colors256(allocfunc_type allo * This dithering process works by letting UAE run internaly in 12bit * mode and doing the dithering on the fly when rendering to the display. * The dithering algorithm is quite fast but uses lot of memory (4*8*2^12 = - * 128Kb). I don't think that is a trouble right now, but when UAE will + * 128Kb). I don't think that is a trouble right now, but when UAE will * emulate AGA and work internaly in 24bit mode, that dithering algorithm * will need 4*8*2^24 = 512Mb. Obviously that fast algorithm will not be - * tractable. However, we could then use an other algorithm, slower, but + * tractable. However, we could then use an other algorithm, slower, but * far more reasonable (I am thinking about the one that is used in DJPEG). */ -UBYTE cidx[4][8*4096]; /* fast, but memory hungry =:-( */ +uae_u8 cidx[4][8*4096]; /* fast, but memory hungry =:-( */ /* * Compute dithering structures */ -void setup_greydither(int bits, allocfunc_type allocfunc) +void setup_greydither_maxcol (int maxcol, allocfunc_type allocfunc) { - int i,j,k,l,t; - int maxcol = 1 << bits; + int i,j,k; xcolnr *map; - + for (i = 0; i < 4096; i++) xcolors[i] = i; - - map = (xcolnr *)malloc(sizeof(xcolnr) * maxcol); + + map = (xcolnr *)malloc (sizeof(xcolnr) * maxcol); + if (!map) { + write_log ("Not enough mem for colormap!\n"); + abort(); + } /* * set the colormap */ - for(i = 0; i < maxcol; ++i) { + for (i = 0; i < maxcol; ++i) { int c, result; c = (15 * i + (maxcol-1)/2) / (maxcol - 1); - result = allocfunc(c, c, c, map + i); + result = allocfunc(c, c, c, map + i); /* @@@ check for errors */ } /* * for each componant compute the mapping */ - for(i=0;i<4;++i) { - for(j=0;j<4;++j) { + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { int r, d = dither[i][j]*17; - for(r=0; r<16; ++r) { + for (r = 0; r<16; ++r) { int g; - for(g=0; g<16; ++g) { + for (g = 0; g < 16; ++g) { int b; - for(b=0; b<16; ++b) { - int rgb = (r<<8) | (g<<4) | b; + for (b = 0; b < 16; ++b) { + int rgb = (r << 8) | (g << 4) | b; int c,p,q; - - c = (77 * r + - 151 * g + + + c = (77 * r + + 151 * g + 28 * b) / 15; /* c in 0..256 */ - - k = maxcol-1; + + k = maxcol-1; p = (c * k) / 256; q = (c * k) % 256; - if(q / k > d / k && p < k) ++p; - cidx[i][rgb + (j+4)*4096] = + if (q /*/ k*/> d /*/ k*/ && p < k) ++p; +/* sam: ^^^^^^^ */ +/* It seems that produces better output */ + cidx[i][rgb + (j+4)*4096] = cidx[i][rgb + j*4096] = map[p]; } } @@ -239,24 +297,33 @@ void setup_greydither(int bits, allocfun free (map); } -void setup_dither(int bits, allocfunc_type allocfunc) +void setup_greydither (int bits, allocfunc_type allocfunc) +{ + setup_greydither_maxcol(1 << bits, allocfunc); +} + +void setup_dither (int bits, allocfunc_type allocfunc) { int nb_cols[3]; /* r,g,b */ int maxcol = 1 << bits; - int i,j,k,l,t; + int i,j,k,l; xcolnr *map; int *redvals, *grnvals, *bluvals; - - map = (xcolnr *)malloc(sizeof(xcolnr) * maxcol); + + map = (xcolnr *)malloc (sizeof(xcolnr) * maxcol); + if (!map) { + write_log ("Not enough mem for colormap!\n"); + abort(); + } for (i = 0; i < 4096; i++) xcolors[i] = i; - + /* * compute #cols per components */ - for(i = 1; i*i*i <= maxcol; ++i) + for (i = 1; i*i*i <= maxcol; ++i) ; --i; @@ -264,26 +331,27 @@ void setup_dither(int bits, allocfunc_ty nb_cols[GRN] = i; nb_cols[BLU] = i; - if(nb_cols[RED]*(++i)*nb_cols[BLU] <= maxcol) { + if (nb_cols[RED]*(++i)*nb_cols[BLU] <= maxcol) { nb_cols[GRN] = i; - if((i)*nb_cols[GRN]*nb_cols[BLU] <= maxcol) nb_cols[RED] = i; + if ((i)*nb_cols[GRN]*nb_cols[BLU] <= maxcol) + nb_cols[RED] = i; } - redvals = (int *)malloc(sizeof(int) * maxcol); + redvals = (int *)malloc (sizeof(int) * maxcol); grnvals = redvals + nb_cols[RED]; - bluvals = grnvals + nb_cols[BLU]; + bluvals = grnvals + nb_cols[GRN]; /* * set the colormap */ - l=0; - for(i = 0; i < nb_cols[RED]; ++i) { - int r = (i * 15 + (nb_cols[RED] - 1)/2) / (nb_cols[RED] - 1); + l = 0; + for (i = 0; i < nb_cols[RED]; ++i) { + int r = (i * 15) / (nb_cols[RED] - 1); redvals[i] = r; - for(j = 0; j < nb_cols[GRN]; ++j) { - int g = (j * 15 + (nb_cols[GRN] - 1)/2) / (nb_cols[GRN] - 1); + for (j = 0; j < nb_cols[GRN]; ++j) { + int g = (j * 15) / (nb_cols[GRN] - 1); grnvals[j] = g; - for(k = 0; k < nb_cols[BLU]; ++k) { - int b = (k * 15 + (nb_cols[BLU] - 1)/2) / (nb_cols[BLU] - 1); + for (k = 0; k < nb_cols[BLU]; ++k) { + int b = (k * 15) / (nb_cols[BLU] - 1); int result; bluvals[k] = b; result = allocfunc(r, g, b, map + l); @@ -291,74 +359,81 @@ void setup_dither(int bits, allocfunc_ty } } } - fprintf(stderr, "%d color(s) lost\n",maxcol - l); +/* write_log ("%d color(s) lost\n",maxcol - l);*/ /* * for each component compute the mapping */ { int r; - for(r=0; r<16; ++r) { + for (r = 0; r < 16; ++r) { int g; - for(g=0; g<16; ++g) { + for (g = 0; g < 16; ++g) { int b; - for(b=0; b<16; ++b) { - int rederr = 0, grnerr = 0, bluerr = 0; - int rgb = (r<<8) | (g<<4) | b; + for (b = 0; b < 16; ++b) { + int rgb = (r << 8) | (g << 4) | b; - for(i=0;i<4;++i) for(j=0;j<4;++j) { + for (i = 0; i < 4; ++i) for (j = 0; j < 4; ++j) { int d = dither[i][j]; int cr, cg, cb, k, q; #if 0 /* Slightly different algorithm. Needs some tuning. */ + int rederr = 0, grnerr = 0, bluerr = 0; + k = nb_cols[RED]-1; cr = r * k / 15; q = r * k - 15*cr; - if (cr < 0) cr = 0; - else - if(q / k > d / k && rederr <= 0) ++cr; + if (cr < 0) + cr = 0; + else if (q / k > d / k && rederr <= 0) + ++cr; if (cr > k) cr = k; rederr += redvals[cr]-r; - + k = nb_cols[GRN]-1; cg = g * k / 15; q = g * k - 15*cg; - if (cg < 0) cg = 0; - else - if (q / k > d / k && grnerr <= 0) ++cg; + if (cg < 0) + cg = 0; + else if (q / k > d / k && grnerr <= 0) + ++cg; if (cg > k) cg = k; grnerr += grnvals[cg]-g; k = nb_cols[BLU]-1; cb = b * k / 15; q = b * k - 15*cb; - if (cb < 0) cb = 0; - else - if (q / k > d / k && bluerr <= 0) ++cb; + if (cb < 0) + cb = 0; + else if (q / k > d / k && bluerr <= 0) + ++cb; if (cb > k) cb = k; bluerr += bluvals[cb]-b; #else k = nb_cols[RED]-1; cr = r * k / 15; q = r * k - 15*cr; - if (cr < 0) cr = 0; - else - if(q / k > d / k) ++cr; + if (cr < 0) + cr = 0; + else if (q /*/ k*/ > d /*/ k*/) + ++cr; if (cr > k) cr = k; - + k = nb_cols[GRN]-1; cg = g * k / 15; q = g * k - 15*cg; - if (cg < 0) cg = 0; - else - if (q / k > d / k) ++cg; + if (cg < 0) + cg = 0; + else if (q /*/ k*/ > d /*/ k*/) + ++cg; if (cg > k) cg = k; k = nb_cols[BLU]-1; cb = b * k / 15; q = b * k - 15*cb; - if (cb < 0) cb = 0; - else - if (q / k > d / k) ++cb; + if (cb < 0) + cb = 0; + else if (q /*/ k*/ > d /*/ k*/) + ++cb; if (cb > k) cb = k; #endif cidx[i][rgb + (j+4)*4096] = cidx[i][rgb + j*4096] = map[(cr*nb_cols[GRN]+cg)*nb_cols[BLU]+cb]; @@ -367,42 +442,54 @@ void setup_dither(int bits, allocfunc_ty } } } + free (redvals); free (map); } -#ifndef X86_ASSEMBLY +#if !defined X86_ASSEMBLY /* * Dither the line. * Make sure you call this only with (len & 3) == 0, or you'll just make * yourself unhappy. */ -void DitherLine(UBYTE *l, UWORD *r4g4b4, int x, int y, UWORD len, int bits) +void DitherLine (uae_u8 *l, uae_u16 *r4g4b4, int x, int y, uae_s16 len, int bits) { - UBYTE *dith = cidx[y&3]+(x&3)*4096; - UBYTE d = 0; + uae_u8 *dith = cidx[y&3]+(x&3)*4096; + uae_u8 d = 0; int bitsleft = 8; - - while(len) { + + if (bits == 8) { + while (len > 0) { + *l++ = dith[0*4096 + *r4g4b4++]; + *l++ = dith[1*4096 + *r4g4b4++]; + *l++ = dith[2*4096 + *r4g4b4++]; + *l++ = dith[3*4096 + *r4g4b4++]; + len -= 4; + } + return; + } + + while (len) { int v; v = dith[0*4096 + *r4g4b4++]; bitsleft -= bits; d |= (v << bitsleft); if (!bitsleft) *l++ = d, bitsleft = 8, d = 0; - + v = dith[1*4096 + *r4g4b4++]; bitsleft -= bits; d |= (v << bitsleft); if (!bitsleft) *l++ = d, bitsleft = 8, d = 0; - + v = dith[2*4096 + *r4g4b4++]; bitsleft -= bits; d |= (v << bitsleft); if (!bitsleft) *l++ = d, bitsleft = 8, d = 0; - + v = dith[3*4096 + *r4g4b4++]; bitsleft -= bits; d |= (v << bitsleft);