comparison libvo/vo_vesa.c @ 2244:4e464b527f5a

vo_vesa support
author nick
date Wed, 17 Oct 2001 18:24:50 +0000
parents
children 98c2bfc87825
comparison
equal deleted inserted replaced
2243:f4b588dba08a 2244:4e464b527f5a
1 /*
2 * video_out_vesa.c
3 *
4 * Copyright (C) Nick Kurshev <nickols_k@mail.ru> - Oct 2001
5 *
6 * You can redistribute this file under terms and conditions
7 * GNU General Public licence v2.
8 * This file is partly based on vbetest.c from lrmi distributive.
9 */
10
11 /*
12 TODO:
13 - DGA support (need volunteers who have corresponding hardware)
14 - hw YUV support (need volunteers who have corresponding hardware)
15 - double (triple) buffering (if it will really speedup playback).
16 - refresh rate support (need additional info from mplayer)
17 */
18 #include <stdio.h>
19 #include <string.h>
20 #include <stddef.h>
21 #include <limits.h>
22
23 #include "config.h"
24 #include "video_out.h"
25 #include "video_out_internal.h"
26
27 #include "fastmemcpy.h"
28 #include "yuv2rgb.h"
29
30 #include "linux/lrmi.h"
31 #include "linux/vbelib.h"
32 #include "bswap.h"
33
34 LIBVO_EXTERN(vesa)
35 extern int verbose;
36
37 #ifndef max
38 #define max(a,b) ((a)>(b)?(a):(b))
39 #endif
40 #ifndef min
41 #define min(a,b) ((a)<(b)?(a):(b))
42 #endif
43
44
45 static vo_info_t vo_info =
46 {
47 "VESA VBE 2.0 video output",
48 "vesa",
49 "Nick Kurshev <nickols_k@mail.ru>",
50 "Requires ROOT privileges"
51 };
52
53 /* driver data */
54
55 /*
56 TODO: for linear framebuffer mode:
57 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
58 win.ptr = linear address of frame buffer;
59 win.low = 0;
60 win.high = vide_memory_size;
61 */
62 struct win_frame
63 {
64 uint8_t *ptr; /* pointer to window's frame memory */
65 uint32_t low; /* lowest boundary of frame */
66 uint32_t high; /* highest boundary of frame */
67 uint8_t idx; /* indicates index of relocatable frame (A or B) */
68 };
69
70 static uint32_t image_width, image_height; /* source image dimension */
71 static uint32_t x_offset,y_offset; /* to center image on screen */
72 static unsigned init_mode; /* mode before run of mplayer */
73 static void *init_state = NULL; /* state before run of mplayer */
74 static struct win_frame win; /* real-mode window to video memory */
75 static void *temp_buffer = NULL; /* for yuv2rgb and sw_scaling */
76 static unsigned video_mode; /* selected video mode for playback */
77 static struct VesaModeInfoBlock video_mode_info;
78
79 #define MOVIE_MODE (MODE_ATTR_COLOR | MODE_ATTR_GRAPHICS)
80 #define FRAME_MODE (MODE_WIN_RELOCATABLE | MODE_WIN_READABLE | MODE_WIN_WRITEABLE)
81 static char * vbeErrToStr(int err)
82 {
83 char *retval;
84 static char sbuff[80];
85 if((err & VBE_VESA_ERROR_MASK) == VBE_VESA_ERROR_MASK)
86 {
87 sprintf(sbuff,"VESA failed = 0x4f%x",err & VBE_VESA_ERRCODE_MASK);
88 retval = sbuff;
89 }
90 else
91 switch(err)
92 {
93 case VBE_OK: retval = "No error"; break;
94 case VBE_VM86_FAIL: retval = "vm86() syscall failed"; break;
95 case VBE_OUT_OF_DOS_MEM: retval = "Out of DOS memory"; break;
96 case VBE_OUT_OF_MEM: retval = "Out of memory"; break;
97 default: sprintf(sbuff,"Uknown error: %i",err); retval=sbuff; break;
98 }
99 return retval;
100 }
101
102 #define PRINT_VBE_ERR(name,err) { printf("vo_vesa: %s returns: %s\n",name,vbeErrToStr(err)); fflush(stdout); }
103
104 static void vesa_term( void )
105 {
106 int err;
107 #if 0
108 if((err=vbeRestoreState(init_state)) != VBE_OK) PRINT_VBE_ERR("vbeRestoreState",err);
109 #endif
110 if((err=vbeSetMode(init_mode,NULL)) != VBE_OK) PRINT_VBE_ERR("vbeSetMode",err);
111 free(temp_buffer);
112 vbeDestroy();
113 }
114
115 #define VALID_WIN_FRAME(offset) (offset >= win.low && offset < win.high)
116 #define VIDEO_PTR(offset) (win.ptr + offset - win.low)
117
118 static inline void __vbeSwitchBank(unsigned long offset)
119 {
120 unsigned long gran;
121 unsigned new_offset;
122 int err;
123 gran = video_mode_info.WinGranularity*1024;
124 new_offset = offset / gran;
125 if((err=vbeSetWindow(win.idx,new_offset)) != VBE_OK)
126 {
127 PRINT_VBE_ERR("vbeSetWindow",err);
128 printf("vo_vesa: Fatal error occured! Can't continue\n");
129 vesa_term();
130 exit(-1);
131 }
132 win.low = new_offset * gran;
133 win.high = win.low + video_mode_info.WinSize*1024;
134 }
135
136 static void __vbeSetPixel(int x, int y, int r, int g, int b)
137 {
138 int x_res = video_mode_info.XResolution;
139 int y_res = video_mode_info.YResolution;
140 int shift_r = video_mode_info.RedFieldPosition;
141 int shift_g = video_mode_info.GreenFieldPosition;
142 int shift_b = video_mode_info.BlueFieldPosition;
143 int pixel_size = (video_mode_info.BitsPerPixel+7)/8;
144 int bpl = video_mode_info.BytesPerScanLine;
145 int color, offset;
146
147 if (x < 0 || x >= x_res || y < 0 || y >= y_res) return;
148 r >>= 8 - video_mode_info.RedMaskSize;
149 g >>= 8 - video_mode_info.GreenMaskSize;
150 b >>= 8 - video_mode_info.BlueMaskSize;
151 color = (r << shift_r) | (g << shift_g) | (b << shift_b);
152 offset = y * bpl + (x * pixel_size);
153 if(!VALID_WIN_FRAME(offset)) __vbeSwitchBank(offset);
154 memcpy(VIDEO_PTR(offset), &color, pixel_size);
155 }
156
157 /*
158 Copies line of frame to video memory. Data should be in the same format as video
159 memory.
160 */
161 static void __vbeCopyBlock(unsigned long offset,uint8_t *image,unsigned long size)
162 {
163 unsigned long delta,src_idx = 0;
164 while(size)
165 {
166 if(!VALID_WIN_FRAME(offset)) __vbeSwitchBank(offset);
167 delta = min(size,win.high - offset);
168 memcpy(VIDEO_PTR(offset),&image[src_idx],delta);
169 src_idx += delta;
170 offset += delta;
171 size -= delta;
172 }
173 }
174
175 static void __vbeCopyBlockSwap(unsigned long offset,uint8_t *image,unsigned long size)
176 {
177 unsigned byte_len;
178 uint8_t ch;
179 while(size)
180 {
181 switch(video_mode_info.BitsPerPixel)
182 {
183 case 8: byte_len = 1; break;
184 default:
185 case 15:
186 printf("vo_vesa: Can't swap non byte aligned data\n");
187 vesa_term();
188 exit(-1);
189 case 16: *(image + offset) = ByteSwap16(*(image + offset));
190 byte_len = 2; break;
191 case 24: ch = *(image+offset);
192 *(image+offset) = *(image+offset+3);
193 *(image+offset+3) = ch;
194 byte_len = 3; break;
195 case 32: *(image + offset) = ByteSwap32(*(image + offset));
196 byte_len = 4; break;
197 }
198 __vbeCopyBlock(offset,image,byte_len);
199 size -= byte_len;
200 image += byte_len;
201 offset += byte_len;
202 }
203 }
204
205 /*
206 Copies frame to video memory. Data should be in the same format as video
207 memory.
208 */
209 static void __vbeCopyData(uint8_t *image)
210 {
211 unsigned long i,image_offset,offset;
212 unsigned pixel_size,image_line_size,screen_line_size,x_shift;
213 pixel_size = (video_mode_info.BitsPerPixel+7)/8;
214 screen_line_size = video_mode_info.XResolution*pixel_size;
215 image_line_size = image_width*pixel_size;
216 x_shift = x_offset*pixel_size;
217 for(i=y_offset;i<image_height;i++)
218 {
219 offset = i*screen_line_size+x_shift;
220 image_offset = i*image_line_size;
221 __vbeCopyBlock(offset,&image[image_offset],image_line_size);
222 }
223 }
224 /* is called for yuv only */
225 static uint32_t draw_slice(uint8_t *image[], int stride[], int w,int h,int x,int y)
226 {
227 yuv2rgb(temp_buffer, image[0], image[1], image[2], w, h, image_width * ((video_mode_info.BitsPerPixel+7)/8),
228 stride[0], stride[1]);
229 __vbeCopyData((uint8_t *)temp_buffer);
230 return 0;
231 }
232
233 static void draw_osd(void)
234 {
235 /* nothing to do for now */
236 }
237
238 static void flip_page(void)
239 {
240 /*Is not required*/
241 }
242
243 /* is called for rgb only */
244 static uint32_t draw_frame(uint8_t *src[])
245 {
246 __vbeCopyData(src[0]);
247 return 0;
248 }
249
250 static uint32_t query_format(uint32_t format)
251 {
252 uint32_t retval;
253 switch(format)
254 {
255 #if 0
256 case IMGFMT_YV12:
257 case IMGFMT_I420:
258 case IMGFMT_IYUV:
259 #endif
260 case IMGFMT_RGB8:
261 case IMGFMT_RGB15:
262 case IMGFMT_RGB16:
263 case IMGFMT_RGB24:
264 case IMGFMT_RGB32:
265 case IMGFMT_BGR8:
266 case IMGFMT_BGR15:
267 case IMGFMT_BGR16:
268 case IMGFMT_BGR24:
269 case IMGFMT_BGR32:
270 retval = 1; break;
271 default:
272 if(verbose)
273 printf("vo_vesa: unknown format: %x = %s\n",format,vo_format_name(format));
274 retval = 0;
275 }
276 return retval;
277 }
278
279 /* fullscreen:
280 * bit 0 (0x01) means fullscreen (-fs)
281 * bit 1 (0x02) means mode switching (-vm)
282 * bit 2 (0x04) enables software scaling (-zoom)
283 * bit 3 (0x08) enables flipping (-flip)
284 */
285 static uint32_t
286 init(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t fullscreen, char *title, uint32_t format)
287 {
288 struct VbeInfoBlock vib;
289 struct VesaModeInfoBlock vmib;
290 size_t i,num_modes;
291 unsigned short *mode_ptr,win_seg;
292 unsigned bpp,best_x = UINT_MAX,best_y=UINT_MAX,best_mode_idx = UINT_MAX;
293 int err;
294 image_width = width;
295 image_height = height;
296 if(fullscreen & (0x1|0x4|0x8))
297 {
298 printf("vo_vesa: switches: -fs, -zoom, -flip are not supported\n");
299 }
300 if(!(temp_buffer = malloc(width*height*4)))
301 {
302 printf("vo_vesa: Can't allocate temporary buffer\n");
303 return -1;
304 }
305 if((err=vbeInit()) != VBE_OK) { PRINT_VBE_ERR("vbeInit",err); return -1; }
306 memcpy(vib.VESASignature,"VBE2",4);
307 if((err=vbeGetControllerInfo(&vib)) != VBE_OK)
308 {
309 PRINT_VBE_ERR("vbeGetControllerInfo",err);
310 printf("vo_vesa: possible reason: No VBE2 BIOS found\n");
311 return -1;
312 }
313 /* Print general info here */
314 printf("vo_vesa: Found VESA VBE BIOS Version %x.%x Revision: %x\n",
315 (int)(vib.VESAVersion >> 8) & 0xff,
316 (int)(vib.VESAVersion & 0xff),
317 (int)(vib.OemSoftwareRev & 0xffff));
318 printf("vo_vesa: OEM info: %s\n",vib.OemStringPtr);
319 printf("vo_vesa: Video memory: %u Kb\n",vib.TotalMemory*64);
320 /* Find best mode here */
321 num_modes = 0;
322 mode_ptr = vib.VideoModePtr;
323 while(*mode_ptr++ != 0xffff) num_modes++;
324 switch(format)
325 {
326 case IMGFMT_BGR8:
327 case IMGFMT_RGB8: bpp = 8; break;
328 case IMGFMT_BGR15:
329 case IMGFMT_RGB15: bpp = 15; break;
330 case IMGFMT_YV12:
331 case IMGFMT_I420:
332 case IMGFMT_IYUV:
333 yuv2rgb_init(video_mode_info.BitsPerPixel, MODE_RGB);
334 default:
335 case IMGFMT_BGR16:
336 case IMGFMT_RGB16: bpp = 16; break;
337 case IMGFMT_BGR24:
338 case IMGFMT_RGB24: bpp = 24; break;
339 case IMGFMT_BGR32:
340 case IMGFMT_RGB32: bpp = 32; break;
341 }
342 if(verbose)
343 {
344 printf("vo_vesa: Requested mode: %ux%u@%x bpp=%u\n",width,height,format,bpp);
345 printf("vo_vesa: Total modes found: %u\n",num_modes);
346 mode_ptr = vib.VideoModePtr;
347 printf("vo_vesa: Mode list:");
348 for(i = 0;i < num_modes;i++)
349 {
350 printf(" %04X",mode_ptr[i]);
351 }
352 printf("\nvo_vesa: Modes in detail:\n");
353 }
354 mode_ptr = vib.VideoModePtr;
355 for(i=0;i < num_modes;i++)
356 {
357 if((err=vbeGetModeInfo(mode_ptr[i],&vmib)) != VBE_OK)
358 {
359 PRINT_VBE_ERR("vbeGetModeInfo",err);
360 return -1;
361 }
362 if(vmib.XResolution > image_width &&
363 vmib.YResolution > image_height &&
364 (vmib.ModeAttributes & MOVIE_MODE) == MOVIE_MODE &&
365 vmib.BitsPerPixel == bpp &&
366 vmib.MemoryModel == memRGB)
367 {
368 if(vmib.XResolution < best_x &&
369 vmib.YResolution < best_y)
370 {
371 best_x = vmib.XResolution;
372 best_y = vmib.YResolution;
373 best_mode_idx = i;
374 }
375 }
376 if(verbose)
377 {
378 printf("vo_vesa: Mode (%03u): mode=%04X %ux%u@%u attr=%u\n"
379 "vo_vesa: #planes=%u model=%u #pages=%u\n"
380 "vo_vesa: winA=%X(attr=%u) winB=%X(attr=%u) winSize=%u winGran=%u\n"
381 "vo_vesa: direct_color=%u DGA_phys_addr=%08X\n"
382 ,i,mode_ptr[i],vmib.XResolution,vmib.YResolution,vmib.BitsPerPixel,vmib.ModeAttributes
383 ,vmib.NumberOfPlanes,vmib.MemoryModel,vmib.NumberOfImagePages
384 ,vmib.WinASegment,vmib.WinAAttributes,vmib.WinBSegment,vmib.WinBAttributes,vmib.WinSize,vmib.WinGranularity
385 ,vmib.DirectColorModeInfo,vmib.PhysBasePtr);
386 if(vmib.MemoryModel == 6 || vmib.MemoryModel == 7)
387 printf("vo_vesa: direct_color_info = %u:%u:%u:%u\n"
388 ,vmib.RedMaskSize,vmib.GreenMaskSize,vmib.BlueMaskSize,vmib.RsvdMaskSize);
389 fflush(stdout);
390 }
391 }
392 if(best_mode_idx != UINT_MAX)
393 {
394 video_mode = vib.VideoModePtr[best_mode_idx];
395 printf("vo_vesa: Using VESA mode (%u) = %x\n",best_mode_idx,video_mode);
396 fflush(stdout);
397 if((err=vbeGetMode(&init_mode)) != VBE_OK)
398 {
399 PRINT_VBE_ERR("vbeGetMode",err);
400 return -1;
401 }
402 if(verbose) printf("vo_vesa: Initial video mode: %x\n",init_mode);
403 if((err=vbeGetModeInfo(video_mode,&video_mode_info)) != VBE_OK)
404 {
405 PRINT_VBE_ERR("vbeGetModeInfo",err);
406 return -1;
407 }
408 if((video_mode_info.WinAAttributes & FRAME_MODE) == FRAME_MODE)
409 win.idx = 0; /* frame A */
410 else
411 if((video_mode_info.WinBAttributes & FRAME_MODE) == FRAME_MODE)
412 win.idx = 1; /* frame B */
413 else { printf("vo_vesa: Can't find usable frame of window\n"); return -1; }
414 if(!(win_seg = win.idx == 0 ? video_mode_info.WinASegment:video_mode_info.WinBSegment))
415 {
416 printf("vo_vesa: Can't find valid window address\n");
417 if(video_mode_info.ModeAttributes & MODE_ATTR_LINEAR)
418 printf("vo_vesa: Your BIOS supports DGA access which is not implemented for now\n");
419 return -1;
420 }
421 win.ptr = PhysToVirtSO(win_seg,0);
422 win.low = 0L;
423 win.high= video_mode_info.WinSize*1024;
424 x_offset = (video_mode_info.XResolution - image_width) / 2;
425 y_offset = (video_mode_info.YResolution - image_height) / 2;
426 #if 0
427 if((err=vbeSaveState(&init_state)) != VBE_OK)
428 {
429 PRINT_VBE_ERR("vbeSaveState",err);
430 return -1;
431 }
432 #endif
433 if((err=vbeSetMode(video_mode,NULL)) != VBE_OK)
434 {
435 PRINT_VBE_ERR("vbeSetMode",err);
436 return -1;
437 }
438 /* Now we are in video mode!!!*/
439 if(verbose)
440 {
441 printf("vo_vesa: Graphics mode was activated\n");
442 fflush(stdout);
443 }
444 }
445 else
446 {
447 printf("vo_vesa: Can't find mode for: %ux%u@%x\n",width,height,format);
448 return -1;
449 }
450 if(verbose)
451 {
452 printf("vo_vesa: VESA initialization complete\n");
453 fflush(stdout);
454 }
455 if(verbose)
456 {
457 int x_res = video_mode_info.XResolution;
458 int y_res = video_mode_info.YResolution;
459 int x, y;
460
461 for (y = 0; y < y_res; ++y)
462 {
463 for (x = 0; x < x_res; ++x)
464 {
465 int r, g, b;
466 if ((x & 16) ^ (y & 16))
467 {
468 r = x * 255 / x_res;
469 g = y * 255 / y_res;
470 b = 255 - x * 255 / x_res;
471 }
472 else
473 {
474 r = 255 - x * 255 / x_res;
475 g = y * 255 / y_res;
476 b = 255 - y * 255 / y_res;
477 }
478
479 __vbeSetPixel(x, y, r, g, b);
480 }
481 }
482 }
483 return 0;
484 }
485
486 static const vo_info_t*
487 get_info(void)
488 {
489 return &vo_info;
490 }
491
492 static void
493 uninit(void)
494 {
495 vesa_term();
496 }
497
498
499 static void check_events(void)
500 {
501 /* Nothing to do */
502 }