ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/video_vosf.h
Revision: 1.49
Committed: 2005-03-28T16:14:25Z (19 years, 5 months ago) by gbeauche
Content type: text/plain
Branch: MAIN
Changes since 1.48: +62 -53 lines
Log Message:
Enable multiple depths in fullscreen DGA modes, i.e. add 1-bit to 16/32-bit
blitters, rewrite update_display_dga_vosf() to actually work with sub byte
pixels. Factor out update_display_window_vosf() since it's long time that
it is no longer checking for first column and last column that have changed.

File Contents

# User Rev Content
1 gbeauche 1.1 /*
2     * video_vosf.h - Video/graphics emulation, video on SEGV signals support
3     *
4 gbeauche 1.48 * Basilisk II (C) 1997-2005 Christian Bauer
5 gbeauche 1.1 *
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 gbeauche 1.34 // Note: this file must be #include'd only in video_x.cpp
25 gbeauche 1.1 #ifdef ENABLE_VOSF
26    
27 cebix 1.19 #include "sigsegv.h"
28     #include "vm_alloc.h"
29 gbeauche 1.46 #ifdef _WIN32
30     #include "util_windows.h"
31     #endif
32 cebix 1.19
33 gbeauche 1.39 // Glue for SDL and X11 support
34 gbeauche 1.38 #ifdef USE_SDL_VIDEO
35     #define MONITOR_INIT SDL_monitor_desc &monitor
36     #define VIDEO_DRV_INIT driver_window *drv
37     #define VIDEO_DRV_ROW_BYTES drv->s->pitch
38     #define VIDEO_DRV_LOCK_PIXELS if (SDL_MUSTLOCK(drv->s)) SDL_LockSurface(drv->s)
39     #define VIDEO_DRV_UNLOCK_PIXELS if (SDL_MUSTLOCK(drv->s)) SDL_UnlockSurface(drv->s)
40     #else
41 gbeauche 1.39 #ifdef SHEEPSHAVER
42 gbeauche 1.38 #define MONITOR_INIT /* nothing */
43 gbeauche 1.33 #define VIDEO_DRV_INIT /* nothing */
44     #define VIDEO_DRV_WINDOW the_win
45     #define VIDEO_DRV_GC the_gc
46     #define VIDEO_DRV_IMAGE img
47     #define VIDEO_DRV_HAVE_SHM have_shm
48     #else
49 gbeauche 1.38 #define MONITOR_INIT X11_monitor_desc &monitor
50 gbeauche 1.33 #define VIDEO_DRV_INIT driver_window *drv
51     #define VIDEO_DRV_WINDOW drv->w
52     #define VIDEO_DRV_GC drv->gc
53     #define VIDEO_DRV_IMAGE drv->img
54     #define VIDEO_DRV_HAVE_SHM drv->have_shm
55 gbeauche 1.38 #endif
56     #define VIDEO_DRV_LOCK_PIXELS /* nothing */
57     #define VIDEO_DRV_UNLOCK_PIXELS /* nothing */
58     #define VIDEO_DRV_ROW_BYTES VIDEO_DRV_IMAGE->bytes_per_line
59 gbeauche 1.33 #endif
60    
61 cebix 1.19 // Variables for Video on SEGV support
62 gbeauche 1.20 static uint8 *the_host_buffer; // Host frame buffer in VOSF mode
63 gbeauche 1.49 static uint32 the_host_buffer_row_bytes; // Host frame buffer number of bytes per row
64 cebix 1.19
65     struct ScreenPageInfo {
66     int top, bottom; // Mapping between this virtual page and Mac scanlines
67     };
68    
69     struct ScreenInfo {
70     uintptr memStart; // Start address aligned to page boundary
71     uint32 memLength; // Length of the memory addressed by the screen pages
72    
73 gbeauche 1.27 uintptr pageSize; // Size of a page
74 cebix 1.19 int pageBits; // Shift count to get the page number
75     uint32 pageCount; // Number of pages allocated to the screen
76    
77     bool dirty; // Flag: set if the frame buffer was touched
78     char * dirtyPages; // Table of flags set if page was altered
79     ScreenPageInfo * pageInfo; // Table of mappings page -> Mac scanlines
80     };
81    
82     static ScreenInfo mainBuffer;
83    
84     #define PFLAG_SET_VALUE 0x00
85     #define PFLAG_CLEAR_VALUE 0x01
86     #define PFLAG_SET_VALUE_4 0x00000000
87     #define PFLAG_CLEAR_VALUE_4 0x01010101
88     #define PFLAG_SET(page) mainBuffer.dirtyPages[page] = PFLAG_SET_VALUE
89     #define PFLAG_CLEAR(page) mainBuffer.dirtyPages[page] = PFLAG_CLEAR_VALUE
90     #define PFLAG_ISSET(page) (mainBuffer.dirtyPages[page] == PFLAG_SET_VALUE)
91     #define PFLAG_ISCLEAR(page) (mainBuffer.dirtyPages[page] != PFLAG_SET_VALUE)
92    
93     #ifdef UNALIGNED_PROFITABLE
94     # define PFLAG_ISSET_4(page) (*((uint32 *)(mainBuffer.dirtyPages + (page))) == PFLAG_SET_VALUE_4)
95     # define PFLAG_ISCLEAR_4(page) (*((uint32 *)(mainBuffer.dirtyPages + (page))) == PFLAG_CLEAR_VALUE_4)
96     #else
97     # define PFLAG_ISSET_4(page) \
98     PFLAG_ISSET(page ) && PFLAG_ISSET(page+1) \
99     && PFLAG_ISSET(page+2) && PFLAG_ISSET(page+3)
100     # define PFLAG_ISCLEAR_4(page) \
101     PFLAG_ISCLEAR(page ) && PFLAG_ISCLEAR(page+1) \
102     && PFLAG_ISCLEAR(page+2) && PFLAG_ISCLEAR(page+3)
103     #endif
104    
105     // Set the selected page range [ first_page, last_page [ into the SET state
106     #define PFLAG_SET_RANGE(first_page, last_page) \
107     memset(mainBuffer.dirtyPages + (first_page), PFLAG_SET_VALUE, \
108     (last_page) - (first_page))
109    
110     // Set the selected page range [ first_page, last_page [ into the CLEAR state
111     #define PFLAG_CLEAR_RANGE(first_page, last_page) \
112     memset(mainBuffer.dirtyPages + (first_page), PFLAG_CLEAR_VALUE, \
113     (last_page) - (first_page))
114    
115     #define PFLAG_SET_ALL do { \
116     PFLAG_SET_RANGE(0, mainBuffer.pageCount); \
117     mainBuffer.dirty = true; \
118     } while (0)
119    
120     #define PFLAG_CLEAR_ALL do { \
121     PFLAG_CLEAR_RANGE(0, mainBuffer.pageCount); \
122     mainBuffer.dirty = false; \
123     } while (0)
124    
125     // Set the following macro definition to 1 if your system
126     // provides a really fast strchr() implementation
127     //#define HAVE_FAST_STRCHR 0
128    
129     static inline int find_next_page_set(int page)
130     {
131     #if HAVE_FAST_STRCHR
132     char *match = strchr(mainBuffer.dirtyPages + page, PFLAG_SET_VALUE);
133     return match ? match - mainBuffer.dirtyPages : mainBuffer.pageCount;
134     #else
135     while (PFLAG_ISCLEAR_4(page))
136     page += 4;
137     while (PFLAG_ISCLEAR(page))
138     page++;
139     return page;
140     #endif
141     }
142    
143     static inline int find_next_page_clear(int page)
144     {
145     #if HAVE_FAST_STRCHR
146     char *match = strchr(mainBuffer.dirtyPages + page, PFLAG_CLEAR_VALUE);
147     return match ? match - mainBuffer.dirtyPages : mainBuffer.pageCount;
148     #else
149     while (PFLAG_ISSET_4(page))
150     page += 4;
151     while (PFLAG_ISSET(page))
152     page++;
153     return page;
154     #endif
155     }
156    
157 gbeauche 1.36 #ifdef HAVE_SPINLOCKS
158     static spinlock_t vosf_lock = SPIN_LOCK_UNLOCKED; // Mutex to protect frame buffer (dirtyPages in fact)
159     #define LOCK_VOSF spin_lock(&vosf_lock)
160     #define UNLOCK_VOSF spin_unlock(&vosf_lock)
161 gbeauche 1.46 #elif defined(_WIN32)
162     static mutex_t vosf_lock; // Mutex to protect frame buffer (dirtyPages in fact)
163     #define LOCK_VOSF vosf_lock.lock();
164     #define UNLOCK_VOSF vosf_lock.unlock();
165 gbeauche 1.36 #elif defined(HAVE_PTHREADS)
166 cebix 1.19 static pthread_mutex_t vosf_lock = PTHREAD_MUTEX_INITIALIZER; // Mutex to protect frame buffer (dirtyPages in fact)
167     #define LOCK_VOSF pthread_mutex_lock(&vosf_lock);
168     #define UNLOCK_VOSF pthread_mutex_unlock(&vosf_lock);
169     #else
170     #define LOCK_VOSF
171     #define UNLOCK_VOSF
172     #endif
173    
174     static int log_base_2(uint32 x)
175     {
176     uint32 mask = 0x80000000;
177     int l = 31;
178     while (l >= 0 && (x & mask) == 0) {
179     mask >>= 1;
180     l--;
181     }
182     return l;
183     }
184    
185 gbeauche 1.20 // Extend size to page boundary
186     static uint32 page_extend(uint32 size)
187     {
188 gbeauche 1.47 const uint32 page_size = vm_get_page_size();
189 gbeauche 1.20 const uint32 page_mask = page_size - 1;
190     return (size + page_mask) & ~page_mask;
191     }
192    
193 cebix 1.19
194     /*
195 gbeauche 1.40 * Check if VOSF acceleration is profitable on this platform
196     */
197    
198 gbeauche 1.41 const int VOSF_PROFITABLE_TRIES = 3; // Make 3 attempts for full screen update
199     const int VOSF_PROFITABLE_THRESHOLD = 16667; // 60 Hz
200 gbeauche 1.40
201     static bool video_vosf_profitable(void)
202     {
203 gbeauche 1.41 int64 durations[VOSF_PROFITABLE_TRIES];
204     int mean_duration = 0;
205 gbeauche 1.40
206 gbeauche 1.41 for (int i = 0; i < VOSF_PROFITABLE_TRIES; i++) {
207     uint64 start = GetTicks_usec();
208     for (int p = 0; p < mainBuffer.pageCount; p++) {
209     uint8 *addr = (uint8 *)(mainBuffer.memStart + (p * mainBuffer.pageSize));
210     addr[0] = 0; // Trigger Screen_fault_handler()
211     }
212     int64 duration = GetTicks_usec() - start;
213     mean_duration += duration;
214     durations[i] = duration;
215    
216     PFLAG_CLEAR_ALL;
217     mainBuffer.dirty = false;
218     if (vm_protect((char *)mainBuffer.memStart, mainBuffer.memLength, VM_PAGE_READ) != 0)
219     return false;
220 gbeauche 1.40 }
221    
222 gbeauche 1.41 mean_duration /= VOSF_PROFITABLE_TRIES;
223     D(bug("Triggered %d screen faults in %ld usec on average\n", mainBuffer.pageCount, mean_duration));
224     return (mean_duration < (VOSF_PROFITABLE_THRESHOLD * (frame_skip ? frame_skip : 1)));
225 gbeauche 1.40 }
226    
227    
228     /*
229 gbeauche 1.27 * Initialize the VOSF system (mainBuffer structure, SIGSEGV handler)
230 cebix 1.19 */
231    
232 gbeauche 1.38 static bool video_vosf_init(MONITOR_INIT)
233 cebix 1.19 {
234 gbeauche 1.42 VIDEO_MODE_INIT_MONITOR;
235 cebix 1.31
236 gbeauche 1.47 const uintptr page_size = vm_get_page_size();
237 gbeauche 1.27 const uintptr page_mask = page_size - 1;
238    
239     // Round up frame buffer base to page boundary
240     mainBuffer.memStart = (((uintptr) the_buffer) + page_mask) & ~page_mask;
241    
242     // The frame buffer size shall already be aligned to page boundary (use page_extend)
243     mainBuffer.memLength = the_buffer_size;
244    
245     mainBuffer.pageSize = page_size;
246     mainBuffer.pageBits = log_base_2(mainBuffer.pageSize);
247     mainBuffer.pageCount = (mainBuffer.memLength + page_mask)/mainBuffer.pageSize;
248    
249     // The "2" more bytes requested are a safety net to insure the
250     // loops in the update routines will terminate.
251     // See "How can we deal with array overrun conditions ?" hereunder for further details.
252 gbeauche 1.29 mainBuffer.dirtyPages = (char *) malloc(mainBuffer.pageCount + 2);
253     if (mainBuffer.dirtyPages == NULL)
254 gbeauche 1.27 return false;
255 cebix 1.19
256 gbeauche 1.27 PFLAG_CLEAR_ALL;
257     PFLAG_CLEAR(mainBuffer.pageCount);
258     PFLAG_SET(mainBuffer.pageCount+1);
259    
260     // Allocate and fill in pageInfo with start and end (inclusive) row in number of bytes
261 gbeauche 1.29 mainBuffer.pageInfo = (ScreenPageInfo *) malloc(mainBuffer.pageCount * sizeof(ScreenPageInfo));
262     if (mainBuffer.pageInfo == NULL)
263 gbeauche 1.27 return false;
264    
265     uint32 a = 0;
266 cebix 1.28 for (unsigned i = 0; i < mainBuffer.pageCount; i++) {
267 gbeauche 1.33 unsigned y1 = a / VIDEO_MODE_ROW_BYTES;
268     if (y1 >= VIDEO_MODE_Y)
269     y1 = VIDEO_MODE_Y - 1;
270    
271     unsigned y2 = (a + mainBuffer.pageSize) / VIDEO_MODE_ROW_BYTES;
272     if (y2 >= VIDEO_MODE_Y)
273     y2 = VIDEO_MODE_Y - 1;
274 gbeauche 1.27
275     mainBuffer.pageInfo[i].top = y1;
276     mainBuffer.pageInfo[i].bottom = y2;
277    
278     a += mainBuffer.pageSize;
279     if (a > mainBuffer.memLength)
280     a = mainBuffer.memLength;
281     }
282    
283     // We can now write-protect the frame buffer
284     if (vm_protect((char *)mainBuffer.memStart, mainBuffer.memLength, VM_PAGE_READ) != 0)
285     return false;
286    
287     // The frame buffer is sane, i.e. there is no write to it yet
288     mainBuffer.dirty = false;
289     return true;
290     }
291 cebix 1.19
292    
293 gbeauche 1.27 /*
294     * Deinitialize VOSF system
295     */
296 cebix 1.19
297 gbeauche 1.27 static void video_vosf_exit(void)
298     {
299 gbeauche 1.29 if (mainBuffer.pageInfo) {
300     free(mainBuffer.pageInfo);
301     mainBuffer.pageInfo = NULL;
302 gbeauche 1.27 }
303 gbeauche 1.29 if (mainBuffer.dirtyPages) {
304     free(mainBuffer.dirtyPages);
305     mainBuffer.dirtyPages = NULL;
306 cebix 1.19 }
307     }
308    
309    
310 gbeauche 1.1 /*
311 gbeauche 1.20 * Screen fault handler
312 gbeauche 1.1 */
313    
314 gbeauche 1.33 bool Screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
315 gbeauche 1.1 {
316 gbeauche 1.16 const uintptr addr = (uintptr)fault_address;
317    
318 gbeauche 1.11 /* Someone attempted to write to the frame buffer. Make it writeable
319 gbeauche 1.20 * now so that the data could actually be written to. It will be made
320 gbeauche 1.11 * read-only back in one of the screen update_*() functions.
321     */
322 gbeauche 1.27 if (((uintptr)addr - mainBuffer.memStart) < mainBuffer.memLength) {
323     const int page = ((uintptr)addr - mainBuffer.memStart) >> mainBuffer.pageBits;
324 gbeauche 1.11 LOCK_VOSF;
325     PFLAG_SET(page);
326 gbeauche 1.27 vm_protect((char *)(addr & -mainBuffer.pageSize), mainBuffer.pageSize, VM_PAGE_READ | VM_PAGE_WRITE);
327 gbeauche 1.13 mainBuffer.dirty = true;
328 gbeauche 1.11 UNLOCK_VOSF;
329 gbeauche 1.16 return true;
330 gbeauche 1.1 }
331    
332 gbeauche 1.11 /* Otherwise, we don't know how to handle the fault, let it crash */
333 gbeauche 1.16 return false;
334 gbeauche 1.1 }
335    
336 gbeauche 1.20
337 gbeauche 1.1 /*
338     * Update display for Windowed mode and VOSF
339     */
340    
341 gbeauche 1.12 /* How can we deal with array overrun conditions ?
342    
343     The state of the framebuffer pages that have been touched are maintained
344     in the dirtyPages[] table. That table is (pageCount + 2) bytes long.
345    
346     Terminology
347    
348     "Last Page" denotes the pageCount-nth page, i.e. dirtyPages[pageCount - 1].
349     "CLEAR Page Guard" refers to the page following the Last Page but is always
350     in the CLEAR state. "SET Page Guard" refers to the page following the CLEAR
351     Page Guard but is always in the SET state.
352    
353     Rough process
354    
355 gbeauche 1.13 The update routines must determine which pages have to be blitted to the
356 gbeauche 1.12 screen. This job consists in finding the first_page that was touched.
357     i.e. find the next page that is SET. Then, finding how many pages were
358     touched starting from first_page. i.e. find the next page that is CLEAR.
359    
360 gbeauche 1.13 There are two cases to check:
361 gbeauche 1.12
362     - Last Page is CLEAR: find_next_page_set() will reach the SET Page Guard
363     but it is beyond the valid pageCount value. Therefore, we exit from the
364     update routine.
365    
366     - Last Page is SET: first_page equals (pageCount - 1) and
367     find_next_page_clear() will reach the CLEAR Page Guard. We blit the last
368     page to the screen. On the next iteration, page equals pageCount and
369     find_next_page_set() will reach the SET Page Guard. We still safely exit
370     from the update routine because the SET Page Guard position is greater
371     than pageCount.
372     */
373    
374 gbeauche 1.33 static inline void update_display_window_vosf(VIDEO_DRV_INIT)
375 gbeauche 1.1 {
376 gbeauche 1.33 VIDEO_MODE_INIT;
377 cebix 1.31
378 gbeauche 1.1 int page = 0;
379     for (;;) {
380 cebix 1.28 const unsigned first_page = find_next_page_set(page);
381 gbeauche 1.11 if (first_page >= mainBuffer.pageCount)
382 gbeauche 1.1 break;
383 gbeauche 1.11
384     page = find_next_page_clear(first_page);
385     PFLAG_CLEAR_RANGE(first_page, page);
386 cebix 1.7
387 gbeauche 1.1 // Make the dirty pages read-only again
388     const int32 offset = first_page << mainBuffer.pageBits;
389     const uint32 length = (page - first_page) << mainBuffer.pageBits;
390 gbeauche 1.17 vm_protect((char *)mainBuffer.memStart + offset, length, VM_PAGE_READ);
391 gbeauche 1.1
392     // There is at least one line to update
393     const int y1 = mainBuffer.pageInfo[first_page].top;
394     const int y2 = mainBuffer.pageInfo[page - 1].bottom;
395     const int height = y2 - y1 + 1;
396 gbeauche 1.38
397 gbeauche 1.49 // Update the_host_buffer
398 gbeauche 1.38 VIDEO_DRV_LOCK_PIXELS;
399 gbeauche 1.49 const int src_bytes_per_row = VIDEO_MODE_ROW_BYTES;
400     const int dst_bytes_per_row = VIDEO_DRV_ROW_BYTES;
401     int i1 = y1 * src_bytes_per_row, i2 = y1 * dst_bytes_per_row, j;
402     for (j = y1; j <= y2; j++) {
403     Screen_blit(the_host_buffer + i2, the_buffer + i1, src_bytes_per_row);
404     i1 += src_bytes_per_row;
405     i2 += dst_bytes_per_row;
406 gbeauche 1.1 }
407 gbeauche 1.38 VIDEO_DRV_UNLOCK_PIXELS;
408    
409     #ifdef USE_SDL_VIDEO
410     SDL_UpdateRect(drv->s, 0, y1, VIDEO_MODE_X, height);
411     #else
412 gbeauche 1.33 if (VIDEO_DRV_HAVE_SHM)
413     XShmPutImage(x_display, VIDEO_DRV_WINDOW, VIDEO_DRV_GC, VIDEO_DRV_IMAGE, 0, y1, 0, y1, VIDEO_MODE_X, height, 0);
414 gbeauche 1.1 else
415 gbeauche 1.33 XPutImage(x_display, VIDEO_DRV_WINDOW, VIDEO_DRV_GC, VIDEO_DRV_IMAGE, 0, y1, 0, y1, VIDEO_MODE_X, height);
416 gbeauche 1.38 #endif
417 gbeauche 1.1 }
418 gbeauche 1.13 mainBuffer.dirty = false;
419 gbeauche 1.1 }
420    
421    
422     /*
423     * Update display for DGA mode and VOSF
424 gbeauche 1.20 * (only in Real or Direct Addressing mode)
425 gbeauche 1.1 */
426    
427     #if REAL_ADDRESSING || DIRECT_ADDRESSING
428     static inline void update_display_dga_vosf(void)
429     {
430 gbeauche 1.33 VIDEO_MODE_INIT;
431 cebix 1.31
432 gbeauche 1.49 int i, j;
433 gbeauche 1.1 int page = 0;
434 gbeauche 1.49
435 gbeauche 1.1 for (;;) {
436 cebix 1.28 const unsigned first_page = find_next_page_set(page);
437 gbeauche 1.11 if (first_page >= mainBuffer.pageCount)
438 gbeauche 1.1 break;
439 gbeauche 1.11
440     page = find_next_page_clear(first_page);
441     PFLAG_CLEAR_RANGE(first_page, page);
442    
443 gbeauche 1.1 // Make the dirty pages read-only again
444     const int32 offset = first_page << mainBuffer.pageBits;
445     const uint32 length = (page - first_page) << mainBuffer.pageBits;
446 gbeauche 1.17 vm_protect((char *)mainBuffer.memStart + offset, length, VM_PAGE_READ);
447 gbeauche 1.1
448     // I am sure that y2 >= y1 and depth != 1
449     const int y1 = mainBuffer.pageInfo[first_page].top;
450     const int y2 = mainBuffer.pageInfo[page - 1].bottom;
451 gbeauche 1.49
452     // Check for first chunk from left and first chunk from right that have changed
453     typedef uint64 chunk_t;
454     const int chunk_size = sizeof(chunk_t);
455 gbeauche 1.33 const int bytes_per_row = VIDEO_MODE_ROW_BYTES;
456 gbeauche 1.49 assert((bytes_per_row % chunk_size) == 0);
457    
458     int b1 = bytes_per_row / chunk_size;
459 gbeauche 1.1 for (j = y1; j <= y2; j++) {
460 gbeauche 1.49 chunk_t * const p1 = (chunk_t *)(the_buffer + (j * bytes_per_row));
461     chunk_t * const p2 = (chunk_t *)(the_buffer_copy + (j * bytes_per_row));
462     for (i = 0; i < b1; i++) {
463 gbeauche 1.1 if (p1[i] != p2[i]) {
464 gbeauche 1.49 b1 = i;
465 gbeauche 1.1 break;
466     }
467     }
468     }
469 gbeauche 1.49
470     int b2 = b1;
471 gbeauche 1.1 for (j = y2; j >= y1; j--) {
472 gbeauche 1.49 chunk_t * const p1 = (chunk_t *)(the_buffer + (j * bytes_per_row));
473     chunk_t * const p2 = (chunk_t *)(the_buffer_copy + (j * bytes_per_row));
474     for (i = (bytes_per_row / chunk_size) - 1; i > b2; i--) {
475 gbeauche 1.1 if (p1[i] != p2[i]) {
476 gbeauche 1.49 b2 = i;
477 gbeauche 1.1 break;
478     }
479     }
480     }
481 gbeauche 1.49 b2++;
482    
483     // Convert to pixel information
484     int x1, x2;
485     switch (VIDEO_MODE_DEPTH) {
486     case VIDEO_DEPTH_1BIT: x1 = (b1 * chunk_size) << 3; x2 = (b2 * chunk_size) << 3; break;
487     case VIDEO_DEPTH_2BIT: x1 = (b1 * chunk_size) << 2; x2 = (b2 * chunk_size) << 2; break;
488     case VIDEO_DEPTH_4BIT: x1 = (b1 * chunk_size) << 1; x2 = (b2 * chunk_size) << 1; break;
489     case VIDEO_DEPTH_8BIT: x1 = b1 * chunk_size; x2 = b2 * chunk_size; break;
490     case VIDEO_DEPTH_16BIT: x1 = (b1 * chunk_size) >> 1; x2 = (b2 * chunk_size) >> 1; break;
491     case VIDEO_DEPTH_32BIT: x1 = (b1 * chunk_size) >> 2; x2 = (b2 * chunk_size) >> 2; break;
492     }
493     const int width = x2 - x1;
494    
495     // Normalize bounds for for the next blit
496     const int src_bytes_per_row = VIDEO_MODE_ROW_BYTES;
497     const int dst_bytes_per_row = the_host_buffer_row_bytes;
498     const int dst_bytes_per_pixel = dst_bytes_per_row / VIDEO_MODE_X;
499     int i2 = y1 * dst_bytes_per_row + x1 * dst_bytes_per_pixel;
500     int i1, n_bytes;
501     if ((int)VIDEO_MODE_DEPTH < VIDEO_DEPTH_8BIT) {
502     const int src_pixels_per_byte = VIDEO_MODE_X / src_bytes_per_row;
503     i1 = y1 * src_bytes_per_row + x1 / src_pixels_per_byte;
504     n_bytes = width / src_pixels_per_byte;
505     } else {
506     const int src_bytes_per_pixel = src_bytes_per_row / VIDEO_MODE_X;
507     i1 = y1 * src_bytes_per_row + x1 * src_bytes_per_pixel;
508     n_bytes = width * src_bytes_per_pixel;
509     }
510    
511 gbeauche 1.1 // Update the_host_buffer and copy of the_buffer
512 gbeauche 1.38 VIDEO_DRV_LOCK_PIXELS;
513 gbeauche 1.1 for (j = y1; j <= y2; j++) {
514 gbeauche 1.49 Screen_blit(the_host_buffer + i2, the_buffer + i1, n_bytes);
515     memcpy(the_buffer_copy + i1, the_buffer + i1, n_bytes);
516     i1 += src_bytes_per_row;
517     i2 += dst_bytes_per_row;
518 gbeauche 1.1 }
519 gbeauche 1.38 VIDEO_DRV_UNLOCK_PIXELS;
520 gbeauche 1.1 }
521 gbeauche 1.13 mainBuffer.dirty = false;
522 gbeauche 1.1 }
523     #endif
524    
525     #endif /* ENABLE_VOSF */
526    
527     #endif /* VIDEO_VOSF_H */