Package org.jnode.driver.video.vmware

Source Code of org.jnode.driver.video.vmware.VMWareCore

/*
* $Id$
*
* Copyright (C) 2003-2014 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)));
    }
}
TOP

Related Classes of org.jnode.driver.video.vmware.VMWareCore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.