Skip to content

Commit

Permalink
Introduce PrimFormToBufferedImageNode
Browse files Browse the repository at this point in the history
  • Loading branch information
fniephaus committed May 1, 2020
1 parent fc5a002 commit 277b0f3
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.color.ColorSpace;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
Expand All @@ -26,12 +25,6 @@
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.awt.image.DirectColorModel;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.util.ArrayDeque;
Expand Down Expand Up @@ -60,22 +53,14 @@
import de.hpi.swa.graal.squeak.nodes.plugins.DropPlugin;
import de.hpi.swa.graal.squeak.nodes.plugins.HostWindowPlugin;
import de.hpi.swa.graal.squeak.shared.SqueakLanguageConfig;
import de.hpi.swa.graal.squeak.util.MiscUtils;

public final class SqueakDisplay implements SqueakDisplayInterface {
private static final String DEFAULT_WINDOW_TITLE = "GraalSqueak";
private static final boolean REPAINT_AUTOMATICALLY = false; // For debugging purposes.
private static final Dimension MINIMUM_WINDOW_SIZE = new Dimension(200, 150);
private static final Toolkit TOOLKIT = Toolkit.getDefaultToolkit();
@CompilationFinal(dimensions = 1) private static final int[] CURSOR_COLORS = new int[]{0x00000000, 0xFF0000FF, 0xFFFFFFFF, 0xFF000000};
private static final DirectColorModel COLOR_MODEL_32BIT = new DirectColorModel(
ColorSpace.getInstance(ColorSpace.CS_sRGB),
32,
0x00ff0000, // Red
0x0000ff00, // Green
0x000000ff, // Blue
0xff000000, // Alpha
true, // Alpha Premultiplied
DataBuffer.TYPE_INT);

public final SqueakImageContext image;
private final JFrame frame = new JFrame(DEFAULT_WINDOW_TITLE);
Expand Down Expand Up @@ -164,20 +149,12 @@ private void setSqDisplay(final PointersObject sqDisplay) {
final int height = (int) (long) sqDisplay.instVarAt0Slow(FORM.HEIGHT);
assert (long) sqDisplay.instVarAt0Slow(FORM.DEPTH) == 32 : "Unsupported display depth";
if (width > 0 && height > 0) {
bufferedImage = new32BitBufferedImage(bitmap.getIntStorage(), width, height);
bufferedImage = MiscUtils.new32BitBufferedImage(bitmap.getIntStorage(), width, height);
repaint();
}
}
}

/* Wraps bitmap in a BufferedImage for efficient drawing. */
private static BufferedImage new32BitBufferedImage(final int[] words, final int width, final int height) {
final DataBufferInt db = new DataBufferInt(words, words.length);
final SampleModel sm = COLOR_MODEL_32BIT.createCompatibleSampleModel(width, height);
final WritableRaster raster = Raster.createWritableRaster(sm, db, new Point(0, 0));
return new BufferedImage(COLOR_MODEL_32BIT, raster, true, null);
}

