1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2012 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
31static int FifoEmptyCount = 0;
32static int FifoFreeCount = 0;
33
34/* Wait for vertical retrace */
35static 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}
44static 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}
51static 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 */
61static int SetHWColorKey(_THIS, SDL_Surface *surface, Uint32 key)
62{
63	return(0);
64}
65
66/* Sets per surface hardware alpha value */
67static int SetHWAlpha(_THIS, SDL_Surface *surface, Uint8 value)
68{
69	return(0);
70}
71#endif /* Not yet implemented */
72
73static 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
111static 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
159static 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
186void 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}
223