Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8227425: Add support for e-paper displays on i.MX6 devices #60

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -69,6 +69,11 @@
*/
private static final int POWERDOWN_DELAY = 1_000;

/**
* Linux system error: ENOTTY 25 Inappropriate ioctl for device.
*/
private static final int ENOTTY = 25;

private final PlatformLogger logger = Logging.getJavaFXLogger();
private final EPDSettings settings;
private final LinuxSystem system;
@@ -296,6 +301,16 @@ private MxcfbUpdateData createDefaultUpdate(int width, int height) {
* <li>{@link EPDSystem#WAVEFORM_MODE_A2}</li>
* </ul>
*
* @implNote This method fails on the Kobo Glo HD Model N437 with the error
* ENOTTY (25), "Inappropriate ioctl for device." The driver on that device
* uses an extended structure with four additional integers, changing its
* size and its corresponding request code. This method could use the
* extended structure, but the driver on the Kobo Glo HD ignores it and
* returns immediately, anyway. Furthermore, newer devices support both the
* current structure and the extended one, but define the extra fields in a
* different order. Therefore, simply use the current structure and ignore
* an error of ENOTTY, picking up the default values for any extra fields.
*
* @param init the initialization mode for clearing the screen to all white
* @param du the direct update mode for changing any gray values to either
* all black or all white
@@ -308,7 +323,7 @@ private void setWaveformModes(int init, int du, int gc4, int gc8, int gc16, int
var modes = new MxcfbWaveformModes();
modes.setModes(modes.p, init, du, gc4, gc8, gc16, gc32);
int rc = system.ioctl(fd, driver.MXCFB_SET_WAVEFORM_MODES, modes.p);
if (rc != 0) {
if (rc != 0 && system.errno() != ENOTTY) {
logger.severe("Failed setting waveform modes: {0} ({1})",
system.getErrorMessage(), system.errno());
}
@@ -325,7 +340,7 @@ private void setWaveformModes(int init, int du, int gc4, int gc8, int gc16, int
private void setTemperature(int temp) {
int rc = driver.ioctl(fd, driver.MXCFB_SET_TEMPERATURE, temp);
if (rc != 0) {
logger.severe("Failed setting temperature to {2} °C: {0} ({1})",
logger.severe("Failed setting temperature to {2} degrees Celsius: {0} ({1})",
system.getErrorMessage(), system.errno(), temp);
}
}
@@ -421,7 +436,7 @@ private int sendUpdate(MxcfbUpdateData update, int waveformMode) {
logger.severe("Failed sending update {2}: {0} ({1})",
system.getErrorMessage(), system.errno(), Integer.toUnsignedLong(updateMarker));
} else if (logger.isLoggable(Level.FINER)) {
logger.finer("Sent update: {0} × {1}, waveform {2}, selected {3}, flags 0x{4}, marker {5}",
logger.finer("Sent update: {0} x {1}, waveform {2}, selected {3}, flags 0x{4}, marker {5}",
update.getUpdateRegionWidth(update.p), update.getUpdateRegionHeight(update.p),
waveformMode, update.getWaveformMode(update.p),
Integer.toHexString(update.getFlags(update.p)).toUpperCase(),
@@ -482,7 +497,7 @@ private int getPowerdownDelay() {
logger.severe("Failed getting power-down delay: {0} ({1})",
system.getErrorMessage(), system.errno());
}
return integer.getInteger(integer.p);
return integer.get(integer.p);
}

/**
@@ -571,20 +586,57 @@ ByteBuffer getOffscreenBuffer() {
* "QuantumRenderer modifies buffer in use by JavaFX Application Thread"
* <https://bugs.openjdk.java.net/browse/JDK-8201567>.
*/
int size = xresVirtual * yresVirtual * Integer.SIZE;
int size = xresVirtual * yres * Integer.BYTES;
return ByteBuffer.allocateDirect(size);
}

/**
* Creates a new mapping of the Linux frame buffer device into memory.
*
* @implNote The virtual y-resolution reported by the device driver can be
* wrong, as shown by the following example on the Kobo Glo HD Model N437
* which reports 2,304 pixels when the correct value is 1,152 pixels
* (6,782,976 / 5,888). Therefore, this method cannot use the frame buffer
* virtual resolution to calculate its size.
*
* <pre>{@code
* $ sudo fbset -i
*
* mode "1448x1072-46"
* # D: 80.000 MHz, H: 50.188 kHz, V: 46.385 Hz
* geometry 1448 1072 1472 2304 32
* timings 12500 16 102 4 4 28 2
* rgba 8/16,8/8,8/0,8/24
* endmode
*
* Frame buffer device information:
* Name : mxc_epdc_fb
* Address : 0x88000000
* Size : 6782976
* Type : PACKED PIXELS
* Visual : TRUECOLOR
* XPanStep : 1
* YPanStep : 1
* YWrapStep : 0
* LineLength : 5888
* Accelerator : No
* }</pre>
*
* @return a byte buffer containing the mapping of the Linux frame buffer
* device
* device if successful; otherwise {@code null}
*/
ByteBuffer getMappedBuffer() {
int size = xresVirtual * yresVirtual * bytesPerPixel;
ByteBuffer buffer = null;
int size = xresVirtual * yres * bytesPerPixel;
logger.fine("Mapping frame buffer: {0} bytes", size);
long addr = system.mmap(0l, size, LinuxSystem.PROT_WRITE, LinuxSystem.MAP_SHARED, fd, 0);
return addr == LinuxSystem.MAP_FAILED ? null : C.getC().NewDirectByteBuffer(addr, size);
if (addr == LinuxSystem.MAP_FAILED) {
logger.severe("Failed mapping {2} bytes of frame buffer: {0} ({1})",
system.getErrorMessage(), system.errno(), size);
} else {
buffer = C.getC().NewDirectByteBuffer(addr, size);
}
return buffer;
}

/**
@@ -594,7 +646,13 @@ ByteBuffer getMappedBuffer() {
* buffer device
*/
void releaseMappedBuffer(ByteBuffer buffer) {
system.munmap(C.getC().GetDirectBufferAddress(buffer), buffer.capacity());
int size = buffer.capacity();
logger.fine("Unmapping frame buffer: {0} bytes", size);
int rc = system.munmap(C.getC().GetDirectBufferAddress(buffer), size);
if (rc != 0) {
logger.severe("Failed unmapping {2} bytes of frame buffer: {0} ({1})",
system.getErrorMessage(), system.errno(), size);
}
}

/**
@@ -614,26 +672,31 @@ long getNativeHandle() {
}

/**
* Gets the virtual horizontal resolution of the frame buffer. See the notes
* for the {@linkplain EPDFrameBuffer#EPDFrameBuffer constructor} above.
* Gets the frame buffer width in pixels. See the notes for the
* {@linkplain EPDFrameBuffer#EPDFrameBuffer constructor} above.
*
* @implNote When using an 8-bit, unrotated, and uninverted frame buffer in
* the Y8 pixel format, the Kobo Clara HD Model N249 works only when this
* method returns the visible x-resolution ({@code xres}) instead of the
* normal virtual x-resolution ({@code xresVirtual}).
*
* @return the virtual width in pixels
* @return the width in pixels
*/
int getWidth() {
return xresVirtual;
return settings.getWidthVisible ? xres : xresVirtual;
}

/**
* Gets the visible vertical resolution of the frame buffer.
* Gets the frame buffer height in pixels.
*
* @return the visible height in pixels
* @return the height in pixels
*/
int getHeight() {
return yres;
}

/**
* Gets the color depth of the frame buffer.
* Gets the frame buffer color depth in bits per pixel.
*
* @return the color depth in bits per pixel
*/
@@ -60,7 +60,7 @@

/**
* The density of this screen in pixels per inch. For now, the value is
* hard-coded to the density of a 6-inch display panel with 800 × 600 px at
* hard-coded to the density of a 6-inch display panel with 800 x 600 px at
* 167 ppi.
*/
private static final int DPI = 167;
@@ -99,6 +99,8 @@
width = fbDevice.getWidth();
height = fbDevice.getHeight();
bitDepth = fbDevice.getBitDepth();
logger.fine("Native screen geometry: {0} px x {1} px x {2} bpp",
width, height, bitDepth);

/*
* If the Linux frame buffer is configured for 32-bit color, compose
@@ -112,8 +114,12 @@
* display, though, allows us to reuse the same frame buffer region
* immediately after sending an update.
*/
ByteBuffer mapping = null;
if (bitDepth == Integer.SIZE) {
fbMapping = fbDevice.getMappedBuffer();
mapping = fbDevice.getMappedBuffer();
}
if (mapping != null) {
fbMapping = mapping;
fbChannel = null;
} else {
Path path = FileSystems.getDefault().getPath(fbPath);
ProTip! Use n and p to navigate between commits in a pull request.