00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "Core/precomp.h"
00020 #include <Display/Display/FBDev/blit_mga.h>
00021 #include <Display/Display/Generic/blitters.h>
00022 #include <Display/Display/Generic/colormap.h>
00023 #include <Display/Display/Generic/displaycard_generic.h>
00024 #include <API/Core/System/error.h>
00025 #include <Display/Display/FBDev/display_fbdev.h>
00026 #include <API/Display/Display/palette.h>
00027 #include <API/Display/Display/surfaceprovider.h>
00028 #include <Display/Display/FBDev/target_fbdev.h>
00029 #include <API/Display/Display/vidmode.h>
00030 #include <API/Display/Display/mousecursor.h>
00031 #include "Core/System/Unix/appconf.h"
00032
00033 #include <stdlib.h>
00034 #include <stdio.h>
00035 #include <string.h>
00036 #include <iostream>
00037
00038 #include <linux/fb.h>
00039 #include <unistd.h>
00040 #include <fcntl.h>
00041 #include <sys/ioctl.h>
00042 #include <sys/mman.h>
00043
00044
00045 #include <math.h>
00046
00047
00048 #include "regs.h"
00049 #include "mmio.h"
00050
00051 CL_FBDev_DisplayCard::CL_FBDev_DisplayCard(int card_no) : CL_DisplayCard_Generic(card_no)
00052 {
00053 FileConfig config("clanlib");
00054 fb_try_accel = config.readEntry("fb_try_accel", "yes");
00055
00056 m_initialized = false;
00057 m_mmioaddr = NULL;
00058
00059 m_palette = new CL_Palette();
00060
00061 m_target = NULL;
00062 fb_mem = NULL;
00063
00064 fd = open("/dev/fb0", O_RDWR);
00065 if (fd<0)
00066 {
00067 throw CL_Error("FB dev: Couldn't open /dev/fb0, you must have read-write access!");
00068 }
00069 }
00070
00071 CL_FBDev_DisplayCard::~CL_FBDev_DisplayCard()
00072 {
00073 CL_MouseCursor::hide();
00074 if (m_initialized)
00075 {
00076
00077 memset((void*)fb_mem,0,fb_fix.smem_len);
00078
00079 delete m_target;
00080 ioctl(fd,FBIOPUT_VSCREENINFO,&fb_var_orig);
00081 }
00082
00083 close(fd);
00084
00085 delete m_palette;
00086 }
00087
00088 CL_Blitters CL_FBDev_DisplayCard::create_hw_blitters(CL_SurfaceProvider *provider)
00089 {
00090 CL_Blitters ret;
00091
00092 if (m_mmioaddr)
00093 {
00094 CL_Blit_MGA *blitter = new CL_Blit_MGA(this, provider, m_mmioaddr);
00095 if (! blitter->init_surface(&ret) )
00096 {
00097 delete blitter;
00098 }
00099 }
00100
00101 return ret;
00102 }
00103
00104 void CL_FBDev_DisplayCard::flip_display(bool sync)
00105 {
00106 cl_assert(m_initialized);
00107
00108 signal_preflip();
00109
00110 m_target->put_image();
00111
00112 if (doublebuffer)
00113 {
00114 fb_var.yoffset = yoffset;
00115 yoffset = (yoffset == get_height()) ? 0 : get_height();
00116
00117 if (m_mmioaddr)
00118 {
00119 mga_waitidle(m_mmioaddr);
00120 }
00121
00122 ioctl( fd, FBIOPAN_DISPLAY, &fb_var);
00123
00124 set_card_clip();
00125 }
00126
00127 signal_postflip();
00128 }
00129
00130 void CL_FBDev_DisplayCard::put_display(const class CL_Rect &rect)
00131 {
00132 cl_assert(m_initialized);
00133
00134 signal_preflip();
00135
00136
00137
00138 cl_assert(false);
00139
00140 signal_postflip();
00141 }
00142
00143 void CL_FBDev_DisplayCard::set_palette(CL_Palette *pal)
00144 {
00145 m_palette = new CL_Palette(pal->palette);
00146 }
00147
00148 CL_Palette *CL_FBDev_DisplayCard::get_palette()
00149 {
00150 return m_palette;
00151 }
00152
00153 void CL_FBDev_DisplayCard::set_videomode(
00154 int width,
00155 int height,
00156 int bpp,
00157 bool fullscreen,
00158 bool allow_resize,
00159 bool video_memory)
00160 {
00161 if (m_initialized)
00162 {
00163 delete m_target; m_target = NULL;
00164 }
00165
00166 set_gfxmode(width, height, bpp, fullscreen, allow_resize);
00167
00168
00169 ioctl( fd, FBIOGET_VSCREENINFO, &fb_var_orig );
00170 ioctl( fd, FBIOGET_FSCREENINFO, &fb_fix );
00171 fb_var = fb_var_orig;
00172
00173
00174
00175 fb_var.activate = FB_ACTIVATE_NOW;
00176 fb_var.accel_flags = 0;
00177 fb_var.xres = get_width();
00178 fb_var.yres = get_height();
00179 fb_var.xres_virtual = get_width();
00180 fb_var.yres_virtual = get_height()*2;
00181 fb_var.bits_per_pixel = bpp;
00182 if (-1 == ioctl(fd,FBIOPUT_VSCREENINFO,&fb_var))
00183 {
00184 doublebuffer = false;
00185 fb_var.yres_virtual = get_height();
00186 if (-1 == ioctl(fd,FBIOPUT_VSCREENINFO,&fb_var))
00187 {
00188
00189 fb_var = fb_var_orig;
00190
00191
00192 if ((int)fb_var.xres < get_width() || (int)fb_var.yres < get_height() || (int)fb_var.bits_per_pixel != bpp)
00193 {
00194 char s[80];
00195 printf( s, "FBDev: Couldn't set proper video mode, need %dx%dx%d!", get_width(), get_height(), bpp );
00196 throw CL_Error( s );
00197 }
00198 }
00199 } else
00200 {
00201 doublebuffer = true;
00202 std::cout << "Using doublebuffer mode (panning)." << std::endl;
00203 yoffset = get_height();
00204 }
00205
00206
00207 fb_var.xoffset = 0;
00208 fb_var.yoffset = 0;
00209 ioctl(fd,FBIOPAN_DISPLAY,&fb_var);
00210
00211
00212 if ( MAP_FAILED == (fb_mem = (unsigned char *) mmap( NULL,
00213 fb_fix.smem_len,
00214 PROT_READ | PROT_WRITE,
00215 MAP_SHARED,
00216 fd, 0 )) )
00217 {
00218 throw CL_Error("FB dev: Couldn't mmap framebuffer");
00219 }
00220
00221
00222 if ( fb_try_accel == "yes" && fb_var.accel_flags == 0 )
00223 {
00224 m_mmioaddr = (unsigned char *) mmap(NULL, fb_fix.mmio_len,
00225 PROT_READ | PROT_WRITE, MAP_SHARED,
00226 fd, fb_fix.smem_len);
00227
00228 if (m_mmioaddr == MAP_FAILED || m_mmioaddr == NULL)
00229 {
00230 std::cout << "No acceleration available." << std::endl;
00231 m_mmioaddr = NULL;
00232 }
00233 else
00234 {
00235 std::cout << "Yeah, using acceleration!" << std::endl;
00236 switch( fb_fix.accel )
00237 {
00238 #ifdef FB_ACCEL_MATROX_MGAG400
00239 case FB_ACCEL_MATROX_MGAG400:
00240 #endif
00241 case FB_ACCEL_MATROX_MGAG200:
00242 m_accel_alpha_rect = true;
00243 m_accel_scale_blit = true;
00244 std::cout << "Using accelerated alpha rectangles." << std::endl;
00245 std::cout << "Using accelerated scaled blits." << std::endl;
00246 break;
00247 default:
00248 m_accel_alpha_rect = false;
00249 m_accel_scale_blit = false;
00250 break;
00251 }
00252 }
00253 } else
00254 {
00255 std::cout << "Not trying to use acceleration." << std::endl;
00256 }
00257
00258
00259 memset((void*)fb_mem,0,fb_fix.smem_len);
00260
00261 m_target = new CL_Target_FBDev( doublebuffer, (char*)fb_mem, get_width(), get_height(), &fb_var, m_mmioaddr );
00262
00263 m_initialized = true;
00264 }
00265
00266 unsigned int CL_FBDev_DisplayCard::get_virt_width()
00267 {
00268 return fb_var.xres_virtual;
00269 }
00270
00271 unsigned char* CL_FBDev_DisplayCard::get_offscreen_mem()
00272 {
00273 if (!m_mmioaddr)
00274 {
00275 return NULL;
00276 }
00277
00278 return fb_mem + m_target->get_pitch()*get_height()*2;
00279 }
00280
00281 bool CL_FBDev_DisplayCard::is_initialized()
00282 {
00283 return m_initialized;
00284 }
00285
00286 const std::list<CL_VidMode*> &CL_FBDev_DisplayCard::get_videomodes()
00287 {
00288 cl_assert(false);
00289 static std::list<CL_VidMode*> ret;
00290 return ret;
00291 }
00292
00293 void CL_FBDev_DisplayCard::draw_rect(
00294 int x1,
00295 int y1,
00296 int x2,
00297 int y2,
00298 float r,
00299 float g,
00300 float b,
00301 float a)
00302 {
00303 throw CL_Error("draw_rect not implemented in fbdev, please tell us to do that");
00304 }
00305
00306 void CL_FBDev_DisplayCard::fill_rect(
00307 int x1,
00308 int y1,
00309 int x2,
00310 int y2,
00311 float r,
00312 float g,
00313 float b,
00314 float a)
00315 {
00316 if (a <= 0.01) return;
00317 if (!m_mmioaddr)
00318 {
00319 CL_DisplayCard_Generic::fill_rect(x1, y1, x2, y2, r, g, b, a);
00320 return;
00321 }
00322 if (a <= 0.99 && !m_accel_alpha_rect)
00323 {
00324 CL_DisplayCard_Generic::fill_rect(x1, y1, x2, y2, r, g, b, a);
00325 return;
00326 }
00327
00328
00329 int trans_x = get_translate_offset_x();
00330 int trans_y = get_translate_offset_y();
00331 x1 += trans_x;
00332 y1 += trans_y;
00333 x2 += trans_x;
00334 y2 += trans_y;
00335
00336 int y = y1 + yoffset;
00337 int h = y2 - y1;
00338
00339 if (a <= 0.99)
00340 {
00341
00342
00343 mga_waitfifo( m_mmioaddr, 3 );
00344 mga_out32( m_mmioaddr, SRC_ALPHA | DST_ONE_MINUS_SRC_ALPHA | ALPHACHANNEL, ALPHACTRL );
00345 mga_out32( m_mmioaddr, 0, ALPHAXINC );
00346 mga_out32( m_mmioaddr, 0, ALPHAYINC );
00347
00348 mga_waitfifo( m_mmioaddr, 3 );
00349 mga_out32( m_mmioaddr, FNORM_TO_F0915(r), DR4 );
00350 mga_out32( m_mmioaddr, 0, DR6 );
00351 mga_out32( m_mmioaddr, 0, DR7 );
00352
00353 mga_waitfifo( m_mmioaddr, 3 );
00354 mga_out32( m_mmioaddr, FNORM_TO_F0915(g), DR8 );
00355 mga_out32( m_mmioaddr, 0, DR10 );
00356 mga_out32( m_mmioaddr, 0, DR11 );
00357
00358 mga_waitfifo( m_mmioaddr, 3 );
00359 mga_out32( m_mmioaddr, FNORM_TO_F0915(b), DR12 );
00360 mga_out32( m_mmioaddr, 0, DR14 );
00361 mga_out32( m_mmioaddr, 0, DR15 );
00362
00363 mga_waitfifo( m_mmioaddr, 5 );
00364 mga_out32( m_mmioaddr, BLTMOD_BFCOL | BOP_COPY | SHFTZERO | SGNZERO | ARZERO | OP_TRAP | ATYPE_I, DWGCTL );
00365 mga_out32( m_mmioaddr, FNORM_TO_F0915(a), ALPHASTART );
00366 mga_out32( m_mmioaddr, (x2 << 16) | x1, FXBNDRY );
00367 mga_out32( m_mmioaddr, (y << 16) | h, YDSTLEN | EXECUTE );
00368
00369 mga_out32( m_mmioaddr, 1, ALPHACTRL );
00370 } else
00371 {
00372
00373
00374 CL_ColorMap cmap(get_target());
00375 unsigned int fill_color = cmap.calc_color(r, g, b, a);
00376
00377 switch( fb_var.bits_per_pixel )
00378 {
00379 case 8:
00380 fill_color &= 0xFF;
00381 fill_color |= (fill_color<<8) | (fill_color<<16) | (fill_color<<24);
00382 break;
00383 case 16:
00384 fill_color &= 0xFFFF;
00385 fill_color |= (fill_color<<16);
00386 break;
00387 }
00388
00389 mga_waitfifo( m_mmioaddr, 4 );
00390 mga_out32( m_mmioaddr, fill_color, FCOL );
00391 mga_out32( m_mmioaddr, (x2 << 16) | x1, FXBNDRY );
00392 mga_out32( m_mmioaddr, (y << 16) | h, YDSTLEN );
00393 mga_out32( m_mmioaddr, BOP_COPY | SHFTZERO | SGNZERO | ARZERO | SOLID | OP_TRAP | ATYPE_BLK, DWGCTL | EXECUTE );
00394 }
00395 }
00396
00397 void CL_FBDev_DisplayCard::set_card_clip()
00398 {
00399 if (!m_mmioaddr)
00400 return;
00401
00402 int topy = m_cur_clip.m_y1 + yoffset;
00403 int boty = (m_cur_clip.m_y2-1) + yoffset;
00404
00405 mga_waitfifo(m_mmioaddr, 3);
00406 mga_out32(m_mmioaddr, (m_cur_clip.m_x1 & 0x07FF) | (((m_cur_clip.m_x2-1) & 0x07FF) << 16), CXBNDRY);
00407 mga_out32(m_mmioaddr, (fb_var.xres_virtual * topy) & 0x00FFFFFF, YTOP);
00408 mga_out32(m_mmioaddr, (fb_var.xres_virtual * boty) & 0x00FFFFFF, YBOT);
00409 }