/* * $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.ati.radeon; import java.util.HashMap; import org.apache.log4j.Logger; import org.jnode.driver.video.HardwareCursor; import org.jnode.driver.video.HardwareCursorAPI; import org.jnode.driver.video.HardwareCursorImage; import org.jnode.system.resource.MemoryResource; import org.jnode.system.resource.ResourceNotFreeException; import org.jnode.util.NumberUtils; /** * @author Ewout Prangsma (epr@users.sourceforge.net) */ public class RadeonHardwareCursor implements RadeonConstants, HardwareCursorAPI { /** My logger */ private static final Logger log = Logger.getLogger(RadeonHardwareCursor.class); /** Radeon register accessor */ private final RadeonVgaIO io; /** Map between HardwareCursorImage and short[] */ private final HashMap<HardwareCursorImage, byte[]> cursorCache = new HashMap<HardwareCursorImage, byte[]>(); /** Memory reserved for cursor images */ private final MemoryResource cursorMem; private int horzOffset; private int vertOffset; /** * Initialize this instance. * * @param io */ public RadeonHardwareCursor(RadeonCore kernel, RadeonVgaIO io) throws IndexOutOfBoundsException, ResourceNotFreeException { this.io = io; this.cursorMem = kernel.claimDeviceMemory(4096, 16); log.debug("Cursor memory at offset 0x" + NumberUtils.hex(cursorMem.getOffset().toInt())); } /** * @see org.jnode.driver.video.HardwareCursorAPI#setCursorImage(org.jnode.driver.video.HardwareCursor) */ public void setCursorImage(HardwareCursor cursor) { // Background color io.setReg32(CUR_CLR0, 0xffffff); // Foreground color io.setReg32(CUR_CLR1, 0); // Set shape final byte[] cur = getCursor(cursor); if (cur != null) { io.setReg32(CUR_HORZ_VERT_OFF, vertOffset + (horzOffset << 16)); cursorMem.setBytes(cur, 0, 0, 1024); } } /** * @see org.jnode.driver.video.HardwareCursorAPI#setCursorPosition(int, int) */ public void setCursorPosition(int x, int y) { // if upper-left corner of cursor is outside of // screen, we have to use special registers to clip it int xorigin = 0; int yorigin = 0; if (x < 0) { xorigin = -x; } if (y < 0) { yorigin = -y; } // Radeon_WaitForFifo( ai, 3 ); io.setReg32(CUR_HORZ_VERT_OFF, CUR_LOCK | ((xorigin + horzOffset) << 16) | (yorigin + vertOffset)); io.setReg32(CUR_HORZ_VERT_POSN, CUR_LOCK | (((xorigin != 0) ? 0 : x) << 16) | ((yorigin != 0) ? 0 : y)); io.setReg32(CUR_OFFSET, (int) cursorMem.getOffset().toInt() + xorigin + yorigin * 16); } /** * @see org.jnode.driver.video.HardwareCursorAPI#setCursorVisible(boolean) */ public void setCursorVisible(boolean visible) { int tmp = io.getReg32(CRTC_GEN_CNTL); if (visible) { tmp |= CRTC_CUR_EN; } else { tmp &= ~CRTC_CUR_EN; } io.setReg32(CRTC_GEN_CNTL, tmp); } /** * Close this hw cursor */ final void close() { setCursorVisible(false); } private byte[] getCursor(HardwareCursor cursor) { final HardwareCursorImage img = cursor.getImage(32, 32); if (img == null) { return null; } final int w = img.getWidth(); final int h = img.getHeight(); horzOffset = 64 - w; vertOffset = 64 - h; byte[] res = (byte[]) cursorCache.get(img); if (res == null) { res = new byte[1024]; final int[] argb = img.getImage(); for (int row = 0; row < h; row++) { final int imgOfs = row * w; final int resOfs = row * 16; for (int x = 0; x < w; x++) { final int resRowIdx = resOfs + (((64 - w) + x) >> 3); final int resRowBit = 1 << (7 - (((64 - w) + x) & 7)); final int v = argb[imgOfs + x]; 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 if (((r + g + b) / 3) >= 128) { // White (CUR_CLR0) // and:0, xor:0 } else { // Black (CUR_CLR1) // and:0, xor:1 res[resRowIdx + 8] |= resRowBit; } } else { // Transparent // and:1, xor:0 res[resRowIdx] |= resRowBit; } } } cursorCache.put(img, res); } return res; } }