1 /*
2 ** RW_SVGALBI.C
3 **
4 ** This file contains ALL Linux specific stuff having to do with the
5 ** software refresh.  When a port is being made the following functions
6 ** must be implemented by the port:
7 **
8 ** SWimp_EndFrame
9 ** SWimp_Init
10 ** SWimp_InitGraphics
11 ** SWimp_SetPalette
12 ** SWimp_Shutdown
13 ** SWimp_SwitchFullscreen
14 */
15 
16 #include <termios.h>
17 #include <sys/ioctl.h>
18 #include <sys/stat.h>
19 #include <sys/vt.h>
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <signal.h>
23 #include <sys/mman.h>
24 
25 #include <asm/io.h>
26 
27 #include "vga.h"
28 #include "vgakeyboard.h"
29 #include "vgamouse.h"
30 
31 #include "../ref_soft/r_local.h"
32 #include "../client/keys.h"
33 #include "../linux/rw_linux.h"
34 
35 /*****************************************************************************/
36 
37 int		VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar;
38 byte	*VGA_pagebase;
39 char	*framebuffer_ptr;
40 
41 void VGA_UpdatePlanarScreen (void *srcbuffer);
42 
43 int num_modes;
44 vga_modeinfo *modes;
45 int current_mode;
46 
47 // Console variables that we need to access from this module
48 
49 /*****************************************************************************/
50 
VID_InitModes(void)51 void VID_InitModes(void)
52 {
53 
54 int i;
55 
56 	// get complete information on all modes
57 
58 	num_modes = vga_lastmodenumber()+1;
59 	modes = malloc(num_modes * sizeof(vga_modeinfo));
60 	for (i=0 ; i<num_modes ; i++)
61 	{
62 		if (vga_hasmode(i))
63 			memcpy(&modes[i], vga_getmodeinfo(i), sizeof (vga_modeinfo));
64 		else
65 			modes[i].width = 0; // means not available
66 	}
67 
68 	// filter for modes i don't support
69 
70 	for (i=0 ; i<num_modes ; i++)
71 	{
72 		if (modes[i].bytesperpixel != 1 && modes[i].colors != 256)
73 			modes[i].width = 0;
74 	}
75 
76 	for (i = 0; i < num_modes; i++)
77 		if (modes[i].width)
78 			ri.Con_Printf(PRINT_ALL, "mode %d: %d %d\n", modes[i].width, modes[i].height);
79 
80 }
81 
82 /*
83 ** SWimp_Init
84 **
85 ** This routine is responsible for initializing the implementation
86 ** specific stuff in a software rendering subsystem.
87 */
SWimp_Init(void * hInstance,void * wndProc)88 int SWimp_Init( void *hInstance, void *wndProc )
89 {
90 	vga_init();
91 
92 	VID_InitModes();
93 
94 	return true;
95 }
96 
get_mode(int width,int height)97 int get_mode(int width, int height)
98 {
99 
100 	int i;
101 	int ok, match;
102 
103 	for (i=0 ; i<num_modes ; i++)
104 		if (modes[i].width &&
105 			modes[i].width == width && modes[i].height == height)
106 				break;
107 	if (i==num_modes)
108 		return -1; // not found
109 
110 	return i;
111 }
112 
113 /*
114 ** SWimp_InitGraphics
115 **
116 ** This initializes the software refresh's implementation specific
117 ** graphics subsystem.  In the case of Windows it creates DIB or
118 ** DDRAW surfaces.
119 **
120 ** The necessary width and height parameters are grabbed from
121 ** vid.width and vid.height.
122 */
SWimp_InitGraphics(qboolean fullscreen)123 static qboolean SWimp_InitGraphics( qboolean fullscreen )
124 {
125 	int bsize, zsize, tsize;
126 
127 	SWimp_Shutdown();
128 
129 	current_mode = get_mode(vid.width, vid.height);
130 
131 	if (current_mode < 0) {
132 		ri.Con_Printf (PRINT_ALL, "Mode %d %d not found\n", vid.width, vid.height);
133 		return false; // mode not found
134 	}
135 
136 	// let the sound and input subsystems know about the new window
137 	ri.Vid_NewWindow (vid.width, vid.height);
138 
139 	ri.Con_Printf (PRINT_ALL, "Setting VGAMode: %d\n", current_mode );
140 
141 //	Cvar_SetValue ("vid_mode", (float)modenum);
142 
143 	VGA_width = modes[current_mode].width;
144 	VGA_height = modes[current_mode].height;
145 	VGA_planar = modes[current_mode].bytesperpixel == 0;
146 	VGA_rowbytes = modes[current_mode].linewidth;
147 
148 	vid.rowbytes = modes[current_mode].linewidth;
149 
150 	if (VGA_planar) {
151 		VGA_bufferrowbytes = modes[current_mode].linewidth * 4;
152 		vid.rowbytes = modes[current_mode].linewidth*4;
153 	}
154 
155 // get goin'
156 
157 	vga_setmode(current_mode);
158 
159 	VGA_pagebase = framebuffer_ptr = (char *) vga_getgraphmem();
160 //		if (vga_setlinearaddressing()>0)
161 //			framebuffer_ptr = (char *) vga_getgraphmem();
162 	if (!framebuffer_ptr)
163 		Sys_Error("This mode isn't hapnin'\n");
164 
165 	vga_setpage(0);
166 
167 	vid.buffer = malloc(vid.rowbytes * vid.height);
168 	if (!vid.buffer)
169 		Sys_Error("Unabled to alloc vid.buffer!\n");
170 
171 	return true;
172 }
173 
174 /*
175 ** SWimp_EndFrame
176 **
177 ** This does an implementation specific copy from the backbuffer to the
178 ** front buffer.  In the Win32 case it uses BitBlt or BltFast depending
179 ** on whether we're using DIB sections/GDI or DDRAW.
180 */
SWimp_EndFrame(void)181 void SWimp_EndFrame (void)
182 {
183 	if (!vga_oktowrite())
184 		return; // can't update screen if it's not active
185 
186 //	if (vid_waitforrefresh.value)
187 //		vga_waitretrace();
188 
189 	if (VGA_planar)
190 		VGA_UpdatePlanarScreen (vid.buffer);
191 
192 	else {
193 		int total = vid.rowbytes * vid.height;
194 		int offset;
195 
196 		for (offset=0;offset<total;offset+=0x10000) {
197 			vga_setpage(offset/0x10000);
198 			memcpy(framebuffer_ptr,
199 					vid.buffer + offset,
200 					((total-offset>0x10000)?0x10000:(total-offset)));
201 		}
202 	}
203 }
204 
205 /*
206 ** SWimp_SetMode
207 */
SWimp_SetMode(int * pwidth,int * pheight,int mode,qboolean fullscreen)208 rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
209 {
210 	rserr_t retval = rserr_ok;
211 
212 	ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode );
213 
214 	if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) )
215 	{
216 		ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
217 		return rserr_invalid_mode;
218 	}
219 
220 	ri.Con_Printf( PRINT_ALL, " %d %d\n", *pwidth, *pheight);
221 
222 	if ( !SWimp_InitGraphics( false ) ) {
223 		// failed to set a valid mode in windowed mode
224 		return rserr_invalid_mode;
225 	}
226 
227 	R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
228 
229 	return retval;
230 }
231 
232 /*
233 ** SWimp_SetPalette
234 **
235 ** System specific palette setting routine.  A NULL palette means
236 ** to use the existing palette.  The palette is expected to be in
237 ** a padded 4-byte xRGB format.
238 */
SWimp_SetPalette(const unsigned char * palette)239 void SWimp_SetPalette( const unsigned char *palette )
240 {
241 	static int tmppal[256*3];
242 	const unsigned char *pal;
243 	int *tp;
244 	int i;
245 
246     if ( !palette )
247         palette = ( const unsigned char * ) sw_state.currentpalette;
248 
249 	if (vga_getcolors() == 256)
250 	{
251 		tp = tmppal;
252 		pal = palette;
253 
254 		for (i=0 ; i < 256 ; i++, pal += 4, tp += 3) {
255 			tp[0] = pal[0] >> 2;
256 			tp[1] = pal[1] >> 2;
257 			tp[2] = pal[2] >> 2;
258 		}
259 
260 		if (vga_oktowrite())
261 			vga_setpalvec(0, 256, tmppal);
262 	}
263 }
264 
265 /*
266 ** SWimp_Shutdown
267 **
268 ** System specific graphics subsystem shutdown routine.  Destroys
269 ** DIBs or DDRAW surfaces as appropriate.
270 */
SWimp_Shutdown(void)271 void SWimp_Shutdown( void )
272 {
273 	if (vid.buffer) {
274 		free(vid.buffer);
275 		vid.buffer = NULL;
276 	}
277 	vga_setmode(TEXT);
278 }
279 
280 /*
281 ** SWimp_AppActivate
282 */
SWimp_AppActivate(qboolean active)283 void SWimp_AppActivate( qboolean active )
284 {
285 }
286 
287 //===============================================================================
288 
289 /*
290 ================
291 Sys_MakeCodeWriteable
292 ================
293 */
Sys_MakeCodeWriteable(unsigned long startaddr,unsigned long length)294 void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
295 {
296 
297 	int r;
298 	unsigned long addr;
299 	int psize = getpagesize();
300 
301 	addr = (startaddr & ~(psize-1)) - psize;
302 
303 //	fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
304 //			addr, startaddr+length, length);
305 
306 	r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
307 
308 	if (r < 0)
309     		Sys_Error("Protection change failed\n");
310 }
311 
312