/* * Assignment 6. * * efficient bitblt. * * Context: You are the project leader and renowned assembly language * hacker in the Electronic Book project. To keep parts count low, * the eBook does not have a hardware bit-blitter. The rendering is * done to off-screen memory (while the user is reading the current * page), and the bitblt routine is used to scroll the screen or * update to the next page. If bitblt is used to scroll or move * windows around, then the source and destination graphics memory * buffer is identical, and only the source and destination rectangles * are different. If bitblt is used to "flip" to the next page, * however, the source and destination graphics memory regions will be * different. (bitblt is used to copy the current page to the * previous-page graphics memory buffer, and then copy the next-page * buffer to the visible buffer. the eBook renderer is then invoked * to draw the next page in the next-page buffer while the user is * reading the current page.) * * Unfortunately, the C implementation of bitblt (given below) isn't * fast enough. Your job, as the project lead / chief assembly * language hacker, is to make it as fast as possible. The eBook is * your company's first product, and the bitblt code should be sped up * by a factor of at least 30-40 to be acceptable for consumers. The * manufacturing line is awaiting your speed improvements, and these * must be done by midnight Sunday, December 12th (due date) in order * for your eBook product to be available to consumers for the * Christmas shopping season. (This is wildly optimistic, by the way.) * * Your President and CEO is offering you big piles of stock options, * since this is a make-or-break product for your company. The IPO * value greatly depends on how well this product is accepted, and * interactive performance is critical. The IPO will occur early next * year. */ /* * Display model. * * The display is a black and white bitmapped display. Each row of * pixels start on a word boundary. The left-most pixel of a row is * the least significant bit of the first word in that row. The 32nd * pixel in the row is the least signficant bit of the next word. */ #define DEBUG 1 #if DEBUG # define WIDTH 80 # define HEIGHT 60 # define VSCROLL_AMOUNT 6 #else # define WIDTH 800 # define HEIGHT 600 # define VSCROLL_AMOUNT 60 #endif /* next model eBook will have higher resolution screens */ #define PIXELS_PER_WORD 32 #define WORDS_PER_ROW ((WIDTH+PIXELS_PER_WORD-1)/PIXELS_PER_WORD) /* * You may skip ahead to "ASSIGNMENT CODE STARTS HERE". */ #if DEBUG /* * "compatibility" layer to simulate SPIM syscalls. you can safely ignore * this code to "Start of assignment code". */ #include void print_int(int a0) { printf("%d",a0); } void print_float(float f12) { printf("%f",f12); } void print_double(double f12) { printf("%f",f12); } void print_string(char *a0) { printf("%s",a0); } int read_int(void) { int v0; scanf("%d",&v0); return v0; } float read_float(void) { float f0; scanf("%f",&f0); return f0; } double read_double(void) { double f0; scanf("%lf",&f0); return f0; } void read_string(char *a0, int a1) { fgets(a0,a1,stdin); } /* sbrk/exit implemented in libc */ #endif /* * ASSIGNMENT CODE STARTS HERE */ /* * get_bit_value. from a graphics buffer, extract the value of the pixel * at a given row,col. */ int get_bit_value(unsigned int *gbuffer, unsigned int row, unsigned int col) { unsigned int *row_start; unsigned int col_word_offset, col_bit_offset; unsigned int w, b; row_start = gbuffer + row * WORDS_PER_ROW; col_word_offset = col / PIXELS_PER_WORD; col_bit_offset = col % PIXELS_PER_WORD; w = *(row_start + col_word_offset); b = (w >> col_bit_offset) & 1; return b; } /* * set_bit_value. set the value of a pixel at a given location in a * graphics buffer. */ void set_bit_value(unsigned int *gbuffer, unsigned int row, unsigned int col, int val) { unsigned int *row_start; unsigned int col_word_offset, col_bit_offset; unsigned int *wptr, w, mask; row_start = gbuffer + row * WORDS_PER_ROW; col_word_offset = col / PIXELS_PER_WORD; col_bit_offset = col % PIXELS_PER_WORD; wptr = row_start + col_word_offset; w = *wptr; mask = 1 << col_bit_offset; w = w & ~mask; if (val) { w = w | mask; } *wptr = w; } /* * bitblt. copy a rectangular region from one graphics buffer to * another. if the source and destination graphics buffers are * identical, then the rectangular regions may overlap; this case is * handled correctly by this code. */ void bitblt(unsigned int *dst, int drow, int dcol, unsigned int *src, int srow, int scol, int height, int width) { int row, col, bit, rcount, ccount; int to_row, from_row, to_col, from_col; if (drow < srow) { if (dcol < scol) { to_row = drow; from_row = srow; for (rcount = 0; rcount < height; rcount++) { to_col = dcol; from_col = scol; for (ccount = 0; ccount < width; ccount++) { bit = get_bit_value(src,from_row,from_col); set_bit_value(dst,to_row,to_col,bit); from_col++; to_col++; } to_row++; from_row++; } } else { to_row = drow; from_row = srow; for (rcount = 0; rcount < height; rcount++) { to_col = dcol + width - 1; from_col = scol + width - 1; for (ccount = 0; ccount < width; ccount++) { bit = get_bit_value(src,from_row,from_col); set_bit_value(dst,to_row,to_col,bit); from_col--; to_col--; } to_row++; from_row++; } } } else { if (dcol < scol) { to_row = drow + height - 1; from_row = srow + height - 1; for (rcount = 0; rcount < height; rcount++) { to_col = dcol; from_col = scol; for (ccount = 0; ccount < width; ccount++) { bit = get_bit_value(src,from_row,from_col); set_bit_value(dst,to_row,to_col,bit); from_col++; to_col++; } to_row--; from_row--; } } else { to_row = drow + height - 1; from_row = srow + height - 1; for (rcount = 0; rcount < height; rcount++) { to_col = dcol + width - 1; from_col = scol + width - 1; for (ccount = 0; ccount < width; ccount++) { bit = get_bit_value(src,from_row,from_col); set_bit_value(dst,to_row,to_col,bit); from_col--; to_col--; } to_row--; from_row--; } } } } #if DEBUG /* * TEST HARNESS */ /* * graphics buffers for debugging */ unsigned int prev_page[HEIGHT * WORDS_PER_ROW]; unsigned int shown_page[HEIGHT * WORDS_PER_ROW]; unsigned int next_page[HEIGHT * WORDS_PER_ROW]; void read_page(unsigned int *gbuffer) { char linebuf[WIDTH + 2]; /* newline, null */ int r,c; for (r = 0; r < HEIGHT; r++) { read_string(linebuf,WIDTH + 2); for (c = 0; c < WIDTH; c++) { if (linebuf[c] == ' ') { set_bit_value(gbuffer,r,c,0); } else { set_bit_value(gbuffer,r,c,1); } } } } void print_page(unsigned int *gbuffer) { int r,c; for (r = 0; r < HEIGHT; r++) { for (c = 0; c < WIDTH; c++) { if (get_bit_value(gbuffer,r,c) == 0) { print_string(" "); } else { print_string("*"); } } print_string("\n"); } } /* place holder. more arguments are needed to do render_page properly */ void render_page(unsigned int *gbuffer) { ; } /* * you must add in your own tests and test datasets */ int main(void) { /* initialize test data */ read_page(prev_page); read_page(shown_page); read_page(next_page); print_string("Before:\n"); print_string("prev_page:\n"); print_page(prev_page); print_string("shown_page:\n"); print_page(shown_page); print_string("next_page:\n"); print_page(next_page); /* scroll down a little */ bitblt(shown_page,0,0,shown_page,VSCROLL_AMOUNT,0,HEIGHT-VSCROLL_AMOUNT,WIDTH); bitblt(shown_page,HEIGHT-VSCROLL_AMOUNT,0,next_page,0,0,VSCROLL_AMOUNT,WIDTH); print_string("after scroll:\n"); print_string("prev_page:\n"); print_page(prev_page); print_string("shown_page:\n"); print_page(shown_page); print_string("next_page:\n"); print_page(next_page); /* move a region */ bitblt(shown_page,10,10,shown_page,25,25,30,30); print_string("after move:\n"); print_string("prev_page:\n"); print_page(prev_page); print_string("shown_page:\n"); print_page(shown_page); print_string("next_page:\n"); print_page(next_page); /* flip to next page */ bitblt(prev_page,0,0,shown_page,0,0,HEIGHT,WIDTH); bitblt(shown_page,0,0,next_page,0,0,HEIGHT,WIDTH); render_page(next_page); print_string("after flip:\n"); print_string("prev_page:\n"); print_page(prev_page); print_string("shown_page:\n"); print_page(shown_page); print_string("next_page:\n"); print_page(next_page); } #endif /* DEBUG -- test harness */