Exemple #1
0
void I_InitGraphics(void)
{
  const char*	displayname = NULL;
  int		n;
  int		pnum;
  int		x=0;
  int		y=0;
  
  {  
    static int		firsttime=1;
    
    if (!firsttime) {
      return;
    }
    firsttime = 0;
  }

  { // Check for screen enlargement
    char str[3] = { '-', 0, 0 };

    for (n=1; n<4; n++) {
      str[1] = n + '0';
      if (M_CheckParm(str)) multiply = n;
    }
  }
  
  X_width = SCREENWIDTH * multiply;
  X_height = SCREENHEIGHT * multiply;
  
  // check for command-line geometry
  if ( (pnum=M_CheckParm("-geom")) ? 1 : (pnum=M_CheckParm("-geometry"))) 
   if (pnum+1 < myargc) { // check parm given
    // warning: char format, different type arg
    char	xsign=' ';
    char	ysign=' ';
    const char* pg = myargv[pnum+1];
    
    pg += strcspn(pg, "+-");
    
    // warning: char format, different type arg 3,5
    n = sscanf(pg, "%c%d%c%d", &xsign, &x, &ysign, &y);
    
    if (n==2)
      x = y = 0;
    else if (n==4) {
      if (xsign == '-')
	x = -x;
      if (ysign == '-')
	y = -y;
    } else
      fprintf(stderr, "I_InitGraphics: bad -geom offsets \"%s\"\n", pg);
  }
  
  // check for command-line display name
  if ( (pnum=M_CheckParm("-disp")) ) // suggest parentheses around assignment
    displayname = myargv[pnum+1];
  // CPhipps - support more standard -display param
  if ( (pnum=M_CheckParm("-display")) ) // ditto
    displayname = myargv[pnum+1];
  // CPhipps - and -displayname as for xterm
  if ( (pnum=M_CheckParm("-displayname")) ) // ditto
    displayname = myargv[pnum+1];

  // open the display
  if (!(X_display = XOpenDisplay(displayname))) {
    if (displayname)
      I_Error("Could not open display [%s]", displayname);
    else
      I_Error("Could not open display (DISPLAY=[%s])", getenv("DISPLAY"));
  }

  // use the default visual 
  X_screen = DefaultScreen(X_display);

  X_deletewin = XInternAtom(X_display, "WM_DELETE_WINDOW", False);

  // check for the MITSHM extension
  // even if it's available, make sure it's a local connection
  lprintf(LO_INFO,"I_InitGraphics:");

#ifdef HAVE_LIBXXF86DGA
  if ((doDga = (M_CheckParm("-dga") && XF86DGAQueryExtension(X_display, &n, &n)) )) {
    lprintf(LO_INFO,"I_InitGraphics: found DGA extension\n");
    if (M_CheckParm("-noaccel") || (X_opt & 1)) doDga = false;
    else lprintf(LO_INFO, "(using DGA)");
  }
  else 
#endif
#ifdef HAVE_LIBXEXT
  if ((doShm = XShmQueryExtension(X_display))) {

    if (!displayname) displayname = getenv("DISPLAY");
    
    if (displayname) {
      // CPhipps - don't modify the original string, please.
      //         - oops my code here was totally wrong
      // I have no idea exactly what should go here.

      if (M_CheckParm("-noaccel") || (X_opt & 1)) doShm = false;
      else lprintf(LO_INFO, "(using MITShm)");
    }
  }
  else 
#endif 
    if (devparm) 
      fprintf(stderr, "No MITShm extension in server");

  if (devparm)
    fputc('\n', stderr);

  if ((X_visual = I_FindMode(X_screen)) == NULL) 
    I_Error("Unsupported visual");
  
  // create the colormap
  X_cmap = XCreateColormap(X_display, RootWindow(X_display, X_screen), 
			   X_visual, true_color ? AllocNone : AllocAll);

#ifdef HAVE_LIBXXF86DGA
  /* setup for DGA */
  if(doDga) {
     char *fb;
     X_mainWindow=RootWindow(X_display, X_screen);
     XF86DGAGetViewPortSize(X_display, X_screen, &DGA_width, &DGA_height);
     XF86DGAGetVideo(X_display, X_screen, &fb,
		     &DGA_real_width, &DGA_pagelen, &DGA_memlen);

     fprintf(stderr,
	     "I_InitGraphics: DGA reports %dx%d scan=%d page=%d mem=%d\n",
	     DGA_width,DGA_height,DGA_real_width,DGA_pagelen,DGA_memlen);

     out_buffer=(void*)fb;

     XF86DGADirectVideo(X_display, X_screen, XF86DGADirectGraphics);
     XF86DGASetVidPage(X_display, X_screen, 0);
     XF86DGAForkApp(X_screen);
     XSelectInput(X_display, X_mainWindow, KeyPressMask | KeyReleaseMask);
     fprintf(stderr,"DGA framebuffer @%p\n",fb);
     memset(fb,0,102400);
  }
#endif

#ifdef HAVE_LIBXXF86DGA
  if(!doDga)
#endif

  { // setup attributes for main window
    unsigned long	attribmask;
    XSetWindowAttributes attribs;

    attribmask = CWEventMask | CWColormap | CWBorderPixel;
    attribs.event_mask = KeyPressMask | KeyReleaseMask
#ifdef MONITOR_VISIBILITY
      | VisibilityChangeMask
#endif
      | ExposureMask;
    
    attribs.colormap = X_cmap;
    attribs.border_pixel = 0;
    
    // create the main window
    X_mainWindow = XCreateWindow( X_display,
				  RootWindow(X_display, X_screen),
				  x, y,
				  X_width, X_height,
				  0, // borderwidth
				  X_bpp, // depth
				  InputOutput, X_visual,
				  attribmask, &attribs );
  }
  
#ifdef HAVE_LIBXXF86DGA
  if(!doDga)
#endif

  {
    XClassHint c_hint;
    XTextProperty x_name;
    XSizeHints s_hint;
    XWMHints wm_hint;
    char lcase_buf[10], ucase_buf[10];
    char* str;

    strcpy(str = lcase_buf, lcase_lxdoom);
    XStringListToTextProperty(&str, 1, &x_name);

    s_hint.flags = PSize | PMinSize | PMaxSize;
    s_hint.min_width = s_hint.max_width = s_hint.base_width = X_width;
    s_hint.min_height = s_hint.max_height = s_hint.base_height = X_height;

    wm_hint.input = True;
    wm_hint.window_group = X_mainWindow;
    wm_hint.flags = InputHint | WindowGroupHint;

    strcpy(c_hint.res_name = lcase_buf, lcase_lxdoom);
    strcpy(c_hint.res_class = ucase_buf, ucase_lxdoom);
    
    XSetWMProtocols(X_display, X_mainWindow, &X_deletewin, 1);
    
    XSetWMProperties(X_display, X_mainWindow, &x_name, &x_name, 
		     (char**)myargv, myargc, &s_hint, &wm_hint, &c_hint);

    XFlush(X_display);
  }

#ifdef HAVE_LIBXXF86DGA
  if(!doDga)
#endif
  // Hide pointer while over this window
  XDefineCursor(X_display, X_mainWindow,
		I_XCreateNullCursor( X_display, X_mainWindow ) );
  
  { // create the GC
    XGCValues		xgcvalues;
    int		valuemask;
    
    valuemask = GCGraphicsExposures;
    xgcvalues.graphics_exposures = False;
    X_gc = XCreateGC(X_display, X_mainWindow, valuemask, &xgcvalues);
  }
  
#ifdef HAVE_LIBXXF86DGA
  if(!doDga)
#endif
  {
     // name the window
     XStoreName(X_display, X_mainWindow, "lxdoom");
  
     // map the window
     XMapWindow(X_display, X_mainWindow);
  }  

  // wait until it is OK to draw
#ifdef HAVE_LIBXXF86DGA
  if(!doDga)
#endif
  do {
    XNextEvent(X_display, &X_event);
  } while (!(X_event.type == Expose && !X_event.xexpose.count));

#ifdef HAVE_LIBXXF86DGA
  if(doDga) {}
  else
#endif

#ifdef HAVE_LIBXEXT
  if (doShm) {
    
    X_shmeventtype = XShmGetEventBase(X_display) + ShmCompletion;
    
    // create the image
    image = XShmCreateImage( X_display, X_visual,
			     X_bpp, ZPixmap,
			     0, &X_shminfo,
			     X_width, X_height );
    
    I_XShmGrabSharedMemory(image->bytes_per_line * image->height);
    
    if (!(out_buffer = (pval*)image->data)) {
      perror("");
      I_Error("shmat() failed in I_InitGraphics()");
    }
    
    // get the X server to attach to it
    if (!XShmAttach(X_display, &X_shminfo))
      I_Error("XShmAttach() failed in InitGraphics()");
    
    if (!expand_buffer) {
      // Render directly into MitSHM memory
      Z_Free(screens[0]);
      screens[0] = (unsigned char *) (image->data); 
    }
  } else
#endif 
  {
    if (!expand_buffer) {
      // Very efficient, render directly into image
      out_buffer = (pval*)screens[0];
    } else {
      // Will have to enlarge from rendering buffer
      //  into image buffer
      out_buffer = (pval*)malloc (X_width * X_height * BYTESPP);
    }

	{ 
/* hack to enable 15 bpp usage */
		int bpp=X_bpp;
		if(bpp==15)bpp=16;

    	image=XCreateImage( X_display, X_visual,
				X_bpp, ZPixmap,
				0, (char*)out_buffer,
				X_width, X_height,
				bpp, 0);
#ifdef NOT_NOW
    image=XCreateImage( X_display, X_visual,
			X_bpp, ZPixmap,
			0, (char*)out_buffer,
			X_width, X_height,
			X_bpp, 0);
#endif

	}
    if (!image) 
      I_Error("XCreateImage: failed to create image %dx%d %d bpp", 
	      X_width, X_height, X_bpp);
  }
  
  atexit(I_ShutdownGraphics);

  I_XInitInputs();
}
static int config(uint32_t width, uint32_t height,
                       uint32_t d_width, uint32_t d_height,
                       uint32_t flags, char *title, uint32_t format)
{

    int x_off, y_off;
    int wanted_width, wanted_height;

    static unsigned char *vo_dga_base;
    static int prev_width, prev_height;

#ifdef HAVE_DGA2
    // needed to change DGA video mode
    int mX = VO_DGA_INVALID_RES, mY = VO_DGA_INVALID_RES, mVBI =
        100000, mMaxY = 0, i, j = 0;
    int dga_modenum;
    XDGAMode *modeline;
    XDGADevice *dgadevice;
#else
#ifdef HAVE_XF86VM
    unsigned int vm_event, vm_error;
    unsigned int vm_ver, vm_rev;
    int i, j = 0, have_vm = 0;
    int mX = VO_DGA_INVALID_RES, mY = VO_DGA_INVALID_RES, mVBI =
        100000, mMaxY = 0, dga_modenum;
#endif
    int bank, ram;
#endif

    vo_dga_src_format = format;

    wanted_width = d_width;
    wanted_height = d_height;

    if (!wanted_height)
        wanted_height = height;
    if (!wanted_width)
        wanted_width = width;

    if (!vo_dbpp)
    {
        if ((format & IMGFMT_BGR_MASK) == IMGFMT_BGR)
        {
            vo_dga_src_mode = vd_ModeValid(format & 0xff);
        }
    } else
    {
        vo_dga_src_mode = vd_ModeValid(vo_dbpp);
    }
    vo_dga_hw_mode = SRC_MODE.vdm_hw_mode;

    if (!vo_dga_src_mode)
    {
        mp_msg(MSGT_VO, MSGL_ERR, "vo_dga: unsupported video format!\n");
        return 1;
    }

    vo_dga_vp_width = vo_screenwidth;
    vo_dga_vp_height = vo_screenheight;

    mp_msg(MSGT_VO, MSGL_V, "vo_dga: XServer res: %dx%d\n",
           vo_dga_vp_width, vo_dga_vp_height);

// choose a suitable mode ...

#ifdef HAVE_DGA2
// Code to change the video mode added by Michael Graffam
// [email protected]

    mp_msg(MSGT_VO, MSGL_V, "vo_dga: vo_modelines=%p, vo_modecount=%d\n",
           vo_modelines, vo_modecount);

    if (vo_modelines == NULL)
    {
        mp_msg(MSGT_VO, MSGL_ERR, "vo_dga: can't get modelines\n");
        return 1;
    }

    mp_msg(MSGT_VO, MSGL_INFO,
           "vo_dga: DGA 2.0 available :-) Can switch resolution AND depth!\n");
    for (i = 0; i < vo_modecount; i++)
    {
        if (vd_ModeEqual(vo_modelines[i].depth,
                         vo_modelines[i].bitsPerPixel,
                         vo_modelines[i].redMask,
                         vo_modelines[i].greenMask,
                         vo_modelines[i].blueMask, vo_dga_hw_mode))
        {

            mp_msg(MSGT_VO, MSGL_V, "maxy: %4d, depth: %2d, %4dx%4d, ",
                   vo_modelines[i].maxViewportY, vo_modelines[i].depth,
                   vo_modelines[i].imageWidth,
                   vo_modelines[i].imageHeight);
            if (check_res
                (i, wanted_width, wanted_height, vo_modelines[i].depth,
                 vo_modelines[i].viewportWidth,
                 vo_modelines[i].viewportHeight,
                 (unsigned) vo_modelines[i].verticalRefresh,
                 vo_modelines[i].maxViewportY, &mX, &mY, &mVBI, &mMaxY))
                j = i;
        }
    }
    mp_msg(MSGT_VO, MSGL_INFO,
           "vo_dga: Selected hardware mode %4d x %4d @ %3d Hz @ depth %2d, bitspp %2d.\n",
           mX, mY, mVBI, HW_MODE.vdm_depth, HW_MODE.vdm_bitspp);
    mp_msg(MSGT_VO, MSGL_INFO,
           "vo_dga: Video parameters by codec: %3d x %3d, depth %2d, bitspp %2d.\n",
           width, height, SRC_MODE.vdm_depth, SRC_MODE.vdm_bitspp);
    vo_dga_vp_width = mX;
    vo_dga_vp_height = mY;

    if ((flags & VOFLAG_SWSCALE) || (flags & VOFLAG_FULLSCREEN))
    {                           /* -zoom or -fs */
        scale_dstW = (d_width + 7) & ~7;
        scale_dstH = d_height;
        scale_srcW = width;
        scale_srcH = height;
        aspect_save_screenres(mX, mY);
        aspect_save_orig(scale_srcW, scale_srcH);
        aspect_save_prescale(scale_dstW, scale_dstH);
        if (flags & VOFLAG_FULLSCREEN)       /* -fs */
            aspect(&scale_dstW, &scale_dstH, A_ZOOM);
        else if (flags & VOFLAG_SWSCALE)  /* -fs */
            aspect(&scale_dstW, &scale_dstH, A_NOZOOM);
        mp_msg(MSGT_VO, MSGL_INFO,
               "vo_dga: Aspect corrected size for SwScaler: %4d x %4d.\n",
               scale_dstW, scale_dstH);
        /* XXX this is a hack, but I'm lazy ;-) :: atmos */
        width = scale_dstW;
        height = scale_dstH;
    }

    vo_dga_width = vo_modelines[j].bytesPerScanline / HW_MODE.vdm_bytespp;
    dga_modenum = vo_modelines[j].num;
    modeline = vo_modelines + j;

#else

#ifdef HAVE_XF86VM

    mp_msg(MSGT_VO, MSGL_INFO,
           "vo_dga: DGA 1.0 compatibility code: Using XF86VidMode for mode switching!\n");

    if (XF86VidModeQueryExtension(mDisplay, &vm_event, &vm_error))
    {
        XF86VidModeQueryVersion(mDisplay, &vm_ver, &vm_rev);
        mp_msg(MSGT_VO, MSGL_INFO,
               "vo_dga: XF86VidMode Extension v%i.%i\n", vm_ver, vm_rev);
        have_vm = 1;
    } else
    {
        mp_msg(MSGT_VO, MSGL_ERR,
               "vo_dga: XF86VidMode Extension not available.\n");
    }

#define GET_VREFRESH(dotclk, x, y)( (((dotclk)/(x))*1000)/(y) )

    if (have_vm)
    {
        int modecount;

        XF86VidModeGetAllModeLines(mDisplay, mScreen, &modecount,
                                   &vo_dga_vidmodes);

        if (vo_dga_vidmodes != NULL)
        {
            for (i = 0; i < modecount; i++)
            {
                if (check_res(i, wanted_width, wanted_height,
                              vo_dga_modes[vo_dga_hw_mode].vdm_depth,
                              vo_dga_vidmodes[i]->hdisplay,
                              vo_dga_vidmodes[i]->vdisplay,
                              GET_VREFRESH(vo_dga_vidmodes[i]->dotclock,
                                           vo_dga_vidmodes[i]->htotal,
                                           vo_dga_vidmodes[i]->vtotal),
                              0, &mX, &mY, &mVBI, &mMaxY))
                    j = i;
            }

            mp_msg(MSGT_VO, MSGL_INFO,
                   "vo_dga: Selected video mode %4d x %4d @ %3d Hz @ depth %2d, bitspp %2d, video %3d x %3d.\n",
                   mX, mY, mVBI,
                   vo_dga_modes[vo_dga_hw_mode].vdm_depth,
                   vo_dga_modes[vo_dga_hw_mode].vdm_bitspp, width, height);
        } else
        {
            mp_msg(MSGT_VO, MSGL_INFO,
                   "vo_dga: XF86VidMode returned no screens - using current resolution.\n");
        }
        dga_modenum = j;
        vo_dga_vp_width = mX;
        vo_dga_vp_height = mY;
    }

#else
    mp_msg(MSGT_VO, MSGL_INFO,
           "vo_dga: Only have DGA 1.0 extension and no XF86VidMode :-(\n");
    mp_msg(MSGT_VO, MSGL_INFO,
           "        Thus, resolution switching is NOT possible.\n");

#endif
#endif

    vo_dga_src_width = width;
    vo_dga_src_height = height;

    if (vo_dga_src_width > vo_dga_vp_width ||
        vo_dga_src_height > vo_dga_vp_height)
    {
        mp_msg(MSGT_VO, MSGL_ERR,
               "vo_dga: Sorry, video larger than viewport is not yet supported!\n");
        // ugly, do something nicer in the future ...
#ifndef HAVE_DGA2
#ifdef HAVE_XF86VM
        if (vo_dga_vidmodes)
        {
            XFree(vo_dga_vidmodes);
            vo_dga_vidmodes = NULL;
        }
#endif
#endif
        return 1;
    }

    if (vo_dga_vp_width == VO_DGA_INVALID_RES)
    {
        mp_msg(MSGT_VO, MSGL_ERR,
               "vo_dga: Something is wrong with your DGA. There doesn't seem to be a\n"
               "         single suitable mode!\n"
               "         Please file a bug report (see DOCS/HTML/en/bugreports.html)\n");
#ifndef HAVE_DGA2
#ifdef HAVE_XF86VM
        if (vo_dga_vidmodes)
        {
            XFree(vo_dga_vidmodes);
            vo_dga_vidmodes = NULL;
        }
#endif
#endif
        return 1;
    }
// now let's start the DGA thing 

    if (!vo_config_count || width != prev_width || height != prev_height)
    {
#ifdef HAVE_DGA2

        if (!XDGAOpenFramebuffer(mDisplay, mScreen))
        {
            mp_msg(MSGT_VO, MSGL_ERR,
                   "vo_dga: Framebuffer mapping failed!!!\n");
            return 1;
        }

        dgadevice = XDGASetMode(mDisplay, mScreen, dga_modenum);
        XDGASync(mDisplay, mScreen);

        vo_dga_base = dgadevice->data;
        XFree(dgadevice);

        XDGASetViewport(mDisplay, mScreen, 0, 0, XDGAFlipRetrace);

#else

#ifdef HAVE_XF86VM
        if (have_vm)
        {
            XF86VidModeLockModeSwitch(mDisplay, mScreen, 0);
            // Two calls are needed to switch modes on my ATI Rage 128. Why?
            // for riva128 one call is enough!
            XF86VidModeSwitchToMode(mDisplay, mScreen,
                                    vo_dga_vidmodes[dga_modenum]);
            XF86VidModeSwitchToMode(mDisplay, mScreen,
                                    vo_dga_vidmodes[dga_modenum]);
        }
#endif

        XF86DGAGetViewPortSize(mDisplay, mScreen,
                               &vo_dga_vp_width, &vo_dga_vp_height);

        XF86DGAGetVideo(mDisplay, mScreen,
                        (char **) &vo_dga_base, &vo_dga_width, &bank,
                        &ram);

        XF86DGADirectVideo(mDisplay, mScreen,
                           XF86DGADirectGraphics | XF86DGADirectMouse |
                           XF86DGADirectKeyb);

        XF86DGASetViewPort(mDisplay, mScreen, 0, 0);

#endif
    }
    // do some more checkings here ...

    mp_msg(MSGT_VO, MSGL_V,
           "vo_dga: bytes/line: %d, screen res: %dx%d, depth: %d, base: %p, bpp: %d\n",
           vo_dga_width, vo_dga_vp_width, vo_dga_vp_height,
           HW_MODE.vdm_bytespp, vo_dga_base, HW_MODE.vdm_bitspp);

    x_off = (vo_dga_vp_width - vo_dga_src_width) >> 1;
    y_off = (vo_dga_vp_height - vo_dga_src_height) >> 1;

    vo_dga_bytes_per_line = vo_dga_src_width * HW_MODE.vdm_bytespp;
    vo_dga_lines = vo_dga_src_height;

    vo_dga_src_offset = 0;
    vo_dga_vp_offset =
        (y_off * vo_dga_width + x_off) * HW_MODE.vdm_bytespp;

    vo_dga_vp_skip = (vo_dga_width - vo_dga_src_width) * HW_MODE.vdm_bytespp;   // todo

    mp_msg(MSGT_VO, MSGL_V, "vo_dga: vp_off=%d, vp_skip=%d, bpl=%d\n",
           vo_dga_vp_offset, vo_dga_vp_skip, vo_dga_bytes_per_line);


    XGrabKeyboard(mDisplay, DefaultRootWindow(mDisplay), True,
                  GrabModeAsync, GrabModeAsync, CurrentTime);
    if (vo_grabpointer)
        XGrabPointer(mDisplay, DefaultRootWindow(mDisplay), True,
                     ButtonPressMask, GrabModeAsync, GrabModeAsync,
                     None, None, CurrentTime);

    if (!vo_config_count || width != prev_width || height != prev_height)
    {
        init_video_buffers(vo_dga_base,
                           vo_dga_vp_height,
                           vo_dga_width * HW_MODE.vdm_bytespp,
#ifdef HAVE_DGA2
                           modeline->maxViewportY,
#else
                           vo_dga_vp_height,
#endif
                           vo_doublebuffering);
        prev_width = width;
        prev_height = height;
    }

    mp_msg(MSGT_VO, MSGL_V, "vo_dga: Using %d frame buffer%s.\n",
           vo_dga_nr_video_buffers,
           vo_dga_nr_video_buffers == 1 ? "" : "s");

    vo_dga_is_running = 1;
    return 0;
}