| 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_fbmatrox.h" |
| 27 | #include "matrox_mmio.h" |
| 28 | |
| 29 | |
| 30 | /* Wait for vertical retrace - taken from the XFree86 Matrox driver */ |
| 31 | static void WaitVBL(_THIS) |
| 32 | { |
| 33 | int count; |
| 34 | |
| 35 | /* find start of retrace */ |
| 36 | mga_waitidle(); |
| 37 | while ( (mga_in8(0x1FDA) & 0x08) ) |
| 38 | ; |
| 39 | while ( !(mga_in8(0x1FDA) & 0x08) ) |
| 40 | ; |
| 41 | /* wait until we're past the start */ |
| 42 | count = mga_in32(0x1E20) + 2; |
| 43 | while ( mga_in32(0x1E20) < count ) |
| 44 | ; |
| 45 | } |
| 46 | static void WaitIdle(_THIS) |
| 47 | { |
| 48 | mga_waitidle(); |
| 49 | } |
| 50 | |
| 51 | /* Sets video mem colorkey and accelerated blit function */ |
| 52 | static int SetHWColorKey(_THIS, SDL_Surface *surface, Uint32 key) |
| 53 | { |
| 54 | return(0); |
| 55 | } |
| 56 | |
| 57 | /* Sets per surface hardware alpha value */ |
| 58 | #if 0 |
| 59 | static int SetHWAlpha(_THIS, SDL_Surface *surface, Uint8 value) |
| 60 | { |
| 61 | return(0); |
| 62 | } |
| 63 | #endif |
| 64 | |
| 65 | static int FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color) |
| 66 | { |
| 67 | int dstX, dstY; |
| 68 | Uint32 fxbndry; |
| 69 | Uint32 ydstlen; |
| 70 | Uint32 fillop; |
| 71 | |
| 72 | /* Don't blit to the display surface when switched away */ |
| 73 | if ( switched_away ) { |
| 74 | return -2; /* no hardware access */ |
| 75 | } |
| 76 | if ( dst == this->screen ) { |
| 77 | SDL_mutexP(hw_lock); |
| 78 | } |
| 79 | |
| 80 | switch (dst->format->BytesPerPixel) { |
| 81 | case 1: |
| 82 | color |= (color<<8); |
| 83 | case 2: |
| 84 | color |= (color<<16); |
| 85 | break; |
| 86 | } |
| 87 | |
| 88 | /* Set up the X/Y base coordinates */ |
| 89 | FB_dst_to_xy(this, dst, &dstX, &dstY); |
| 90 | |
| 91 | /* Adjust for the current rectangle */ |
| 92 | dstX += rect->x; |
| 93 | dstY += rect->y; |
| 94 | |
| 95 | /* Set up the X boundaries */ |
| 96 | fxbndry = (dstX | ((dstX+rect->w) << 16)); |
| 97 | |
| 98 | /* Set up the Y boundaries */ |
| 99 | ydstlen = (rect->h | (dstY << 16)); |
| 100 | |
| 101 | /* Set up for color fill operation */ |
| 102 | fillop = MGADWG_TRAP | MGADWG_SOLID | |
| 103 | MGADWG_ARZERO | MGADWG_SGNZERO | MGADWG_SHIFTZERO; |
| 104 | |
| 105 | /* Execute the operations! */ |
| 106 | mga_wait(5); |
| 107 | mga_out32(MGAREG_DWGCTL, fillop | MGADWG_REPLACE); |
| 108 | mga_out32(MGAREG_FCOL, color); |
| 109 | mga_out32(MGAREG_FXBNDRY, fxbndry); |
| 110 | mga_out32(MGAREG_YDSTLEN + MGAREG_EXEC, ydstlen); |
| 111 | |
| 112 | FB_AddBusySurface(dst); |
| 113 | |
| 114 | if ( dst == this->screen ) { |
| 115 | SDL_mutexV(hw_lock); |
| 116 | } |
| 117 | return(0); |
| 118 | } |
| 119 | |
| 120 | static int HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect, |
| 121 | SDL_Surface *dst, SDL_Rect *dstrect) |
| 122 | { |
| 123 | SDL_VideoDevice *this = current_video; |
| 124 | int pitch, w, h; |
| 125 | int srcX, srcY; |
| 126 | int dstX, dstY; |
| 127 | Uint32 sign; |
| 128 | Uint32 start, stop; |
| 129 | int skip; |
| 130 | Uint32 blitop; |
| 131 | |
| 132 | /* FIXME: For now, only blit to display surface */ |
| 133 | if ( dst->pitch != SDL_VideoSurface->pitch ) { |
| 134 | return(src->map->sw_blit(src, srcrect, dst, dstrect)); |
| 135 | } |
| 136 | |
| 137 | /* Don't blit to the display surface when switched away */ |
| 138 | if ( switched_away ) { |
| 139 | return -2; /* no hardware access */ |
| 140 | } |
| 141 | if ( dst == this->screen ) { |
| 142 | SDL_mutexP(hw_lock); |
| 143 | } |
| 144 | |
| 145 | /* Calculate source and destination base coordinates (in pixels) */ |
| 146 | w = dstrect->w; |
| 147 | h = dstrect->h; |
| 148 | FB_dst_to_xy(this, src, &srcX, &srcY); |
| 149 | FB_dst_to_xy(this, dst, &dstX, &dstY); |
| 150 | |
| 151 | /* Adjust for the current blit rectangles */ |
| 152 | srcX += srcrect->x; |
| 153 | srcY += srcrect->y; |
| 154 | dstX += dstrect->x; |
| 155 | dstY += dstrect->y; |
| 156 | pitch = dst->pitch/dst->format->BytesPerPixel; |
| 157 | |
| 158 | /* Set up the blit direction (sign) flags */ |
| 159 | sign = 0; |
| 160 | if ( srcX < dstX ) { |
| 161 | sign |= 1; |
| 162 | } |
| 163 | if ( srcY < dstY ) { |
| 164 | sign |= 4; |
| 165 | srcY += (h - 1); |
| 166 | dstY += (h - 1); |
| 167 | } |
| 168 | |
| 169 | /* Set up the blit source row start, end, and skip (in pixels) */ |
| 170 | stop = start = (srcY * pitch) + srcX; |
| 171 | if ( srcX < dstX ) { |
| 172 | start += (w - 1); |
| 173 | } else { |
| 174 | stop += (w - 1); |
| 175 | } |
| 176 | if ( srcY < dstY ) { |
| 177 | skip = -pitch; |
| 178 | } else { |
| 179 | skip = pitch; |
| 180 | } |
| 181 | |
| 182 | /* Set up the blit operation */ |
| 183 | if ( (src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) { |
| 184 | Uint32 colorkey; |
| 185 | |
| 186 | blitop = MGADWG_BFCOL | MGADWG_BITBLT | |
| 187 | MGADWG_SHIFTZERO | MGADWG_RSTR | (0x0C << 16) | |
| 188 | MGADWG_TRANSC; |
| 189 | |
| 190 | colorkey = src->format->colorkey; |
| 191 | switch (dst->format->BytesPerPixel) { |
| 192 | case 1: |
| 193 | colorkey |= (colorkey<<8); |
| 194 | case 2: |
| 195 | colorkey |= (colorkey<<16); |
| 196 | break; |
| 197 | } |
| 198 | mga_wait(2); |
| 199 | mga_out32(MGAREG_FCOL, colorkey); |
| 200 | mga_out32(MGAREG_BCOL, 0xFFFFFFFF); |
| 201 | } else { |
| 202 | blitop = MGADWG_BFCOL | MGADWG_BITBLT | |
| 203 | MGADWG_SHIFTZERO | MGADWG_RSTR | (0x0C << 16); |
| 204 | } |
| 205 | mga_wait(7); |
| 206 | mga_out32(MGAREG_SGN, sign); |
| 207 | mga_out32(MGAREG_AR3, start); |
| 208 | mga_out32(MGAREG_AR0, stop); |
| 209 | mga_out32(MGAREG_AR5, skip); |
| 210 | mga_out32(MGAREG_FXBNDRY, (dstX | ((dstX + w-1) << 16))); |
| 211 | mga_out32(MGAREG_YDSTLEN, (dstY << 16) | h); |
| 212 | mga_out32(MGAREG_DWGCTL + MGAREG_EXEC, blitop); |
| 213 | |
| 214 | FB_AddBusySurface(src); |
| 215 | FB_AddBusySurface(dst); |
| 216 | |
| 217 | if ( dst == this->screen ) { |
| 218 | SDL_mutexV(hw_lock); |
| 219 | } |
| 220 | return(0); |
| 221 | } |
| 222 | |
| 223 | static int CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dst) |
| 224 | { |
| 225 | int accelerated; |
| 226 | |
| 227 | /* Set initial acceleration on */ |
| 228 | src->flags |= SDL_HWACCEL; |
| 229 | |
| 230 | /* Set the surface attributes */ |
| 231 | if ( (src->flags & SDL_SRCALPHA) == SDL_SRCALPHA ) { |
| 232 | if ( ! this->info.blit_hw_A ) { |
| 233 | src->flags &= ~SDL_HWACCEL; |
| 234 | } |
| 235 | } |
| 236 | if ( (src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) { |
| 237 | if ( ! this->info.blit_hw_CC ) { |
| 238 | src->flags &= ~SDL_HWACCEL; |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | /* Check to see if final surface blit is accelerated */ |
| 243 | accelerated = !!(src->flags & SDL_HWACCEL); |
| 244 | if ( accelerated ) { |
| 245 | src->map->hw_blit = HWAccelBlit; |
| 246 | } |
| 247 | return(accelerated); |
| 248 | } |
| 249 | |
| 250 | void FB_MatroxAccel(_THIS, __u32 card) |
| 251 | { |
| 252 | /* We have hardware accelerated surface functions */ |
| 253 | this->CheckHWBlit = CheckHWBlit; |
| 254 | wait_vbl = WaitVBL; |
| 255 | wait_idle = WaitIdle; |
| 256 | |
| 257 | /* The Matrox has an accelerated color fill */ |
| 258 | this->info.blit_fill = 1; |
| 259 | this->FillHWRect = FillHWRect; |
| 260 | |
| 261 | /* The Matrox has accelerated normal and colorkey blits. */ |
| 262 | this->info.blit_hw = 1; |
| 263 | /* The Millenium I appears to do the colorkey test a word |
| 264 | at a time, and the transparency is intverted. (?) |
| 265 | */ |
| 266 | if ( card != FB_ACCEL_MATROX_MGA2064W ) { |
| 267 | this->info.blit_hw_CC = 1; |
| 268 | this->SetHWColorKey = SetHWColorKey; |
| 269 | } |
| 270 | |
| 271 | #if 0 /* Not yet implemented? */ |
| 272 | /* The Matrox G200/G400 has an accelerated alpha blit */ |
| 273 | if ( (card == FB_ACCEL_MATROX_MGAG200) |
| 274 | || (card == FB_ACCEL_MATROX_MGAG400) |
| 275 | ) { |
| 276 | this->info.blit_hw_A = 1; |
| 277 | this->SetHWAlpha = SetHWAlpha; |
| 278 | } |
| 279 | #endif |
| 280 | } |