| 1 | /* |
| 2 | SDL - Simple DirectMedia Layer |
| 3 | Copyright (C) 1997-2009 Sam Lantinga |
| 4 | |
| 5 | This library is free software; you can redistribute it and/or |
| 6 | modify it under the terms of the GNU Lesser General Public |
| 7 | License as published by the Free Software Foundation; either |
| 8 | version 2.1 of the License, or (at your option) any later version. |
| 9 | |
| 10 | This library is distributed in the hope that it will be useful, |
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | Lesser General Public License for more details. |
| 14 | |
| 15 | You should have received a copy of the GNU Lesser General Public |
| 16 | License along with this library; if not, write to the Free Software |
| 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 18 | |
| 19 | Sam Lantinga |
| 20 | slouken@libsdl.org |
| 21 | */ |
| 22 | #include "SDL_config.h" |
| 23 | |
| 24 | #include "SDL_video.h" |
| 25 | #include "../SDL_blit.h" |
| 26 | #include "SDL_fbriva.h" |
| 27 | #include "riva_mmio.h" |
| 28 | #include "riva_regs.h" |
| 29 | |
| 30 | |
| 31 | static int FifoEmptyCount = 0; |
| 32 | static int FifoFreeCount = 0; |
| 33 | |
| 34 | /* Wait for vertical retrace */ |
| 35 | static void WaitVBL(_THIS) |
| 36 | { |
| 37 | volatile Uint8 *port = (Uint8 *)(mapped_io + PCIO_OFFSET + 0x3DA); |
| 38 | |
| 39 | while ( (*port & 0x08) ) |
| 40 | ; |
| 41 | while ( !(*port & 0x08) ) |
| 42 | ; |
| 43 | } |
| 44 | static void NV3WaitIdle(_THIS) |
| 45 | { |
| 46 | RivaRop *Rop = (RivaRop *)(mapped_io + ROP_OFFSET); |
| 47 | while ( (Rop->FifoFree < FifoEmptyCount) || |
| 48 | (*(mapped_io + PGRAPH_OFFSET + 0x000006B0) & 0x01) ) |
| 49 | ; |
| 50 | } |
| 51 | static void NV4WaitIdle(_THIS) |
| 52 | { |
| 53 | RivaRop *Rop = (RivaRop *)(mapped_io + ROP_OFFSET); |
| 54 | while ( (Rop->FifoFree < FifoEmptyCount) || |
| 55 | (*(mapped_io + PGRAPH_OFFSET + 0x00000700) & 0x01) ) |
| 56 | ; |
| 57 | } |
| 58 | |
| 59 | #if 0 /* Not yet implemented? */ |
| 60 | /* Sets video mem colorkey and accelerated blit function */ |
| 61 | static int SetHWColorKey(_THIS, SDL_Surface *surface, Uint32 key) |
| 62 | { |
| 63 | return(0); |
| 64 | } |
| 65 | |
| 66 | /* Sets per surface hardware alpha value */ |
| 67 | static int SetHWAlpha(_THIS, SDL_Surface *surface, Uint8 value) |
| 68 | { |
| 69 | return(0); |
| 70 | } |
| 71 | #endif /* Not yet implemented */ |
| 72 | |
| 73 | static int FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color) |
| 74 | { |
| 75 | int dstX, dstY; |
| 76 | int dstW, dstH; |
| 77 | RivaBitmap *Bitmap = (RivaBitmap *)(mapped_io + BITMAP_OFFSET); |
| 78 | |
| 79 | /* Don't blit to the display surface when switched away */ |
| 80 | if ( switched_away ) { |
| 81 | return -2; /* no hardware access */ |
| 82 | } |
| 83 | if ( dst == this->screen ) { |
| 84 | SDL_mutexP(hw_lock); |
| 85 | } |
| 86 | |
| 87 | /* Set up the X/Y base coordinates */ |
| 88 | dstW = rect->w; |
| 89 | dstH = rect->h; |
| 90 | FB_dst_to_xy(this, dst, &dstX, &dstY); |
| 91 | |
| 92 | /* Adjust for the current rectangle */ |
| 93 | dstX += rect->x; |
| 94 | dstY += rect->y; |
| 95 | |
| 96 | RIVA_FIFO_FREE(Bitmap, 1); |
| 97 | Bitmap->Color1A = color; |
| 98 | |
| 99 | RIVA_FIFO_FREE(Bitmap, 2); |
| 100 | Bitmap->UnclippedRectangle[0].TopLeft = (dstX << 16) | dstY; |
| 101 | Bitmap->UnclippedRectangle[0].WidthHeight = (dstW << 16) | dstH; |
| 102 | |
| 103 | FB_AddBusySurface(dst); |
| 104 | |
| 105 | if ( dst == this->screen ) { |
| 106 | SDL_mutexV(hw_lock); |
| 107 | } |
| 108 | return(0); |
| 109 | } |
| 110 | |
| 111 | static int HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect, |
| 112 | SDL_Surface *dst, SDL_Rect *dstrect) |
| 113 | { |
| 114 | SDL_VideoDevice *this = current_video; |
| 115 | int srcX, srcY; |
| 116 | int dstX, dstY; |
| 117 | int dstW, dstH; |
| 118 | RivaScreenBlt *Blt = (RivaScreenBlt *)(mapped_io + BLT_OFFSET); |
| 119 | |
| 120 | /* FIXME: For now, only blit to display surface */ |
| 121 | if ( dst->pitch != SDL_VideoSurface->pitch ) { |
| 122 | return(src->map->sw_blit(src, srcrect, dst, dstrect)); |
| 123 | } |
| 124 | |
| 125 | /* Don't blit to the display surface when switched away */ |
| 126 | if ( switched_away ) { |
| 127 | return -2; /* no hardware access */ |
| 128 | } |
| 129 | if ( dst == this->screen ) { |
| 130 | SDL_mutexP(hw_lock); |
| 131 | } |
| 132 | |
| 133 | /* Calculate source and destination base coordinates (in pixels) */ |
| 134 | dstW = dstrect->w; |
| 135 | dstH = dstrect->h; |
| 136 | FB_dst_to_xy(this, src, &srcX, &srcY); |
| 137 | FB_dst_to_xy(this, dst, &dstX, &dstY); |
| 138 | |
| 139 | /* Adjust for the current blit rectangles */ |
| 140 | srcX += srcrect->x; |
| 141 | srcY += srcrect->y; |
| 142 | dstX += dstrect->x; |
| 143 | dstY += dstrect->y; |
| 144 | |
| 145 | RIVA_FIFO_FREE(Blt, 3); |
| 146 | Blt->TopLeftSrc = (srcY << 16) | srcX; |
| 147 | Blt->TopLeftDst = (dstY << 16) | dstX; |
| 148 | Blt->WidthHeight = (dstH << 16) | dstW; |
| 149 | |
| 150 | FB_AddBusySurface(src); |
| 151 | FB_AddBusySurface(dst); |
| 152 | |
| 153 | if ( dst == this->screen ) { |
| 154 | SDL_mutexV(hw_lock); |
| 155 | } |
| 156 | return(0); |
| 157 | } |
| 158 | |
| 159 | static int CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dst) |
| 160 | { |
| 161 | int accelerated; |
| 162 | |
| 163 | /* Set initial acceleration on */ |
| 164 | src->flags |= SDL_HWACCEL; |
| 165 | |
| 166 | /* Set the surface attributes */ |
| 167 | if ( (src->flags & SDL_SRCALPHA) == SDL_SRCALPHA ) { |
| 168 | if ( ! this->info.blit_hw_A ) { |
| 169 | src->flags &= ~SDL_HWACCEL; |
| 170 | } |
| 171 | } |
| 172 | if ( (src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) { |
| 173 | if ( ! this->info.blit_hw_CC ) { |
| 174 | src->flags &= ~SDL_HWACCEL; |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | /* Check to see if final surface blit is accelerated */ |
| 179 | accelerated = !!(src->flags & SDL_HWACCEL); |
| 180 | if ( accelerated ) { |
| 181 | src->map->hw_blit = HWAccelBlit; |
| 182 | } |
| 183 | return(accelerated); |
| 184 | } |
| 185 | |
| 186 | void FB_RivaAccel(_THIS, __u32 card) |
| 187 | { |
| 188 | RivaRop *Rop = (RivaRop *)(mapped_io + ROP_OFFSET); |
| 189 | |
| 190 | /* We have hardware accelerated surface functions */ |
| 191 | this->CheckHWBlit = CheckHWBlit; |
| 192 | wait_vbl = WaitVBL; |
| 193 | switch (card) { |
| 194 | case FB_ACCEL_NV3: |
| 195 | wait_idle = NV3WaitIdle; |
| 196 | break; |
| 197 | case FB_ACCEL_NV4: |
| 198 | wait_idle = NV4WaitIdle; |
| 199 | break; |
| 200 | default: |
| 201 | /* Hmm... FIXME */ |
| 202 | break; |
| 203 | } |
| 204 | FifoEmptyCount = Rop->FifoFree; |
| 205 | |
| 206 | /* The Riva has an accelerated color fill */ |
| 207 | this->info.blit_fill = 1; |
| 208 | this->FillHWRect = FillHWRect; |
| 209 | |
| 210 | /* The Riva has accelerated normal and colorkey blits. */ |
| 211 | this->info.blit_hw = 1; |
| 212 | #if 0 /* Not yet implemented? */ |
| 213 | this->info.blit_hw_CC = 1; |
| 214 | this->SetHWColorKey = SetHWColorKey; |
| 215 | #endif |
| 216 | |
| 217 | #if 0 /* Not yet implemented? */ |
| 218 | /* The Riva has an accelerated alpha blit */ |
| 219 | this->info.blit_hw_A = 1; |
| 220 | this->SetHWAlpha = SetHWAlpha; |
| 221 | #endif |
| 222 | } |