Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/ios-packaging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
- '.github/workflows/ios-packaging.yml'
- 'maven/codenameone-maven-plugin/**'
- 'vm/ByteCodeTranslator/**'
- 'Ports/iOSPort/**'
- 'scripts/build-ios-app.sh'
- 'scripts/run-ios-ui-tests.sh'
- 'scripts/run-ios-native-tests.sh'
Expand All @@ -18,6 +19,7 @@ on:
- '.github/workflows/ios-packaging.yml'
- 'maven/codenameone-maven-plugin/**'
- 'vm/ByteCodeTranslator/**'
- 'Ports/iOSPort/**'
- 'scripts/build-ios-app.sh'
- 'scripts/run-ios-ui-tests.sh'
- 'scripts/run-ios-native-tests.sh'
Expand Down Expand Up @@ -68,7 +70,9 @@ jobs:
id: setup_hash
run: |
set -euo pipefail
echo "hash=$(shasum -a 256 scripts/setup-workspace.sh | awk '{print $1}')" >> "$GITHUB_OUTPUT"
SETUP_HASH=$(shasum -a 256 scripts/setup-workspace.sh | awk '{print $1}')
IOS_PORT_HASH=$(find Ports/iOSPort/src -type f -name '*.java' | sort | xargs shasum -a 256 | shasum -a 256 | awk '{print $1}')
echo "hash=${SETUP_HASH}-${IOS_PORT_HASH}" >> "$GITHUB_OUTPUT"

- name: Set TMPDIR
run: echo "TMPDIR=${{ runner.temp }}" >> $GITHUB_ENV
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
import com.codename1.ui.util.ImageIO;
import com.codename1.util.AsyncResource;
import com.codename1.util.FailureCallback;
import com.codename1.util.Simd;
import com.codename1.util.StringUtil;
import com.codename1.util.SuccessCallback;

Expand Down Expand Up @@ -8397,6 +8398,12 @@ public ImageIO getImageIO() {
return null;
}

/// Creates the SIMD implementation for this platform.
/// Ports may override this to provide accelerated SIMD behavior.
public Simd createSimd() {
return new Simd();
}