@Override
@TruffleBoundary
public void showDisplayBitsLeftTopRightBottom(final PointersObject destForm, final int left, final int top, final int right, final int bottom) {
Expand Down Expand Up @@ -313,7 +290,7 @@ public void setCursor(final int[] cursorWords, final int[] mask, final int width
}
final BufferedImage bufferedImage;
if (depth == 32) {
bufferedImage = new32BitBufferedImage(cursorWords, width, height);
bufferedImage = MiscUtils.new32BitBufferedImage(cursorWords, width, height);
} else {
bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
for (int y = 0; y < height; y++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,33 @@

import java.util.List;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.NodeFactory;
import com.oracle.truffle.api.dsl.Specialization;

import de.hpi.swa.graal.squeak.SqueakLanguage;
import de.hpi.swa.graal.squeak.exceptions.PrimitiveExceptions.PrimitiveFailed;
import de.hpi.swa.graal.squeak.image.SqueakImageContext;
import de.hpi.swa.graal.squeak.interop.JavaObjectWrapper;
import de.hpi.swa.graal.squeak.model.CompiledCodeObject;
import de.hpi.swa.graal.squeak.model.CompiledMethodObject;
import de.hpi.swa.graal.squeak.model.NativeObject;
import de.hpi.swa.graal.squeak.model.PointersObject;
import de.hpi.swa.graal.squeak.model.layout.ObjectLayouts.FORM;
import de.hpi.swa.graal.squeak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectReadNode;
import de.hpi.swa.graal.squeak.nodes.primitives.AbstractPrimitiveFactoryHolder;
import de.hpi.swa.graal.squeak.nodes.primitives.AbstractPrimitiveNode;
import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.BinaryPrimitive;
import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.BinaryPrimitiveWithoutFallback;
import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.UnaryPrimitiveWithoutFallback;
import de.hpi.swa.graal.squeak.nodes.primitives.SqueakPrimitive;
import de.hpi.swa.graal.squeak.util.MiscUtils;

public final class GraalSqueakPlugin extends AbstractPrimitiveFactoryHolder {

Expand Down Expand Up @@ -89,4 +100,35 @@ protected static final Object doGet(@SuppressWarnings("unused") final Object rec
return JavaObjectWrapper.wrap(target);
}
}

@GenerateNodeFactory
@ImportStatic(FORM.class)
@SqueakPrimitive(names = "primitiveFormToBufferedImage")
protected abstract static class PrimFormToBufferedImageNode extends AbstractPrimitiveNode implements BinaryPrimitive {
protected PrimFormToBufferedImageNode(final CompiledMethodObject method) {
super(method);
}

@Specialization(guards = "form.instsize() > OFFSET")
protected static final Object doFormToBufferedImage(@SuppressWarnings("unused") final Object receiver, final PointersObject form,
@Cached final AbstractPointersObjectReadNode readNode,
@CachedContext(SqueakLanguage.class) final SqueakImageContext image) {
try {
/* Extract information from form. */
final NativeObject bits = (NativeObject) readNode.execute(form, FORM.BITS);
final int width = (int) (long) readNode.execute(form, FORM.WIDTH);
final int height = (int) (long) readNode.execute(form, FORM.HEIGHT);
final long depth = (long) readNode.execute(form, FORM.DEPTH);
if (!bits.isIntType() || depth != 32) {
CompilerDirectives.transferToInterpreter();
throw PrimitiveFailed.GENERIC_ERROR;
}
/* Use bitmap's storage as backend for BufferedImage. */
return image.env.asGuestValue(MiscUtils.new32BitBufferedImage(bits.getIntStorage(), width, height));
} catch (final ClassCastException e) {
CompilerDirectives.transferToInterpreter();
throw PrimitiveFailed.GENERIC_ERROR;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@
*/
package de.hpi.swa.graal.squeak.util;

import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.awt.image.DirectColorModel;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.io.File;
import java.lang.management.CompilationMXBean;
import java.lang.management.GarbageCollectorMXBean;
Expand All @@ -30,6 +38,16 @@ public final class MiscUtils {
private static final RuntimeMXBean RUNTIME_BEAN = ManagementFactory.getRuntimeMXBean();
private static final List<GarbageCollectorMXBean> GC_BEANS = ManagementFactory.getGarbageCollectorMXBeans();

private static final DirectColorModel COLOR_MODEL_32BIT = new DirectColorModel(
ColorSpace.getInstance(ColorSpace.CS_sRGB),
32,
0x00ff0000, // Red
0x0000ff00, // Green
0x000000ff, // Blue
0xff000000, // Alpha
true, // Alpha Premultiplied
DataBuffer.TYPE_INT);

// The delta between Squeak Epoch (January 1st 1901) and POSIX Epoch (January 1st 1970)
public static final long EPOCH_DELTA_SECONDS = (69L * 365 + 17) * 24 * 3600;
public static final long EPOCH_DELTA_MICROSECONDS = EPOCH_DELTA_SECONDS * 1000 * 1000;
Expand Down Expand Up @@ -172,6 +190,15 @@ public static String getVMPath() {
return System.getProperty("java.home") + File.separatorChar + "bin" + File.separatorChar + binaryName;
}

/* Wraps bitmap in a BufferedImage for efficient drawing. */
@TruffleBoundary
public static BufferedImage new32BitBufferedImage(final int[] words, final int width, final int height) {
final DataBufferInt db = new DataBufferInt(words, words.length);
final SampleModel sm = COLOR_MODEL_32BIT.createCompatibleSampleModel(width, height);
final WritableRaster raster = Raster.createWritableRaster(sm, db, null);
return new BufferedImage(COLOR_MODEL_32BIT, raster, true, null);
}

@TruffleBoundary
public static long runtimeFreeMemory() {
return Runtime.getRuntime().freeMemory();
Expand Down

0 comments on commit 277b0f3

Please sign in to comment.