/* * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package com.sun.glass.ui.monocle; import java.io.IOException; import java.nio.ByteBuffer; class LinuxFrameBuffer { private long fd; private LinuxSystem system; private LinuxSystem.FbVarScreenInfo screenInfo; private int width; private int height; private int bitDepth; private int byteDepth; private int offsetX, offsetY; private int offsetY1, offsetY2; private int offsetX1, offsetX2; private int state; // 0 = single buffer, 1 = showing buf 1, 2 = showing buf 2 private int FBIO_WAITFORVSYNC; LinuxFrameBuffer(String devNode) throws IOException { system = LinuxSystem.getLinuxSystem(); FBIO_WAITFORVSYNC = system.IOW('F', 0x20, 4); fd = system.open(devNode, LinuxSystem.O_RDWR); if (fd == -1) { throw new IOException(system.getErrorMessage()); } screenInfo = new LinuxSystem.FbVarScreenInfo(); if (system.ioctl(fd, LinuxSystem.FBIOGET_VSCREENINFO, screenInfo.p) != 0) { system.close(fd); throw new IOException(system.getErrorMessage()); } bitDepth = screenInfo.getBitsPerPixel(screenInfo.p); byteDepth = bitDepth >>> 3; width = screenInfo.getXRes(screenInfo.p); height = screenInfo.getYRes(screenInfo.p); int virtualWidth = screenInfo.getXResVirtual(screenInfo.p); int virtualHeight = screenInfo.getYResVirtual(screenInfo.p); offsetX = screenInfo.getOffsetX(screenInfo.p); offsetY = screenInfo.getOffsetY(screenInfo.p); if (virtualHeight >= height * 2) { if (offsetY >= height) { offsetY1 = offsetY; offsetY2 = 0; } else if (virtualHeight - offsetY >= height * 2) { offsetY1 = offsetY; offsetY2 = offsetY + height; } else { offsetY1 = 0; offsetY2 = width * byteDepth; } offsetX1 = offsetX2 = offsetX; state = 1; } else if (virtualWidth >= width * 2) { if (offsetX >= width) { offsetX1 = offsetX; offsetX2 = 0; } else if (virtualWidth - offsetX >= width * 2) { offsetX1 = offsetX; offsetX2 = offsetX + height; } else { offsetX1 = 0; offsetX2 = width * byteDepth; } offsetY1 = offsetY2 = offsetY; state = 1; } } boolean canDoubleBuffer() { return state != 0; } int getNativeOffset() { int nativeOffsetX = screenInfo.getOffsetX(screenInfo.p); int nativeOffsetY = screenInfo.getOffsetY(screenInfo.p); if (system.ioctl(fd, LinuxSystem.FBIOGET_VSCREENINFO, screenInfo.p) == 0) { nativeOffsetX = screenInfo.getOffsetX(screenInfo.p); nativeOffsetY = screenInfo.getOffsetY(screenInfo.p); } return (nativeOffsetY * width) * byteDepth; } int getNextAddress() { switch (state) { case 1: return (offsetX2 + offsetY2 * width) * byteDepth; case 2: return (offsetX1 + offsetY1 * width) * byteDepth; default: return (offsetX + offsetY * width) * byteDepth; } } void next() throws IOException { if (state != 0) { int newOffsetX, newOffsetY; if (state == 1) { newOffsetX = offsetX2; newOffsetY = offsetY2; } else { newOffsetX = offsetX1; newOffsetY = offsetY1; } screenInfo.setActivate(screenInfo.p, LinuxSystem.FB_ACTIVATE_VBL); screenInfo.setOffset(screenInfo.p, newOffsetX, newOffsetY); if (system.ioctl(fd, LinuxSystem.FBIOPAN_DISPLAY, screenInfo.p) != 0) { // turn off double-buffering and don't try to pan again state = 0; throw new IOException(system.getErrorMessage()); } else { offsetX = newOffsetX; offsetY = newOffsetY; state = 3 - state; } } } void vSync() { system.ioctl(fd, FBIO_WAITFORVSYNC, 0); } ByteBuffer getMappedBuffer() { int mappedFBSize = screenInfo.getXResVirtual(screenInfo.p) * screenInfo.getYResVirtual(screenInfo.p) * byteDepth; long addr = system.mmap(0l, mappedFBSize, LinuxSystem.PROT_WRITE, LinuxSystem.MAP_SHARED, fd, 0); if (addr != LinuxSystem.MAP_FAILED) { return C.getC().NewDirectByteBuffer(addr, mappedFBSize); } return null; } void releaseMappedBuffer(ByteBuffer b) { system.munmap(C.getC().GetDirectBufferAddress(b), b.capacity()); } void close() { system.close(fd); } boolean isDoubleBuffer() { return state > 0; } int getWidth() { return width; } int getHeight() { return height; } int getDepth() { return bitDepth; } }