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