123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- // This file is Copyright (c) 2023 Victor Suarez Rovere <suarezvictor@gmail.com>
- // SPDX-License-Identifier: AGPL-3.0-only
- #define RAND_SEED 0xABCDEF
- static uint32_t lfsr = RAND_SEED; //won't work until suitable seed is set
- void srand32(uint32_t seed)
- {
- lfsr = seed;
- }
- uint32_t rand32(void)
- {
- const uint32_t POLY_MASK = 0xB4BCD35C;
- int feedback = lfsr & 1;
- lfsr >>= 1;
- if (feedback)
- lfsr ^= POLY_MASK;
- return lfsr;
- }
- // drawing tests -----------------------------------------------------------------------------------
- static accel_rectangle_fill32_layout_t *rectangle_regs = accel_rectangle_fill32_regs;
- static accel_ellipse_fill32_layout_t *ellipse_regs = accel_ellipse_fill32_regs;
- static accel_line32_layout_t *line_regs = accel_line32_regs;
- void draw_char(char ch, int x, int y, int width, int height, uint32_t rgba)
- {
- if(ch == ':')
- {
- int x0 = x+4*width;
- int y0 = y+2*height;
- accel_ellipse_fill(ellipse_regs, x0, y0, x0+2*width, y0+4*height, rgba);
- y0 += 6*width;
- #if defined(FRAMEBUFFER_CACHE_HANDLING) && !defined(CSR_ACCEL_RECTANGLE_FILL32_BASE) && defined(CSR_ACCEL_ELLIPSE_FILL32_BASE)
- flush_l2_cache(); //corrects screen pixels
- flush_cpu_dcache();
- #endif
- accel_ellipse_fill(ellipse_regs, x0, y0, x0+2*width, y0+4*height, rgba);
- return;
- }
- if(ch == '.')
- {
- int x0 = x+4*width;
- int y0 = y+12*height;
- #if defined(FRAMEBUFFER_CACHE_HANDLING) && !defined(CSR_ACCEL_RECTANGLE_FILL32_BASE) && defined(CSR_ACCEL_ELLIPSE_FILL32_BASE)
- flush_l2_cache(); //corrects screen pixels
- flush_cpu_dcache();
- #endif
- accel_ellipse_fill(ellipse_regs, x0, y0, x0+2*width, y0+2*height, rgba);
- return;
- }
-
- if(ch < '0' || ch > '9')
- return;
-
- /*
- 012345
- WWWW 0
- WW WW 2
- WW WW 4
- WWWW 6
- WW WW 8
- WW WW 10
- WWWW 12
- */
-
- struct segment
- {
- const char *mask;
- int x, y, w, h;
- } const segments[7]={
- {"1011011111", 1, 0, 4, 2}, //A (top)
- {"1111100111", 4, 1, 2, 6}, //B (top right)
- {"1101111111", 4, 7, 2, 6}, //C (bottom right)
- {"1011011011", 1, 12, 4, 2}, //D (bottom)
- {"1010001010", 0, 7, 2, 6}, //E (bottom left)
- {"1000111011", 0, 1, 2, 6}, //F (top left)
- {"0011111011", 1, 6, 4, 2}, //G (middle)
- };
- const struct segment *s = segments;
- for(int i=0; i < 7; ++i, ++s)
- {
- if(s->mask[ch-'0'] != '0')
- {
- int x0 = x+width*s->x;
- int y0 = y+height*s->y;
- int x1 = x0+width*s->w;
- int y1 = y0+height*s->h;
- if(x0 >= 0 && x1 < FRAME_WIDTH && y0 >= 0 && y1 < FRAME_HEIGHT)
- {
- #if defined(FRAMEBUFFER_CACHE_HANDLING) && !defined(CSR_ACCEL_ELLIPSE_FILL32_BASE) && defined(CSR_ACCEL_RECTANGLE_FILL32_BASE)
- //FIXME: recheck condition...
- flush_l2_cache(); //corrects screen pixels
- flush_cpu_dcache();
- #endif
- accel_rectangle_fill(rectangle_regs, x0, y0, x1, y1, rgba);
- }
- }
- }
- struct corner
- {
- const char *mask;
- int x, y, w, h;
- } const corners[6]={
- {"1000111011", 0, 0, 2, 2}, //top-left
- {"1011000111", 4, 0, 2, 2}, //top-right
- {"0010011000", 4, 6, 2, 2}, //center-right
- {"1001011011", 4, 12, 2, 2}, //bottom-right
- {"1010001010", 0, 12, 2, 2}, //bottom-left
- {"0010110001", 0, 6, 2, 2}, //center-left
- };
- const struct corner *c = corners;
- for(int i=0; i < 6; ++i, ++c)
- {
- if(c->mask[ch-'0'] != '0')
- {
- int x0 = x+width*c->x;
- int y0 = y+height*c->y;
- int x1 = x0+width*c->w;
- int y1 = y0+height*c->h;
- if(x0 >= 0 && x1 < FRAME_WIDTH && y0 >= 0 && y1 < FRAME_HEIGHT)
- {
- accel_ellipse_fill(ellipse_regs, x0, y0, x1, y1, rgba);
- }
- }
- }
-
- //accel_rectangle(line_regs, x-2, y-2, x+width*6+2, y+height*15-5, rgba); //optionally draw some lines around digits
- }
- void draw_clock(void)
- {
- static uint64_t ttarget;
- static int init = 0;
- static uint32_t bkcolor = 0xFF800000;
- if(!init)
- {
- ttarget = higres_ticks();
- init=1;
- accel_rectangle_fill(rectangle_regs, 0, 0, FRAME_WIDTH-1, FRAME_HEIGHT-1, bkcolor);
- srand32(RAND_SEED);
- }
- #define DIGITS 7 //7, 9 or 10
- int64_t dt = higres_ticks() - ttarget;
- const uint64_t period = higres_ticks_freq()/(DIGITS == 10 ? 100 : DIGITS == 9 ? 10 : 1);
-
- static char timedigits[11]=
- { //01234567890
- //XX:XX:XX.00
- __TIME__ ".00"
- };
-
- static int x0 = 10, y0 = 350;
- static int dx = 1, dy = 1;
- const int sz = 7;
- if(dt >= 0)
- {
- ttarget += period;
- int incr = 1;
- // 0123456789012345
- // XXYY:XXYY:XXYY.ZZZZ
- static const int pos[11]={0,2,3, 5,7,8, 10,12,13, 15,17};
- uint32_t color = rand32() | 0xFF004000;
-
- for(int i = DIGITS; i >= 0; --i) //9 for 1/10th seconds, 10 for 1/100th seconds
- {
- int isnum = timedigits[i] >= '0' && timedigits[i] <= '9';
- if(incr && isnum)
- {
- char ovf = (i==6 || i==3) ? '5':'9'; //overflow value (decimal or sexagesimal)
- if(timedigits[i] == ovf)
- timedigits[i]='0';
- else
- {
- ++timedigits[i];
- incr = 0; //stop carry
- }
- }
- int x = x0+pos[i]*4*sz;
- int y = y0;
- if(isnum) //FIXME: to avoid problems with superposition of characters, all previous digits should be drawn prior to current ones
- draw_char('8', x-dx, y-dy, sz, sz, bkcolor); //clear previous digit
- else
- draw_char(timedigits[i], x-dx, y-dy, sz, sz, bkcolor); //clear previous symbol
- //if(timedigits[i]==':')
- // color = timedigits[9]<'5' ? 0xFFC0C0C0 : bkcolor;
- draw_char(timedigits[i], x, y, sz, sz, color);
- }
- const int xlimit = FRAME_WIDTH-(pos[DIGITS]*4+7)*sz;
- const int ylimit = FRAME_HEIGHT-sz*(14+1);
- #if DIGITS == 7
- int x0_new = ((uint32_t)ttarget*37*41) % xlimit; //random like
- int y0_new = ((uint32_t)ttarget*43*67) % ylimit; //random like
- dx = x0_new-x0;
- dy = y0_new-y0;
- #else
- //bouncing
- if(x0 >= xlimit)
- dx = -1;
- if(x0 <= 0)
- dx = 1;
- if(y0 >= ylimit)
- dy = -1;
- if(y0 <= 1*sz)
- dy = 1;
- #endif
- x0 += dx;
- y0 += dy;
- #ifdef FRAMEBUFFER_CACHE_HANDLING
- flush_l2_cache(); //corrects screen pixels
- flush_cpu_dcache();
- #endif
- }
- }
- unsigned draw_shape(void)
- {
- unsigned count;
- pix_t pix;
- int x0 = rand32() % FRAME_WIDTH;
- int x1 = rand32() % FRAME_WIDTH;
- int y0 = rand32() % FRAME_HEIGHT;
- int y1 = rand32() % FRAME_HEIGHT;
- pix.rgba = rand32();
- pix.a |= 0xFF; //0x80 for semi opaque
- pix.r = (pix.r * pix.a) >> 8;
- pix.g = (pix.g * pix.a) >> 8;
- pix.b = (pix.b * pix.a) >> 8;
- #if defined(CSR_ACCEL_RECTANGLE_FILL32_BASE) && defined(CSR_ACCEL_ELLIPSE_FILL32_BASE)
- if(rand32() & 1)
- count = accel_ellipse_fill(ellipse_regs, x0, y0, x1, y1, pix.rgba);
- else
- {
- #ifdef CSR_ACCEL_LINE32_BASE
- count = accel_rectangle(line_regs, x0, y0, x1, y1, pix.rgba^0xFFFFFF);
- count += accel_line(line_regs, x0, y0, x1, y1, pix.rgba^0xFFFFFF);
- count += accel_line(line_regs, x1, y0, x0, y1, pix.rgba^0xFFFFFF);
- #else //FIXME: there are pixel errors if using both rectangles and lines (maybe when they overlap)
- count = accel_rectangle_fill(rectangle_regs, x0, y0, x1, y1, pix.rgba);
- #endif
- }
- #else
- #ifdef CSR_ACCEL_ELLIPSE_FILL32_BASE
- count = accel_ellipse_fill(ellipse_regs, x0, y0, x1, y1, pix.rgba);
- #endif
- #ifdef CSR_ACCEL_LINE32_BASE
- count = accel_rectangle(line_regs, x0, y0, x1, y1, pix.rgba^0xFFFFFF);
- count += accel_line(line_regs, x0, y0, x1, y1, pix.rgba^0xFFFFFF);
- count += accel_line(line_regs, x1, y0, x0, y1, pix.rgba^0xFFFFFF);
- #else
- count = accel_rectangle_fill(rectangle_regs, x0, y0, x1, y1, pix.rgba);
- #endif
- #endif
-
- //printf("count %d\n", count);
- return count;
- }
- void draw_shapes(int pixcount)
- {
- srand32(RAND_SEED); //reset pseudorandom function generator
-
- if(0)
- accel_rectangle_fill(rectangle_regs, 0, 0, FRAME_WIDTH, FRAME_HEIGHT, 0x404040); //avoids cache issues
- else
- {
- memset((void*)VIDEO_FRAMEBUFFER_BASE, 0x40, FRAME_HEIGHT*FRAME_PITCH); //set background to solid color
- #ifdef FRAMEBUFFER_CACHE_HANDLING
- flush_l2_cache(); //flush cache to correct issues, if not the test fails!
- //flush_cpu_dcache(); //seems optional
- #endif
- }
- uint64_t start = higres_ticks();
- uint64_t c = 0;
- while(c < pixcount)
- {
- uint32_t ops = draw_shape();
- c += ops;
- }
- int64_t dt = higres_ticks() - start;
- int elapsed = dt*1000000/higres_ticks_freq();
- int opspersec = c*higres_ticks_freq()/dt;
- printf("elapsed %d us, ops/s: %d (%d FPS @%dx%d)\n",
- elapsed, opspersec, opspersec/(FRAME_WIDTH*FRAME_HEIGHT), FRAME_WIDTH, FRAME_HEIGHT);
- }
- //test ---------------------------------------------------------------------------------------------
- int drawing_test(void)
- {
- pix_t *fb_tmp = (pix_t*) malloc(FRAME_HEIGHT*FRAME_PITCH);
- assert(fb_tmp != NULL);
- int pixcount = higres_ticks_freq()/10; //FIXME: this is just to compensate slow simulations
- printf("\nCurrent test: draw %d pixels\n", pixcount);
- // disable acellerators
- rectangle_regs = NULL;
- ellipse_regs = NULL;
- line_regs = NULL;
- printf("Start software rendering\n");
- draw_shapes(pixcount);
- /*
- #ifdef FRAMEBUFFER_CACHE_HANDLING //seems optional since test passes anyways
- printf("flush caches and save data\n");
- flush_l2_cache();
- flush_cpu_dcache();
- #endif
- */
- memcpy(fb_tmp, (void*)VIDEO_FRAMEBUFFER_BASE, FRAME_HEIGHT*FRAME_PITCH);
-
- printf("Switch to hardware rendering\n");
- rectangle_regs = accel_rectangle_fill32_regs;
- ellipse_regs = accel_ellipse_fill32_regs;
- line_regs = accel_line32_regs;
- draw_shapes(pixcount);
- printf("Just waiting a bit to evaluate image...\n");
- uint64_t ttarget = higres_ticks()+higres_ticks_freq()*5;
- while(higres_ticks() < ttarget);
-
- int errors = 0;
- pix_t *src = fb_tmp, *dst = (pix_t*) VIDEO_FRAMEBUFFER_BASE;
- while((void*) dst < (void*)(VIDEO_FRAMEBUFFER_BASE + FRAME_HEIGHT*FRAME_PITCH))
- {
- int match = dst->rgba == src->rgba;
- dst->rgba = match ? 0x404040 : 0x000000FF;
- ++src;
- ++dst;
- errors += (match == 0);
- }
-
- #ifdef FRAMEBUFFER_CACHE_HANDLING
- flush_l2_cache(); //corrects screen pixels
- //flush_cpu_dcache(); //no effect on screen
- #endif
- free(fb_tmp);
-
-
- printf("Pixel errors: %d (screen should have no red pixels)\n", errors);
-
- return errors;
- }
|