ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/video_vosf.h
Revision: 1.52
Committed: 2005-05-12T14:39:56Z (19 years, 1 month ago) by gbeauche
Content type: text/plain
Branch: MAIN
Changes since 1.51: +14 -8 lines
Log Message:
Fix SDL/DGA build. Drop useless "inline" for updates. Overlapping scanlines
optimization.

File Contents

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