// Copyright (C) 1996 Keith Whitwell. // This file may only be copied under the terms of the GNU Library General // Public License - see the file COPYING in the lib3d distribution. #include #include #include #include #include // Abstract base for the DGA devices. class SvgaDevice : public Device { public: SvgaDevice( Exemplar ); SvgaDevice( uint width, uint height, uint depth ); ~SvgaDevice(); const char *getName() const { return "SvgaDevice"; } uint allocateColour( uint , uint , uint ); void processPendingEvents(); void swapBuffers(); protected: Device *clone( uint width, uint height, uint depth ); int estimateSpeed() const { return 11; } bool initialize(); protected: uchar *base; uchar *dest; int scanSize; int bankSize; int ram; int col; int idx; }; SvgaDevice::SvgaDevice(uint width, uint height, uint min_depth) : Device(width, height, min_depth), idx(1) { col = 0; if (isBad()) return; if (getenv("DISPLAY")) { debug() << "DISPLAY variable is set - skipping" << endlog; setBad(); return; } if (geteuid() != 0) { debug() << "Failed to create XDgaDevice - must be suid root" << endlog; setBad(); return; } vga_init(); int mode; if ((mode = vga_getdefaultmode()) < 0) { if (width <= 320) { mode = G320x200x256; } else if (width <= 640) { mode = G640x480x256; } else if (width <= 800) { mode = G800x600x256; } else { mode = G1024x768x256; } } if(!vga_hasmode(mode)) { mode = G320x200x256; if(!vga_hasmode(mode)) { setBad(); return; } } vga_modeinfo *modeinfo = vga_getmodeinfo(mode); // Disable bank switching if possible if (modeinfo->flags & CAPABLE_LINEAR == 0) { mode = G320x200x256; } else if (mode != G320x200x256) { vga_setlinearaddressing(); } modeinfo = vga_getmodeinfo(mode); if (uint(modeinfo->bytesperpixel*8) < min_depth) { setBad(); return; } vga_setmode(mode); // Get info from SVGAlib depth = modeinfo->bytesperpixel * 8; scanSize = modeinfo->linewidth; pixelSize = modeinfo->bytesperpixel; //nrColours = modeinfo->colors; base = vga_getgraphmem(); // memset(base, 0, bankSize); int centering = ((modeinfo->height - height) / 2 * scanSize + (modeinfo->width - width) / 2 * pixelSize); dest = (uchar *)base + centering; rowSize = width * pixelSize; frameBuf = new uchar[height * rowSize]; memset(frameBuf, 0, height * rowSize); } SvgaDevice::~SvgaDevice() { if (isActive()) { vga_setmode(TEXT); } } SvgaDevice::SvgaDevice( Exemplar e ) : Device( e ) { registerChildClass( this ); } static SvgaDevice advertise( Device::exemplar ); Device * SvgaDevice::clone( uint width, uint height, uint depth ) { return new SvgaDevice( width, height, depth ); } bool SvgaDevice::initialize() { return true; } uint SvgaDevice::allocateColour( uint red, uint green, uint blue ) { vga_setpalette(idx, red>>10, green>>10, blue>>10); return idx++; // return vga_setrgbcolor(red/256, green/256, blue/256); } void SvgaDevice::swapBuffers() { uint xn = min(xmin, oldxmin) * pixelSize; uint xx = max(xmax, oldxmax) * pixelSize; uint yn = min(ymin, oldymin); uint yx = max(ymax, oldymax); if (xn < xx && yn < yx) { xn &= ~0x03; if (xx & 0x03) { xx &= ~0x03; xx += 0x04; } uchar *to = dest + xn + (yn * scanSize); uchar *from = frameBuf + xn + (yn * rowSize); uint wid = xx - xn; int i = yx - yn; #if 0 // Memcpy turns out faster on Linux - I haven't investigated why. wid = wid >> 2; asm("cld"); do { asm ("rep\n\t" "movsl" : /* no output registers */ : "c" (wid), "S" (from), "D" (to) : "%ecx", "%edi", "%esi" ); to += scanSize; from += rowSize; } while (--i); #else do { memcpy(to, from, wid); to += scanSize; from += rowSize; } while (--i); #endif } } void SvgaDevice::processPendingEvents() { }