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