ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/video_vosf.h
Revision: 1.2
Committed: 2000-09-23T06:51:30Z (24 years, 2 months ago) by gbeauche
Content type: text/plain
Branch: MAIN
Changes since 1.1: +70 -15 lines
Log Message:
- fixed blitters for big endian systems, will probably work now

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 0
95 #define FB_FUNC_NAME do_fbcopy_raw
96 #include "video_blit.h"
97 #endif
98
99
100 // RGB 555
101
102 #ifdef WORDS_BIGENDIAN
103 # define FB_FUNC_NAME do_fbcopy_15_obo
104 #else
105 # define FB_FUNC_NAME do_fbcopy_15_nbo
106 #endif
107
108 #define FB_BLIT_1(dst, src) \
109 (dst = (((src) >> 8) & 0xff) | (((src) & 0xff) << 8))
110
111 #define FB_BLIT_2(dst, src) \
112 (dst = (((src) >> 8) & 0x00ff00ff) | (((src) & 0x00ff00ff) << 8))
113
114 #define FB_DEPTH 15
115 #include "video_blit.h"
116
117
118 // RGB 565
119
120 #ifdef WORDS_BIGENDIAN
121
122 // native byte order
123
124 #define FB_BLIT_1(dst, src) \
125 (dst = (((src) & 0x1f) | (((src) << 1) & 0xffc0)))
126
127 #define FB_BLIT_2(dst, src) \
128 (dst = (((src) & 0x001f001f) | (((src) << 1) & 0xffc0ffc0)))
129
130 #define FB_DEPTH 16
131 #define FB_FUNC_NAME do_fbcopy_16_nbo
132 #include "video_blit.h"
133
134 // opposite byte order (untested)
135
136 #define FB_BLIT_1(dst, src) \
137 (dst = ((((src) >> 6) & 0xff) | (((src) & 0x60) << 9)))
138
139 #define FB_BLIT_2(dst, src) \
140 (dst = ((((src) >> 6) & 0x00ff00ff) | (((src) & 0x00600060) << 9)))
141
142 #define FB_DEPTH 16
143 #define FB_FUNC_NAME do_fbcopy_16_obo
144 #include "video_blit.h"
145
146 #else
147
148 // native byte order
149
150 #define FB_BLIT_1(dst, src) \
151 (dst = (((src) >> 8) & 0x001f) | (((src) << 9) & 0xfe00) | (((src) >> 7) & 0x01c0))
152
153 #define FB_BLIT_2(dst, src) \
154 (dst = (((src) >> 8) & 0x001f001f) | (((src) << 9) & 0xfe00fe00) | (((src) >> 7) & 0x01c001c0))
155
156 #define FB_DEPTH 16
157 #define FB_FUNC_NAME do_fbcopy_16_nbo
158 #include "video_blit.h"
159
160 // opposite byte order (untested)
161
162 #define FB_BLIT_1(dst, src) \
163 (dst = (((src) & 0x1f00) | (((src) << 1) & 0xe0fe) | (((src) >> 15) & 1)))
164
165 #define FB_BLIT_2(dst, src) \
166 (dst = (((src) & 0x1f001f00) | (((src) << 1) & 0xe0fee0fe) | (((src) >> 15) & 0x10001)))
167
168 #define FB_DEPTH 16
169 #define FB_FUNC_NAME do_fbcopy_16_obo
170 #include "video_blit.h"
171
172 #endif
173
174 // RGB 888
175
176 #ifdef WORDS_BIGENDIAN
177 # define FB_FUNC_NAME do_fbcopy_24_obo
178 #else
179 # define FB_FUNC_NAME do_fbcopy_24_nbo
180 #endif
181
182 #define FB_BLIT_1(dst, src) \
183 (dst = (src))
184
185 #define FB_BLIT_2(dst, src) \
186 (dst = (((src) >> 24) & 0xff) | (((src) >> 16) & 0xff00) | (((src) & 0xff00) << 16) | (((src) & 0xff) << 24))
187
188 #define FB_DEPTH 24
189 #include "video_blit.h"
190
191
192 /*
193 * Frame buffer copy functions map table
194 */
195
196 typedef void (*fbcopy_func)(uint8 *, const uint8 *, uint32);
197 static fbcopy_func do_update_framebuffer;
198
199 #define FBCOPY_FUNC(aHandler) do_ ## aHandler
200
201 #if REAL_ADDRESSING || DIRECT_ADDRESSING
202 #define WD(X) { FBCOPY_FUNC(X), FBCOPY_FUNC(X) }
203 #else
204 #define WD(X) { FBCOPY_FUNC(fbcopy_raw), FBCOPY_FUNC(fbcopy_raw) }
205 #endif
206
207 // fb_copy_funcs[depth_id][native_byte_order][dga_mode]
208 // NT : not tested
209 // OK : has been successfully tested
210 // NBO : native byte order
211 // OBO : opposite byte order
212 static fbcopy_func fbcopy_funcs[ID_DEPTH_COUNT][2][2] = {
213 #ifdef WORDS_BIGENDIAN
214 /* opposite byte order native byte order */
215 /* 1 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // NT
216 /* 8 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // OK (NBO)
217 /* 15 bpp */ { WD(fbcopy_15_obo) , WD(fbcopy_raw) }, // NT
218 /* 16 bpp */ { WD(fbcopy_16_obo) , WD(fbcopy_16_nbo) }, // NT
219 /* 24 bpp */ { WD(fbcopy_24_obo) , WD(fbcopy_raw) } // NT
220 #else
221 /* opposite byte order native byte order */
222 /* 1 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // NT
223 /* 8 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // OK (NBO)
224 /* 15 bpp */ { WD(fbcopy_raw) , WD(fbcopy_15_nbo) }, // OK (NBO)
225 /* 16 bpp */ { WD(fbcopy_16_obo) , WD(fbcopy_16_nbo) }, // OK (NBO)
226 /* 24 bpp */ { WD(fbcopy_raw) , WD(fbcopy_24_nbo) } // NT
227 #endif
228 };
229
230 #undef WD
231
232 #define FBCOPY_FUNC_ERROR \
233 ErrorAlert("Invalid screen depth")
234
235 #define GET_FBCOPY_FUNC(aDepth, aNativeByteOrder, aDisplay) \
236 ((depth_id(aDepth) == ID_DEPTH_UNKNOWN) ? ( FBCOPY_FUNC_ERROR, (fbcopy_func)0 ) : \
237 fbcopy_funcs[depth_id(aDepth)][(aNativeByteOrder)][(aDisplay) == DISPLAY_DGA ? 1 : 0])
238
239
240 /*
241 * Screen fault handler
242 */
243
244 static inline void do_handle_screen_fault(unsigned long addr)
245 {
246 if ((addr < mainBuffer.memStart) || (addr >= mainBuffer.memEnd)) {
247 fprintf(stderr, "Segmentation fault at 0x%08X\n", addr);
248 abort();
249 }
250
251 const int page = (addr - mainBuffer.memStart) >> mainBuffer.pageBits;
252 caddr_t page_ad = (caddr_t)(addr & ~(mainBuffer.pageSize - 1));
253 #ifdef HAVE_PTHREADS
254 pthread_mutex_lock(&Screen_draw_lock);
255 #endif
256 PFLAG_SET(page);
257 mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE);
258 #ifdef HAVE_PTHREADS
259 pthread_mutex_unlock(&Screen_draw_lock);
260 #endif
261 }
262
263 #if defined(HAVE_SIGINFO_T)
264 static void Screen_fault_handler(int, siginfo_t * sip, void *)
265 {
266 D(bug("Screen_fault_handler: ADDR=0x%08X\n", sip->si_addr));
267 do_handle_screen_fault((unsigned long)sip->si_addr);
268 }
269 #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
270 # if defined(__i386__) && defined(__linux__)
271 static void Screen_fault_handler(int, struct sigcontext scs)
272 {
273 D(bug("Screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", scs.cr2, scs.eip));
274 do_handle_screen_fault((unsigned long)scs.cr2);
275 }
276 # else
277 # error "No suitable subterfuge for Video on SEGV signals"
278 # endif
279 #else
280 # error "Can't do Video on SEGV signals"
281 #endif
282
283
284 /*
285 * Screen fault handler initialization
286 */
287
288 #if defined(HAVE_SIGINFO_T)
289 static bool Screen_fault_handler_init()
290 {
291 // Setup SIGSEGV handler to process writes to frame buffer
292 sigemptyset(&vosf_sa.sa_mask);
293 vosf_sa.sa_sigaction = Screen_fault_handler;
294 vosf_sa.sa_flags = 0;
295 return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
296 }
297 #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
298 static bool Screen_fault_handler_init()
299 {
300 // Setup SIGSEGV handler to process writes to frame buffer
301 sigemptyset(&vosf_sa.sa_mask);
302 vosf_sa.sa_handler = (void (*)(int)) Screen_fault_handler;
303 vosf_sa.sa_flags = 0;
304 return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
305 }
306 #endif
307
308
309 /*
310 * Update display for Windowed mode and VOSF
311 */
312
313 static inline void update_display_window_vosf(void)
314 {
315 int page = 0;
316 for (;;) {
317 while (PFLAG_ISCLEAR_4(page))
318 page += 4;
319
320 while (PFLAG_ISCLEAR(page))
321 page++;
322
323 if (page >= mainBuffer.pageCount)
324 break;
325
326 const int first_page = page;
327 PFLAG_CLEAR(first_page);
328 while ((++page < mainBuffer.pageCount) && PFLAG_ISSET(page))
329 PFLAG_CLEAR(page);
330
331 // Make the dirty pages read-only again
332 const int32 offset = first_page << mainBuffer.pageBits;
333 const uint32 length = (page - first_page) << mainBuffer.pageBits;
334 mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
335
336 // There is at least one line to update
337 const int y1 = mainBuffer.pageInfo[first_page].top;
338 const int y2 = mainBuffer.pageInfo[page - 1].bottom;
339 const int height = y2 - y1 + 1;
340
341 const int bytes_per_row = VideoMonitor.bytes_per_row;
342 const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
343 int i, j;
344
345 // Check for first column from left and first column
346 // from right that have changed
347 int x1 = VideoMonitor.x * bytes_per_pixel - 1;
348 for (j = y1; j <= y2; j++) {
349 uint8 * const p1 = &the_buffer[j * bytes_per_row];
350 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
351 for (i = 0; i < x1; i++) {
352 if (p1[i] != p2[i]) {
353 x1 = i;
354 break;
355 }
356 }
357 }
358 x1 /= bytes_per_pixel;
359
360 int x2 = x1 * bytes_per_pixel;
361 for (j = y2; j >= y1; j--) {
362 uint8 * const p1 = &the_buffer[j * bytes_per_row];
363 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
364 for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
365 if (p1[i] != p2[i]) {
366 x2 = i;
367 break;
368 }
369 }
370 }
371 x2 /= bytes_per_pixel;
372
373 // Update the_host_buffer and copy of the_buffer
374 // There is at least one pixel to copy
375 const int width = x2 - x1 + 1;
376 i = y1 * bytes_per_row + x1 * bytes_per_pixel;
377 for (j = y1; j <= y2; j++) {
378 do_update_framebuffer(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
379 memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
380 i += bytes_per_row;
381 }
382
383 if (have_shm)
384 XShmPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, width, height, 0);
385 else
386 XPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, width, height);
387 }
388 }
389
390
391 /*
392 * Update display for DGA mode and VOSF
393 * (only in Direct Addressing mode)
394 */
395
396 #if REAL_ADDRESSING || DIRECT_ADDRESSING
397 static inline void update_display_dga_vosf(void)
398 {
399 int page = 0;
400 for (;;) {
401 while (PFLAG_ISCLEAR_4(page))
402 page += 4;
403
404 while (PFLAG_ISCLEAR(page))
405 page++;
406
407 if (page >= mainBuffer.pageCount)
408 break;
409
410 const int first_page = page;
411 PFLAG_CLEAR(first_page);
412 while ((++page < mainBuffer.pageCount) && PFLAG_ISSET(page))
413 PFLAG_CLEAR(page);
414
415 // Make the dirty pages read-only again
416 const int32 offset = first_page << mainBuffer.pageBits;
417 const uint32 length = (page - first_page) << mainBuffer.pageBits;
418 mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
419
420 // I am sure that y2 >= y1 and depth != 1
421 const int y1 = mainBuffer.pageInfo[first_page].top;
422 const int y2 = mainBuffer.pageInfo[page - 1].bottom;
423
424 const int bytes_per_row = VideoMonitor.bytes_per_row;
425 const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
426 int i, j;
427
428 // Check for first column from left and first column
429 // from right that have changed
430 int x1 = VideoMonitor.x * bytes_per_pixel - 1;
431 for (j = y1; j <= y2; j++) {
432 uint8 * const p1 = &the_buffer[j * bytes_per_row];
433 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
434 for (i = 0; i < x1; i++) {
435 if (p1[i] != p2[i]) {
436 x1 = i;
437 break;
438 }
439 }
440 }
441 x1 /= bytes_per_pixel;
442
443 int x2 = x1 * bytes_per_pixel;
444 for (j = y2; j >= y1; j--) {
445 uint8 * const p1 = &the_buffer[j * bytes_per_row];
446 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
447 for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
448 if (p1[i] != p2[i]) {
449 x2 = i;
450 break;
451 }
452 }
453 }
454 x2 /= bytes_per_pixel;
455
456 // Update the_host_buffer and copy of the_buffer
457 // There should be at least one pixel to copy
458 const int width = x2 - x1 + 1;
459 i = y1 * bytes_per_row + x1 * bytes_per_pixel;
460 for (j = y1; j <= y2; j++) {
461 do_update_framebuffer(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
462 memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
463 i += bytes_per_row;
464 }
465 }
466 }
467 #endif
468
469 #endif /* ENABLE_VOSF */
470
471 #endif /* VIDEO_VOSF_H */