ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/video_vosf.h
Revision: 1.13
Committed: 2001-01-28T14:05:19Z (23 years, 10 months ago) by gbeauche
Content type: text/plain
Branch: MAIN
Changes since 1.12: +13 -198 lines
Log Message:
Mainly changes to the VOSF code:
- improved blitters selection
- improved blitters performance if UNALIGNED_PROFITABLE is set
- cleaned up 8 bpp blitters

File Contents

# Content
1 /*
2 * video_vosf.h - Video/graphics emulation, video on SEGV signals support
3 *
4 * Basilisk II (C) 1997-2001 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 uintptr align_on_page_boundary(uintptr 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 fault handler
49 */
50
51 const uintptr INVALID_PC = (uintptr)-1;
52
53 static inline void do_handle_screen_fault(uintptr addr, uintptr pc = INVALID_PC)
54 {
55 /* Someone attempted to write to the frame buffer. Make it writeable
56 * now so that the data could actually be written. It will be made
57 * read-only back in one of the screen update_*() functions.
58 */
59 if ((addr >= mainBuffer.memStart) && (addr < mainBuffer.memEnd)) {
60 const int page = (addr - mainBuffer.memStart) >> mainBuffer.pageBits;
61 caddr_t page_ad = (caddr_t)(addr & ~(mainBuffer.pageSize - 1));
62 LOCK_VOSF;
63 PFLAG_SET(page);
64 mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE);
65 mainBuffer.dirty = true;
66 UNLOCK_VOSF;
67 return;
68 }
69
70 /* Otherwise, we don't know how to handle the fault, let it crash */
71 fprintf(stderr, "do_handle_screen_fault: unhandled address 0x%08X", addr);
72 if (pc != INVALID_PC)
73 fprintf(stderr, " [IP=0x%08X]", pc);
74 fprintf(stderr, "\n");
75
76 signal(SIGSEGV, SIG_DFL);
77 }
78
79 #if defined(HAVE_SIGINFO_T)
80
81 static void Screen_fault_handler(int, siginfo_t * sip, void *)
82 {
83 D(bug("Screen_fault_handler: ADDR=0x%08X\n", sip->si_addr));
84 do_handle_screen_fault((uintptr)sip->si_addr);
85 }
86
87 #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
88
89 # if defined(__i386__) && defined(__linux__)
90 static void Screen_fault_handler(int, struct sigcontext scs)
91 {
92 D(bug("Screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", scs.cr2, scs.eip));
93 do_handle_screen_fault((uintptr)scs.cr2, (uintptr)scs.eip);
94 }
95
96 # elif defined(__m68k__) && defined(__NetBSD__)
97
98 # include <m68k/frame.h>
99 static void Screen_fault_handler(int, int code, struct sigcontext *scp)
100 {
101 D(bug("Screen_fault_handler: ADDR=0x%08X\n", code));
102 struct sigstate {
103 int ss_flags;
104 struct frame ss_frame;
105 };
106 struct sigstate *state = (struct sigstate *)scp->sc_ap;
107 uintptr fault_addr;
108 switch (state->ss_frame.f_format) {
109 case 7: // 68040 access error
110 // "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown
111 fault_addr = state->ss_frame.f_fmt7.f_fa;
112 break;
113 default:
114 fault_addr = (uintptr)code;
115 break;
116 }
117 do_handle_screen_fault(fault_addr);
118 }
119
120 # else
121 # error "No suitable subterfuge for Video on SEGV signals"
122 # endif
123 #else
124 # error "Can't do Video on SEGV signals"
125 #endif
126
127
128 /*
129 * Screen fault handler initialization
130 */
131
132 #if defined(HAVE_SIGINFO_T)
133 static bool Screen_fault_handler_init()
134 {
135 // Setup SIGSEGV handler to process writes to frame buffer
136 sigemptyset(&vosf_sa.sa_mask);
137 vosf_sa.sa_sigaction = Screen_fault_handler;
138 vosf_sa.sa_flags = SA_SIGINFO;
139 return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
140 }
141 #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
142 static bool Screen_fault_handler_init()
143 {
144 // Setup SIGSEGV handler to process writes to frame buffer
145 sigemptyset(&vosf_sa.sa_mask);
146 vosf_sa.sa_handler = (void (*)(int)) Screen_fault_handler;
147 #if !EMULATED_68K && defined(__NetBSD__)
148 sigaddset(&vosf_sa.sa_mask, SIGALRM);
149 vosf_sa.sa_flags = SA_ONSTACK;
150 #else
151 vosf_sa.sa_flags = 0;
152 #endif
153 return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
154 }
155 #endif
156
157
158 /*
159 * Update display for Windowed mode and VOSF
160 */
161
162 // From video_blit.cpp
163 extern void (*Screen_blit)(uint8 * dest, const uint8 * source, uint32 length);
164 extern bool Screen_blitter_init(XVisualInfo * visual_info, bool native_byte_order);
165
166 /* How can we deal with array overrun conditions ?
167
168 The state of the framebuffer pages that have been touched are maintained
169 in the dirtyPages[] table. That table is (pageCount + 2) bytes long.
170
171 Terminology
172
173 "Last Page" denotes the pageCount-nth page, i.e. dirtyPages[pageCount - 1].
174 "CLEAR Page Guard" refers to the page following the Last Page but is always
175 in the CLEAR state. "SET Page Guard" refers to the page following the CLEAR
176 Page Guard but is always in the SET state.
177
178 Rough process
179
180 The update routines must determine which pages have to be blitted to the
181 screen. This job consists in finding the first_page that was touched.
182 i.e. find the next page that is SET. Then, finding how many pages were
183 touched starting from first_page. i.e. find the next page that is CLEAR.
184
185 There are two cases to check:
186
187 - Last Page is CLEAR: find_next_page_set() will reach the SET Page Guard
188 but it is beyond the valid pageCount value. Therefore, we exit from the
189 update routine.
190
191 - Last Page is SET: first_page equals (pageCount - 1) and
192 find_next_page_clear() will reach the CLEAR Page Guard. We blit the last
193 page to the screen. On the next iteration, page equals pageCount and
194 find_next_page_set() will reach the SET Page Guard. We still safely exit
195 from the update routine because the SET Page Guard position is greater
196 than pageCount.
197 */
198
199 static inline void update_display_window_vosf(void)
200 {
201 int page = 0;
202 for (;;) {
203 const int first_page = find_next_page_set(page);
204 if (first_page >= mainBuffer.pageCount)
205 break;
206
207 page = find_next_page_clear(first_page);
208 PFLAG_CLEAR_RANGE(first_page, page);
209
210 // Make the dirty pages read-only again
211 const int32 offset = first_page << mainBuffer.pageBits;
212 const uint32 length = (page - first_page) << mainBuffer.pageBits;
213 mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
214
215 // There is at least one line to update
216 const int y1 = mainBuffer.pageInfo[first_page].top;
217 const int y2 = mainBuffer.pageInfo[page - 1].bottom;
218 const int height = y2 - y1 + 1;
219
220 const int bytes_per_row = VideoMonitor.bytes_per_row;
221 const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
222 int i, j;
223
224 // Check for first column from left and first column
225 // from right that have changed
226 int x1, x2, width;
227 if (depth == 1) {
228
229 x1 = VideoMonitor.x - 1;
230 for (j = y1; j <= y2; j++) {
231 uint8 * const p1 = &the_buffer[j * bytes_per_row];
232 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
233 for (i = 0; i < (x1>>3); i++) {
234 if (p1[i] != p2[i]) {
235 x1 = i << 3;
236 break;
237 }
238 }
239 }
240
241 x2 = x1;
242 for (j = y2; j >= y1; j--) {
243 uint8 * const p1 = &the_buffer[j * bytes_per_row];
244 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
245 for (i = (VideoMonitor.x>>3) - 1; i > (x2>>3); i--) {
246 if (p1[i] != p2[i]) {
247 x2 = (i << 3) + 7;
248 break;
249 }
250 }
251 }
252 width = x2 - x1 + 1;
253
254 // Update the_host_buffer and copy of the_buffer
255 i = y1 * bytes_per_row + (x1 >> 3);
256 for (j = y1; j <= y2; j++) {
257 Screen_blit(the_host_buffer + i, the_buffer + i, width >> 3);
258 memcpy(the_buffer_copy + i, the_buffer + i, width >> 3);
259 i += bytes_per_row;
260 }
261
262 } else {
263
264 x1 = VideoMonitor.x * bytes_per_pixel - 1;
265 for (j = y1; j <= y2; j++) {
266 uint8 * const p1 = &the_buffer[j * bytes_per_row];
267 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
268 for (i = 0; i < x1; i++) {
269 if (p1[i] != p2[i]) {
270 x1 = i;
271 break;
272 }
273 }
274 }
275 x1 /= bytes_per_pixel;
276
277 x2 = x1 * bytes_per_pixel;
278 for (j = y2; j >= y1; j--) {
279 uint8 * const p1 = &the_buffer[j * bytes_per_row];
280 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
281 for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
282 if (p1[i] != p2[i]) {
283 x2 = i;
284 break;
285 }
286 }
287 }
288 x2 /= bytes_per_pixel;
289 width = x2 - x1 + 1;
290
291 // Update the_host_buffer and copy of the_buffer
292 i = y1 * bytes_per_row + x1 * bytes_per_pixel;
293 for (j = y1; j <= y2; j++) {
294 Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
295 memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
296 i += bytes_per_row;
297 }
298 }
299
300 if (have_shm)
301 XShmPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, width, height, 0);
302 else
303 XPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, width, height);
304 }
305 mainBuffer.dirty = false;
306 }
307
308
309 /*
310 * Update display for DGA mode and VOSF
311 * (only in Direct Addressing mode)
312 */
313
314 #if REAL_ADDRESSING || DIRECT_ADDRESSING
315 static inline void update_display_dga_vosf(void)
316 {
317 int page = 0;
318 for (;;) {
319 const int first_page = find_next_page_set(page);
320 if (first_page >= mainBuffer.pageCount)
321 break;
322
323 page = find_next_page_clear(first_page);
324 PFLAG_CLEAR_RANGE(first_page, page);
325
326 // Make the dirty pages read-only again
327 const int32 offset = first_page << mainBuffer.pageBits;
328 const uint32 length = (page - first_page) << mainBuffer.pageBits;
329 mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
330
331 // I am sure that y2 >= y1 and depth != 1
332 const int y1 = mainBuffer.pageInfo[first_page].top;
333 const int y2 = mainBuffer.pageInfo[page - 1].bottom;
334
335 const int bytes_per_row = VideoMonitor.bytes_per_row;
336 const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
337 int i, j;
338
339 // Check for first column from left and first column
340 // from right that have changed
341 int x1 = VideoMonitor.x * bytes_per_pixel - 1;
342 for (j = y1; j <= y2; j++) {
343 uint8 * const p1 = &the_buffer[j * bytes_per_row];
344 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
345 for (i = 0; i < x1; i++) {
346 if (p1[i] != p2[i]) {
347 x1 = i;
348 break;
349 }
350 }
351 }
352 x1 /= bytes_per_pixel;
353
354 int x2 = x1 * bytes_per_pixel;
355 for (j = y2; j >= y1; j--) {
356 uint8 * const p1 = &the_buffer[j * bytes_per_row];
357 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
358 for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
359 if (p1[i] != p2[i]) {
360 x2 = i;
361 break;
362 }
363 }
364 }
365 x2 /= bytes_per_pixel;
366
367 // Update the_host_buffer and copy of the_buffer
368 // There should be at least one pixel to copy
369 const int width = x2 - x1 + 1;
370 i = y1 * bytes_per_row + x1 * bytes_per_pixel;
371 for (j = y1; j <= y2; j++) {
372 Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
373 memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
374 i += bytes_per_row;
375 }
376 }
377 mainBuffer.dirty = false;
378 }
379 #endif
380
381 #endif /* ENABLE_VOSF */
382
383 #endif /* VIDEO_VOSF_H */