/// Workaround for XMLVM bug
public boolean instanceofObjArray(Object o) {
return o instanceof Object[];
Expand Down
6 changes: 6 additions & 0 deletions CodenameOne/src/com/codename1/ui/CN.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import com.codename1.ui.events.WindowEvent;
import com.codename1.ui.geom.Dimension;
import com.codename1.ui.geom.Rectangle;
import com.codename1.util.Simd;
import com.codename1.util.RunnableWithResultSync;

import java.io.IOException;
Expand Down Expand Up @@ -1032,6 +1033,11 @@ public static String getPlatformName() {
return Display.impl.getPlatformName();
}

/// Returns the SIMD API for the current platform.
public static Simd getSimd() {
return Display.getInstance().getSimd();
}


/// Opens the device Dialer application with the given phone number
///
Expand Down
15 changes: 15 additions & 0 deletions CodenameOne/src/com/codename1/ui/Display.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import com.codename1.ui.util.EventDispatcher;
import com.codename1.ui.util.ImageIO;
import com.codename1.util.AsyncResource;
import com.codename1.util.Simd;
import com.codename1.util.RunnableWithResultSync;
import com.codename1.util.SuccessCallback;

Expand Down Expand Up @@ -216,6 +217,7 @@ public final class Display extends CN1Constants {
long time;
private int transitionDelay = -1;
private String selectedVirtualKeyboard = null;
private Simd simd;
private CrashReport crashReporter;
private EventDispatcher errorHandler;
private boolean inNativeUI;
Expand Down Expand Up @@ -343,6 +345,7 @@ public static void init(Object m) {
commandBehaviour = impl.getCommandBehavior();
}
impl = (CodenameOneImplementation) ImplementationFactory.getInstance().createImplementation();
INSTANCE.simd = null;

impl.setDisplayLock(lock);
impl.initImpl(m);
Expand Down Expand Up @@ -493,6 +496,18 @@ CodenameOneImplementation getImplementation() {
return impl;
}

/// Returns the SIMD API instance bound to the current implementation.
public Simd getSimd() {
if (simd == null) {
Simd created = impl.createSimd();
if (created == null) {
created = new Simd();
}
simd = created;
}
return simd;
}

/// Indicates the maximum frames the API will try to draw every second
/// by default this is set to 10. The advantage of limiting
/// framerate is to allow the CPU to perform other tasks besides drawing.
Expand Down
153 changes: 134 additions & 19 deletions CodenameOne/src/com/codename1/ui/Image.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.codename1.ui.geom.Dimension;
import com.codename1.ui.util.EventDispatcher;
import com.codename1.ui.util.ImageIO;
import com.codename1.util.Simd;

import java.io.IOException;
import java.io.InputStream;
Expand All @@ -44,6 +45,8 @@
///
/// @author Chen Fishbein
public class Image implements ActionSource {
private static final int SIMD_BLOCK_SIZE = 64;
private static boolean simdOptimizationsEnabled = Simd.get().isSupported();
int transform;
private EventDispatcher listeners;
private Object rgbCache;
Expand All @@ -57,6 +60,23 @@ public class Image implements ActionSource {
private byte[] svgData;
private String imageName;

/// Indicates whether Image SIMD optimizations are enabled. When unset this defaults
/// to the current platform SIMD support.
public static boolean isSimdOptimizationsEnabled() {
return simdOptimizationsEnabled;
}

/// Enables or disables Image SIMD optimizations explicitly.
public static void setSimdOptimizationsEnabled(boolean enabled) {
simdOptimizationsEnabled = enabled;
}

/// Clears the explicit Image SIMD override and restores the default behavior of
/// using SIMD whenever it is supported by the current platform.
public static void resetSimdOptimizationsEnabled() {
simdOptimizationsEnabled = Simd.get().isSupported();
}

/// Subclasses may use this and point to an underlying native image which might be
/// null for a case of an image that doesn't use native drawing
///
Expand Down Expand Up @@ -1053,9 +1073,22 @@ public boolean isSVG() {
public Object createMask() {
int[] rgb = getRGBCached();
int rlen = rgb.length;
byte[] mask = new byte[rlen];
for (int iter = 0; iter < rlen; iter++) {
mask[iter] = (byte) (rgb[iter] & 0xff);
byte[] mask;
if (isSimdOptimizationsEnabled() && rlen >= 16) {
Simd simd = Simd.get();
mask = simd.allocByte(rlen);
int blockSize = Math.min(rlen, SIMD_BLOCK_SIZE);
int[] scratch = simd.allocInt(blockSize);
for (int offset = 0; offset < rlen; offset += blockSize) {
int length = Math.min(blockSize, rlen - offset);
System.arraycopy(rgb, offset, scratch, 0, length);
simd.packIntToByteTruncate(scratch, 0, mask, offset, length);
}
} else {
mask = new byte[rlen];
for (int iter = 0; iter < rlen; iter++) {
mask[iter] = (byte) (rgb[iter] & 0xff);
}
}
return new IndexedImage(getWidth(), getHeight(), null, mask);
}
Expand Down Expand Up @@ -1156,11 +1189,34 @@ public Image applyMask(Object mask) {
if (mWidth != getWidth() || mHeight != getHeight()) {
throw new IllegalArgumentException("Mask and image sizes don't match");
}
int mdlen = maskData.length;
for (int iter = 0; iter < mdlen; iter++) {
int maskAlpha = maskData[iter] & 0xff;
maskAlpha = (maskAlpha << 24) & 0xff000000;
rgb[iter] = (rgb[iter] & 0xffffff) | maskAlpha;
if (isSimdOptimizationsEnabled() && maskData.length >= 16) {
Simd simd = Simd.get();
int blockSize = Math.min(maskData.length, SIMD_BLOCK_SIZE);
int srcOffset = 0;
int alphaOffset = blockSize;
int maskOffset = blockSize * 2;
int[] scratch = simd.allocInt(blockSize * 3);
byte[] scratchBytes = simd.allocByte(blockSize);
for (int iter = 0; iter < blockSize; iter++) {
scratch[maskOffset + iter] = 0xffffff;
}
for (int offset = 0; offset < maskData.length; offset += blockSize) {
int length = Math.min(blockSize, maskData.length - offset);
System.arraycopy(rgb, offset, scratch, srcOffset, length);
System.arraycopy(maskData, offset, scratchBytes, 0, length);
simd.and(scratch, srcOffset, scratch, maskOffset, scratch, srcOffset, length);
simd.unpackUnsignedByteToInt(scratchBytes, 0, scratch, alphaOffset, length);
simd.shl(scratch, alphaOffset, 24, scratch, alphaOffset, length);
simd.or(scratch, srcOffset, scratch, alphaOffset, scratch, srcOffset, length);
System.arraycopy(scratch, srcOffset, rgb, offset, length);
}
} else {
int mdlen = maskData.length;
for (int iter = 0; iter < mdlen; iter++) {
int maskAlpha = maskData[iter] & 0xff;
maskAlpha = (maskAlpha << 24) & 0xff000000;
rgb[iter] = (rgb[iter] & 0xffffff) | maskAlpha;
}
}
return createImage(rgb, mWidth, mHeight);
}
Expand Down Expand Up @@ -1306,11 +1362,38 @@ public Image modifyAlpha(byte alpha) {
int h = getHeight();
int size = w * h;
int[] arr = getRGB();
int alphaInt = (((int) alpha) << 24) & 0xff000000;
for (int iter = 0; iter < size; iter++) {
int currentAlpha = (arr[iter] >> 24) & 0xff;
if (currentAlpha != 0) {
arr[iter] = (arr[iter] & 0xffffff) | alphaInt;
if (isSimdOptimizationsEnabled() && size >= 16) {
Simd simd = Simd.get();
int blockSize = Math.min(size, SIMD_BLOCK_SIZE);
int srcOffset = 0;
int workOffset = blockSize;
int maskOffset = blockSize * 2;
int alphaOffset = blockSize * 3;
int zeroOffset = blockSize * 4;
int[] scratch = simd.allocInt(blockSize * 5);
byte[] scratchBytes = simd.allocByte(blockSize);
int alphaInt = (((int) alpha) << 24) & 0xff000000;
for (int iter = 0; iter < blockSize; iter++) {
scratch[maskOffset + iter] = 0xffffff;
scratch[alphaOffset + iter] = alphaInt;
}
for (int offset = 0; offset < size; offset += blockSize) {
int length = Math.min(blockSize, size - offset);
System.arraycopy(arr, offset, scratch, srcOffset, length);
simd.shrLogical(scratch, srcOffset, 24, scratch, workOffset, length);
simd.cmpEq(scratch, workOffset, scratch, zeroOffset, scratchBytes, 0, length);
simd.and(scratch, srcOffset, scratch, maskOffset, scratch, workOffset, length);
simd.or(scratch, workOffset, scratch, alphaOffset, scratch, workOffset, length);
simd.select(scratchBytes, 0, scratch, srcOffset, scratch, workOffset, scratch, srcOffset, length);
System.arraycopy(scratch, srcOffset, arr, offset, length);
}
} else {
int alphaInt = (((int) alpha) << 24) & 0xff000000;
for (int iter = 0; iter < size; iter++) {
int currentAlpha = (arr[iter] >> 24) & 0xff;
if (currentAlpha != 0) {
arr[iter] = (arr[iter] & 0xffffff) | alphaInt;
}
}
}
Image i = new Image(arr, w, h);
Expand Down Expand Up @@ -1378,12 +1461,44 @@ public Image modifyAlpha(byte alpha, int removeColor) {
int size = w * h;
int[] arr = new int[size];
getRGB(arr, 0, 0, 0, w, h);
int alphaInt = (((int) alpha) << 24) & 0xff000000;
for (int iter = 0; iter < size; iter++) {
if ((arr[iter] & 0xff000000) != 0) {
arr[iter] = (arr[iter] & 0xffffff) | alphaInt;
if (removeColor == (0xffffff & arr[iter])) {
arr[iter] = 0;
if (isSimdOptimizationsEnabled() && size >= 16) {
Simd simd = Simd.get();
int blockSize = Math.min(size, SIMD_BLOCK_SIZE);
int srcOffset = 0;
int workOffset = blockSize;
int maskOffset = blockSize * 2;
int alphaOffset = blockSize * 3;
int zeroOffset = blockSize * 4;
int removeColorOffset = blockSize * 5;
int[] scratch = simd.allocInt(blockSize * 6);
byte[] scratchBytes = simd.allocByte(blockSize);
int alphaInt = (((int) alpha) << 24) & 0xff000000;
for (int iter = 0; iter < blockSize; iter++) {
scratch[maskOffset + iter] = 0xffffff;
scratch[alphaOffset + iter] = alphaInt;
scratch[removeColorOffset + iter] = removeColor & 0xffffff;
}
for (int offset = 0; offset < size; offset += blockSize) {
int length = Math.min(blockSize, size - offset);
System.arraycopy(arr, offset, scratch, srcOffset, length);
simd.shrLogical(scratch, srcOffset, 24, scratch, workOffset, length);
simd.cmpEq(scratch, workOffset, scratch, zeroOffset, scratchBytes, 0, length);
simd.and(scratch, srcOffset, scratch, maskOffset, scratch, workOffset, length);
simd.or(scratch, workOffset, scratch, alphaOffset, scratch, workOffset, length);
simd.select(scratchBytes, 0, scratch, srcOffset, scratch, workOffset, scratch, srcOffset, length);
simd.and(scratch, srcOffset, scratch, maskOffset, scratch, workOffset, length);
simd.cmpEq(scratch, workOffset, scratch, removeColorOffset, scratchBytes, 0, length);
simd.select(scratchBytes, 0, scratch, zeroOffset, scratch, srcOffset, scratch, srcOffset, length);
System.arraycopy(scratch, srcOffset, arr, offset, length);
}
} else {
int alphaInt = (((int) alpha) << 24) & 0xff000000;
for (int iter = 0; iter < size; iter++) {
if ((arr[iter] & 0xff000000) != 0) {
arr[iter] = (arr[iter] & 0xffffff) | alphaInt;
if (removeColor == (0xffffff & arr[iter])) {
arr[iter] = 0;
}
}
}
}
Expand Down
39 changes: 34 additions & 5 deletions CodenameOne/src/com/codename1/ui/RGBImage.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
*/
package com.codename1.ui;

import com.codename1.util.Simd;

/// An image that stores its data as an integer RGB array internally,
/// this image cannot be manipulated via Graphics primitives however its
/// array is accessible and modifiable programmatically. This is very useful
Expand Down Expand Up @@ -140,11 +142,38 @@ public Image rotate(int degrees) {
public Image modifyAlpha(byte alpha) {
int[] arr = new int[rgb.length];
System.arraycopy(rgb, 0, arr, 0, rgb.length);
int alphaInt = (((int) alpha) << 24) & 0xff000000;
int rlen = rgb.length;
for (int iter = 0; iter < rlen; iter++) {
if ((arr[iter] & 0xff000000) != 0) {
arr[iter] = (arr[iter] & 0xffffff) | alphaInt;
if (Image.isSimdOptimizationsEnabled() && arr.length >= 16) {
Simd simd = Simd.get();
int blockSize = Math.min(arr.length, 64);
int srcOffset = 0;
int workOffset = blockSize;
int maskOffset = blockSize * 2;
int alphaOffset = blockSize * 3;
int zeroOffset = blockSize * 4;
int[] scratch = simd.allocInt(blockSize * 5);
byte[] scratchBytes = simd.allocByte(blockSize);
int alphaInt = (((int) alpha) << 24) & 0xff000000;
for (int iter = 0; iter < blockSize; iter++) {
scratch[maskOffset + iter] = 0xffffff;
scratch[alphaOffset + iter] = alphaInt;
}
for (int offset = 0; offset < arr.length; offset += blockSize) {
int length = Math.min(blockSize, arr.length - offset);
System.arraycopy(arr, offset, scratch, srcOffset, length);
simd.shrLogical(scratch, srcOffset, 24, scratch, workOffset, length);
simd.cmpEq(scratch, workOffset, scratch, zeroOffset, scratchBytes, 0, length);
simd.and(scratch, srcOffset, scratch, maskOffset, scratch, workOffset, length);
simd.or(scratch, workOffset, scratch, alphaOffset, scratch, workOffset, length);
simd.select(scratchBytes, 0, scratch, srcOffset, scratch, workOffset, scratch, srcOffset, length);
System.arraycopy(scratch, srcOffset, arr, offset, length);
}
} else {
int alphaInt = (((int) alpha) << 24) & 0xff000000;
int rlen = rgb.length;
for (int iter = 0; iter < rlen; iter++) {
if ((arr[iter] & 0xff000000) != 0) {
arr[iter] = (arr[iter] & 0xffffff) | alphaInt;
}
}
}
return new RGBImage(arr, width, height);
Expand Down
Loading
Loading