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