OpenJDK / openjfx / 8u-dev / rt
view modules/graphics/src/main/native-glass/lens/lensport/imx6Cursor.c @ 6576:babda162124b
RT-36387 [IMX, Lens] Black rectangle seen instead of cursor on first run after reboot.
Reviewed by dblaukopf, tested with HelloRectangle.
author | Lisa.Selle@oracle.com |
---|---|
date | Mon, 31 Mar 2014 16:57:36 -0400 |
parents | a0a619f9f425 |
children | 7eaadd798f33 |
line wrap: on
line source
/* * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #ifdef IMX6_PLATFORM #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <linux/fb.h> #include <sys/ioctl.h> #include <sys/types.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <dlfcn.h> #include <errno.h> #include <linux/mxcfb.h> // note: i.MX unique header #include "lensPort.h" #include "lensPortInternal.h" #include "lensPortLogger.h" #define LENSFB_IMX6_CURSOR_DEVICE "/dev/fb1" #define LENSFB_IMX6_CURSOR_SIZE 16 typedef struct { int fd; int width; int height; int x,y; int screenWidth; int screenHeight; jlong currentCursor; // When the cursor is at the extreme right or bottom of the screen, it // needs to be shifted to show in the correct location. IMX doesn't let us // position the framebuffer so that it is only partically visible. int xShift; int yShift; jboolean isVisible; } Imx6FBCursor; static Imx6FBCursor cursor = { .fd = -1, .width = 0, .height = 0, .x = 0, .y = 0, .currentCursor = 0, .isVisible = 0, .xShift = 0, .yShift = 0 }; //TODO : platform supports 32 and 16 bits, how do we choose what to use ? static int use32bit = 0; typedef struct { jint width; jint height; jint x; jint y; jbyte* buffer; jint bufferSize; } Imx6CursorImage; static void fbImx6BlankCursor(){ char buffer[256]; int bytesToWrite; // Set buffer to be transparent memset((void*)buffer, use32bit ? 0 : LENSFB_16_CURSOR_COLOR_KEY, sizeof(buffer)); if (lseek(cursor.fd, 0, SEEK_SET) == -1) { GLASS_LOG_SEVERE("Cannot rewrite cursor image"); return; } bytesToWrite = cursor.width * cursor.height * (use32bit ? 4 : 2); while (bytesToWrite > 0) { int n = bytesToWrite > sizeof(buffer) ? sizeof(buffer) : bytesToWrite; int res; if ((res = write(cursor.fd, buffer, n)) < n) { GLASS_LOG_SEVERE("Cannot write cursor plane %i bytes, wrote %i bytes", n, res); return; } bytesToWrite -= n; } } /* Updates values of xShift and yShift based on the cursor location */ static void fbImx6AdjustShift(){ if (cursor.x > cursor.screenWidth - cursor.width) { cursor.xShift = cursor.width + cursor.x - cursor.screenWidth; } else { cursor.xShift = 0; } if (cursor.y > cursor.screenHeight - cursor.height) { cursor.yShift = cursor.height + cursor.y - cursor.screenHeight; } else { cursor.yShift = 0; } } /* Writes an image into the cursor framebuffer with the given x and y shits. */ static void fbImx6WriteCursor(int fd, jbyte *cursorImage, int bpp) { int i, j, k; char buffer[256]; int cursorSize = cursor.width * cursor.height * bpp; int xShift = cursor.xShift; int yShift = cursor.yShift; if (!cursor.isVisible) { return; } if (lseek(cursor.fd, 0, SEEK_SET) == -1) { GLASS_LOG_SEVERE("Cannot rewrite cursor image"); return; } GLASS_LOG_FINEST("Cursor shift = (%i, %i) at (%i, %i)\n", xShift, yShift, cursor.x, cursor.y); if (xShift == 0 && yShift == 0) { GLASS_LOG_FINEST("write(cursor.fd, .. %i)", cursorSize); if ((i = write(cursor.fd, cursorImage, cursorSize)) < cursorSize) { GLASS_LOG_SEVERE("Cannot write cursor plane cursorSize : %i, wrote %i bytes", cursorSize, i); } return; } // Set buffer to be transparent memset((void*)buffer, use32bit ? 0 : LENSFB_16_CURSOR_COLOR_KEY, sizeof(buffer)); // fill the y-shift rectangular area for (i = 0; i < yShift; i++) { for (j = 0; j < cursor.width * bpp; j += sizeof(buffer)) { size_t n = cursor.width * bpp - j; if (n > sizeof(buffer)) { n = sizeof(buffer); } GLASS_LOG_FINEST("write(cursor.fd, .. %u)", n); if (write(cursor.fd, buffer, n) < (int)n) { GLASS_LOG_SEVERE("Cannot write cursor plane"); return; } } } // set the rest of the image for (i = 0; i < cursor.height - yShift; i++) { for (j = 0; j < xShift * bpp; j += sizeof(buffer)) { size_t n = xShift * bpp; if (n > sizeof(buffer)) { n = sizeof(buffer); } GLASS_LOG_FINEST("write(cursor.fd, .. %u)", n); if (write(cursor.fd, buffer, n) < (int)n) { GLASS_LOG_SEVERE("Cannot write cursor plane"); return; } } size_t n = (cursor.width - xShift) * bpp; GLASS_LOG_FINEST("write(cursor.fd, .. %u)", n); if (write(cursor.fd, cursorImage + i * cursor.width * bpp, n) < (int)n) { GLASS_LOG_SEVERE("Cannot write cursor plane"); return; } } } static int fbImx6ChangeCursorSize(int width, int height) { struct fb_var_screeninfo screenInfo; if (ioctl(cursor.fd, FBIOGET_VSCREENINFO, &screenInfo)) { GLASS_LOG_SEVERE("Error %s in getting screen info", strerror(errno)); return -1; } screenInfo.xres = width; screenInfo.yres = height; screenInfo.xres_virtual = width; screenInfo.yres_virtual = height; screenInfo.xoffset = 0; screenInfo.yoffset = 0; screenInfo.activate = 0; if(ioctl(cursor.fd, FBIOPUT_VSCREENINFO, &screenInfo)) { GLASS_LOG_SEVERE("Error %s in setting screen info", strerror(errno)); return -1; } cursor.width = width; cursor.height = height; return 0; } static void fbImx6CursorInitialize(int screenWidth, int screenHeight, int screenDepth) { struct fb_var_screeninfo screenInfo; int rc; char * zero = "0\n"; int fbc = -1; int fbo = -1; //TODO : the following 2 settings can be moved to a setup script procedure if ((fbc = open("/sys/class/graphics/fbcon/cursor_blink",O_RDWR)) < 0) { GLASS_LOG_SEVERE("Error %s in opening /sys/class/graphics/fbcon/cursor_blink", strerror(errno)); } else { write(fbc,zero,1); close(fbc); } if ((fbo = open("/sys/class/graphics/fb1/blank", O_RDWR)) < 0) { GLASS_LOG_SEVERE("Error %s in opening /sys/class/graphics/fb1/blank", strerror(errno)); } else { write(fbo,zero,1); close(fbo); } // Init cursor global variable fields cursor.width = LENSFB_IMX6_CURSOR_SIZE; cursor.height = LENSFB_IMX6_CURSOR_SIZE; cursor.x = 0; cursor.y = 0; cursor.currentCursor = 0; cursor.isVisible = 0; cursor.screenWidth = screenWidth; cursor.screenHeight = screenHeight; cursor.fd = open(LENSFB_IMX6_CURSOR_DEVICE, O_RDWR); if (cursor.fd < 0) { GLASS_LOG_SEVERE("Cannot open framebuffer device %s",LENSFB_IMX6_CURSOR_DEVICE); return; } if (ioctl(cursor.fd, FBIOGET_VSCREENINFO, &screenInfo)) { GLASS_LOG_SEVERE("Error %s in getting screen info", strerror(errno)); return; } GLASS_LOG_INFO("Initializing %d bits pixel %dx%d cursor, current %d bits\n", (use32bit ? 32 : 16), LENSFB_IMX6_CURSOR_SIZE, LENSFB_IMX6_CURSOR_SIZE, screenInfo.bits_per_pixel); screenInfo.xres = LENSFB_IMX6_CURSOR_SIZE; screenInfo.yres = LENSFB_IMX6_CURSOR_SIZE; screenInfo.xres_virtual = LENSFB_IMX6_CURSOR_SIZE; screenInfo.yres_virtual = LENSFB_IMX6_CURSOR_SIZE; screenInfo.xoffset = 0; screenInfo.yoffset = 0; screenInfo.activate = 0; if (use32bit) { screenInfo.bits_per_pixel = 32; screenInfo.red.length = 8; screenInfo.red.offset = 16; screenInfo.green.length = 8; screenInfo.green.offset = 8; screenInfo.blue.length = 8; screenInfo.blue.offset = 0; screenInfo.transp.length = 8; screenInfo.transp.offset = 24; } else { // 565 screenInfo.bits_per_pixel = 16; screenInfo.red.length = 5; screenInfo.red.offset = 11; screenInfo.green.length = 6; screenInfo.green.offset = 5; screenInfo.blue.length = 5; screenInfo.blue.offset = 0; screenInfo.transp.length = 0; screenInfo.transp.offset = 0; } if(ioctl(cursor.fd, FBIOPUT_VSCREENINFO, &screenInfo)) { GLASS_LOG_SEVERE("Error %s in setting screen info", strerror(errno)); return; } if(ioctl(cursor.fd, FBIOBLANK, FB_BLANK_UNBLANK)) { GLASS_LOG_SEVERE("Error %s in gstting cursor no-blanking", strerror(errno)); return; } if (use32bit) { // alpha is taken from each pixel struct mxcfb_loc_alpha loc_alpha; loc_alpha.enable = 1; loc_alpha.alpha_in_pixel = 1; if (ioctl(cursor.fd, MXCFB_SET_LOC_ALPHA, &loc_alpha) < 0) { GLASS_LOG_SEVERE("Error %s in setting local alpha", strerror(errno)); } } else { struct mxcfb_color_key color_key; color_key.color_key = RGB565TOCOLORKEY(LENSFB_16_CURSOR_COLOR_KEY); color_key.enable = 1; if ( ioctl(cursor.fd, MXCFB_SET_CLR_KEY, &color_key) < 0) { GLASS_LOG_SEVERE("Error %s in setting 16 bits color key", strerror(errno)); } struct mxcfb_gbl_alpha gbl_alpha; gbl_alpha.alpha = 255; gbl_alpha.enable = 1; if(ioctl(cursor.fd, MXCFB_SET_GBL_ALPHA, &gbl_alpha) < 0) { GLASS_LOG_SEVERE("Error %s in setting global alpha", strerror(errno)); } } struct mxcfb_pos cpos = {(screenWidth - 16)/2, (screenHeight - 16)/2}; if (ioctl(cursor.fd, MXCFB_SET_OVERLAY_POS, &cpos)) { GLASS_LOG_SEVERE("Error %s in setting overlay position", strerror(errno)); } fbImx6BlankCursor(); } static jlong fbImx6CreateNativeCursor(JNIEnv *env, jint x, jint y, jbyte *srcArray, jint width, jint height) { Imx6CursorImage *cursorImage = (Imx6CursorImage *)malloc(sizeof(Imx6CursorImage)); cursorImage->x = x; cursorImage->y = y; cursorImage->width = width; cursorImage->height = height; cursorImage->bufferSize = width * height * (use32bit ? 4 : 2); cursorImage->buffer = (jbyte*)malloc(cursorImage->bufferSize); GLASS_LOG_INFO("Creating x : %d y : %d width : %d height : %d cursor %d bits per pixel",x, y, width, height, (use32bit ? 32 : 16)); if (use32bit) { memcpy((void*)(cursorImage->buffer), srcArray, cursorImage->bufferSize); } else { //565 int i; uint16_t* dst = (uint16_t*)(cursorImage->buffer); uint32_t* src = (uint32_t*)srcArray; for (i = 0; i < cursorImage->bufferSize; i += 2) { int pixel = *src++; if ((pixel & 0xff000000) != 0) { *dst++ = ((pixel >> 8) & 0xf800) | ((pixel >> 5) & 0x7e0) | ((pixel >> 3) & 0x1f); } else { *dst++ = LENSFB_16_CURSOR_COLOR_KEY; } } } return ptr_to_jlong(cursorImage); } static void fbImx6ReleaseNativeCursor(jlong nativeCursorHandle) { Imx6CursorImage *cursorImage = (Imx6CursorImage *)jlong_to_ptr(nativeCursorHandle); if (cursorImage->buffer != NULL) { free(cursorImage->buffer); } free(cursorImage); } static void fbImx6SetNativeCursor(jlong nativeCursorHandle) { Imx6CursorImage *cursorImage = (Imx6CursorImage *)jlong_to_ptr(nativeCursorHandle); if (cursor.fd != -1 && cursor.currentCursor != nativeCursorHandle && cursorImage != NULL && cursorImage->buffer != NULL) { if (cursorImage->width != cursor.width || cursorImage->height != cursor.height) { fbImx6BlankCursor(); if (fbImx6ChangeCursorSize(cursorImage->width, cursorImage->height)) { GLASS_LOG_SEVERE("Error in fbImx6ChangeCursorSize() w : %d h : %d", cursorImage->width, cursorImage->height); return; } } cursor.currentCursor = nativeCursorHandle; fbImx6AdjustShift(); fbImx6WriteCursor(cursor.fd, cursorImage->buffer, use32bit ? 4 : 2); } } static void fbImx6CursorSetPosition(int x, int y) { int xShift = cursor.xShift; int yShift = cursor.yShift; if (x < 0) { x = 0; } if (y < 0) { y = 0; } if (x > cursor.screenWidth - 1) { x = cursor.screenWidth - 1; } if (y > cursor.screenHeight - 1) { y = cursor.screenHeight - 1; } cursor.x = x; cursor.y = y; if (cursor.isVisible) { fbImx6AdjustShift(); x -= cursor.xShift; y -= cursor.yShift; if (xShift != cursor.xShift || yShift != cursor.yShift) { GLASS_LOG_FINEST("Calling lseek to rewind cursor fd"); Imx6CursorImage *fbCursorImage = (Imx6CursorImage *) jlong_to_ptr(cursor.currentCursor); fbImx6WriteCursor(cursor.fd, fbCursorImage->buffer, use32bit ? 4 : 2); } struct mxcfb_pos cpos = {x, y}; if (ioctl(cursor.fd, MXCFB_SET_OVERLAY_POS, &cpos)) { GLASS_LOG_SEVERE("Error %s in setting overlay position", strerror(errno)); } } } void fbImx6CursorClose() { if (cursor.fd >= 0) { if (cursor.isVisible) { fbImx6BlankCursor(); } close(cursor.fd); cursor.fd = -1; cursor.isVisible = 0; cursor.currentCursor = 0; cursor.width = 0; cursor.height = 0; } } static void fbImx6SetVisible(jboolean isVisible) { if (isVisible) { if (!cursor.isVisible && cursor.currentCursor != 0) { cursor.isVisible = 1; Imx6CursorImage *fbCursorImage = (Imx6CursorImage *) jlong_to_ptr(cursor.currentCursor); fbImx6WriteCursor(cursor.fd, fbCursorImage->buffer, use32bit ? 4 : 2); } } else { if (cursor.isVisible) { fbImx6BlankCursor(); } cursor.isVisible = 0; } } static char * platformName = "imx6"; jboolean check_imx6_cursor(LensNativePort *lensPort) { if (access("/dev/mxc_vpu", F_OK) == 0) { lensPort->platformName = platformName; lensPort->setNativeCursor = fbImx6SetNativeCursor; lensPort->cursorInitialize = fbImx6CursorInitialize; lensPort->cursorSetPosition = fbImx6CursorSetPosition; lensPort->cursorClose = fbImx6CursorClose; lensPort->createNativeCursor = fbImx6CreateNativeCursor; lensPort->releaseNativeCursor = fbImx6ReleaseNativeCursor; lensPort->setVisible = fbImx6SetVisible; lensPort->cursorTranslucency = (use32bit ? JNI_TRUE : JNI_FALSE); return JNI_TRUE; } return JNI_FALSE; } #endif // IMX6_PLATFORM