ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/video_vosf.h
Revision: 1.16
Committed: 2001-05-20T20:31:50Z (23 years, 6 months ago) by gbeauche
Content type: text/plain
Branch: MAIN
CVS Tags: snapshot-29052001, release-0_9-1
Changes since 1.15: +9 -100 lines
Log Message:
- new and updated SIGSEGV support functions:
  + configure script cleanups
  + possible support for Direct Addressing / VOSF on other platforms

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 // Screen fault handler
47 static bool screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
48 {
49 D(bug("screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", fault_address, fault_instruction));
50 const uintptr addr = (uintptr)fault_address;
51
52 /* Someone attempted to write to the frame buffer. Make it writeable
53 * now so that the data could actually be written. It will be made
54 * read-only back in one of the screen update_*() functions.
55 */
56 if ((addr >= mainBuffer.memStart) && (addr < mainBuffer.memEnd)) {
57 const int page = (addr - mainBuffer.memStart) >> mainBuffer.pageBits;
58 caddr_t page_ad = (caddr_t)(addr & ~(mainBuffer.pageSize - 1));
59 LOCK_VOSF;
60 PFLAG_SET(page);
61 mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE);
62 mainBuffer.dirty = true;
63 UNLOCK_VOSF;
64 return true;
65 }
66
67 /* Otherwise, we don't know how to handle the fault, let it crash */
68 fprintf(stderr, "do_handle_screen_fault: unhandled address 0x%08X", addr);
69 if (fault_instruction != SIGSEGV_INVALID_PC)
70 fprintf(stderr, " [IP=0x%08X]", fault_instruction);
71 fprintf(stderr, "\n");
72 return false;
73 }
74
75 /*
76 * Update display for Windowed mode and VOSF
77 */
78
79 // From video_blit.cpp
80 extern void (*Screen_blit)(uint8 * dest, const uint8 * source, uint32 length);
81 extern bool Screen_blitter_init(XVisualInfo * visual_info, bool native_byte_order);
82
83 /* How can we deal with array overrun conditions ?
84
85 The state of the framebuffer pages that have been touched are maintained
86 in the dirtyPages[] table. That table is (pageCount + 2) bytes long.
87
88 Terminology
89
90 "Last Page" denotes the pageCount-nth page, i.e. dirtyPages[pageCount - 1].
91 "CLEAR Page Guard" refers to the page following the Last Page but is always
92 in the CLEAR state. "SET Page Guard" refers to the page following the CLEAR
93 Page Guard but is always in the SET state.
94
95 Rough process
96
97 The update routines must determine which pages have to be blitted to the
98 screen. This job consists in finding the first_page that was touched.
99 i.e. find the next page that is SET. Then, finding how many pages were
100 touched starting from first_page. i.e. find the next page that is CLEAR.
101
102 There are two cases to check:
103
104 - Last Page is CLEAR: find_next_page_set() will reach the SET Page Guard
105 but it is beyond the valid pageCount value. Therefore, we exit from the
106 update routine.
107
108 - Last Page is SET: first_page equals (pageCount - 1) and
109 find_next_page_clear() will reach the CLEAR Page Guard. We blit the last
110 page to the screen. On the next iteration, page equals pageCount and
111 find_next_page_set() will reach the SET Page Guard. We still safely exit
112 from the update routine because the SET Page Guard position is greater
113 than pageCount.
114 */
115
116 static inline void update_display_window_vosf(void)
117 {
118 int page = 0;
119 for (;;) {
120 const int first_page = find_next_page_set(page);
121 if (first_page >= mainBuffer.pageCount)
122 break;
123
124 page = find_next_page_clear(first_page);
125 PFLAG_CLEAR_RANGE(first_page, page);
126
127 // Make the dirty pages read-only again
128 const int32 offset = first_page << mainBuffer.pageBits;
129 const uint32 length = (page - first_page) << mainBuffer.pageBits;
130 mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
131
132 // There is at least one line to update
133 const int y1 = mainBuffer.pageInfo[first_page].top;
134 const int y2 = mainBuffer.pageInfo[page - 1].bottom;
135 const int height = y2 - y1 + 1;
136
137 const int bytes_per_row = VideoMonitor.bytes_per_row;
138 const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
139 int i = y1 * bytes_per_row, j;
140
141 if (depth == 1) {
142
143 // Update the_host_buffer and copy of the_buffer
144 for (j = y1; j <= y2; j++) {
145 Screen_blit(the_host_buffer + i, the_buffer + i, VideoMonitor.x >> 3);
146 i += bytes_per_row;
147 }
148
149 } else {
150
151 // Update the_host_buffer and copy of the_buffer
152 for (j = y1; j <= y2; j++) {
153 Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * VideoMonitor.x);
154 i += bytes_per_row;
155 }
156 }
157
158 if (have_shm)
159 XShmPutImage(x_display, the_win, the_gc, img, 0, y1, 0, y1, VideoMonitor.x, height, 0);
160 else
161 XPutImage(x_display, the_win, the_gc, img, 0, y1, 0, y1, VideoMonitor.x, height);
162 }
163
164 mainBuffer.dirty = false;
165 }
166
167
168 /*
169 * Update display for DGA mode and VOSF
170 * (only in Direct Addressing mode)
171 */
172
173 #if REAL_ADDRESSING || DIRECT_ADDRESSING
174 static inline void update_display_dga_vosf(void)
175 {
176 int page = 0;
177 for (;;) {
178 const int first_page = find_next_page_set(page);
179 if (first_page >= mainBuffer.pageCount)
180 break;
181
182 page = find_next_page_clear(first_page);
183 PFLAG_CLEAR_RANGE(first_page, page);
184
185 // Make the dirty pages read-only again
186 const int32 offset = first_page << mainBuffer.pageBits;
187 const uint32 length = (page - first_page) << mainBuffer.pageBits;
188 mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
189
190 // I am sure that y2 >= y1 and depth != 1
191 const int y1 = mainBuffer.pageInfo[first_page].top;
192 const int y2 = mainBuffer.pageInfo[page - 1].bottom;
193
194 const int bytes_per_row = VideoMonitor.bytes_per_row;
195 const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
196 int i, j;
197
198 // Check for first column from left and first column
199 // from right that have changed
200 int x1 = VideoMonitor.x * bytes_per_pixel - 1;
201 for (j = y1; j <= y2; j++) {
202 uint8 * const p1 = &the_buffer[j * bytes_per_row];
203 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
204 for (i = 0; i < x1; i++) {
205 if (p1[i] != p2[i]) {
206 x1 = i;
207 break;
208 }
209 }
210 }
211 x1 /= bytes_per_pixel;
212
213 int x2 = x1 * bytes_per_pixel;
214 for (j = y2; j >= y1; j--) {
215 uint8 * const p1 = &the_buffer[j * bytes_per_row];
216 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
217 for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
218 if (p1[i] != p2[i]) {
219 x2 = i;
220 break;
221 }
222 }
223 }
224 x2 /= bytes_per_pixel;
225
226 // Update the_host_buffer and copy of the_buffer
227 // There should be at least one pixel to copy
228 const int width = x2 - x1 + 1;
229 i = y1 * bytes_per_row + x1 * bytes_per_pixel;
230 for (j = y1; j <= y2; j++) {
231 Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
232 memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
233 i += bytes_per_row;
234 }
235 }
236 mainBuffer.dirty = false;
237 }
238 #endif
239
240 #endif /* ENABLE_VOSF */
241
242 #endif /* VIDEO_VOSF_H */