/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.driver.video.vmware; import gnu.classpath.SystemProperties; import java.awt.Color; import java.awt.Rectangle; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.image.ColorModel; import java.awt.image.DirectColorModel; import java.awt.image.Raster; import java.io.PrintWriter; import java.security.PrivilegedExceptionAction; import javax.naming.NameNotFoundException; import org.apache.log4j.Logger; import org.jnode.awt.util.BitmapGraphics; import org.jnode.driver.DriverException; import org.jnode.driver.bus.pci.PCIDevice; import org.jnode.driver.bus.pci.PCI_IDs; import org.jnode.driver.video.FrameBufferConfiguration; import org.jnode.driver.video.HardwareCursor; import org.jnode.driver.video.HardwareCursorAPI; import org.jnode.driver.video.HardwareCursorImage; import org.jnode.driver.video.Surface; import org.jnode.driver.video.util.AbstractSurface; import org.jnode.naming.InitialNaming; import org.jnode.system.resource.IOResource; import org.jnode.system.resource.MemoryResource; import org.jnode.system.resource.ResourceManager; import org.jnode.system.resource.ResourceNotFreeException; import org.jnode.system.resource.ResourceOwner; import org.jnode.util.AccessControllerUtils; import org.jnode.util.NumberUtils; import org.vmmagic.unboxed.Address; /** * @author epr * @author Levente S\u00e1ntha */ public class VMWareCore extends AbstractSurface implements VMWareConstants, PCI_IDs, HardwareCursorAPI { /** * My logger */ private static final Logger log = Logger.getLogger(VMWareCore.class); private final VMWareDriver driver; private final int indexPort; private final int valuePort; private final IOResource ports; private final MemoryResource fifoMem; private final MemoryResource videoRam; private final int videoRamSize; private final int maxWidth; private final int maxHeight; private final int bitsPerPixel; private final int redMask; private final int greenMask; private final int blueMask; private final int alphaMask; private final int redMaskShift; private final int greenMaskShift; private final int blueMaskShift; private final int alphaMaskShift; private final int capabilities; private final int fifoCapabilities; private final int deviceId; private int bytesPerLine; private int offset; private int displayWidth; private boolean fifoDirty = false; private BitmapGraphics bitmapGraphics; private ColorModel model; private static final int MOUSE_ID = 0; private int curX; private int curY; private boolean curVisible; /** * Create a new instance * * @param driver * @param device */ public VMWareCore(VMWareDriver driver, PCIDevice device) throws ResourceNotFreeException, DriverException { super(640, 480); this.driver = driver; final int basePort; if (device.getConfig().getDeviceID() == PCI_DEVICE_ID_VMWARE_SVGA) { basePort = SVGA_LEGACY_BASE_PORT; this.indexPort = SVGA_LEGACY_BASE_PORT + SVGA_INDEX_PORT * 4; this.valuePort = SVGA_LEGACY_BASE_PORT + SVGA_VALUE_PORT * 4; } else { basePort = device.getConfig().asHeaderType0().getBaseAddresses()[0].getIOBase(); this.indexPort = basePort + SVGA_INDEX_PORT; this.valuePort = basePort + SVGA_VALUE_PORT; } log.debug("Found VMWare SVGA device using ports 0x" + NumberUtils.hex(indexPort) + " and 0x" + NumberUtils.hex(valuePort)); try { // Allocate IO register space final ResourceManager rm = InitialNaming.lookup(ResourceManager.NAME); ports = claimPorts(rm, device, basePort, SVGA_NUM_PORTS * 4); // Detect deviceID deviceId = getVMWareID(); if (deviceId == SVGA_ID_0 || deviceId == SVGA_ID_INVALID) { dumpState(); throw new DriverException("No supported VMWare SVGA found, found id 0x" + NumberUtils.hex(deviceId)); } else { log.debug("VMWare SVGA ID: 0x" + NumberUtils.hex(deviceId)); } // Initialize and start FIFO fifoMem = initFifo(device, rm); // Read info this.capabilities = getReg32(SVGA_REG_CAPABILITIES); this.fifoCapabilities = hasCapability(SVGA_CAP_EXTENDED_FIFO) ? getFIFO(SVGA_FIFO_CAPABILITIES) : 0; this.videoRamSize = getReg32(SVGA_REG_FB_MAX_SIZE); this.maxWidth = getReg32(SVGA_REG_MAX_WIDTH); this.maxHeight = getReg32(SVGA_REG_MAX_HEIGHT); final int bitsPerPixel = getReg32(SVGA_REG_BITS_PER_PIXEL); this.bytesPerLine = getReg32(SVGA_REG_BYTES_PER_LINE); // Allocate framebuffer memory final Address videoRamAddr; if (device.getConfig().getDeviceID() == PCI_DEVICE_ID_VMWARE_SVGA2) { videoRamAddr = Address.fromLong(device.getConfig().asHeaderType0().getBaseAddresses()[1].getMemoryBase()); } else { videoRamAddr = Address.fromIntZeroExtend(SVGA_REG_FB_START); } this.videoRam = rm.claimMemoryResource(device, videoRamAddr, videoRamSize, ResourceManager.MEMMODE_NORMAL); this.bitsPerPixel = bitsPerPixel; switch (bitsPerPixel) { case 8: bitmapGraphics = BitmapGraphics.create8bppInstance(videoRam, width, height, bytesPerLine, 0); break; case 16: bitmapGraphics = BitmapGraphics.create16bppInstance(videoRam, width, height, bytesPerLine, 0); break; case 24: bitmapGraphics = BitmapGraphics.create24bppInstance(videoRam, width, height, bytesPerLine, 0); break; case 32: bitmapGraphics = BitmapGraphics.create32bppInstance(videoRam, width, height, bytesPerLine, 0); break; default: throw new DriverException("Unknown bits/pixel value " + bitsPerPixel); } this.redMask = getReg32(SVGA_REG_RED_MASK); this.greenMask = getReg32(SVGA_REG_GREEN_MASK); this.blueMask = getReg32(SVGA_REG_BLUE_MASK); String transparency = SystemProperties.getProperty("org.jnode.awt.transparency"); if (transparency != null && "true".equals(transparency)) { // todo get this in the safe way this.alphaMask = 0xff000000; // - transparency enabled } else { this.alphaMask = 0x00000000; // - transparency disabled } this.redMaskShift = getMaskShift(redMask); this.greenMaskShift = getMaskShift(greenMask); this.blueMaskShift = getMaskShift(blueMask); this.alphaMaskShift = getMaskShift(alphaMask); } catch (NameNotFoundException ex) { throw new ResourceNotFreeException(ex); } } /** * Release all resources */ public final void release() { ports.release(); fifoMem.release(); videoRam.release(); } /** * Open a given configuration * * @param config */ public void open(FrameBufferConfiguration config) { final int w = config.getScreenWidth(); final int h = config.getScreenHeight(); setMode(w, h, config.getColorModel()); fillRect(0, 0, w, h, 0, PAINT_MODE); dumpState(); // For debugging purposes defineCursor(); } /** * Close the SVGA screen * * @see org.jnode.driver.video.Surface#close() */ public synchronized void close() { disableSVGA(); driver.close(this); super.close(); } /** * Initialize the graphics mode * * @param width * @param height */ public final void setMode(int width, int height, ColorModel model) { setReg32(SVGA_REG_WIDTH, width); setReg32(SVGA_REG_HEIGHT, height); setReg32(SVGA_REG_ENABLE, 1); this.model = model; this.offset = getReg32(SVGA_REG_FB_OFFSET); setReg32(SVGA_REG_GUEST_ID, GUEST_OS_OTHER); this.displayWidth = (getReg32(SVGA_REG_BYTES_PER_LINE) * 8) / ((bitsPerPixel + 7) & ~7); this.bytesPerLine = getReg32(SVGA_REG_BYTES_PER_LINE); setSize(width, height); this.width = width; this.height = height; switch (bitsPerPixel) { case 8: bitmapGraphics = BitmapGraphics.create8bppInstance(videoRam, width, height, bytesPerLine, offset); break; case 16: bitmapGraphics = BitmapGraphics.create16bppInstance(videoRam, width, height, bytesPerLine, offset); break; case 24: bitmapGraphics = BitmapGraphics.create24bppInstance(videoRam, width, height, bytesPerLine, offset); break; case 32: bitmapGraphics = BitmapGraphics.create32bppInstance(videoRam, width, height, bytesPerLine, offset, model.getTransparency()); break; } dumpState(); } public FrameBufferConfiguration[] getConfigs() { final ColorModel cm = new DirectColorModel(bitsPerPixel, redMask, greenMask, blueMask, alphaMask); return new FrameBufferConfiguration[]{ new VMWareConfiguration(800, 600, cm), new VMWareConfiguration(1024, 768, cm), new VMWareConfiguration(1280, 1024, cm), new VMWareConfiguration(640, 480, cm), new VMWareConfiguration(1280, 800, cm), }; } /** * Disable the SVGA mode. */ public final void disableSVGA() { setReg32(SVGA_REG_ENABLE, 0); } /** * Update the entire screen */ public final void updateScreen() { updateScreen(0, 0, width, height); } /** * Update the given region of the screen */ public final void updateScreen(int x, int y, int width, int height) { writeWordToFIFO(SVGA_CMD_UPDATE); writeWordToFIFO(x); writeWordToFIFO(y); writeWordToFIFO(width); writeWordToFIFO(height); } /** * Draw the given shape * * @param shape * @param color * @param mode */ public final synchronized void draw(Shape shape, Shape clip, AffineTransform tx, Color color, int mode) { syncFIFO(); super.draw(shape, clip, tx, color, mode); final Rectangle r = getBounds(shape, tx); updateScreen(r.x - 1, r.y - 1, r.width + 2, r.height + 2); } /** * @see org.jnode.driver.video.Surface#copyArea(int, int, int, int, int, * int) */ public void copyArea(int x, int y, int width, int height, int dx, int dy) { bitmapGraphics.copyArea(x, y, width, height, dx, dy); updateScreen(x + dx, y + dy, width, height); } /** * Draw an image to this surface * * @param src * @param srcX * @param srcY * @param x The upper left x coordinate * @param y The upper left y coordinate * @param w * @param h * @param bgColor The background color to use for transparent pixels. If * null, no transparent pixels are unmodified on the destination */ public void drawCompatibleRaster(Raster src, int srcX, int srcY, int x, int y, int w, int h, Color bgColor) { if (bgColor != null) { bitmapGraphics.drawImage(src, srcX, srcY, x, y, w, h, convertColor(bgColor)); } else { bitmapGraphics.drawImage(src, srcX, srcY, x, y, w, h); } updateScreen(x, y, w, h); } /** * @see org.jnode.driver.video.Surface#fill(Shape, Shape, AffineTransform, * Color, int) */ public final synchronized void fill(Shape shape, Shape clip, AffineTransform tx, Color color, int mode) { syncFIFO(); super.fill(shape, clip, tx, color, mode); final Rectangle b = getBounds(shape, tx); updateScreen(b.x, b.y, b.width, b.height); } /** * Fill a given rectangle with a given color */ public final synchronized void fillRectangle(int x1, int y1, int x2, int y2, Color color, int mode) { fillRect(x1, y1, x2 - x1, y2 - y1, convertColor(color), mode); } /** * Fill a given rectangle with a given color * * @param x * @param y * @param width * @param height * @param color * @param mode */ public final void fillRect(int x, int y, int width, int height, int color, int mode) { if (x < 0) { width = Math.max(0, x + width); x = 0; } if (y < 0) { height = Math.max(0, y + height); y = 0; } if ((width <= 0) || (height <= 0)) return; if (mode == Surface.XOR_MODE) { if (hasCapability(SVGA_CAP_RASTER_OP)) { writeWordToFIFO(SVGA_CMD_RECT_ROP_FILL); writeWordToFIFO(color); writeWordToFIFO(x); writeWordToFIFO(y); writeWordToFIFO(width); writeWordToFIFO(height); writeWordToFIFO(SVGA_ROP_XOR); return; } } else /* Paint mode */ { if (hasCapability(SVGA_CAP_RECT_FILL)) { writeWordToFIFO(SVGA_CMD_RECT_FILL); writeWordToFIFO(color); writeWordToFIFO(x); writeWordToFIFO(y); writeWordToFIFO(width); writeWordToFIFO(height); return; } } // bitmapGraphics.fillRect(x, y, width, height, color, mode); super.fillRect(x, y, width, height, color, mode); } /** * Dump the state of the SVGA to log. */ public final void dumpState() { log.debug("Max. Resolution " + maxWidth + "*" + maxHeight); log.debug("Cur. Resolution " + width + "*" + height); log.debug("Bits/Pixel " + bitsPerPixel); log.debug("Bytes/Line " + bytesPerLine); log.debug("Offset " + offset); log.debug("Display width " + displayWidth); log.debug("Red mask 0x" + NumberUtils.hex(getReg32(SVGA_REG_RED_MASK))); log.debug("Green mask 0x" + NumberUtils.hex(getReg32(SVGA_REG_GREEN_MASK))); log.debug("Blue mask 0x" + NumberUtils.hex(getReg32(SVGA_REG_BLUE_MASK))); log.debug("Capabilities 0x" + NumberUtils.hex(capabilities)); log.debug("FB.size 0x" + NumberUtils.hex(getReg32(SVGA_REG_FB_SIZE))); log.debug("FB.maxsize 0x" + NumberUtils.hex(getReg32(SVGA_REG_FB_MAX_SIZE))); } /** * Set the pixel at the given location to the given color. * * @param x * @param y * @param color */ public final void drawPixel(int x, int y, int color, int mode) { bitmapGraphics.drawPixels(x, y, 1, color, mode); /* * if ((x >= 0) && (x < width) && (y > = 0) && (y < height)) { y; final * int ofs; if (mode == Surface.XOR_MODE) { switch (bitsPerPixel) { case * 8 : ofs = ofsY + x; videoRam.xorByte(ofs, (byte) color, 1); break; * case 16 : ofs = ofsY + (x << 1); videoRam.xorShort(ofs, (short) * color, 1); break; case 24 : 3); videoRam.xorShort(ofs, (short) (color & * 0xFFFF), 1); videoRam.xorByte(ofs + 2, (byte) ((color >> 16) & 0xFF), * 1); break; case 32 : ofs = ofsY + (x << 2); videoRam.xorInt(ofs, * color, 1); break; default : throw new RuntimeException("Unknown * bitsPerPixel"); } } else { switch (bitsPerPixel) { case 8 : ofs = * ofsY + x; videoRam.setByte(ofs, (byte) color); break; case 16 : ofs = * ofsY + (x << 1); videoRam.setShort(ofs, (short) color); break; case * 24 : 3); videoRam.setShort(ofs, (short) (color & 0xFFFF)); * videoRam.setByte(ofs + 2, (byte) ((color >> 16) & 0xFF)); break; case * 32 : ofs = ofsY + (x << 2); videoRam.setInt(ofs, color); break; * default : throw new RuntimeException("Unknown bitsPerPixel"); } } */ } /** * Low level draw line method. This method does not call updateScreen. * * @param x1 * @param y1 * @param x2 * @param y2 * @param c * @param mode */ public final void drawLine(int x1, int y1, int x2, int y2, int c, int mode) { super.drawLine(x1, y1, x2, y2, c, mode); // todo optimize it /* * if (x1 == x2) { // Vertical line fillRect(x1, Math.min(y1, y2), 1, * Math.abs(y2 - y1), c, mode); } else if (y1 == y2) { // Horizontal * line //drawHorizontalLine(Math.min(x1, x2), y1, Math.abs(x2 - x1)+1, * c, mode); fillRect(Math.min(x1, x2), y1, Math.abs(x2 - x1) + 1, 1, c, * mode); } else { super.drawLine(x1, y1, x2, y2, c, mode); } */ } protected final void drawHorizontalLine(int x, int y, int w, int color, int mode) { if ((x >= 0) && (x < width) && (y >= 0) && (y < height)) { w = Math.min(width - x, w); final int ofsY = bytesPerLine * y; int ofs; if (mode == Surface.XOR_MODE) { switch (bitsPerPixel) { case 8: ofs = ofsY + x; videoRam.xorByte(ofs, (byte) color, w); break; case 16: ofs = ofsY + (x << 1); videoRam.xorShort(ofs, (short) color, w); break; case 24: ofs = ofsY + (x * 3); while (w > 0) { videoRam.xorShort(ofs, (short) (color & 0xFFFF), 1); videoRam.xorByte(ofs + 2, (byte) ((color >> 16) & 0xFF), 1); w--; ofs += 3; } break; case 32: ofs = ofsY + (x << 2); videoRam.xorInt(ofs, color, w); break; default: throw new RuntimeException("Unknown bitsPerPixel"); } } else { switch (bitsPerPixel) { case 8: ofs = ofsY + x; videoRam.setByte(ofs, (byte) color, w); break; case 16: ofs = ofsY + (x << 1); videoRam.setShort(ofs, (short) color, w); break; case 24: ofs = ofsY + (x * 3); while (w > 0) { videoRam.setShort(ofs, (short) (color & 0xFFFF)); videoRam.setByte(ofs + 2, (byte) ((color >> 16) & 0xFF)); w--; ofs += 3; } break; case 32: ofs = ofsY + (x << 2); videoRam.setInt(ofs, color, w); break; default: throw new RuntimeException("Unknown bitsPerPixel"); } } } } /** * Gets the contents of a 32-bit SVGA register * * @param index * @return */ private int getReg32(int index) { ports.outPortDword(indexPort, index); return ports.inPortDword(valuePort); } /** * Sets the contents of a 32-bit SVGA register * * @param index * @param value */ private void setReg32(int index, int value) { ports.outPortDword(indexPort, index); ports.outPortDword(valuePort, value); } /** * Write the given word to the FIFO. * * @param value */ private void writeWordToFIFO(int value) { fifoDirty = true; // Debug.out.println ("VMWare::WriteWordToFIFO(" + // Integer.toHexString(nValue) + ") pos: " // + ReadFIFO (SVGA_FIFO_NEXT_CMD)); /* Need to sync? */ final int fifoMin = getFIFO(SVGA_FIFO_MIN); final int fifoMax = getFIFO(SVGA_FIFO_MAX); final int fifoNextCmd = getFIFO(SVGA_FIFO_NEXT_CMD); if ((fifoNextCmd + 4 == getFIFO(SVGA_FIFO_STOP)) || (fifoNextCmd == (fifoMax - 4) && getFIFO(SVGA_FIFO_STOP) == fifoMin)) { log.debug("VMWare::WriteWordToFIFO() syncing FIFO"); setReg32(SVGA_REG_SYNC, 1); while (getReg32(SVGA_REG_BUSY) != 0) { Thread.yield(); } } setFIFO(fifoNextCmd / 4, value); setFIFO(SVGA_FIFO_NEXT_CMD, fifoNextCmd + 4); if (getFIFO(SVGA_FIFO_NEXT_CMD) == fifoMax) { setFIFO(SVGA_FIFO_NEXT_CMD, fifoMin); } } /** * Wait until the SVGA is ready */ private final void syncFIFO() { if (fifoDirty) { setReg32(SVGA_REG_SYNC, 1); while (getReg32(SVGA_REG_BUSY) != 0) { Thread.yield(); } fifoDirty = false; } } /** * Gets a FIFO entry * * @param index * @return */ private final int getFIFO(int index) { return fifoMem.getInt(index * 4); } /** * Sets a FIFO entry * * @param index * @param value */ private final void setFIFO(int index, int value) { fifoMem.setInt(index * 4, value); } /** * Convert the given color to a value suitable for VMWare * * @param color */ protected final int convertColor(Color color) { return convertColor(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); } /** * Convert the given color to a value suitable for VMWare * * @param r * @param g * @param b */ protected final int convertColor(int r, int g, int b) { return ((r << redMaskShift) & redMask) | ((g << greenMaskShift) & greenMask) | ((b << blueMaskShift) & blueMask); } protected final int convertColor(int r, int g, int b, int a) { return ((a << alphaMaskShift) & alphaMask) | ((r << redMaskShift) & redMask) | ((g << greenMaskShift) & greenMask) | ((b << blueMaskShift) & blueMask); } /** * Gets the SVGA_ID of the VMware SVGA adapter. This function should hide * any backward compatibility mess. */ private int getVMWareID() { int vmware_svga_id; /*********************************************************************** * Any version with any SVGA_ID_ to SVGA_ID_0 to support versions of * this driver with SVGA_ID_0. * * Versions of SVGA_ID_0 ignore writes to the SVGA_REG_ID register. * * Versions of SVGA_ID_1 will allow us to overwrite the content of the * SVGA_REG_ID register only with the values SVGA_ID_0 or SVGA_ID_1. * * Versions of SVGA_ID_2 will allow us to overwrite the content of the * SVGA_REG_ID register only with the values SVGA_ID_0 or SVGA_ID_1 or * SVGA_ID_2. */ setReg32(SVGA_REG_ID, SVGA_ID_2); vmware_svga_id = getReg32(SVGA_REG_ID); if (vmware_svga_id == SVGA_ID_2) { return SVGA_ID_2; } setReg32(SVGA_REG_ID, SVGA_ID_1); vmware_svga_id = getReg32(SVGA_REG_ID); if (vmware_svga_id == SVGA_ID_1) { return SVGA_ID_1; } if (vmware_svga_id == SVGA_ID_0) { return SVGA_ID_0; } /* No supported VMware SVGA devices found */ return SVGA_ID_INVALID; } /** * Claim and initialize the FIFO. * * @param device * @param rm * @return */ private final MemoryResource initFifo(PCIDevice device, ResourceManager rm) throws ResourceNotFreeException { final int size = getReg32(SVGA_REG_MEM_SIZE); final Address address; if (device.getConfig().getDeviceID() == PCI_DEVICE_ID_VMWARE_SVGA2) { address = Address.fromLong(device.getConfig().asHeaderType0().getBaseAddresses()[2].getMemoryBase()); } else { final int physBase = getReg32(SVGA_REG_MEM_START); address = Address.fromIntZeroExtend(physBase); } log.debug("Found FIFO at 0x" + NumberUtils.hex(address.toInt()) + ", size 0x" + NumberUtils.hex(size)); final MemoryResource res = rm.claimMemoryResource(device, address, size, ResourceManager.MEMMODE_NORMAL); final int fifoMin = SVGA_FIFO_NUM_REGS * 4; res.setInt(SVGA_FIFO_MIN * 4, fifoMin); res.setInt(SVGA_FIFO_MAX * 4, size); res.setInt(SVGA_FIFO_NEXT_CMD * 4, fifoMin); res.setInt(SVGA_FIFO_STOP * 4, fifoMin); setReg32(SVGA_REG_CONFIG_DONE, 1); return res; } /** * Gets the size of the video ram in bytes. */ final int getVideoRamSize() { return this.videoRamSize; } /** * Gets the maximum screen height in pixels */ final int getMaxHeight() { return this.maxHeight; } /** * Gets the maximum screen width in pixels */ final int getMaxWidth() { return this.maxWidth; } /** * Gets the number of bits per pixel */ final int getBitsPerPixel() { return this.bitsPerPixel; } /** * Gets the number of bytes per line */ final int getBytesPerLine() { return this.bytesPerLine; } /** * Gets the number of shift needed for the given mask. * <p/> * E.g. getMaskShift(0xFF00) == 8 * * @param mask * @return */ private int getMaskShift(int mask) { if (mask == 0) return 0; int count = 0; while ((mask & 1) == 0) { count++; mask = mask >> 1; } return count; } /** * @see org.jnode.driver.video.Surface#getColorModel() */ public ColorModel getColorModel() { return model; } /** * @see org.jnode.driver.video.HardwareCursorAPI#setCursorPosition(int, int) */ public synchronized void setCursorPosition(int x, int y) { this.curX = x; this.curY = y; setCursor(curVisible, curX, curY); } /** * @see org.jnode.driver.video.HardwareCursorAPI#setCursorVisible(boolean) */ public synchronized void setCursorVisible(boolean visible) { this.curVisible = visible; setCursor(curVisible, curX, curY); } /** * Sets the cursor image. * * @param cursor */ public void setCursorImage(HardwareCursor cursor) { if (hasCapability(SVGA_CAP_ALPHA_CURSOR)) { defineARGBCursor(cursor.getImage(20, 20)); } else { defineCursor(cursor.getImage(20, 20)); } } private static int SVGA_BITMAP_SIZE(int w, int h) { return ((((w) + 31) >> 5) * (h)); } private static int SVGA_PIXMAP_SIZE(int w, int h, int bpp) { return (((((w) * (bpp)) + 31) >> 5) * (h)); } /** * Sets the cursor image. */ private void defineCursor(HardwareCursorImage cursor) { final int[] argb = cursor.getImage(); final int width = cursor.getWidth(); final int height = cursor.getHeight(); final int bpp = getBitsPerPixel(); final int size = width * height; if (argb.length != size) throw new IllegalArgumentException("argb.length != width*height"); final int bmSize = SVGA_BITMAP_SIZE(width, height); final int pmSize = SVGA_PIXMAP_SIZE(width, height, bpp); final int[] andMask = new int[size]; final int[] xorMask = new int[size]; for (int i = 0; i < size; i++) { final int v = argb[i]; final int a = (v >>> 24) & 0xFF; final int r = (v >> 16) & 0xFF; final int g = (v >> 8) & 0xFF; final int b = v & 0xFF; if (a != 0) { // opaque andMask[i] = 0; xorMask[i] = v & convertColor(r, g, b, a); } else { // transparent andMask[i] = 0xFFFFFFFF; xorMask[i] = 0; } } // Wait for the FIFO syncFIFO(); // Command writeWordToFIFO(SVGA_CMD_DEFINE_CURSOR); // Mouse id writeWordToFIFO(MOUSE_ID); // Hotspot X writeWordToFIFO(cursor.getHotSpotX()); // Hotspot Y writeWordToFIFO(cursor.getHotSpotY()); // Width writeWordToFIFO(width); // Height writeWordToFIFO(height); // Depth for AND mask writeWordToFIFO(1); // Depth for XOR mask writeWordToFIFO(bpp); // Scanlines for AND mask for (int i = 0; i < bmSize; i++) { writeWordToFIFO(andMask[i]); } // Scanlines for XOR mask for (int i = 0; i < pmSize; i++) { writeWordToFIFO(xorMask[i]); } } /** * Sets the cursor image. */ private void defineARGBCursor(HardwareCursorImage cursor) { final int[] argb = cursor.getImage(); final int size = cursor.getWidth() * cursor.getHeight(); if (argb.length != size) throw new IllegalArgumentException("argb.length != width*height"); // Wait for the FIFO syncFIFO(); // Command writeWordToFIFO(SVGA_CMD_DEFINE_ALPHA_CURSOR); // Mouse id writeWordToFIFO(MOUSE_ID); // Hotspot X writeWordToFIFO(cursor.getHotSpotX()); // Hotspot Y writeWordToFIFO(cursor.getHotSpotY()); // Width writeWordToFIFO(cursor.getWidth()); // Height writeWordToFIFO(cursor.getHeight()); // Scanlines for (int i = 0; i < size; i++) { writeWordToFIFO(argb[i]); } } private void defineCursor() { // Wait for the FIFO syncFIFO(); final int width = 4; final int height = 4; final int bpp = getBitsPerPixel(); // Command writeWordToFIFO(SVGA_CMD_DEFINE_CURSOR); // Mouse id writeWordToFIFO(MOUSE_ID); // Hotspot X writeWordToFIFO(0); // Hotspot Y writeWordToFIFO(0); // Width writeWordToFIFO(width); // Height writeWordToFIFO(height); // Depth for AND mask writeWordToFIFO(1); // Depth for XOR mask writeWordToFIFO(bpp); // Scanlines for AND mask final int bmSize = SVGA_BITMAP_SIZE(width, height); for (int i = 0; i < bmSize; i++) { writeWordToFIFO(0); } // Scanlines for XOR mask final int pmSize = SVGA_PIXMAP_SIZE(width, height, bpp); for (int i = 0; i < pmSize; i++) { writeWordToFIFO(0xFFFFFF); } syncFIFO(); setCursor(false, 0, 0); } private void setCursor(boolean visible, int x, int y) { if (hasFIFOCapability(SVGA_FIFO_CAP_CURSOR_BYPASS_3)) { setFIFO(SVGA_FIFO_CURSOR_ON, visible ? 1 : 0); setFIFO(SVGA_FIFO_CURSOR_X, x); setFIFO(SVGA_FIFO_CURSOR_Y, y); setFIFO(SVGA_FIFO_CURSOR_COUNT, getFIFO(SVGA_FIFO_CURSOR_COUNT) + 1); } else { setReg32(SVGA_REG_CURSOR_ID, MOUSE_ID); if (visible) { if (hasCapability(SVGA_CAP_CURSOR)) { if (hasCapability(SVGA_CAP_CURSOR_BYPASS)) { // //System.out.println("bypass " + x + ", " + y); setReg32(SVGA_REG_CURSOR_X, x); setReg32(SVGA_REG_CURSOR_Y, y); } else { // System.out.println("move " + x + ", " + y); syncFIFO(); writeWordToFIFO(SVGA_CMD_MOVE_CURSOR); writeWordToFIFO(x); writeWordToFIFO(y); } } } setReg32(SVGA_REG_CURSOR_ON, visible ? 1 : 0); } } /** * Check whether the SVGA device has a particular capability bits. */ private boolean hasCapability(int cap) { return ((this.capabilities & cap) == cap); } /** * Check whether the SVGA device has a particular FIFO capability bits. */ private boolean hasFIFOCapability(int fifoCap) { return (fifoCapabilities & fifoCap) == fifoCap; } /** * Claim an IO port range. */ private IOResource claimPorts(final ResourceManager rm, final ResourceOwner owner, final int low, final int length) throws ResourceNotFreeException, DriverException { try { return AccessControllerUtils.doPrivileged(new PrivilegedExceptionAction<IOResource>() { public IOResource run() throws ResourceNotFreeException { return rm.claimIOResource(owner, low, length); } }); } catch (ResourceNotFreeException ex) { throw ex; } catch (Exception ex) { throw new DriverException("Unknown exception", ex); } } /** * @see org.jnode.driver.video.Surface#drawAlphaRaster(java.awt.image.Raster, * java.awt.geom.AffineTransform, int, int, int, int, int, int, * java.awt.Color) */ public void drawAlphaRaster(Raster raster, AffineTransform tx, int srcX, int srcY, int dstX, int dstY, int width, int height, Color color) { bitmapGraphics.drawAlphaRaster(raster, tx, srcX, srcY, dstX, dstY, width, height, convertColor(color)); } @Override public int getRGBPixel(int x, int y) { return bitmapGraphics.doGetPixel(x, y); } @Override public int[] getRGBPixels(Rectangle region) { return bitmapGraphics.doGetPixels(region); } @Override public void update(int x, int y, int width, int height) { syncFIFO(); updateScreen(x, y, width, height); } public void showInfo(PrintWriter out) { out.println("Capabilities : " + NumberUtils.hex(capabilities)); out.println("FIFO Capabil.: " + NumberUtils.hex(fifoCapabilities)); out.println("Bit/pixel : " + bitsPerPixel); out.println("FIFO_MIN : " + NumberUtils.hex(getFIFO(SVGA_FIFO_MIN))); out.println("FIFO_MAX : " + NumberUtils.hex(getFIFO(SVGA_FIFO_MAX))); out.println("FIFO_NEXT_CMD: " + NumberUtils.hex(getFIFO(SVGA_FIFO_NEXT_CMD))); out.println("FIFO_STOP : " + NumberUtils.hex(getFIFO(SVGA_FIFO_STOP))); } }