ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/video_vosf.h
Revision: 1.1
Committed: 2000-09-22T17:16:05Z (24 years, 1 month ago) by gbeauche
Content type: text/plain
Branch: MAIN
Log Message:
- video on SEGV signals

File Contents

# Content
1 /*
2 * video_vosf.h - Video/graphics emulation, video on SEGV signals support
3 *
4 * Basilisk II (C) 1997-2000 Christian Bauer
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #ifndef VIDEO_VOSF_H
22 #define VIDEO_VOSF_H
23
24 // Note: this file is #include'd in video_x.cpp
25 #ifdef ENABLE_VOSF
26
27 /*
28 * Page-aligned memory allocation
29 */
30
31 // Align on page boundaries
32 static uint32 align_on_page_boundary(uint32 size)
33 {
34 const uint32 page_size = getpagesize();
35 const uint32 page_mask = page_size - 1;
36 return (size + page_mask) & ~page_mask;
37 }
38
39 // Allocate memory on page boundary
40 static void * allocate_framebuffer(uint32 size, uint8 * hint = 0)
41 {
42 // Remind that the system can allocate at 0x00000000...
43 return mmap((caddr_t)hint, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zero_fd, 0);
44 }
45
46
47 /*
48 * Screen depth identification
49 */
50
51 enum {
52 ID_DEPTH_UNKNOWN = -1,
53 ID_DEPTH_1,
54 ID_DEPTH_8,
55 ID_DEPTH_15,
56 ID_DEPTH_16,
57 ID_DEPTH_24,
58 ID_DEPTH_32 = ID_DEPTH_24,
59 ID_DEPTH_COUNT
60 };
61
62 static int depth_id(int depth)
63 {
64 int id;
65 switch (depth) {
66 case 1 : id = ID_DEPTH_1; break;
67 case 8 : id = ID_DEPTH_8; break;
68 case 15 : id = ID_DEPTH_15; break;
69 case 16 : id = ID_DEPTH_16; break;
70 case 24 : id = ID_DEPTH_24; break;
71 case 32 : id = ID_DEPTH_32; break;
72 default : id = ID_DEPTH_UNKNOWN;
73 }
74 return id;
75 }
76
77
78 /*
79 * Frame buffer copy function templates
80 */
81
82 // No conversion required
83
84 #define MEMCPY_PROFITABLE
85 #ifdef MEMCPY_PROFITABLE
86 static void do_fbcopy_raw(uint8 * dest, const uint8 * source, uint32 length)
87 {
88 memcpy(dest, source, length);
89 }
90 #else
91 #error "incomplete"
92 #define FB_BLIT_1(dst, src) (dst = (src))
93 #define FB_BLIT_2(dst, src) (dst = (src))
94 #define FB_DEPTH 8
95 #define FB_FUNC_NAME do_fbcopy_raw
96 #include "video_blit.h"
97 #endif
98
99
100 // RGB 555
101
102 #define FB_BLIT_1(dst, src) \
103 (dst = (((src) >> 8) & 0xff) | (((src) & 0xff) << 8))
104
105 #define FB_BLIT_2(dst, src) \
106 (dst = (((src) >> 8) & 0x00ff00ff) | (((src) & 0x00ff00ff) << 8))
107
108 #define FB_DEPTH 15
109 #define FB_FUNC_NAME do_fbcopy_15
110 #include "video_blit.h"
111
112
113 // RGB 565
114
115 #define FB_BLIT_1(dst, src) \
116 (dst = (((src) >> 8) & 0x001f) | (((src) << 9) & 0xfe00) | (((src) >> 7) & 0x01c0))
117
118 #define FB_BLIT_2(dst, src) \
119 (dst = (((src) >> 8) & 0x001f001f) | (((src) << 9) & 0xfe00fe00) | (((src) >> 7) & 0x01c001c0))
120
121 #define FB_DEPTH 16
122 #define FB_FUNC_NAME do_fbcopy_16
123 #include "video_blit.h"
124
125
126 // RGB 888
127
128 #define FB_BLIT_1(dst, src) \
129 (dst = (src))
130
131 #define FB_BLIT_2(dst, src) \
132 (dst = (((src) >> 24) & 0xff) | (((src) >> 16) & 0xff00) | (((src) & 0xff00) << 16) | (((src) & 0xff) << 24))
133
134 #define FB_DEPTH 24
135 #define FB_FUNC_NAME do_fbcopy_24
136 #include "video_blit.h"
137
138
139 /*
140 * Frame buffer copy functions map table
141 */
142
143 typedef void (*fbcopy_func)(uint8 *, const uint8 *, uint32);
144 static fbcopy_func do_update_framebuffer;
145
146 #define FBCOPY_FUNC(aHandler) do_ ## aHandler
147
148 #if REAL_ADDRESSING || DIRECT_ADDRESSING
149 #define WD(X) { FBCOPY_FUNC(X), FBCOPY_FUNC(X) }
150 #else
151 #define WD(X) { FBCOPY_FUNC(fbcopy_raw), FBCOPY_FUNC(fbcopy_raw) }
152 #endif
153
154 // fb_copy_funcs[depth_id][native_byte_order][dga_mode]
155 // NT : not tested
156 // OK : has been successfully tested
157 // NBO : native byte order
158 static fbcopy_func fbcopy_funcs[ID_DEPTH_COUNT][2][2] = {
159 #ifdef WORDS_BIGENDIAN
160 /* alt byte order native byte order */
161 /* 1 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // NT
162 /* 8 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // OK (NBO)
163 /* 15 bpp */ { WD(fbcopy_15) , WD(fbcopy_raw) }, // NT
164 /* 16 bpp */ { WD(fbcopy_16) , WD(fbcopy_raw) }, // NT
165 /* 24 bpp */ { WD(fbcopy_24) , WD(fbcopy_raw) } // NT
166 #else
167 /* 1 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // NT
168 /* 8 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // OK (NBO)
169 /* 15 bpp */ { WD(fbcopy_15) , WD(fbcopy_15) }, // OK (NBO)
170 /* 16 bpp */ { WD(fbcopy_16) , WD(fbcopy_16) }, // OK (NBO)
171 /* 24 bpp */ { WD(fbcopy_24) , WD(fbcopy_24) } // NT
172 #endif
173 };
174
175 #undef WD
176
177 #define FBCOPY_FUNC_ERROR \
178 ErrorAlert("Invalid screen depth")
179
180 #define GET_FBCOPY_FUNC(aDepth, aNativeByteOrder, aDisplay) \
181 ((depth_id(aDepth) == ID_DEPTH_UNKNOWN) ? ( FBCOPY_FUNC_ERROR, (fbcopy_func)0 ) : \
182 fbcopy_funcs[depth_id(aDepth)][(aNativeByteOrder)][(aDisplay) == DISPLAY_DGA ? 1 : 0])
183
184
185 /*
186 * Screen fault handler
187 */
188
189 static inline void do_handle_screen_fault(unsigned long addr)
190 {
191 if ((addr < mainBuffer.memStart) || (addr >= mainBuffer.memEnd)) {
192 fprintf(stderr, "Segmentation fault at 0x%08X\n", addr);
193 abort();
194 }
195
196 const int page = (addr - mainBuffer.memStart) >> mainBuffer.pageBits;
197 caddr_t page_ad = (caddr_t)(addr & ~(mainBuffer.pageSize - 1));
198 #ifdef HAVE_PTHREADS
199 pthread_mutex_lock(&Screen_draw_lock);
200 #endif
201 PFLAG_SET(page);
202 mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE);
203 #ifdef HAVE_PTHREADS
204 pthread_mutex_unlock(&Screen_draw_lock);
205 #endif
206 }
207
208 #if defined(HAVE_SIGINFO_T)
209 static void Screen_fault_handler(int, siginfo_t * sip, void *)
210 {
211 D(bug("Screen_fault_handler: ADDR=0x%08X\n", sip->si_addr));
212 do_handle_screen_fault((unsigned long)sip->si_addr);
213 }
214 #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
215 # if defined(__i386__) && defined(__linux__)
216 static void Screen_fault_handler(int, struct sigcontext scs)
217 {
218 D(bug("Screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", scs.cr2, scs.eip));
219 do_handle_screen_fault((unsigned long)scs.cr2);
220 }
221 # else
222 # error "No suitable subterfuge for Video on SEGV signals"
223 # endif
224 #else
225 # error "Can't do Video on SEGV signals"
226 #endif
227
228
229 /*
230 * Screen fault handler initialization
231 */
232
233 #if defined(HAVE_SIGINFO_T)
234 static bool Screen_fault_handler_init()
235 {
236 // Setup SIGSEGV handler to process writes to frame buffer
237 sigemptyset(&vosf_sa.sa_mask);
238 vosf_sa.sa_sigaction = Screen_fault_handler;
239 vosf_sa.sa_flags = 0;
240 return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
241 }
242 #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
243 static bool Screen_fault_handler_init()
244 {
245 // Setup SIGSEGV handler to process writes to frame buffer
246 sigemptyset(&vosf_sa.sa_mask);
247 vosf_sa.sa_handler = (void (*)(int)) Screen_fault_handler;
248 vosf_sa.sa_flags = 0;
249 return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
250 }
251 #endif
252
253
254 /*
255 * Update display for Windowed mode and VOSF
256 */
257
258 static inline void update_display_window_vosf(void)
259 {
260 int page = 0;
261 for (;;) {
262 while (PFLAG_ISCLEAR_4(page))
263 page += 4;
264
265 while (PFLAG_ISCLEAR(page))
266 page++;
267
268 if (page >= mainBuffer.pageCount)
269 break;
270
271 const int first_page = page;
272 PFLAG_CLEAR(first_page);
273 while ((++page < mainBuffer.pageCount) && PFLAG_ISSET(page))
274 PFLAG_CLEAR(page);
275
276 // Make the dirty pages read-only again
277 const int32 offset = first_page << mainBuffer.pageBits;
278 const uint32 length = (page - first_page) << mainBuffer.pageBits;
279 mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
280
281 // There is at least one line to update
282 const int y1 = mainBuffer.pageInfo[first_page].top;
283 const int y2 = mainBuffer.pageInfo[page - 1].bottom;
284 const int height = y2 - y1 + 1;
285
286 const int bytes_per_row = VideoMonitor.bytes_per_row;
287 const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
288 int i, j;
289
290 // Check for first column from left and first column
291 // from right that have changed
292 int x1 = VideoMonitor.x * bytes_per_pixel - 1;
293 for (j = y1; j <= y2; j++) {
294 uint8 * const p1 = &the_buffer[j * bytes_per_row];
295 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
296 for (i = 0; i < x1; i++) {
297 if (p1[i] != p2[i]) {
298 x1 = i;
299 break;
300 }
301 }
302 }
303 x1 /= bytes_per_pixel;
304
305 int x2 = x1 * bytes_per_pixel;
306 for (j = y2; j >= y1; j--) {
307 uint8 * const p1 = &the_buffer[j * bytes_per_row];
308 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
309 for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
310 if (p1[i] != p2[i]) {
311 x2 = i;
312 break;
313 }
314 }
315 }
316 x2 /= bytes_per_pixel;
317
318 // Update the_host_buffer and copy of the_buffer
319 // There is at least one pixel to copy
320 const int width = x2 - x1 + 1;
321 i = y1 * bytes_per_row + x1 * bytes_per_pixel;
322 for (j = y1; j <= y2; j++) {
323 do_update_framebuffer(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
324 memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
325 i += bytes_per_row;
326 }
327
328 if (have_shm)
329 XShmPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, width, height, 0);
330 else
331 XPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, width, height);
332 }
333 }
334
335
336 /*
337 * Update display for DGA mode and VOSF
338 * (only in Direct Addressing mode)
339 */
340
341 #if REAL_ADDRESSING || DIRECT_ADDRESSING
342 static inline void update_display_dga_vosf(void)
343 {
344 int page = 0;
345 for (;;) {
346 while (PFLAG_ISCLEAR_4(page))
347 page += 4;
348
349 while (PFLAG_ISCLEAR(page))
350 page++;
351
352 if (page >= mainBuffer.pageCount)
353 break;
354
355 const int first_page = page;
356 PFLAG_CLEAR(first_page);
357 while ((++page < mainBuffer.pageCount) && PFLAG_ISSET(page))
358 PFLAG_CLEAR(page);
359
360 // Make the dirty pages read-only again
361 const int32 offset = first_page << mainBuffer.pageBits;
362 const uint32 length = (page - first_page) << mainBuffer.pageBits;
363 mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
364
365 // I am sure that y2 >= y1 and depth != 1
366 const int y1 = mainBuffer.pageInfo[first_page].top;
367 const int y2 = mainBuffer.pageInfo[page - 1].bottom;
368
369 const int bytes_per_row = VideoMonitor.bytes_per_row;
370 const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
371 int i, j;
372
373 // Check for first column from left and first column
374 // from right that have changed
375 int x1 = VideoMonitor.x * bytes_per_pixel - 1;
376 for (j = y1; j <= y2; j++) {
377 uint8 * const p1 = &the_buffer[j * bytes_per_row];
378 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
379 for (i = 0; i < x1; i++) {
380 if (p1[i] != p2[i]) {
381 x1 = i;
382 break;
383 }
384 }
385 }
386 x1 /= bytes_per_pixel;
387
388 int x2 = x1 * bytes_per_pixel;
389 for (j = y2; j >= y1; j--) {
390 uint8 * const p1 = &the_buffer[j * bytes_per_row];
391 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
392 for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
393 if (p1[i] != p2[i]) {
394 x2 = i;
395 break;
396 }
397 }
398 }
399 x2 /= bytes_per_pixel;
400
401 // Update the_host_buffer and copy of the_buffer
402 // There should be at least one pixel to copy
403 const int width = x2 - x1 + 1;
404 i = y1 * bytes_per_row + x1 * bytes_per_pixel;
405 for (j = y1; j <= y2; j++) {
406 do_update_framebuffer(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
407 memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
408 i += bytes_per_row;
409 }
410 }
411 }
412 #endif
413
414 #endif /* ENABLE_VOSF */
415
416 #endif /* VIDEO_VOSF_H */