SDL-1.2.14
[sdl_omap.git] / src / video / fbcon / SDL_fbmatrox.c
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 }