Skip to content

Commit

Permalink
big color accuracy improvements when using HDR (#263)
Browse files Browse the repository at this point in the history
- ***Breaking changes***: requires `Glow Worm Luciferin` firmware (v5.19.4).   
- **Color accuracy has been significantly improved when using HDR contents.** Closes [#268](#268).
- New [color orders](https://github.com/sblantipodi/firefly_luciferin/wiki/RGB-and-RGBW-support#how-to-change-color-order) to support newer LED strips.
- Get command path dynamically for restarting. Closes [#262](#262). Thanks @Ape for the PR.
- Fix "Sources not selected" crash on Wayland. Closes [#264](#264). Thanks @Ape for the PR.
- OnBoard-Led managment for esp8266. Closes [#266](#266).
- When setting a low brightness color on Firefly Luciferin, it’s not possible to increase the brightness in the [web interface](https://github.com/sblantipodi/firefly_luciferin/wiki/Remote-Access#luciferin-web-interface). Fixed.
- Fix "Slow rainbow" effect switching to "Solid" automatically.
  • Loading branch information
sblantipodi authored Jan 19, 2025
1 parent 4a0e4fe commit fcb28fb
Show file tree
Hide file tree
Showing 18 changed files with 584 additions and 98 deletions.
46 changes: 20 additions & 26 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,26 @@ a {

### In this release

- ***Breaking changes***: requires `Glow Worm Luciferin` firmware (v5.19.4).
- **Color accuracy has been significantly improved when using HDR contents.**
Closes [#268](https://github.com/sblantipodi/firefly_luciferin/issues/268).
-

New [color orders](https://github.com/sblantipodi/firefly_luciferin/wiki/RGB-and-RGBW-support#how-to-change-color-order)
to support newer LED strips.

- Get command path dynamically for restarting. Closes [#262](https://github.com/sblantipodi/firefly_luciferin/pull/262).
Thanks @Ape for the PR.
- Fix "Sources not selected" crash on Wayland. Closes [#264](https://github.com/sblantipodi/firefly_luciferin/pull/264).
Thanks @Ape for the PR.
- OnBoard-Led managment for esp8266. Closes [#266](https://github.com/sblantipodi/firefly_luciferin/pull/266).
- When setting a low brightness color on Firefly Luciferin, it’s not possible to increase the brightness in
the [web interface](https://github.com/sblantipodi/firefly_luciferin/wiki/Remote-Access#luciferin-web-interface).
Fixed.
- Fix "Slow rainbow" effect switching to "Solid" automatically.

### In the previous releases:

- ***Breaking changes***: requires `Glow Worm Luciferin` firmware (v5.18.2).
- The priority of UDP packets in wireless mode has been increased to signal to the router that Luciferin traffic
requires lower latency than standard packets.
Expand All @@ -46,30 +66,4 @@ a {
Closes [#261](https://github.com/sblantipodi/firefly_luciferin/pull/261).
- The snap version was crashing at startup when there were temporary files created by other instances of Firefly Luciferin on the system. Fixed.

### In the previous releases:

- ***Breaking changes***: requires `Glow Worm Luciferin` firmware (v5.17.8).
- **Capture pipeline has been optimized for DX12 on Windows.** Previously, under heavy GPU load, capture framerates would drop significantly, causing occasional LED stuttering. Now, the pipeline has been restructured to better utilize hardware resources, completely eliminating stuttering. This change, along with the previous SIMD extension released with the previous version of Firefly Luciferin, makes Luciferin one of the most optimized and fastest software for bias lighting available at the moment.
- **New effects and improvements to the existing ones.**
- **Firefly Luciferin is now able to run on a Linux sandbox:**
- **Added support for Flatpak** with immediate availability on **[Flathub](https://flathub.org/apps/org.dpsoftware.FireflyLuciferin)**. Closes [#207](https://github.com/sblantipodi/firefly_luciferin/issues/207).
- **Added support for Snap** with immediate availability on **[Snap Store](https://snapcraft.io/fireflyluciferin)**.
- **The response latency during Linux screen capture has been widely reduced.**
- **Added a [Tray icon](https://github.com/sblantipodi/firefly_luciferin/wiki/Linux-support#luciferin-supports-wayland) and minimize to tray on Linux.** Thanks @sorcererlc for the continued support. Closes [#234](https://github.com/sblantipodi/firefly_luciferin/issues/234).
- **New non intrusive [notification](https://github.com/sblantipodi/firefly_luciferin/wiki/Linux-support#luciferin-supports-wayland) system on Linux.**
- **The `Info` menu now displays the current CPU latency.** Lower values indicate better performance. This value can be
influenced by your screen resolution, capture area dimensions, CPU/RAM overclocking, and AVX extensions available on
the CPU.
- **Home Assistant: Luciferin entities are now grouped under one devices**, these entites has been renamed:
- light.glow_worm_luciferin -> light.luciferin_switch
- sensor.firefly_luciferin_consuming -> sensor.luciferin_firefly_consuming
- sensor.glow_worm_luciferin_consuming -> sensor.luciferin_glow_worm_consuming
- sensor.last_update_glow_worm_luciferin -> sensor.luciferin_last_update_glow_worm
- sensor.firefly_luciferin_producing -> sensor.luciferin_firefly_producing
- sensor.glow_worm_luciferin_version -> sensor.luciferin_glow_worm_version
- button.reboot_glow_worm_luciferin -> button.luciferin_reboot_glow_worm
- [Update notifications](https://github.com/sblantipodi/firefly_luciferin/wiki/Luciferin-update-management) are now less intrusive and no longer launch the update popup at computer startup. A simple notification informs about the available update, and you can proceed to install it by right-clicking on the tray icon and selecting 'install updates'.
- Linux Wayland didn't ask you which screen to record when the recording permission expired. Fixed.
- [Power saving](https://github.com/sblantipodi/firefly_luciferin/wiki/Power-saving-features) mode is not interrupted by small changes on the screen like icons changing state in the system tray or incoming notifications.

[Click here for the complete changelog of previous versions.](https://github.com/sblantipodi/firefly_luciferin/releases)
5 changes: 3 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<jna.version>5.16.0</jna.version>
<gstreamer.version>1.4.0</gstreamer.version>
<paho.version>1.2.5</paho.version>
<logback.version>1.5.15</logback.version>
<logback.version>1.5.16</logback.version>
<slf4j.version>2.0.16</slf4j.version>
<xtaudio.version>2.0</xtaudio.version>
<dbus.java.version>5.1.0</dbus.java.version>
Expand Down Expand Up @@ -242,6 +242,8 @@
<compilerArgs>
<arg>--add-modules</arg>
<arg>jdk.incubator.vector</arg>
<arg>--add-exports</arg>
<arg>jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED</arg>
</compilerArgs>
</configuration>
</plugin>
Expand Down Expand Up @@ -289,7 +291,6 @@
</execution>
</executions>
</plugin>

</plugins>
</build>
<repositories>
Expand Down
1 change: 0 additions & 1 deletion src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,4 @@
opens org.dpsoftware.grabber to javafx.fxml, javafx.web;
exports org.dpsoftware.gui.trayicon;
opens org.dpsoftware.gui.trayicon to javafx.fxml, javafx.web;

}
5 changes: 4 additions & 1 deletion src/main/java/org/dpsoftware/FireflyLuciferin.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ public FireflyLuciferin() {
NativeExecutor.exit();
}
manageLocale();
MainSingleton.getInstance().sharedQueue = new LinkedBlockingQueue<>(MainSingleton.getInstance().config.getLedMatrixInUse(ledMatrixInUse).size() * 30);
// TODO
// Queue is configured to hold a single frame, don't use `put` on it, but `offer` to prevent to block the writing thread.
MainSingleton.getInstance().sharedQueue = new LinkedBlockingQueue<>(1);
imageProcessor = new ImageProcessor(true);
serialManager = new SerialManager();
grabberManager = new GrabberManager();
Expand Down Expand Up @@ -280,6 +282,7 @@ public void start(Stage stage) throws Exception {
}
}
grabberManager.getFPS();
grabberManager.pingDevice();
imageProcessor.calculateBorders();
// If this instance spawns new instances, don't launch grabbers here.
if (!(MainSingleton.getInstance().spawnInstances && MainSingleton.getInstance().config.getMultiMonitor() > 1)) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/dpsoftware/MainSingleton.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public class MainSingleton {
public Configuration config;
// Start and Stop threads
public boolean RUNNING = false;
// This queue orders elements FIFO. Producer offers some data, consumer throws data to the Serial port
// This queue orders elements FIFO. Producer offers some data, consumer throws data to the Serial port.
public BlockingQueue<Color[]> sharedQueue;
public Color[] lastLedColor;
// Number of LEDs on the strip
Expand Down
38 changes: 11 additions & 27 deletions src/main/java/org/dpsoftware/NativeExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@

import java.awt.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
Expand All @@ -60,7 +59,7 @@ public final class NativeExecutor {
* Don't use this method directly and prefer the runNativeWaitForOutput() or runNativeNoWaitForOutput() shortcut.
*
* @param cmdToRunUsingArgs Command to run and args, in an array
* @param waitForOutput Example: If you need to exit the app you don't need to wait for the output or the app will not exit
* @param waitForOutput Example: If you need to exit the app you don't need to wait for the output or the app will not exit (millis)
* @return A list of string containing the output, empty list if command does not exist
*/
public static List<String> runNative(String[] cmdToRunUsingArgs, int waitForOutput) {
Expand All @@ -85,7 +84,7 @@ public static List<String> runNative(String[] cmdToRunUsingArgs, int waitForOutp
cmdOutput.add(line);
}
} else {
log.error("The command has exceeded the time limit and has been terminated.");
log.error("The command {} has exceeded the time limit and has been terminated.", Arrays.toString(cmdToRunUsingArgs));
process.destroy();
}
}
Expand All @@ -95,7 +94,6 @@ public static List<String> runNative(String[] cmdToRunUsingArgs, int waitForOutp
return cmdOutput;
}


/**
* Spawn new Luciferin Native instance
*
Expand Down Expand Up @@ -171,40 +169,26 @@ private static void restartCmd(List<String> execCommand) {
execCommand.addAll(Arrays.stream(Constants.FLATPAK_RUN).toList());
} else if (NativeExecutor.isSnap()) {
execCommand.addAll(Arrays.stream(Constants.SNAP_RUN).toList());
} else if (System.getProperty(Constants.JPACKAGE_APP_PATH) != null) {
execCommand.add(System.getProperty(Constants.JPACKAGE_APP_PATH));
} else if (getJpackageInstallationPath() != null) {
execCommand.add(getJpackageInstallationPath());
} else {
execCommand.add(System.getProperty(Constants.JAVA_HOME) + Constants.JAVA_BIN);
execCommand.addAll(ManagementFactory.getRuntimeMXBean().getInputArguments());
execCommand.add(Constants.JAR_PARAM);
execCommand.add(System.getProperty(Constants.JAVA_COMMAND).split("\\s+")[0]);
}

if (NativeExecutor.isRunningOnSandbox()) {
execCommand.add(Constants.RESTART_DELAY);
}
}

/**
* Get the installation path
* Get the installation path for jpackage app
*
* @return path
*/
public static String getInstallationPath() {
String luciferinClassPath = FireflyLuciferin.class.getProtectionDomain().getCodeSource().getLocation().getPath();
log.info("Installation path={}", luciferinClassPath);
if (luciferinClassPath.contains(".jar")) {
if (NativeExecutor.isWindows()) {
return luciferinClassPath.replace("/", "\\")
.substring(1, luciferinClassPath.length() - Constants.REGISTRY_JARNAME_WINDOWS.length())
.replace("%20", " ") + Constants.REGISTRY_KEY_VALUE_WINDOWS;
} else {
return "/" + luciferinClassPath
.substring(1, luciferinClassPath.length() - Constants.REGISTRY_JARNAME_LINUX.length())
.replace("%20", " ") + Constants.REGISTRY_KEY_VALUE_LINUX;
}
}
return Constants.REGISTRY_DEFAULT_KEY_VALUE;
public static String getJpackageInstallationPath() {
return System.getProperty(Constants.JPACKAGE_APP_PATH);
}

/**
Expand Down Expand Up @@ -481,13 +465,13 @@ public static void setSimdAvxInstructions() {
* Write Windows registry key to Launch Firefly Luciferin when system starts
*/
public void writeRegistryKey() {
String installationPath = getInstallationPath();
if (!installationPath.isEmpty()) {
log.info("Writing Windows Registry key");
String installationPath = getJpackageInstallationPath();
if (installationPath != null && !installationPath.isEmpty()) {
log.debug("Writing Windows Registry key");
Advapi32Util.registrySetStringValue(WinReg.HKEY_CURRENT_USER, Constants.REGISTRY_KEY_PATH,
Constants.REGISTRY_KEY_NAME, installationPath);
}
log.info(Advapi32Util.registryGetStringValue(WinReg.HKEY_CURRENT_USER,
log.debug("Registry key: {}", Advapi32Util.registryGetStringValue(WinReg.HKEY_CURRENT_USER,
Constants.REGISTRY_KEY_PATH, Constants.REGISTRY_KEY_NAME));
}

Expand Down
8 changes: 3 additions & 5 deletions src/main/java/org/dpsoftware/config/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -678,13 +678,8 @@ public class Constants {
public static final String REGISTRY_KEY_PATH_SCREEN_SAVER = "Control Panel\\Desktop";
public static final String REGISTRY_KEY_NAME = "FireflyLuciferin";
public static final String REGISTRY_KEY_NAME_SCREEN_SAVER = "SCRNSAVE.EXE";
public static final String REGISTRY_KEY_VALUE_WINDOWS = "Firefly Luciferin.exe";
public static final String REGISTRY_KEY_VALUE_LINUX = "bin/FireflyLuciferin";
public static final String REGISTRY_DEFAULT_KEY_VALUE = "C:\\Users\\sblantipodi\\AppData\\Local\\Firefly Luciferin\\Firefly Luciferin.exe";
public static final String REGISTRY_THEME_PATH = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize\\";
public static final String REGISTRY_THEME_KEY = "AppsUseLightTheme";
public static final String REGISTRY_JARNAME_WINDOWS = "app\\FireflyLuciferin-jar-with-dependencies.jar";
public static final String REGISTRY_JARNAME_LINUX = "lib/app/FireflyLuciferin-jar-with-dependencies.jar";
public static final String SCREENSAVER_EXTENSION = ".scr";
public static final String CMD_LIST_RUNNING_PROCESS = "tasklist.exe /fo csv /nh | findstr /i \"\\" + SCREENSAVER_EXTENSION + "\"";
public static final String CMD_SHELL_FOR_CMD_EXECUTION = "cmd.exe";
Expand All @@ -694,6 +689,8 @@ public class Constants {
public static final int CMD_WAIT_DELAY = 10000;
public static final int SPAWN_INSTANCE_WAIT_START_DELAY = 3000;
public static final String[] CMD_CUDA_CHECK = {"/bin/sh", "-c", "gst-inspect-1.0 nvcodec | grep cuda"};
public static final String[] PING_WINDOWS = {"ping", "-n", "2"};
public static final String[] PING_LINUX = {"ping", "-c", "2"};
public static final String[] CUDA_REQUIRED_PLUGINS = {"cudaupload", "cudascale", "cudaconvert", "cudadownload"};
// Native executor
public static final String DPKG_CHECK_CMD = "dpkg --version";
Expand All @@ -702,6 +699,7 @@ public class Constants {
public static final String WAYLAND = "wayland";
public static final String RESTART_DELAY = "RESTART_DELAY";
public static final int RESTART_DELAY_SECONDS = 3;
public static final int RESTART_TIMEOUT = -180;
public static final String[] FLATPAK_RUN = {"flatpak-spawn", "FireflyLuciferin"};
public static final String[] SNAP_RUN = {"FireflyLuciferin"};
public static final String FLATPAK_ID = "FLATPAK_ID";
Expand Down
33 changes: 26 additions & 7 deletions src/main/java/org/dpsoftware/config/Enums.java
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,8 @@ public enum Language implements LocalizedEnum {
FR("enum.language.fr"),
HU("enum.language.hu"),
IT("enum.language.it"),
RU("enum.language.ru");
RU("enum.language.ru"),
PL("enum.language.pl");
private final String language;

Language(String language) {
Expand Down Expand Up @@ -535,12 +536,30 @@ public String getValue() {
}

public enum ColorOrder {
GRB(1),
RGB(2),
BGR(3),
BRG(4),
RBG(5),
GBR(6);
GRB_GRBW(1),
RGB_RGBW(2),
BGR_BGRW(3),
BRG_BRGW(4),
RBG_RBGW(5),
GBR_GBRW(6),
GRWB(7),
GWBR(8),
WRBG(9),
RGWB(10),
RWBG(11),
WGBR(12),
BGWR(13),
BWRG(14),
WGRB(15),
BRWG(16),
BWGR(17),
WRGB(18),
RBWG(19),
RWGB(20),
WBGR(21),
GBWR(22),
GWRB(23),
WBRG(24);
private final int colorOrder;

ColorOrder(int colorOrder) {
Expand Down
27 changes: 15 additions & 12 deletions src/main/java/org/dpsoftware/grabber/GStreamerGrabber.java
Original file line number Diff line number Diff line change
Expand Up @@ -312,18 +312,18 @@ private static Color[] processBufferUsingCpu(int width, int height, IntBuffer rg
(long) (Math.min(offsetX + SPECIES.length(), widthPlusStride) + baseBufferOffset) * Integer.BYTES, ByteOrder.nativeOrder(), mask2);
IntVector rgbVector3 = IntVector.fromMemorySegment(SPECIES, memorySegment,
(long) (Math.min(offsetX + 2 * SPECIES.length(), widthPlusStride) + baseBufferOffset) * Integer.BYTES, ByteOrder.nativeOrder(), mask3);
IntVector rVector = rgbVector1.and(0xFF0000).lanewise(VectorOperators.LSHR, 16)
r += rgbVector1.and(0xFF0000).lanewise(VectorOperators.LSHR, 16)
.add(rgbVector2.and(0xFF0000).lanewise(VectorOperators.LSHR, 16))
.add(rgbVector3.and(0xFF0000).lanewise(VectorOperators.LSHR, 16));
IntVector gVector = rgbVector1.and(0x00FF00).lanewise(VectorOperators.LSHR, 8)
.add(rgbVector3.and(0xFF0000).lanewise(VectorOperators.LSHR, 16))
.reduceLanes(VectorOperators.ADD);
g += rgbVector1.and(0x00FF00).lanewise(VectorOperators.LSHR, 8)
.add(rgbVector2.and(0x00FF00).lanewise(VectorOperators.LSHR, 8))
.add(rgbVector3.and(0x00FF00).lanewise(VectorOperators.LSHR, 8));
IntVector bVector = rgbVector1.and(0x0000FF)
.add(rgbVector3.and(0x00FF00).lanewise(VectorOperators.LSHR, 8))
.reduceLanes(VectorOperators.ADD);
b += rgbVector1.and(0x0000FF)
.add(rgbVector2.and(0x0000FF))
.add(rgbVector3.and(0x0000FF));
r += rVector.reduceLanes(VectorOperators.ADD);
g += gVector.reduceLanes(VectorOperators.ADD);
b += bVector.reduceLanes(VectorOperators.ADD);
.add(rgbVector3.and(0x0000FF))
.reduceLanes(VectorOperators.ADD);
pickNumber += mask1.trueCount() + mask2.trueCount() + mask3.trueCount();
}
}
Expand Down Expand Up @@ -438,8 +438,11 @@ void frameInsertion(Color[] leds) {
final int dRed = leds[j].getRed() - previousFrame[j].getRed();
final int dGreen = leds[j].getGreen() - previousFrame[j].getGreen();
final int dBlue = leds[j].getBlue() - previousFrame[j].getBlue();
final Color c = new Color(previousFrame[j].getRed() + ((dRed * i) / frameToCompute),
previousFrame[j].getGreen() + ((dGreen * i) / frameToCompute), previousFrame[j].getBlue() + ((dBlue * i) / frameToCompute));
Color c = new Color(
previousFrame[j].getRed() + (dRed * i) / frameToCompute,
previousFrame[j].getGreen() + (dGreen * i) / frameToCompute,
previousFrame[j].getBlue() + (dBlue * i) / frameToCompute
);
frameInsertion[j] = c;
}
long finish = System.currentTimeMillis();
Expand All @@ -449,7 +452,7 @@ void frameInsertion(Color[] leds) {
if (timeElapsed > Constants.SMOOTHING_SKIP_FAST_FRAMES) {
PipelineManager.offerToTheQueue(frameInsertion);
} else {
log.debug("Frames is coming too fast, GPU is trying to catch up, skipping frame={}, Elapsed={}", i, timeElapsed);
log.debug("Frames are coming too fast, GPU is trying to catch up, skipping frame={}, Elapsed={}", i, timeElapsed);
start = System.currentTimeMillis();
previousFrame = leds.clone();
break;
Expand Down
Loading

0 comments on commit fcb28fb

Please sign in to comment.