#include #include #include #include "libsys.h" #include "mips_gfx.h" #define USE_HW_BLITTER // ------------------------------------------------------------- // Functions // ------------------------------------------------------------- void __gfx_block_set_8(UINT32* pDst, UINT32 value) { __asm__ volatile ( "sw %[value], 0(%[pDst])\n" "sw %[value], 4(%[pDst])\n" "sw %[value], 8(%[pDst])\n" "sw %[value], 12(%[pDst])\n" "sw %[value], 16(%[pDst])\n" "sw %[value], 20(%[pDst])\n" "sw %[value], 24(%[pDst])\n" "sw %[value], 28(%[pDst])\n" : : [pDst] "r" (pDst), [value] "r" (value) ); } void __gfx_block_copy_8(UINT32* pDst, UINT32* pSrc) { __asm__ volatile ( ".set noreorder\n" ".set nomacro\n" "lw $s0, 0(%[pSrc])\n" "lw $s1, 4(%[pSrc])\n" "sw $s0, 0(%[pDst])\n" "lw $s0, 8(%[pSrc])\n" "sw $s1, 4(%[pDst])\n" "lw $s1, 12(%[pSrc])\n" "sw $s0, 8(%[pDst])\n" "lw $s0, 16(%[pSrc])\n" "sw $s1, 12(%[pDst])\n" "lw $s1, 20(%[pSrc])\n" "sw $s0, 16(%[pDst])\n" "lw $s0, 24(%[pSrc])\n" "sw $s1, 20(%[pDst])\n" "lw $s1, 28(%[pSrc])\n" "sw $s0, 24(%[pDst])\n" "sw $s1, 28(%[pDst])\n" ".set macro\n" ".set reorder\n" : : [pDst] "r" (pDst), [pSrc] "r" (pSrc) : "s0", "s1" ); } void __gfx_copy_32(UINT32* pDst, UINT32* pSrc, UINT32 nblocks) { while (nblocks) { __gfx_block_copy_8(pDst, pSrc); pDst += 8; pSrc += 8; nblocks--; } } void GFX_DirtyRectSetClean(buf_t *pBuf) { pBuf->rect.xmin = pBuf->w; pBuf->rect.xmax = 0; pBuf->rect.ymin = pBuf->h; pBuf->rect.ymax = 0; pBuf->is_dirty = 0; } void GFX_DirtyRectInit(buf_t *pBuf, UINT32 w, UINT32 h) { pBuf->w = w; pBuf->h = h; pBuf->regs = (vga_hw_t*)SYS_VGA_CTRL; GFX_DirtyRectSetClean(pBuf); } void GFX_DirtyRectUpdate(buf_t *pBuf, UINT32 xmin, UINT32 xmax, UINT32 ymin, UINT32 ymax) { if (xmin < pBuf->rect.xmin) { pBuf->is_dirty = 1; pBuf->rect.xmin = xmin; } if (xmax > pBuf->rect.xmax) { pBuf->is_dirty = 1; pBuf->rect.xmax = xmax; } if (ymin < pBuf->rect.ymin) { pBuf->is_dirty = 1; pBuf->rect.ymin = ymin; } if (ymax > pBuf->rect.ymax) { pBuf->is_dirty = 1; pBuf->rect.ymax = ymax; } if (pBuf->is_dirty && ((pBuf->rect.xmax-pBuf->rect.xmin)%8)) pBuf->rect.xmax = pBuf->rect.xmin + ((pBuf->rect.xmax-pBuf->rect.xmin)/8 + 1) * 8; // Make len_x multiple of 8 } void GFX_DirtyRectCopy(buf_t *pBuf) { UINT32 xmin, xmax, ymin, ymax, x, y; UINT32 *pDst, *pDst_end; UINT32 *pSrc, *pSrc_end; xmin = pBuf->rect.xmin; xmax = pBuf->rect.xmax; ymin = pBuf->rect.ymin; ymax = pBuf->rect.ymax; ymin *= pBuf->w; ymax *= pBuf->w; #ifdef USE_HW_BLITTER pSrc = (UINT32*)&pBuf->pLast->pFB[xmin + ymin]; pDst = (UINT32*)&pBuf->pFB[xmin + ymin]; while (pBuf->regs->pVGA_ctrl & SYS_VGA_BIT_BLIT_BSY); pBuf->regs->pVGA_src0 = (UINT32)pSrc; pBuf->regs->pVGA_dst = (UINT32)pDst; pBuf->regs->pVGA_src0_dimx = (UINT32)4*pBuf->w; pBuf->regs->pVGA_dst_dimx = (UINT32)4*pBuf->w; pBuf->regs->pVGA_nx = (UINT32)(pBuf->rect.xmax-pBuf->rect.xmin); pBuf->regs->pVGA_ny = (UINT32)(pBuf->rect.ymax-pBuf->rect.ymin); pBuf->regs->pVGA_ctrl |= SYS_VGA_BIT_BLIT_REQ; #else if (!((xmax-xmin)%8)) { for (y=ymin; y < ymax; y += pBuf->w) { pSrc = &pBuf->pLast->pFB[xmin + y]; pSrc_end = &pBuf->pLast->pFB[xmax + y]; pDst = &pBuf->pFB[xmin + y]; pDst_end = &pBuf->pFB[xmax + y]; while(pDst < pDst_end) { __gfx_block_copy_8(pDst, pSrc); pDst += 8; pSrc += 8; } } return; } // fprintf(stderr, "GFX_DirtyRectCopy(): Slow copy!\n"); for (y=ymin; y < ymax; y += pBuf->w) { for (x=xmin; x < xmax; x++) { pBuf->pFB[x + y] = pBuf->pLast->pFB[x + y]; } } #endif } void GFX_init(gfx_t *pObj) { int i; buf_t *pBuf; UINT32 w, h, fps; pObj->regs = (vga_hw_t*)SYS_VGA_CTRL; pObj->regs->pVGA_ctrl &= ~SYS_VGA_BIT_MSTEN; w = Screen_get_resx(); h = Screen_get_resy(); fps = Screen_get_fps(); printf("VGA screen = %d x %d @ %d fps\n", w, h, fps); pObj->w = w; pObj->h = h; // Init background buffer pObj->pBG = (UINT32*)calloc(w * h, sizeof(buf_t)); // Init framebuffers pObj->pBuf = (buf_t*)calloc(1, sizeof(buf_t)); pBuf = pObj->pBuf; pBuf->pFB = (UINT32*)calloc((w+8) * h, sizeof(UINT32)); // w+8 because of dirty rectangle 8 byte min. x-size for (i=1; i < GFX_NUM_FRAME_BUFFERS; i++) { pBuf->pNext = (buf_t*)calloc(1, sizeof(buf_t)); pBuf->pNext->pLast = pBuf; pBuf = pBuf->pNext; pBuf->pFB = (UINT32*)calloc((w+8) * h, sizeof(UINT32)); // w+8 because of dirty rectangle 8 byte min. x-size } pObj->pBuf->pLast = pBuf; pBuf->pNext = pObj->pBuf; pBuf = pObj->pBuf; for (i=0; i < GFX_NUM_FRAME_BUFFERS; i++) { GFX_DirtyRectInit(pBuf, w, h); // fprintf(stderr, "pBuf = %08X, pLast = %08X, pNext = %08X\n", pBuf, pBuf->pLast, pBuf->pNext); pBuf = pBuf->pNext; } pObj->regs->pVGA_front = (UINT32)pObj->pBuf->pLast->pFB; pObj->regs->pVGA_back = (UINT32)pObj->pBuf->pLast->pFB; pObj->regs->pVGA_ctrl |= SYS_VGA_BIT_MSTEN; } void GFX_set_background(gfx_t *pObj, UINT32 *pImage, UINT32 image_nx, UINT32 image_ny, UINT32 image_scale_x, UINT32 image_scale_y) { UINT32 off_x, off_y; UINT32 i, j; UINT32 *pDst, *pSrc; buf_t *pBuf; if (!pImage) return; off_x = (pObj->w-(image_scale_x*image_nx))/2; off_y = (pObj->h-(image_scale_y*image_ny))/2; pDst = ((UINT32*)pObj->pBG) + pObj->w*off_y + off_x; pSrc = pImage; for (i=0; i < image_ny*image_nx; i += 8) { __gfx_block_copy_8(pDst, pSrc); pDst += 8; pSrc += 8; } pBuf = pObj->pBuf; pDst = pBuf->pFB; pSrc = pObj->pBG; for (i=0; i < image_ny*image_nx; i += 8) { __gfx_block_copy_8(pDst, pSrc); pDst += 8; pSrc += 8; } do { GFX_DirtyRectUpdate(pBuf, 0, pObj->w, 0, pObj->h); pBuf = pBuf->pNext; } while(pBuf != pObj->pBuf); } void GFX_frame(gfx_t *pObj, UINT32 sync_mode) { // Wait until back buffer becomes front if (sync_mode == GFX_FRAME_SYNC) { while(pObj->regs->pVGA_front == (UINT32)pObj->pBuf->pFB); } GFX_copy_front2back(pObj); // Invalidate D-Cache after blitting has finished while (pObj->regs->pVGA_ctrl & SYS_VGA_BIT_BLIT_BSY); DCACHE_invalidate_all(); } void GFX_show(gfx_t *pObj) { pObj->regs->pVGA_back = (UINT32)pObj->pBuf->pFB; pObj->pBuf = pObj->pBuf->pNext; } void GFX_copy_front2back(gfx_t *pObj) { buf_t *pBuf; pBuf = pObj->pBuf; // Lopp over all frame buffers, except front buffer while(pBuf != pObj->pBuf->pLast) { if (pBuf->is_dirty) { // fprintf(stderr, "Dirty rect [%08X]: w=%d, h=%d\n", (int)pBuf, pBuf->rect.xmax - pBuf->rect.xmin, pBuf->rect.ymax - pBuf->rect.ymin); GFX_DirtyRectCopy(pBuf); GFX_DirtyRectSetClean(pBuf); } pBuf = pBuf->pNext; } } void GFX_get_FB_front(gfx_t *pObj, UINT32 **ppFB) { *ppFB = pObj->pBuf->pLast->pFB; } void box_create(box_t *pObj, UINT32 w, UINT32 h) { pObj->w = w; pObj->h = h; } void GFX_restore(gfx_t *pObj, box_t *pBox, UINT32 posx, UINT32 posy) { UINT32 xmin, xmax, ymin, ymax, x, y; UINT32 *pDst, *pDst_end; UINT32 *pSrc, *pSrc_end; buf_t *pBuf; xmin = posx; xmax = pBox->w + posx; if (xmax > pObj->w) xmax = pObj->w; ymin = posy; ymax = pBox->h + posy; if (ymax > pObj->h) ymax = pObj->h; pBuf = pObj->pBuf->pNext; // Lopp over all frame buffers, except current back buffer while(pBuf != pObj->pBuf) { GFX_DirtyRectUpdate(pBuf, xmin, xmax, ymin, ymax); pBuf = pBuf->pNext; } pBuf = pObj->pBuf; x = xmax - xmin + 1; if (x%2) x++; y = ymax - ymin + 1; if (y%2) y++; ymin *= pObj->w; ymax *= pObj->w; #ifdef USE_HW_BLITTER pSrc = (UINT32*)&pObj->pBG[xmin + ymin]; pDst = (UINT32*)&pBuf->pFB[xmin + ymin]; while (pObj->regs->pVGA_ctrl & SYS_VGA_BIT_BLIT_BSY); pObj->regs->pVGA_src0 = (UINT32)pSrc; pObj->regs->pVGA_dst = (UINT32)pDst; pObj->regs->pVGA_src0_dimx = (UINT32)4*pObj->w; pObj->regs->pVGA_dst_dimx = (UINT32)4*pObj->w; pObj->regs->pVGA_nx = (UINT32)x - 1; pObj->regs->pVGA_ny = (UINT32)y - 1; pObj->regs->pVGA_ctrl |= SYS_VGA_BIT_BLIT_REQ; #else if (!((xmax-xmin)%8)) { for (y=ymin; y < ymax; y += pBuf->w) { pSrc = &pObj->pBG[xmin + y]; pSrc_end = &pObj->pBG[xmax + y]; pDst = &pBuf->pFB[xmin + y]; pDst_end = &pBuf->pFB[xmax + y]; while(pDst < pDst_end) { __gfx_block_copy_8(pDst, pSrc); pDst += 8; pSrc += 8; } } return; } // fprintf(stderr, "GFX_DirtyRectCopy(): Slow copy!\n"); for (y=ymin; y < ymax; y += pBuf->w) { for (x=xmin; x < xmax; x++) { pBuf->pFB[x + y] = pObj->pBG[x + y]; } } #endif } void GFX_box_draw(gfx_t *pObj, box_t *pBox, UINT32 posx, UINT32 posy, UINT32 color) { UINT32 xmin, xmax, ymin, ymax, x, y; UINT32 *pFB, *pFB_end; buf_t *pBuf; xmin = posx; xmax = pBox->w + posx; if (xmax > pObj->w) xmax = pObj->w; ymin = posy; ymax = pBox->h + posy; if (ymax > pObj->h) ymax = pObj->h; pBuf = pObj->pBuf->pNext; // Lopp over all frame buffers, except current back buffer while(pBuf != pObj->pBuf) { GFX_DirtyRectUpdate(pBuf, xmin, xmax, ymin, ymax); pBuf = pBuf->pNext; } pBuf = pObj->pBuf; ymin *= pObj->w; ymax *= pObj->w; while (pObj->regs->pVGA_ctrl & SYS_VGA_BIT_BLIT_BSY); if (!((xmax-xmin)%8)) { for (y=ymin; y < ymax; y += pObj->w) { pFB = &pBuf->pFB[xmin + y]; pFB_end = &pBuf->pFB[xmax + y]; while(pFB < pFB_end) { __gfx_block_set_8(pFB, color); pFB += 8; } } return; } // fprintf(stderr, "GFX_box_draw(): Slow copy!\n"); for (y=ymin; y < ymax; y += pObj->w) { for (x=xmin; x < xmax; x++) { pBuf->pFB[x + y] = color; } } } void GFX_box_draw_bg(gfx_t *pObj, box_t *pBox, UINT32 posx, UINT32 posy, UINT32 color) { UINT32 xmin, xmax, ymin, ymax, x, y; UINT32 *pFB, *pFB_end; xmin = posx; xmax = pBox->w + posx; if (xmax > pObj->w) xmax = pObj->w; ymin = posy; ymax = pBox->h + posy; if (ymax > pObj->h) ymax = pObj->h; ymin *= pObj->w; ymax *= pObj->w; while (pObj->regs->pVGA_ctrl & SYS_VGA_BIT_BLIT_BSY); if (!((xmax-xmin)%8)) { for (y=ymin; y < ymax; y += pObj->w) { pFB = &pObj->pBG[xmin + y]; pFB_end = &pObj->pBG[xmax + y]; while(pFB < pFB_end) { __gfx_block_set_8(pFB, color); pFB += 8; } } return; } // fprintf(stderr, "GFX_box_draw_bg(): Slow copy!\n"); for (y=ymin; y < ymax; y += pObj->w) { for (x=xmin; x < xmax; x++) { pObj->pBG[x + y] = color; } } } void GFX_box_draw_direct(gfx_t *pObj, box_t *pBox, UINT32 posx, UINT32 posy, UINT32 color) { UINT32 xmin, xmax, ymin, ymax, x, y; UINT32 *pFB, *pFB_end; buf_t *pBuf; pBuf = pObj->pBuf->pLast; xmin = posx; xmax = pBox->w + posx; if (xmax > pObj->w) xmax = pObj->w; ymin = posy; ymax = pBox->h + posy; if (ymax > pObj->h) ymax = pObj->h; ymin *= pObj->w; ymax *= pObj->w; if (!((xmax-xmin)%8)) { for (y=ymin; y < ymax; y += pObj->w) { pFB = &pBuf->pFB[xmin + y]; pFB_end = &pBuf->pFB[xmax + y]; while(pFB < pFB_end) { __gfx_block_set_8(pFB, color); pFB += 8; } } return; } // fprintf(stderr, "GFX_box_draw_direct(): Slow copy!\n"); for (y=ymin; y < ymax; y += pObj->w) { for (x=xmin; x < xmax; x++) { pBuf->pFB[x + y] = color; } } }