diff options
Diffstat (limited to 'src/gfx/rndr_gu1.c')
-rw-r--r-- | src/gfx/rndr_gu1.c | 1584 |
1 files changed, 1584 insertions, 0 deletions
diff --git a/src/gfx/rndr_gu1.c b/src/gfx/rndr_gu1.c new file mode 100644 index 0000000..5ad5af1 --- /dev/null +++ b/src/gfx/rndr_gu1.c @@ -0,0 +1,1584 @@ +/* Copyright (c) 2005 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Neither the name of the Advanced Micro Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * */ + +/* + * This file contains routines to program the 2D acceleration hardware for + * the first generation graphics unit (GXLV, SC1200). + * + * gfx_set_bpp + * gfx_set_solid_pattern + * gfx_set_mono_pattern + * gfx_set_color_pattern + * gfx_set_solid_source + * gfx_set_mono_source + * gfx_set_raster_operation + * gfx_pattern_fill + * gfx_screen_to_screen_blt + * gfx_screen_to_screen_xblt + * gfx_color_bitmap_to_screen_blt + * gfx_color_bitmap_to_screen_xblt + * gfx_mono_bitmap_to_screen_blt + * gfx_bresenham_line + * gfx_wait_until_idle + * */ + +#if GFX_NO_IO_IN_WAIT_MACROS +#define GFX_WAIT_PENDING \ + while(READ_REG16(GP_BLIT_STATUS) & BS_BLIT_PENDING) { ; } +#define GFX_WAIT_BUSY \ + while(READ_REG16(GP_BLIT_STATUS) & BS_BLIT_BUSY) { ; } +#define GFX_WAIT_PIPELINE \ + while (READ_REG16(GP_BLIT_STATUS) & BS_PIPELINE_BUSY) { ; } +#else +#define GFX_WAIT_PENDING \ + while(READ_REG16(GP_BLIT_STATUS) & BS_BLIT_PENDING) { INB (0x80); } +#define GFX_WAIT_BUSY \ + while(READ_REG16(GP_BLIT_STATUS) & BS_BLIT_BUSY) { INB (0x80); } +#define GFX_WAIT_PIPELINE \ + while (READ_REG16(GP_BLIT_STATUS) & BS_PIPELINE_BUSY) { INB (0x80); } +#endif + +void gu1_detect_blt_buffer_base(void); + +/*--------------------------------------------------------------------------- + * GFX_SET_BPP + * + * This routine sets the bits per pixel value in the graphics engine. + * It is also stored in a static variable to use in the future calls to + * the rendering routines. + *--------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_set_bpp(unsigned short bpp) +#else +void +gfx_set_bpp(unsigned short bpp) +#endif +{ + int control = 0; + unsigned short pitch = gfx_get_display_pitch(); + + GFXbpp = bpp; + + /* DETECT BASE ADDRESSES FOR BLT BUFFERS */ + /* Different for 2K or 3K of scratchpad. Also need to calculate */ + /* the number of pixels that can fit in a BLT buffer - need to */ + /* subtract 16 for alignment considerations. The 2K case, for */ + /* example, is 816 bytes wide, allowing 800 pixels in 8 BPP, which */ + /* means rendering operations won't be split for 800x600. */ + + gu1_detect_blt_buffer_base(); + GFXbufferWidthPixels = GFXbb1Base - GFXbb0Base - 16; + if (bpp > 8) { + /* If 16bpp, divide GFXbufferWidthPixels by 2 */ + GFXbufferWidthPixels >>= 1; + } + + /* SET THE GRAPHICS CONTROLLER BPP AND PITCH */ + if (bpp > 8) { + /* Set the 16bpp bit if necessary */ + control = BC_16BPP; + } + if ((gfx_cpu_version == GFX_CPU_PYRAMID) && (pitch > 2048)) { + control |= BC_FB_WIDTH_4096; + } else if (pitch > 1024) { + control |= BC_FB_WIDTH_2048; + } + GFX_WAIT_BUSY; + WRITE_REG32(GP_BLIT_STATUS, control); +} + +/* + *--------------------------------------------------------------------------- + * GFX_SET_SOLID_SOURCE + * + * This routine is used to specify a solid source color. For the Xfree96 + * display driver, the source color is used to specify a planemask and the + * ROP is adjusted accordingly. + *--------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_set_solid_source(unsigned long color) +#else +void +gfx_set_solid_source(unsigned long color) +#endif +{ + /* CLEAR TRANSPARENCY FLAG */ + + GFXsourceFlags = 0; + + /* FORMAT 8 BPP COLOR */ + /* GX requires 8BPP color data be duplicated into bits [15:8]. */ + + if (GFXbpp == 8) { + color &= 0x00FF; + color |= (color << 8); + } + + /* POLL UNTIL ABLE TO WRITE THE SOURCE COLOR */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_SRC_COLOR_0, (unsigned short)color); + WRITE_REG16(GP_SRC_COLOR_1, (unsigned short)color); +} + +/* + *--------------------------------------------------------------------------- + * GFX_SET_MONO_SOURCE + * + * This routine is used to specify the monochrome source colors. + * It must be called *after* loading any pattern data (those routines + * clear the source flags). + *--------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_set_mono_source(unsigned long bgcolor, unsigned long fgcolor, + unsigned short transparent) +#else +void +gfx_set_mono_source(unsigned long bgcolor, unsigned long fgcolor, + unsigned short transparent) +#endif +{ + /* SET TRANSPARENCY FLAG */ + + GFXsourceFlags = transparent ? RM_SRC_TRANSPARENT : 0; + + /* FORMAT 8 BPP COLOR */ + /* GX requires 8BPP color data be duplicated into bits [15:8]. */ + + if (GFXbpp == 8) { + bgcolor &= 0x00FF; + bgcolor |= (bgcolor << 8); + fgcolor &= 0x00FF; + fgcolor |= (fgcolor << 8); + } + + /* POLL UNTIL ABLE TO WRITE THE SOURCE COLOR */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_SRC_COLOR_0, (unsigned short)bgcolor); + WRITE_REG16(GP_SRC_COLOR_1, (unsigned short)fgcolor); +} + +/* + *--------------------------------------------------------------------------- + * GFX_SET_SOLID_PATTERN + * + * This routine is used to specify a solid pattern color. It is called + * before performing solid rectangle fills or more complicated BLTs that + * use a solid pattern color. + * + * The driver should always call "gfx_load_raster_operation" after a call + * to this routine to make sure that the pattern flags are set appropriately. + *--------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_set_solid_pattern(unsigned long color) +#else +void +gfx_set_solid_pattern(unsigned long color) +#endif +{ + /* CLEAR TRANSPARENCY FLAG */ + + GFXsourceFlags = 0; + + /* SET PATTERN FLAGS */ + + GFXpatternFlags = 0; + + /* FORMAT 8 BPP COLOR */ + /* GX requires 8BPP color data be duplicated into bits [15:8]. */ + + if (GFXbpp == 8) { + color &= 0x00FF; + color |= (color << 8); + } + + /* SAVE THE REFORMATTED COLOR FOR LATER */ + /* Used to call the "GFX_solid_fill" routine for special cases. */ + + GFXsavedColor = color; + + /* POLL UNTIL ABLE TO WRITE THE PATTERN COLOR */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_PAT_COLOR_0, (unsigned short)color); +} + +/* + *--------------------------------------------------------------------------- + * GFX_SET_MONO_PATTERN + * + * This routine is used to specify a monochrome pattern. + *--------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_set_mono_pattern(unsigned long bgcolor, unsigned long fgcolor, + unsigned long data0, unsigned long data1, unsigned char transparent) +#else +void +gfx_set_mono_pattern(unsigned long bgcolor, unsigned long fgcolor, + unsigned long data0, unsigned long data1, unsigned char transparent) +#endif +{ + /* CLEAR TRANSPARENCY FLAG */ + + GFXsourceFlags = 0; + + /* SET PATTERN FLAGS */ + + GFXpatternFlags = transparent ? RM_PAT_MONO | RM_PAT_TRANSPARENT : + RM_PAT_MONO; + + /* FORMAT 8 BPP COLOR */ + /* GXm requires 8BPP color data be duplicated into bits [15:8]. */ + + if (GFXbpp == 8) { + bgcolor &= 0x00FF; + bgcolor |= (bgcolor << 8); + fgcolor &= 0x00FF; + fgcolor |= (fgcolor << 8); + } + + /* POLL UNTIL ABLE TO WRITE THE PATTERN COLORS AND DATA */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_PAT_COLOR_0, (unsigned short)bgcolor); + WRITE_REG16(GP_PAT_COLOR_1, (unsigned short)fgcolor); + WRITE_REG32(GP_PAT_DATA_0, data0); + WRITE_REG32(GP_PAT_DATA_1, data1); +} + +/* + *--------------------------------------------------------------------------- + * GFX_SET_COLOR_PATTERN + * + * This routine is used to specify a color pattern. + *--------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_set_color_pattern(unsigned long bgcolor, unsigned long fgcolor, + unsigned long data0, unsigned long data1, unsigned long data2, + unsigned long data3, unsigned char transparent) +#else +void +gfx_set_color_pattern(unsigned long bgcolor, unsigned long fgcolor, + unsigned long data0, unsigned long data1, unsigned long data2, + unsigned long data3, unsigned char transparent) +#endif +{ + /* CLEAR TRANSPARENCY FLAG */ + + GFXsourceFlags = 0; + + /* SET PATTERN FLAGS */ + + GFXpatternFlags = transparent ? RM_PAT_MONO | RM_PAT_TRANSPARENT : + RM_PAT_MONO; + + GFXpatternFlags |= RM_PAT_COLOR; + /* FORMAT 8 BPP COLOR */ + /* GXm requires 8BPP color data be duplicated into bits [15:8]. */ + + if (GFXbpp == 8) { + bgcolor &= 0x00FF; + bgcolor |= (bgcolor << 8); + fgcolor &= 0x00FF; + fgcolor |= (fgcolor << 8); + } + + /* POLL UNTIL ABLE TO WRITE THE PATTERN COLORS AND DATA */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_PAT_COLOR_0, (unsigned short)bgcolor); + WRITE_REG16(GP_PAT_COLOR_1, (unsigned short)fgcolor); + WRITE_REG32(GP_PAT_DATA_0, data0); + WRITE_REG32(GP_PAT_DATA_1, data1); + if (GFXbpp > 8) { + WRITE_REG32(GP_PAT_DATA_2, data2); + WRITE_REG32(GP_PAT_DATA_3, data3); + } +} + +/* + *--------------------------------------------------------------------------- + * GFX_LOAD_COLOR_PATTERN_LINE + * + * This routine is used to load a single line of a 8x8 color pattern. + *--------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_load_color_pattern_line(short y, unsigned long *pattern_8x8) +#else +void +gfx_load_color_pattern_line(short y, unsigned long *pattern_8x8) +#endif +{ + /* CLEAR TRANSPARENCY FLAG */ + + GFXsourceFlags = 0; + + /* SET PATTERN FLAGS */ + + GFXpatternFlags = RM_PAT_COLOR; + + y &= 7; + + if (GFXbpp > 8) + pattern_8x8 += (y << 2); + else + pattern_8x8 += (y << 1); + + /* POLL UNTIL ABLE TO WRITE THE PATTERN COLORS AND DATA */ + + GFX_WAIT_PENDING; + WRITE_REG32(GP_PAT_DATA_0, pattern_8x8[0]); + WRITE_REG32(GP_PAT_DATA_1, pattern_8x8[1]); + if (GFXbpp > 8) { + WRITE_REG32(GP_PAT_DATA_2, pattern_8x8[2]); + WRITE_REG32(GP_PAT_DATA_3, pattern_8x8[3]); + } +} + +/* + *--------------------------------------------------------------------------- + * GFX_SET_RASTER_OPERATION + * + * This routine loads the specified raster operation. It sets the pattern + * flags appropriately. + *--------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_set_raster_operation(unsigned char rop) +#else +void +gfx_set_raster_operation(unsigned char rop) +#endif +{ + unsigned short rop16; + + /* GENERATE 16-BIT VERSION OF ROP WITH PATTERN FLAGS */ + + rop16 = (unsigned short)rop | GFXpatternFlags; + if ((rop & 0x33) ^ ((rop >> 2) & 0x33)) + rop16 |= GFXsourceFlags; + + /* SAVE ROP FOR LATER COMPARISONS */ + /* Need to have the pattern flags included */ + + GFXsavedRop = rop16; + + /* SET FLAG INDICATING ROP REQUIRES DESTINATION DATA */ + /* True if even bits (0:2:4:6) do not equal the correspinding */ + /* even bits (1:3:5:7). */ + + GFXusesDstData = ((rop & 0x55) ^ ((rop >> 1) & 0x55)); + + /* POLL UNTIL ABLE TO WRITE THE PATTERN COLOR */ + /* Only one operation can be pending at a time. */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_RASTER_MODE, rop16); +} + +/* + *--------------------------------------------------------------------------- + * GFX_SOLID_FILL + * + * This routine MUST be used when performing a solid rectangle fill with + * the ROPs of PATCOPY (0xF0), BLACKNESS (0x00), WHITENESS (0xFF), or + * PATINVERT (0x0F). There is a bug in GXm for these cases that requires a + * workaround. + * + * For BLACKNESS (ROP = 0x00), set the color to 0x0000. + * For WHITENESS (ROP = 0xFF), set the color to 0xFFFF. + * For PATINVERT (ROP = 0x0F), invert the desired color. + * + * X screen X position (left) + * Y screen Y position (top) + * WIDTH width of rectangle, in pixels + * HEIGHT height of rectangle, in scanlines + * COLOR fill color + * + * THIS ROUTINE SHOULD NOT BE DIRECTLY CALLED FROM THE DRIVER. The driver + * should always use GFX_pattern_fill and let that routine call this one + * when approipriate. This is to hide quirks specific to MediaGX hardware. + *--------------------------------------------------------------------------- + */ +void +gu1_solid_fill(unsigned short x, unsigned short y, + unsigned short width, unsigned short height, unsigned long color) +{ + unsigned short section; + + /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */ + /* Only one operation can be pending at a time. */ + + GFX_WAIT_PENDING; + + /* SET REGISTERS TO DRAW RECTANGLE */ + + WRITE_REG16(GP_DST_XCOOR, x); + WRITE_REG16(GP_DST_YCOOR, y); + WRITE_REG16(GP_HEIGHT, height); + WRITE_REG16(GP_RASTER_MODE, 0x00F0); /* PATCOPY */ + WRITE_REG16(GP_PAT_COLOR_0, (unsigned short)color); + + /* CHECK WIDTH FOR GX BUG WORKAROUND */ + + if (width <= 16) { + /* OK TO DRAW SMALL RECTANGLE IN ONE PASS */ + + WRITE_REG16(GP_WIDTH, width); + WRITE_REG16(GP_BLIT_MODE, 0); + } else { + /* DRAW FIRST PART OF RECTANGLE */ + /* Get to a 16 pixel boundary. */ + + section = 0x10 - (x & 0x0F); + WRITE_REG16(GP_WIDTH, section); + WRITE_REG16(GP_BLIT_MODE, 0); + + /* POLL UNTIL ABLE TO LOAD THE SECOND RECTANGLE */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_DST_XCOOR, x + section); + WRITE_REG16(GP_DST_YCOOR, y); + WRITE_REG16(GP_WIDTH, width - section); + WRITE_REG16(GP_BLIT_MODE, 0); + } +} + +/* + *---------------------------------------------------------------------------- + * GFX_PATTERN_FILL + * + * This routine is used to fill a rectangular region. The pattern must + * be previously loaded using one of GFX_load_*_pattern routines. Also, the + * raster operation must be previously specified using the + * "GFX_load_raster_operation" routine. + * + * X screen X position (left) + * Y screen Y position (top) + * WIDTH width of rectangle, in pixels + * HEIGHT height of rectangle, in scanlines + *---------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_pattern_fill(unsigned short x, unsigned short y, + unsigned short width, unsigned short height) +#else +void +gfx_pattern_fill(unsigned short x, unsigned short y, + unsigned short width, unsigned short height) +#endif +{ + unsigned short section, buffer_width, blit_mode; + + /* CHECK IF OPTIMIZED SOLID CASES */ + /* Check all 16 bits of the ROP to include solid pattern flags. */ + + switch (GFXsavedRop) { + /* CHECK FOR SPECIAL CASES WITHOUT DESTINATION DATA */ + /* Need hardware workaround for fast "burst write" cases. */ + + case 0x00F0: + gu1_solid_fill(x, y, width, height, (unsigned short)GFXsavedColor); + break; + case 0x000F: + gu1_solid_fill(x, y, width, height, (unsigned short)~GFXsavedColor); + break; + case 0x0000: + gu1_solid_fill(x, y, width, height, 0x0000); + break; + case 0x00FF: + gu1_solid_fill(x, y, width, height, 0xFFFF); + break; + + /* REMAINING CASES REQUIRE DESTINATION DATA OR NOT SOLID COLOR */ + + default: + + /* DETERMINE BLT MODE VALUE */ + /* Still here for non-solid patterns without destination data. */ + + blit_mode = GFXusesDstData ? BM_READ_DST_FB0 : 0; + + /* SET SOURCE EXPANSION MODE */ + /* If the ROP requires source data, then the source data is all 1's */ + /* and then expanded into the desired color in GP_SRC_COLOR_1. */ + + blit_mode |= BM_SOURCE_EXPAND; + + /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */ + /* Write the registers that do not change for each section. */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_HEIGHT, height); + + /* SINCE ONLY DESTINATION DATA, WE CAN USE BOTH BB0 AND BB1. */ + /* Therefore, width available = BLT buffer width * 2. */ + + buffer_width = GFXbufferWidthPixels << 1; + + /* REPEAT UNTIL FINISHED WITH RECTANGLE */ + /* Perform BLT in vertical sections, as wide as the BLT buffer */ + /* allows. Hardware does not split the operations, so */ + /* software must do it to avoid large scanlines that would */ + /* overflow the BLT buffers. */ + + while (width > 0) { + /* DETERMINE WIDTH OF SECTION */ + + if (width > buffer_width) + section = buffer_width; + else + section = width; + + /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_DST_XCOOR, x); + WRITE_REG16(GP_DST_YCOOR, y); + WRITE_REG16(GP_WIDTH, section); + WRITE_REG16(GP_BLIT_MODE, blit_mode); + + /* ADJUST PARAMETERS FOR NEXT SECTION */ + + width -= section; + x += section; + } + break; + } +} + +/* + *---------------------------------------------------------------------------- + * GFX_COLOR_PATTERN_FILL + * + * This routine is used to render a rectangle using the current raster + * operation and the specified color pattern. It allows an 8x8 color + * pattern to be rendered without multiple calls to the gfx_set_color_pattern + * and gfx_pattern_fill routines. + * + * X screen X position (left) + * Y screen Y position (top) + * WIDTH width of rectangle, in pixels + * HEIGHT height of rectangle, in scanlines + * *PATTERN pointer to 8x8 color pattern data + *---------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_color_pattern_fill(unsigned short x, unsigned short y, + unsigned short width, unsigned short height, unsigned long *pattern) +#else +void +gfx_color_pattern_fill(unsigned short x, unsigned short y, + unsigned short width, unsigned short height, unsigned long *pattern) +#endif +{ + unsigned short blit_mode, passes, cur_y, pat_y, i; + unsigned short buffer_width, line_width; + unsigned short bpp_shift, section, cur_x; + + /* SET APPROPRIATE INCREMENT */ + + bpp_shift = (GFXbpp > 8) ? 2 : 1; + + /* SET DESTINATION REQUIRED */ + + blit_mode = GFXusesDstData ? BM_READ_DST_FB0 : 0; + + /* SET SOURCE EXPANSION */ + + blit_mode |= BM_SOURCE_EXPAND; + + /* OVERRIDE RASTER MODE TO FORCE A COLOR PATTERN */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_RASTER_MODE, + (GFXsavedRop & ~RM_PAT_MASK & ~RM_PAT_TRANSPARENT) | RM_PAT_COLOR); + + /* WRITE THE REGISTERS THAT DO NOT CHANGE */ + /* If destination data is required, the width and */ + /* x position will be overwritten. */ + + WRITE_REG16(GP_HEIGHT, 1); + WRITE_REG16(GP_WIDTH, width); + WRITE_REG16(GP_DST_XCOOR, x); + + /* THE ENTIRE PATTERN WILL NOT BE DRAWN IF THE HEIGHT IS LESS THAN 8 */ + + passes = (height < 8) ? height : 8; + + /* SINCE ONLY DESTINATION DATA, WE CAN USE BOTH BB0 AND BB1. */ + /* Therefore, width available = BLT buffer width * 2. */ + + buffer_width = GFXbufferWidthPixels << 1; + + for (i = 0; i < passes; i++) { + pat_y = ((y + i) & 7) << bpp_shift; + cur_y = y + i; + + /* WRITE THE PATTERN DATA FOR THE ACTIVE LINE */ + + GFX_WAIT_PENDING; + WRITE_REG32(GP_PAT_DATA_0, pattern[pat_y]); + WRITE_REG32(GP_PAT_DATA_1, pattern[pat_y + 1]); + + if (GFXbpp > 8) { + WRITE_REG32(GP_PAT_DATA_2, pattern[pat_y + 2]); + WRITE_REG32(GP_PAT_DATA_3, pattern[pat_y + 3]); + } + + /* SPLIT BLT LINE INTO SECTIONS IF REQUIRED */ + /* If no destination data is required, we can ignore */ + /* the BLT buffers. Otherwise, we must separate the BLT */ + /* so as not to overflow the buffers */ + + if (blit_mode & BM_READ_DST_BB0) { + line_width = width; + cur_x = x; + + while (line_width) { + section = + (line_width > buffer_width) ? buffer_width : line_width; + cur_y = y + i; + + GFX_WAIT_PENDING; + WRITE_REG16(GP_DST_XCOOR, cur_x); + WRITE_REG16(GP_WIDTH, section); + + while (cur_y < y + height) { + GFX_WAIT_PENDING; + WRITE_REG16(GP_DST_YCOOR, cur_y); + WRITE_REG16(GP_BLIT_MODE, blit_mode); + cur_y += 8; + } + + cur_x += section; + line_width -= section; + } + + } else { + while (cur_y < y + height) { + GFX_WAIT_PENDING; + WRITE_REG16(GP_DST_YCOOR, cur_y); + WRITE_REG16(GP_BLIT_MODE, blit_mode); + cur_y += 8; + } + } + + } + + /* RESTORE ORIGINAL ROP AND FLAGS */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_RASTER_MODE, GFXsavedRop); + +} + +/* + *---------------------------------------------------------------------------- + * SCREEN TO SCREEN BLT + * + * This routine should be used to perform a screen to screen BLT when the + * ROP does not require destination data. + * + * SRCX screen X position to copy from + * SRCY screen Y position to copy from + * DSTX screen X position to copy to + * DSTY screen Y position to copy to + * WIDTH width of rectangle, in pixels + * HEIGHT height of rectangle, in scanlines + *---------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_screen_to_screen_blt(unsigned short srcx, unsigned short srcy, + unsigned short dstx, unsigned short dsty, unsigned short width, + unsigned short height) +#else +void +gfx_screen_to_screen_blt(unsigned short srcx, unsigned short srcy, + unsigned short dstx, unsigned short dsty, unsigned short width, + unsigned short height) +#endif +{ + unsigned short section, buffer_width; + unsigned short blit_mode; + + /* CHECK IF RASTER OPERATION REQUIRES DESTINATION DATA */ + + blit_mode = GFXusesDstData ? BM_READ_DST_FB1 | BM_READ_SRC_FB : + BM_READ_SRC_FB; + + /* CHECK Y DIRECTION */ + /* Hardware has support for negative Y direction. */ + + if (dsty > srcy) { + blit_mode |= BM_REVERSE_Y; + srcy += height - 1; + dsty += height - 1; + } + + /* CHECK X DIRECTION */ + /* Hardware does not support negative X direction since at the time */ + /* of development all supported resolutions could fit a scanline of */ + /* data at once into the BLT buffers (using both BB0 and BB1). This */ + /* code is more generic to allow for any size BLT buffer. */ + + if (dstx > srcx) { + srcx += width; + dstx += width; + } + + /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */ + /* Write the registers that do not change for each section. */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_HEIGHT, height); + + /* CHECK AVAILABLE BLT BUFFER SIZE */ + /* Can use both BLT buffers if no destination data is required. */ + + buffer_width = GFXusesDstData ? GFXbufferWidthPixels : + GFXbufferWidthPixels << 1; + + /* REPEAT UNTIL FINISHED WITH RECTANGLE */ + /* Perform BLT in vertical sections, as wide as the BLT buffer allows. */ + /* Hardware does not split the operations, so software must do it to */ + /* avoid large scanlines that would overflow the BLT buffers. */ + + while (width > 0) { + /* CHECK WIDTH OF CURRENT SECTION */ + + if (width > buffer_width) + section = buffer_width; + else + section = width; + + /* PROGRAM REGISTERS THAT ARE THE SAME FOR EITHER X DIRECTION */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_SRC_YCOOR, srcy); + WRITE_REG16(GP_DST_YCOOR, dsty); + WRITE_REG16(GP_WIDTH, section); + + /* CHECK X DIRECTION */ + + if (dstx > srcx) { + /* NEGATIVE X DIRECTION */ + /* Still positive X direction within the section. */ + + srcx -= section; + dstx -= section; + WRITE_REG16(GP_SRC_XCOOR, srcx); + WRITE_REG16(GP_DST_XCOOR, dstx); + WRITE_REG16(GP_BLIT_MODE, blit_mode); + } else { + /* POSITIVE X DIRECTION */ + + WRITE_REG16(GP_SRC_XCOOR, srcx); + WRITE_REG16(GP_DST_XCOOR, dstx); + WRITE_REG16(GP_BLIT_MODE, blit_mode); + dstx += section; + srcx += section; + } + width -= section; + } +} + +/* + *---------------------------------------------------------------------------- + * SCREEN TO SCREEN TRANSPARENT BLT + * + * This routine should be used to perform a screen to screen BLT when a + * specified color should by transparent. The only supported ROP is SRCCOPY. + * + * SRCX screen X position to copy from + * SRCY screen Y position to copy from + * DSTX screen X position to copy to + * DSTY screen Y position to copy to + * WIDTH width of rectangle, in pixels + * HEIGHT height of rectangle, in scanlines + * COLOR transparent color + *---------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_screen_to_screen_xblt(unsigned short srcx, unsigned short srcy, + unsigned short dstx, unsigned short dsty, unsigned short width, + unsigned short height, unsigned long color) +#else +void +gfx_screen_to_screen_xblt(unsigned short srcx, unsigned short srcy, + unsigned short dstx, unsigned short dsty, unsigned short width, + unsigned short height, unsigned long color) +#endif +{ + unsigned short section, buffer_width; + unsigned short blit_mode = BM_READ_SRC_FB; + + /* CHECK Y DIRECTION */ + /* Hardware has support for negative Y direction. */ + + if (dsty > srcy) { + blit_mode |= BM_REVERSE_Y; + srcy += height - 1; + dsty += height - 1; + } + + /* CHECK X DIRECTION */ + /* Hardware does not support negative X direction since at the time */ + /* of development all supported resolutions could fit a scanline of */ + /* data at once into the BLT buffers (using both BB0 and BB1). This */ + /* code is more generic to allow for any size BLT buffer. */ + + if (dstx > srcx) { + srcx += width; + dstx += width; + } + + /* CALCULATE BLT BUFFER SIZE */ + /* Need to use BB1 to store the BLT buffer data. */ + + buffer_width = GFXbufferWidthPixels; + + /* WRITE TRANSPARENCY COLOR TO BLT BUFFER 1 */ + + if (GFXbpp == 8) { + color &= 0x00FF; + color |= (color << 8); + } + color = (color & 0x0000FFFF) | (color << 16); + + /* WAIT UNTIL PIPELINE IS NOT BUSY BEFORE LOADING DATA INTO BB1 */ + /* Need to make sure any previous BLT using BB1 is complete. */ + /* Only need to load 32 bits of BB1 for the 1 pixel BLT that follows. */ + + GFX_WAIT_BUSY; + WRITE_SCRATCH32(GFXbb1Base, color); + + /* DO BOGUS BLT TO LATCH DATA FROM BB1 */ + /* Already know graphics pipeline is idle. */ + /* Only need to latch data into the holding registers for the current */ + /* data from BB1. A 1 pixel wide BLT will suffice. */ + + WRITE_REG32(GP_DST_XCOOR, 0); + WRITE_REG32(GP_SRC_XCOOR, 0); + WRITE_REG32(GP_WIDTH, 0x00010001); + WRITE_REG16(GP_RASTER_MODE, 0x00CC); + WRITE_REG16(GP_BLIT_MODE, BM_READ_SRC_FB | BM_READ_DST_BB1); + + /* WRITE REGISTERS FOR REAL SCREEN TO SCREEN BLT */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_HEIGHT, height); + WRITE_REG16(GP_RASTER_MODE, 0x10C6); + WRITE_REG32(GP_PAT_COLOR_0, 0xFFFFFFFF); + + /* REPEAT UNTIL FINISHED WITH RECTANGLE */ + /* Perform BLT in vertical sections, as wide as the BLT buffer allows. */ + /* Hardware does not split the operations, so software must do it to */ + /* avoid large scanlines that would overflow the BLT buffers. */ + + while (width > 0) { + /* CHECK WIDTH OF CURRENT SECTION */ + + if (width > buffer_width) + section = buffer_width; + else + section = width; + + /* PROGRAM REGISTERS THAT ARE THE SAME FOR EITHER X DIRECTION */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_SRC_YCOOR, srcy); + WRITE_REG16(GP_DST_YCOOR, dsty); + WRITE_REG16(GP_WIDTH, section); + + /* CHECK X DIRECTION */ + /* Again, this must be done in software, and can be removed if the */ + /* display driver knows that the BLT buffers will always be large */ + /* enough to contain an entire scanline of a screen to screen BLT. */ + + if (dstx > srcx) { + /* NEGATIVE X DIRECTION */ + /* Still positive X direction within the section. */ + + srcx -= section; + dstx -= section; + WRITE_REG16(GP_SRC_XCOOR, srcx); + WRITE_REG16(GP_DST_XCOOR, dstx); + WRITE_REG16(GP_BLIT_MODE, blit_mode); + } else { + /* POSITIVE X DIRECTION */ + + WRITE_REG16(GP_SRC_XCOOR, srcx); + WRITE_REG16(GP_DST_XCOOR, dstx); + WRITE_REG16(GP_BLIT_MODE, blit_mode); + dstx += section; + srcx += section; + } + width -= section; + } +} + +/* + *---------------------------------------------------------------------------- + * COLOR BITMAP TO SCREEN BLT + * + * This routine transfers color bitmap data to the screen. For most cases, + * when the ROP is SRCCOPY, it may be faster to write a separate routine that + * copies the data to the frame buffer directly. This routine should be + * used when the ROP requires destination data. + * + * Transparency is handled by another routine. + * + * SRCX X offset within source bitmap + * SRCY Y offset within source bitmap + * DSTX screen X position to render data + * DSTY screen Y position to render data + * WIDTH width of rectangle, in pixels + * HEIGHT height of rectangle, in scanlines + * *DATA pointer to bitmap data + * PITCH pitch of bitmap data (bytes between scanlines) + *---------------------------------------------------------------------------- + */ + +#if GFX_2DACCEL_DYNAMIC +void +gu1_color_bitmap_to_screen_blt(unsigned short srcx, unsigned short srcy, + unsigned short dstx, unsigned short dsty, unsigned short width, + unsigned short height, unsigned char *data, long pitch) +#else +void +gfx_color_bitmap_to_screen_blt(unsigned short srcx, unsigned short srcy, + unsigned short dstx, unsigned short dsty, unsigned short width, + unsigned short height, unsigned char *data, long pitch) +#endif +{ + unsigned short section, buffer_width; + unsigned short blit_mode = BM_READ_SRC_BB0; + unsigned short temp_height; + unsigned long dword_bytes_needed, bytes_extra; + unsigned long bpp_shift; + long array_offset; + + /* CHECK SIZE OF BLT BUFFER */ + + buffer_width = GFXbufferWidthPixels; + + /* CHECK IF RASTER OPERATION REQUIRES DESTINATION DATA */ + /* If no destination data, we have twice the room for */ + /* source data. */ + + if (GFXusesDstData) + blit_mode |= BM_READ_DST_FB1; + else + buffer_width <<= 1; + + /* SET THE SCRATCHPAD BASE */ + + SET_SCRATCH_BASE(GFXbb0Base); + + /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */ + /* Write the registers that do not change for each section. */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_HEIGHT, 1); + + bpp_shift = (GFXbpp + 7) >> 4; + + while (width > 0) { + if (width > buffer_width) + section = buffer_width; + else + section = width; + + dword_bytes_needed = (section << bpp_shift) & ~3l; + bytes_extra = (section << bpp_shift) & 3l; + + temp_height = height; + + /* WRITE THE REGISTERS FOR EACH SECTION */ + /* The GX hardware will auto-increment the Y coordinate, meaning */ + /* that we don't have to. */ + + WRITE_REG16(GP_WIDTH, section); + WRITE_REG16(GP_DST_XCOOR, dstx); + WRITE_REG16(GP_DST_YCOOR, dsty); + + /* CALCULATE THE BITMAP OFFSET */ + + array_offset = + (unsigned long)srcy *(long)pitch + ((long)srcx << bpp_shift); + + while (temp_height--) { + GFX_WAIT_PIPELINE; + + /* WRITE ALL DATA TO THE BLT BUFFERS */ + /* The WRITE_SCRATCH_STRING macro assumes that the data begins + * at the scratchpad offset set by the SET_SCRATCH_BASE macro. + * */ + + WRITE_SCRATCH_STRING(dword_bytes_needed, bytes_extra, data, + array_offset); + WRITE_REG16(GP_BLIT_MODE, blit_mode); + + array_offset += pitch; + } + + width -= section; + srcx += section; + dstx += section; + } +} + +/* + *---------------------------------------------------------------------------- + * COLOR BITMAP TO SCREEN TRANSPARENT BLT + * + * This routine transfers color bitmap data to the screen with transparency. + * The transparent color is specified. The only supported ROP is SRCCOPY, + * meaning that transparency cannot be applied if the ROP requires + * destination data (this is a hardware restriction). + * + * SRCX X offset within source bitmap + * SRCY Y offset within source bitmap + * DSTX screen X position to render data + * DSTY screen Y position to render data + * WIDTH width of rectangle, in pixels + * HEIGHT height of rectangle, in scanlines + * *DATA pointer to bitmap data + * PITCH pitch of bitmap data (bytes between scanlines) + * COLOR transparent color + *---------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_color_bitmap_to_screen_xblt(unsigned short srcx, unsigned short srcy, + unsigned short dstx, unsigned short dsty, unsigned short width, + unsigned short height, unsigned char *data, long pitch, + unsigned long color) +#else +void +gfx_color_bitmap_to_screen_xblt(unsigned short srcx, unsigned short srcy, + unsigned short dstx, unsigned short dsty, unsigned short width, + unsigned short height, unsigned char *data, long pitch, + unsigned long color) +#endif +{ + unsigned short section, buffer_width; + unsigned short temp_height; + unsigned long dword_bytes_needed, bytes_extra; + unsigned long bpp_shift; + long array_offset; + + /* CHECK SIZE OF BLT BUFFER */ + + buffer_width = GFXbufferWidthPixels; + + /* WRITE TRANSPARENCY COLOR TO BLT BUFFER 1 */ + + if (GFXbpp == 8) { + color &= 0x00FF; + color |= (color << 8); + } + color = (color & 0x0000FFFF) | (color << 16); + + /* WAIT UNTIL PIPELINE IS NOT BUSY BEFORE LOADING DATA INTO BB1 */ + /* Need to make sure any previous BLT using BB1 is complete. */ + /* Only need to load 32 bits of BB1 for the 1 pixel BLT that follows. */ + + GFX_WAIT_PIPELINE; + GFX_WAIT_PENDING; + WRITE_SCRATCH32(GFXbb1Base, color); + + /* DO BOGUS BLT TO LATCH DATA FROM BB1 */ + /* Already know graphics pipeline is idle. */ + /* Only need to latch data into the holding registers for the current */ + /* data from BB1. A 1 pixel wide BLT will suffice. */ + + WRITE_REG32(GP_DST_XCOOR, 0); + WRITE_REG32(GP_SRC_XCOOR, 0); + WRITE_REG32(GP_WIDTH, 0x00010001); + WRITE_REG16(GP_RASTER_MODE, 0x00CC); + WRITE_REG16(GP_BLIT_MODE, BM_READ_SRC_FB | BM_READ_DST_BB1); + + /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */ + /* Write the registers that do not change for each section. */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_HEIGHT, 1); + WRITE_REG16(GP_RASTER_MODE, 0x10C6); + WRITE_REG32(GP_PAT_COLOR_0, 0xFFFFFFFF); + + bpp_shift = (GFXbpp + 7) >> 4; + + /* SET THE SCRATCHPAD BASE */ + + SET_SCRATCH_BASE(GFXbb0Base); + + while (width > 0) { + if (width > buffer_width) + section = buffer_width; + else + section = width; + + dword_bytes_needed = (section << bpp_shift) & ~3l; + bytes_extra = (section << bpp_shift) & 3l; + + temp_height = height; + + /* WRITE THE REGISTERS FOR EACH SECTION */ + /* The GX hardware will auto-increment the Y coordinate, meaning */ + /* that we don't have to. */ + + WRITE_REG16(GP_WIDTH, section); + WRITE_REG16(GP_DST_XCOOR, dstx); + WRITE_REG16(GP_DST_YCOOR, dsty); + + /* CALCULATE THE BITMAP OFFSET */ + + array_offset = + (unsigned long)srcy *(long)pitch + ((long)srcx << bpp_shift); + + while (temp_height--) { + GFX_WAIT_PIPELINE; + + /* WRITE ALL DATA TO THE BLT BUFFERS */ + /* The WRITE_SCRATCH_STRING macro assumes that the data begins at the */ + /* scratchpad offset set by the SET_SCRATCH_BASE macro. */ + + WRITE_SCRATCH_STRING(dword_bytes_needed, bytes_extra, data, + array_offset); + WRITE_REG16(GP_BLIT_MODE, BM_READ_SRC_BB0); + + array_offset += pitch; + } + + width -= section; + srcx += section; + dstx += section; + } +} + +/* + *---------------------------------------------------------------------------- + * MONOCHROME BITMAP TO SCREEN BLT + * + * This routine transfers monochrome bitmap data to the screen. + * + * SRCX X offset within source bitmap + * SRCY Y offset within source bitmap + * DSTX screen X position to render data + * DSTY screen Y position to render data + * WIDTH width of rectangle, in pixels + * HEIGHT height of rectangle, in scanlines + * *DATA pointer to bitmap data + * PITCH pitch of bitmap data (bytes between scanlines) + *---------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_mono_bitmap_to_screen_blt(unsigned short srcx, unsigned short srcy, + unsigned short dstx, unsigned short dsty, unsigned short width, + unsigned short height, unsigned char *data, short pitch) +#else +void +gfx_mono_bitmap_to_screen_blt(unsigned short srcx, unsigned short srcy, + unsigned short dstx, unsigned short dsty, unsigned short width, + unsigned short height, unsigned char *data, short pitch) +#endif +{ + unsigned short section, buffer_width; + unsigned short blit_mode = BM_READ_SRC_BB0 | BM_SOURCE_EXPAND; + unsigned short temp_height; + unsigned long dword_bytes_needed, bytes_extra; + long array_offset; + + /* CHECK IF RASTER OPERATION REQUIRES DESTINATION DATA */ + /* If no destination data, the source data will always fit. */ + /* So, in that event we will set the buffer width to a */ + /* fictitiously large value such that the BLT is never split. */ + + if (GFXusesDstData) { + buffer_width = GFXbufferWidthPixels; + blit_mode |= BM_READ_DST_FB1; + } else + buffer_width = 3200; + + /* CHECK IF DATA ALREADY IN BLIT BUFFER */ + /* If the pointer is NULL, data for the full BLT is already there */ + /* WARNING: This could cause problems if destination data is */ + /* involved and it overflows the BLT buffer. Need to remove */ + /* this option and change the drivers to use a temporary buffer. */ + + if (!data) { + GFX_WAIT_PENDING; + WRITE_REG16(GP_SRC_XCOOR, srcx & 7); + WRITE_REG16(GP_DST_XCOOR, dstx); + WRITE_REG16(GP_DST_YCOOR, dsty); + WRITE_REG16(GP_WIDTH, width); + WRITE_REG16(GP_HEIGHT, height); + WRITE_REG16(GP_BLIT_MODE, blit_mode); + return; + } + + /* SET THE SCRATCHPAD BASE */ + + SET_SCRATCH_BASE(GFXbb0Base); + + /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */ + /* Write the registers that do not change for each section. */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_HEIGHT, 1); + + while (width > 0) { + if (width > buffer_width) + section = buffer_width; + else + section = width; + + /* CALCULATE BYTES NEEDED */ + /* Add 1 for possible alignment issues. */ + + dword_bytes_needed = ((section + 7 + (srcx & 7)) >> 3) & ~3l; + bytes_extra = ((section + 7 + (srcx & 7)) >> 3) & 3l; + + temp_height = height; + + /* WRITE THE REGISTERS FOR EACH SECTION */ + /* The GX hardware will auto-increment the Y coordinate, meaning */ + /* that we don't have to. */ + + WRITE_REG16(GP_WIDTH, section); + WRITE_REG16(GP_DST_XCOOR, dstx); + WRITE_REG16(GP_DST_YCOOR, dsty); + WRITE_REG16(GP_SRC_XCOOR, srcx & 7); + + /* CALCULATE THE BITMAP OFFSET */ + + array_offset = (unsigned long)srcy *(long)pitch + ((long)srcx >> 3); + + while (temp_height--) { + GFX_WAIT_PIPELINE; + + /* WRITE ALL DATA TO THE BLT BUFFERS */ + /* The WRITE_SCRATCH_STRING macro assumes that the data begins at the */ + /* scratchpad offset set by the SET_SCRATCH_BASE macro. */ + + WRITE_SCRATCH_STRING(dword_bytes_needed, bytes_extra, data, + array_offset); + WRITE_REG16(GP_BLIT_MODE, blit_mode); + + array_offset += pitch; + } + + width -= section; + srcx += section; + dstx += section; + } +} + +/* + *---------------------------------------------------------------------------- + * MONOCHROME TEXT BLT + * + * This routine transfers contiguous monochrome text data to the screen. + * + * DSTX screen X position to render data + * DSTY screen Y position to render data + * WIDTH width of rectangle, in pixels + * HEIGHT height of rectangle, in scanlines + * *DATA pointer to bitmap data + *---------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_text_blt(unsigned short dstx, unsigned short dsty, unsigned short width, + unsigned short height, unsigned char *data) +#else +void +gfx_text_blt(unsigned short dstx, unsigned short dsty, unsigned short width, + unsigned short height, unsigned char *data) +#endif +{ + unsigned long dword_bytes_needed, bytes_extra; + long pitch, buffer_bytes, data_bytes; + + /* CALCULATE DATA SIZE */ + + pitch = (width + 7) >> 3; + data_bytes = (long)height *pitch; + + /* CHECK FOR SIMPLE CASE */ + /* This routine is designed to render a source copy text glyph. If + * destination data is required or the source data will not fit, we will + * punt the operation to the more versatile (and slow) mono bitmap routine + * */ + + if (GFXbpp > 8) + buffer_bytes = GFXbufferWidthPixels << 1; + else + buffer_bytes = GFXbufferWidthPixels; + + if (GFXusesDstData || data_bytes > buffer_bytes) { + gfx_mono_bitmap_to_screen_blt(0, 0, dstx, dsty, width, height, data, + (short)pitch); + return; + } + + /* SET THE SCRATCHPAD BASE */ + + SET_SCRATCH_BASE(GFXbb0Base); + + /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */ + + dword_bytes_needed = data_bytes & ~3l; + bytes_extra = data_bytes & 3l; + + GFX_WAIT_PENDING; + WRITE_REG16(GP_HEIGHT, height); + WRITE_REG16(GP_WIDTH, width); + WRITE_REG16(GP_DST_XCOOR, dstx); + WRITE_REG16(GP_DST_YCOOR, dsty); + WRITE_REG16(GP_SRC_XCOOR, 0); + + /* WRITE ALL DATA TO THE BLT BUFFERS */ + /* The WRITE_SCRATCH_STRING macro assumes that the data begins at the */ + /* scratchpad offset set by the SET_SCRATCH_BASE macro. */ + + GFX_WAIT_PIPELINE; + + WRITE_SCRATCH_STRING(dword_bytes_needed, bytes_extra, data, 0); + WRITE_REG16(GP_BLIT_MODE, BM_READ_SRC_BB0 | BM_SOURCE_TEXT); +} + +/* + *---------------------------------------------------------------------------- + * BRESENHAM LINE + * + * This routine draws a vector using the specified Bresenham parameters. + * Currently this file does not support a routine that accepts the two + * endpoints of a vector and calculates the Bresenham parameters. If it + * ever does, this routine is still required for vectors that have been + * clipped. + * + * X screen X position to start vector + * Y screen Y position to start vector + * LENGTH length of the vector, in pixels + * INITERR Bresenham initial error term + * AXIALERR Bresenham axial error term + * DIAGERR Bresenham diagonal error term + * FLAGS VM_YMAJOR, VM_MAJOR_INC, VM_MINOR_INC + *---------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_bresenham_line(unsigned short x, unsigned short y, + unsigned short length, unsigned short initerr, + unsigned short axialerr, unsigned short diagerr, unsigned short flags) +#else +void +gfx_bresenham_line(unsigned short x, unsigned short y, + unsigned short length, unsigned short initerr, + unsigned short axialerr, unsigned short diagerr, unsigned short flags) +#endif +{ + unsigned short vector_mode = flags; + + if (GFXusesDstData) + vector_mode |= VM_READ_DST_FB; + + /* CHECK NULL LENGTH */ + + if (!length) + return; + + /* LOAD THE REGISTERS FOR THE VECTOR */ + + GFX_WAIT_PENDING; + WRITE_REG16(GP_DST_XCOOR, x); + WRITE_REG16(GP_DST_YCOOR, y); + WRITE_REG16(GP_VECTOR_LENGTH, length); + WRITE_REG16(GP_INIT_ERROR, initerr); + WRITE_REG16(GP_AXIAL_ERROR, axialerr); + WRITE_REG16(GP_DIAG_ERROR, diagerr); + WRITE_REG16(GP_VECTOR_MODE, vector_mode); +} + +/*--------------------------------------------------------------------------- + * GFX_WAIT_UNTIL_IDLE + * + * This routine waits until the graphics engine is idle. This is required + * before allowing direct access to the frame buffer. + *--------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +void +gu1_wait_until_idle(void) +#else +void +gfx_wait_until_idle(void) +#endif +{ + GFX_WAIT_BUSY; +} + +/*--------------------------------------------------------------------------- + * GFX_TEST_BLT_PENDING + * + * This routine returns 1 if a BLT is pending, meaning that a call to + * perform a rendering operation would stall. Otherwise it returns 0. + * It is used by Darwin during random testing to only start a BLT + * operation when it knows the Durango routines won't spin on graphics + * (so Darwin can continue to do frame buffer reads and writes). + *--------------------------------------------------------------------------- + */ +#if GFX_2DACCEL_DYNAMIC +int +gu1_test_blt_pending(void) +#else +int +gfx_test_blt_pending(void) +#endif +{ + if (READ_REG16(GP_BLIT_STATUS) & BS_BLIT_PENDING) + return (1); + else + return (0); +} + +/*--------------------------------------------------------------------------- + * BLT BUFFERS!!!!! + *--------------------------------------------------------------------------- + */ + +/* THE BOOT CODE MUST SET THE BLT BUFFER BASES USING THE "CPU_WRITE" */ +/* INSTRUCTION TO ONE OF THE FOLLOWING VALUES: */ + +#define BB0_BASE_2K 0x800 +#define BB1_BASE_2K 0xB30 +#define BB0_BASE_3K 0x400 +#define BB1_BASE_3K 0x930 + +/*--------------------------------------------------------------------------- + * gu1_detect_blt_buffer_base + * + * This detection is hidden from the driver by being called from the + * "gfx_set_bpp" routine. + * + * This is fairly ugly for the following reasons: + * + * - It is the boot code that must set the BLT buffer bases to the + * appropriate values and load the scratchpad tags. + * - The old drivers would also set the base address values to what they + * knew they should be for the 2K or 3K scratchpad configuration. + * - Unfortunately, to set the base addresses requires the use of the + * CPU_WRITE instruction, an instruction specific to GX. + * - Using the CPU_WRITE instruction requires the use of assembly to + * produce the appropriate op codes. + * - Assembly is something that is avoided in Durango because it is not + * platform independent. Some compilers do not support inline assembly. + * - Therefore Durango cannot use the CPU_WRITE instruction. + * - Therefore drivers using Durango must rely on the boot code to set + * the appropriate values. Durango uses this routine to check where + * the base addresses have been set. + * - Unfortunately, it is not as simple as using IO to check for 2K or 3K + * scratchpad size. In VSA1, even though the boot code may set it for + * 3K, SoftVGA comes along and resets it to 2K for it's use in text + * redraws. It used to be that the display driver would set it back + * to 3K. + * - So, the Durango code was changed to just always use 2K. + * - But, the XpressROM code sets it for 3K, and the newer versions of + * SoftVGA do not interfere with that, so then Durango needs to use + * the 3K values to work properly. + * - Therefore, Durango does somewhat of a kludge by writing to directly + * to the scratchpad at both the 2K and 3K locations, then performing + * a unobtrusive BLT that loads data into BB0 (the graphics engine + * always knows the true base). After the BLT, Durango looks to see + * which location changed to know where the base address is. + * - This is a relatively simple way to allow Durango to work on old + * and new platforms without using theCPU_WRITE instructions. + * + * To summarize, the BLT buffers are one of the most painful aspects of + * the GX graphics unit design, and have been removed from future designs + * (the graphics unit has its own dedicated RAM). Durango has tried to + * hide the BLT buffer use from the drivers. + *--------------------------------------------------------------------------- + */ +void +gu1_detect_blt_buffer_base(void) +{ + /* ASSUME 2K */ + + GFXbb0Base = BB0_BASE_2K; + GFXbb1Base = BB1_BASE_2K; + + /* CHECK IF SCRATCHPAD IS SET TO 3K OR 4K */ + /* Boot code should still set 3K values for 4K. */ + + if (gfx_gxm_config_read(GXM_CONFIG_GCR) & 0x08) { + /* WRITE DATA TO 3K LOCATION */ + + GFX_WAIT_BUSY; + WRITE_SCRATCH32(BB0_BASE_3K, 0xFEEDFACE); + + /* HAVE THE GRAPHICS UNIT STORE SOMETHING IN BB0 */ + + WRITE_REG32(GP_DST_XCOOR, 0x00000000); /* AT (0,0) */ + WRITE_REG32(GP_WIDTH, 0x00010004); /* 4x1 BLT */ + WRITE_REG16(GP_RASTER_MODE, 0x00AA); /* KEEP DST */ + WRITE_REG16(GP_BLIT_MODE, BM_READ_DST_FB0); /* STORE IN BB0 */ + + /* CHECK 3K LOCATION */ + /* Breaks if data happened to be 0xFEEDFACE - unlikely. */ + + GFX_WAIT_BUSY; + if (READ_SCRATCH32(BB0_BASE_3K) != 0xFEEDFACE) { + GFXbb0Base = BB0_BASE_3K; + GFXbb1Base = BB1_BASE_3K; + } + } +} + +/* END OF FILE */ |