8005530: [lcms] Improve performance of ColorConverOp for default destinations
Reviewed-by: prr, jgodinez
--- a/jdk/make/sun/cmm/lcms/Makefile Tue Mar 05 17:18:55 2013 +0400
+++ b/jdk/make/sun/cmm/lcms/Makefile Thu Mar 07 14:05:21 2013 +0400
@@ -28,6 +28,9 @@
LIBRARY = lcms
PRODUCT = sun
+# Use highest level of optimization on this library
+OPTIMIZATION_LEVEL = HIGHEST
+
include $(BUILDDIR)/common/Defs.gmk
#
--- a/jdk/make/sun/cmm/lcms/mapfile-vers Tue Mar 05 17:18:55 2013 +0400
+++ b/jdk/make/sun/cmm/lcms/mapfile-vers Thu Mar 07 14:05:21 2013 +0400
@@ -27,13 +27,12 @@
SUNWprivate_1.1 {
global:
- Java_sun_java2d_cmm_lcms_LCMS_loadProfile;
- Java_sun_java2d_cmm_lcms_LCMS_freeProfile;
+ Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative;
+ Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative;
Java_sun_java2d_cmm_lcms_LCMS_getProfileSize;
Java_sun_java2d_cmm_lcms_LCMS_getProfileData;
- Java_sun_java2d_cmm_lcms_LCMS_getTagSize;
- Java_sun_java2d_cmm_lcms_LCMS_getTagData;
- Java_sun_java2d_cmm_lcms_LCMS_setTagData;
+ Java_sun_java2d_cmm_lcms_LCMS_getTagNative;
+ Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative;
Java_sun_java2d_cmm_lcms_LCMS_colorConvert;
Java_sun_java2d_cmm_lcms_LCMS_getProfileID;
Java_sun_java2d_cmm_lcms_LCMS_initLCMS;
--- a/jdk/makefiles/CompileNativeLibraries.gmk Tue Mar 05 17:18:55 2013 +0400
+++ b/jdk/makefiles/CompileNativeLibraries.gmk Thu Mar 07 14:05:21 2013 +0400
@@ -1218,7 +1218,7 @@
OUTPUT_DIR:=$(INSTALL_LIBRARIES_HERE),\
SRC:=$(JDK_TOPDIR)/src/share/native/sun/java2d/cmm/lcms,\
LANG:=C,\
- OPTIMIZATION:=LOW, \
+ OPTIMIZATION:=HIGHEST, \
CFLAGS:=$(filter-out -xc99=%none,$(CFLAGS_JDKLIB)) \
$(SHARED_LIBRARY_FLAGS) \
-I$(JDK_TOPDIR)/src/share/native/sun/java2d \
--- a/jdk/makefiles/mapfiles/liblcms/mapfile-vers Tue Mar 05 17:18:55 2013 +0400
+++ b/jdk/makefiles/mapfiles/liblcms/mapfile-vers Thu Mar 07 14:05:21 2013 +0400
@@ -27,13 +27,12 @@
SUNWprivate_1.1 {
global:
- Java_sun_java2d_cmm_lcms_LCMS_loadProfile;
- Java_sun_java2d_cmm_lcms_LCMS_freeProfile;
+ Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative;
+ Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative;
Java_sun_java2d_cmm_lcms_LCMS_getProfileSize;
Java_sun_java2d_cmm_lcms_LCMS_getProfileData;
- Java_sun_java2d_cmm_lcms_LCMS_getTagSize;
- Java_sun_java2d_cmm_lcms_LCMS_getTagData;
- Java_sun_java2d_cmm_lcms_LCMS_setTagData;
+ Java_sun_java2d_cmm_lcms_LCMS_getTagNative;
+ Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative;
Java_sun_java2d_cmm_lcms_LCMS_colorConvert;
Java_sun_java2d_cmm_lcms_LCMS_getProfileID;
Java_sun_java2d_cmm_lcms_LCMS_initLCMS;
--- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java Tue Mar 05 17:18:55 2013 +0400
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java Thu Mar 07 14:05:21 2013 +0400
@@ -25,29 +25,91 @@
package sun.java2d.cmm.lcms;
-import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
-import java.awt.color.CMMException;
+import java.util.Arrays;
+import java.util.HashMap;
import sun.java2d.cmm.ColorTransform;
import sun.java2d.cmm.PCMM;
-import sun.java2d.cmm.lcms.LCMS;
-import sun.java2d.cmm.lcms.LCMSTransform;
public class LCMS implements PCMM {
/* methods invoked from ICC_Profile */
- public native long loadProfile(byte[] data);
+ @Override
+ public long loadProfile(byte[] data) {
+ long id = loadProfileNative(data);
+
+ if (id != 0L) {
+ if (profiles == null) {
+ profiles = new HashMap<>();
+ }
+ profiles.put(id, new TagCache(id));
+ }
+ return id;
+ }
- public native void freeProfile(long profileID);
+ private native long loadProfileNative(byte[] data);
+
+ @Override
+ public void freeProfile(long profileID) {
+ TagCache c = profiles.remove(profileID);
+ if (c != null) {
+ c.clear();
+ }
+ if (profiles.isEmpty()) {
+ profiles = null;
+ }
+ freeProfileNative(profileID);
+ }
+
+ private native void freeProfileNative(long profileID);
public native synchronized int getProfileSize(long profileID);
public native synchronized void getProfileData(long profileID, byte[] data);
- public native synchronized int getTagSize(long profileID, int tagSignature);
- public native synchronized void getTagData(long profileID, int tagSignature,
- byte[] data);
- public native synchronized void setTagData(long profileID, int tagSignature,
+ @Override
+ public synchronized int getTagSize(long profileID, int tagSignature) {
+ TagCache cache = profiles.get(profileID);
+
+ if (cache == null) {
+ cache = new TagCache(profileID);
+ profiles.put(profileID, cache);
+ }
+
+ TagData t = cache.getTag(tagSignature);
+ return t == null ? 0 : t.getSize();
+ }
+
+ private static native byte[] getTagNative(long profileID, int signature);
+
+ @Override
+ public synchronized void getTagData(long profileID, int tagSignature,
+ byte[] data)
+ {
+ TagCache cache = profiles.get(profileID);
+
+ if (cache == null) {
+ cache = new TagCache(profileID);
+ profiles.put(profileID, cache);
+ }
+
+ TagData t = cache.getTag(tagSignature);
+ if (t != null) {
+ t.copyDataTo(data);
+ }
+ }
+
+ @Override
+ public synchronized void setTagData(long profileID, int tagSignature, byte[] data) {
+ TagCache cache = profiles.get(profileID);
+
+ if (cache != null) {
+ cache.clear();
+ }
+ setTagDataNative(profileID, tagSignature, data);
+ }
+
+ private native synchronized void setTagDataNative(long profileID, int tagSignature,
byte[] data);
public static native long getProfileID(ICC_Profile profile);
@@ -103,4 +165,59 @@
initLCMS(LCMSTransform.class, LCMSImageLayout.class, ICC_Profile.class);
}
+
+ private static class TagData {
+ private int signature;
+ private byte[] data;
+
+ TagData(int sig, byte[] data) {
+ this.signature = sig;
+ this.data = data;
+ }
+
+ int getSize() {
+ return data.length;
+ }
+
+ byte[] getData() {
+ return Arrays.copyOf(data, data.length);
+ }
+
+ void copyDataTo(byte[] dst) {
+ System.arraycopy(data, 0, dst, 0, data.length);
+ }
+
+ int getSignature() {
+ return signature;
+ }
+ }
+
+ private static class TagCache {
+ private long profileID;
+ private HashMap<Integer, TagData> tags;
+
+ TagCache(long id) {
+ profileID = id;
+
+ tags = new HashMap<>();
+ }
+
+ TagData getTag(int sig) {
+ TagData t = tags.get(sig);
+ if (t == null) {
+ byte[] tagData = getTagNative(profileID, sig);
+ if (tagData != null) {
+ t = new TagData(sig, tagData);
+ tags.put(sig, t);
+ }
+ }
+ return t;
+ }
+
+ void clear() {
+ tags.clear();
+ }
+ }
+
+ private static HashMap<Long, TagCache> profiles;
}
--- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java Tue Mar 05 17:18:55 2013 +0400
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java Thu Mar 07 14:05:21 2013 +0400
@@ -22,26 +22,19 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-
package sun.java2d.cmm.lcms;
-import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.ComponentColorModel;
-import java.awt.image.Raster;
-import java.awt.image.WritableRaster;
-import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.ComponentSampleModel;
import java.awt.image.DataBuffer;
-import java.awt.image.DataBufferByte;
-import java.awt.image.DataBufferUShort;
-import java.awt.image.DataBufferInt;
import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
import sun.awt.image.ByteComponentRaster;
import sun.awt.image.ShortComponentRaster;
import sun.awt.image.IntegerComponentRaster;
-
class LCMSImageLayout {
public static int BYTES_SH(int x) {
@@ -49,47 +42,34 @@
}
public static int EXTRA_SH(int x) {
- return x<<7;
+ return x << 7;
}
public static int CHANNELS_SH(int x) {
- return x<<3;
+ return x << 3;
}
-
- public static final int SWAPFIRST = 1<<14;
-
- public static final int DOSWAP = 1<<10;
-
+ public static final int SWAPFIRST = 1 << 14;
+ public static final int DOSWAP = 1 << 10;
public static final int PT_RGB_8 =
- CHANNELS_SH(3) | BYTES_SH(1);
-
+ CHANNELS_SH(3) | BYTES_SH(1);
public static final int PT_GRAY_8 =
- CHANNELS_SH(1) | BYTES_SH(1);
-
+ CHANNELS_SH(1) | BYTES_SH(1);
public static final int PT_GRAY_16 =
- CHANNELS_SH(1) | BYTES_SH(2);
-
+ CHANNELS_SH(1) | BYTES_SH(2);
public static final int PT_RGBA_8 =
- EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1);
-
+ EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1);
public static final int PT_ARGB_8 =
- EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1) | SWAPFIRST;
-
+ EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1) | SWAPFIRST;
public static final int PT_BGR_8 =
- DOSWAP | CHANNELS_SH(3) | BYTES_SH(1);
-
+ DOSWAP | CHANNELS_SH(3) | BYTES_SH(1);
public static final int PT_ABGR_8 =
- DOSWAP | EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1);
-
- public static final int PT_BGRA_8 = EXTRA_SH(1) | CHANNELS_SH(3) |
- BYTES_SH(1) | DOSWAP | SWAPFIRST;
-
- public static final int DT_BYTE = 0;
- public static final int DT_SHORT = 1;
- public static final int DT_INT = 2;
- public static final int DT_DOUBLE = 3;
-
-
+ DOSWAP | EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1);
+ public static final int PT_BGRA_8 = EXTRA_SH(1) | CHANNELS_SH(3)
+ | BYTES_SH(1) | DOSWAP | SWAPFIRST;
+ public static final int DT_BYTE = 0;
+ public static final int DT_SHORT = 1;
+ public static final int DT_INT = 2;
+ public static final int DT_DOUBLE = 3;
boolean isIntPacked = false;
int pixelType;
int dataType;
@@ -98,25 +78,30 @@
int nextRowOffset;
int offset;
+ /* This flag indicates whether the image can be processed
+ * at once by doTransfrom() native call. Otherwise, the
+ * image is processed scan by scan.
+ */
+ private boolean imageAtOnce = false;
Object dataArray;
+
private LCMSImageLayout(int np, int pixelType, int pixelSize) {
this.pixelType = pixelType;
width = np;
height = 1;
- nextRowOffset = np*pixelSize;
+ nextRowOffset = np * pixelSize;
offset = 0;
}
private LCMSImageLayout(int width, int height, int pixelType,
- int pixelSize) {
+ int pixelSize) {
this.pixelType = pixelType;
this.width = width;
this.height = height;
- nextRowOffset = width*pixelSize;
+ nextRowOffset = width * pixelSize;
offset = 0;
}
-
public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) {
this(np, pixelType, pixelSize);
dataType = DT_BYTE;
@@ -135,102 +120,218 @@
dataArray = data;
}
- public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize)
- {
+ public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize) {
this(np, pixelType, pixelSize);
dataType = DT_DOUBLE;
dataArray = data;
}
- public LCMSImageLayout(BufferedImage image) {
- ShortComponentRaster shortRaster;
- IntegerComponentRaster intRaster;
- ByteComponentRaster byteRaster;
+ private LCMSImageLayout() {
+ }
+
+ /* This method creates a layout object for given image.
+ * Returns null if the image is not supported by current implementation.
+ */
+ public static LCMSImageLayout createImageLayout(BufferedImage image) {
+ LCMSImageLayout l = new LCMSImageLayout();
+
switch (image.getType()) {
case BufferedImage.TYPE_INT_RGB:
- pixelType = PT_ARGB_8;
- isIntPacked = true;
+ l.pixelType = PT_ARGB_8;
+ l.isIntPacked = true;
break;
case BufferedImage.TYPE_INT_ARGB:
- pixelType = PT_ARGB_8;
- isIntPacked = true;
+ l.pixelType = PT_ARGB_8;
+ l.isIntPacked = true;
break;
case BufferedImage.TYPE_INT_BGR:
- pixelType = PT_ABGR_8;
- isIntPacked = true;
+ l.pixelType = PT_ABGR_8;
+ l.isIntPacked = true;
break;
case BufferedImage.TYPE_3BYTE_BGR:
- pixelType = PT_BGR_8;
+ l.pixelType = PT_BGR_8;
break;
case BufferedImage.TYPE_4BYTE_ABGR:
- pixelType = PT_ABGR_8;
+ l.pixelType = PT_ABGR_8;
break;
case BufferedImage.TYPE_BYTE_GRAY:
- pixelType = PT_GRAY_8;
+ l.pixelType = PT_GRAY_8;
break;
case BufferedImage.TYPE_USHORT_GRAY:
- pixelType = PT_GRAY_16;
+ l.pixelType = PT_GRAY_16;
break;
default:
- // TODO: Add support for some images having
- // SinglePixelPackedModel and ComponentSampleModel
- throw new IllegalArgumentException(
- "CMMImageLayout - bad image type passed to constructor");
+ /* ColorConvertOp creates component images as
+ * default destination, so this kind of images
+ * has to be supported.
+ */
+ ColorModel cm = image.getColorModel();
+ if (cm instanceof ComponentColorModel) {
+ ComponentColorModel ccm = (ComponentColorModel) cm;
+
+ // verify whether the component size is fine
+ int[] cs = ccm.getComponentSize();
+ for (int s : cs) {
+ if (s != 8) {
+ return null;
+ }
+ }
+
+ return createImageLayout(image.getRaster());
+
+ }
+ return null;
}
- width = image.getWidth();
- height = image.getHeight();
+ l.width = image.getWidth();
+ l.height = image.getHeight();
switch (image.getType()) {
case BufferedImage.TYPE_INT_RGB:
case BufferedImage.TYPE_INT_ARGB:
case BufferedImage.TYPE_INT_BGR:
- intRaster = (IntegerComponentRaster)image.getRaster();
- nextRowOffset = intRaster.getScanlineStride()*4;
- offset = intRaster.getDataOffset(0)*4;
- dataArray = intRaster.getDataStorage();
- dataType = DT_INT;
+ do {
+ IntegerComponentRaster intRaster = (IntegerComponentRaster)
+ image.getRaster();
+ l.nextRowOffset = intRaster.getScanlineStride() * 4;
+ l.offset = intRaster.getDataOffset(0) * 4;
+ l.dataArray = intRaster.getDataStorage();
+ l.dataType = DT_INT;
+
+ if (l.nextRowOffset == l.width * 4 * intRaster.getPixelStride()) {
+ l.imageAtOnce = true;
+ }
+ } while (false);
break;
case BufferedImage.TYPE_3BYTE_BGR:
case BufferedImage.TYPE_4BYTE_ABGR:
- byteRaster = (ByteComponentRaster)image.getRaster();
- nextRowOffset = byteRaster.getScanlineStride();
- int firstBand = image.getSampleModel().getNumBands() - 1;
- offset = byteRaster.getDataOffset(firstBand);
- dataArray = byteRaster.getDataStorage();
- dataType = DT_BYTE;
+ do {
+ ByteComponentRaster byteRaster = (ByteComponentRaster)
+ image.getRaster();
+ l.nextRowOffset = byteRaster.getScanlineStride();
+ int firstBand = image.getSampleModel().getNumBands() - 1;
+ l.offset = byteRaster.getDataOffset(firstBand);
+ l.dataArray = byteRaster.getDataStorage();
+ l.dataType = DT_BYTE;
+ if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) {
+ l.imageAtOnce = true;
+ }
+ } while (false);
break;
case BufferedImage.TYPE_BYTE_GRAY:
- byteRaster = (ByteComponentRaster)image.getRaster();
- nextRowOffset = byteRaster.getScanlineStride();
- offset = byteRaster.getDataOffset(0);
- dataArray = byteRaster.getDataStorage();
- dataType = DT_BYTE;
+ do {
+ ByteComponentRaster byteRaster = (ByteComponentRaster)
+ image.getRaster();
+ l.nextRowOffset = byteRaster.getScanlineStride();
+ l.offset = byteRaster.getDataOffset(0);
+ l.dataArray = byteRaster.getDataStorage();
+ l.dataType = DT_BYTE;
+
+ if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) {
+ l.imageAtOnce = true;
+ }
+ } while (false);
break;
case BufferedImage.TYPE_USHORT_GRAY:
- shortRaster = (ShortComponentRaster)image.getRaster();
- nextRowOffset = shortRaster.getScanlineStride()*2;
- offset = shortRaster.getDataOffset(0) * 2;
- dataArray = shortRaster.getDataStorage();
- dataType = DT_SHORT;
+ do {
+ ShortComponentRaster shortRaster = (ShortComponentRaster)
+ image.getRaster();
+ l.nextRowOffset = shortRaster.getScanlineStride() * 2;
+ l.offset = shortRaster.getDataOffset(0) * 2;
+ l.dataArray = shortRaster.getDataStorage();
+ l.dataType = DT_SHORT;
+
+ if (l.nextRowOffset == l.width * 2 * shortRaster.getPixelStride()) {
+ l.imageAtOnce = true;
+ }
+ } while (false);
break;
+ default:
+ return null;
+ }
+ return l;
+ }
+
+ private static enum BandOrder {
+ DIRECT,
+ INVERTED,
+ ARBITRARY,
+ UNKNOWN;
+
+ public static BandOrder getBandOrder(int[] bandOffsets) {
+ BandOrder order = UNKNOWN;
+
+ int numBands = bandOffsets.length;
+
+ for (int i = 0; (order != ARBITRARY) && (i < bandOffsets.length); i++) {
+ switch (order) {
+ case UNKNOWN:
+ if (bandOffsets[i] == i) {
+ order = DIRECT;
+ } else if (bandOffsets[i] == (numBands - 1 - i)) {
+ order = INVERTED;
+ } else {
+ order = ARBITRARY;
+ }
+ break;
+ case DIRECT:
+ if (bandOffsets[i] != i) {
+ order = ARBITRARY;
+ }
+ break;
+ case INVERTED:
+ if (bandOffsets[i] != (numBands - 1 - i)) {
+ order = ARBITRARY;
+ }
+ break;
+ }
+ }
+ return order;
}
}
- public static boolean isSupported(BufferedImage image) {
- switch (image.getType()) {
- case BufferedImage.TYPE_INT_RGB:
- case BufferedImage.TYPE_INT_ARGB:
- case BufferedImage.TYPE_INT_BGR:
- case BufferedImage.TYPE_3BYTE_BGR:
- case BufferedImage.TYPE_4BYTE_ABGR:
- case BufferedImage.TYPE_BYTE_GRAY:
- case BufferedImage.TYPE_USHORT_GRAY:
- return true;
+ public static LCMSImageLayout createImageLayout(Raster r) {
+ LCMSImageLayout l = new LCMSImageLayout();
+ if (r instanceof ByteComponentRaster) {
+ ByteComponentRaster br = (ByteComponentRaster)r;
+
+ ComponentSampleModel csm = (ComponentSampleModel)r.getSampleModel();
+
+ l.pixelType = CHANNELS_SH(br.getNumBands()) | BYTES_SH(1);
+
+ int[] bandOffsets = csm.getBandOffsets();
+ BandOrder order = BandOrder.getBandOrder(bandOffsets);
+
+ int firstBand = 0;
+ switch (order) {
+ case INVERTED:
+ l.pixelType |= DOSWAP;
+ firstBand = csm.getNumBands() - 1;
+ break;
+ case DIRECT:
+ // do nothing
+ break;
+ default:
+ // unable to create the image layout;
+ return null;
+ }
+
+ l.nextRowOffset = br.getScanlineStride();
+ l.offset = br.getDataOffset(firstBand);
+ l.dataArray = br.getDataStorage();
+ l.dataType = DT_BYTE;
+
+ l.width = br.getWidth();
+ l.height = br.getHeight();
+
+ if (l.nextRowOffset == l.width * br.getPixelStride()) {
+ l.imageAtOnce = true;
+ }
+ return l;
}
- return false;
+ return null;
}
}
--- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java Tue Mar 05 17:18:55 2013 +0400
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java Thu Mar 07 14:05:21 2013 +0400
@@ -161,13 +161,18 @@
}
public void colorConvert(BufferedImage src, BufferedImage dst) {
- if (LCMSImageLayout.isSupported(src) &&
- LCMSImageLayout.isSupported(dst))
- {
- doTransform(new LCMSImageLayout(src), new LCMSImageLayout(dst));
- return;
+ LCMSImageLayout srcIL, dstIL;
+
+ dstIL = LCMSImageLayout.createImageLayout(dst);
+
+ if (dstIL != null) {
+ srcIL = LCMSImageLayout.createImageLayout(src);
+ if (srcIL != null) {
+ doTransform(srcIL, dstIL);
+ return;
+ }
}
- LCMSImageLayout srcIL, dstIL;
+
Raster srcRas = src.getRaster();
WritableRaster dstRas = dst.getRaster();
ColorModel srcCM = src.getColorModel();
@@ -439,6 +444,14 @@
public void colorConvert(Raster src, WritableRaster dst) {
LCMSImageLayout srcIL, dstIL;
+ dstIL = LCMSImageLayout.createImageLayout(dst);
+ if (dstIL != null) {
+ srcIL = LCMSImageLayout.createImageLayout(src);
+ if (srcIL != null) {
+ doTransform(srcIL, dstIL);
+ return;
+ }
+ }
// Can't pass src and dst directly to CMM, so process per scanline
SampleModel srcSM = src.getSampleModel();
SampleModel dstSM = dst.getSampleModel();
--- a/jdk/src/share/demo/java2d/J2DBench/build.xml Tue Mar 05 17:18:55 2013 +0400
+++ b/jdk/src/share/demo/java2d/J2DBench/build.xml Thu Mar 07 14:05:21 2013 +0400
@@ -52,7 +52,7 @@
<javac debug="flase" source="1.5" target="1.5" srcdir="${src}" destdir="${build}"/>
</target>
- <target name="run" depends="dist"
+ <target name="run" depends="dist"
description="run J2DBench" >
<java jar="${dist}/J2DBench.jar"
fork="true"
@@ -60,7 +60,7 @@
</java>
</target>
- <target name="analyze" depends="dist"
+ <target name="analyze" depends="dist"
description="run J2DAnalyzer" >
<java jar="${dist}/J2DAnalyzer.jar"
fork="true"
@@ -80,6 +80,10 @@
<copy todir="${build}/j2dbench/tests/iio/images">
<fileset dir="${resources}/images" />
</copy>
+ <mkdir dir="${build}/j2dbench/tests/cmm/images"/>
+ <copy todir="${build}/j2dbench/tests/cmm/images">
+ <fileset dir="${resources}/cmm_images" />
+ </copy>
</target>
<target name="dist" depends="compile, resources"
@@ -88,14 +92,14 @@
<mkdir dir="${dist}"/>
<!-- Put everything in ${build} into the J2DBench.jar file -->
- <jar jarfile="${dist}/J2DBench.jar" basedir="${build}"
+ <jar jarfile="${dist}/J2DBench.jar" basedir="${build}"
excludes="j2dbench/report/**" >
<manifest>
<attribute name="Built-By" value="${user.name}"/>
<attribute name="Main-Class" value="j2dbench.J2DBench"/>
</manifest>
</jar>
- <jar jarfile="${dist}/J2DAnalyzer.jar" basedir="${build}"
+ <jar jarfile="${dist}/J2DAnalyzer.jar" basedir="${build}"
includes="j2dbench/report/**" >
<manifest>
<attribute name="Built-By" value="${user.name}"/>
Binary file jdk/src/share/demo/java2d/J2DBench/resources/cmm_images/img_icc_large.jpg has changed
Binary file jdk/src/share/demo/java2d/J2DBench/resources/cmm_images/img_icc_medium.jpg has changed
Binary file jdk/src/share/demo/java2d/J2DBench/resources/cmm_images/img_icc_small.jpg has changed
--- a/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/ColorConversionTests.java Tue Mar 05 17:18:55 2013 +0400
+++ b/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/ColorConversionTests.java Thu Mar 07 14:05:21 2013 +0400
@@ -51,6 +51,7 @@
DataConversionTests.init();
ColorConvertOpTests.init();
+ EmbeddedProfileTests.init();
}
protected ColorConversionTests(Group parent, String nodeName, String description) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/EmbeddedProfileTests.java Thu Mar 07 14:05:21 2013 +0400
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This source code is provided to illustrate the usage of a given feature
+ * or technique and has been deliberately simplified. Additional steps
+ * required for a production-quality application, such as security checks,
+ * input validation and proper error handling, might not be present in
+ * this sample code.
+ */
+
+package j2dbench.tests.cmm;
+
+import j2dbench.Group;
+import j2dbench.Option;
+import j2dbench.Result;
+import j2dbench.TestEnvironment;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.net.URL;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.ImageInputStream;
+
+/* This benchmark verifies how changes in cmm library affects image decoding */
+public class EmbeddedProfileTests extends ColorConversionTests {
+
+ protected static Group grpRoot;
+ protected static Group grpOptionsRoot;
+
+ protected static Option inputImages;
+
+ public static void init() {
+ grpRoot = new Group(colorConvRoot, "embed", "Embedded Profile Tests");
+
+ grpOptionsRoot = new Group(grpRoot, "embedOptions", "Options");
+
+ inputImages = createImageList();
+
+ new ReadImageTest();
+ }
+
+ private static enum IccImageResource {
+ SMALL("images/img_icc_small.jpg", "512x512", "Small: 512x512"),
+ MEDIUM("images/img_icc_medium.jpg", "2048x2048", "Medium: 2048x2048"),
+ LARGE("images/img_icc_large.jpg", "4096x4096", "Large: 4096x4096");
+
+ private IccImageResource(String file, String name, String description) {
+ this.url = CMMTests.class.getResource(file);
+ this.abbrev = name;
+ this.description = description;
+ }
+
+ public final URL url;
+ public final String abbrev;
+ public final String description;
+ }
+
+ private static Option createImageList() {
+ IccImageResource[] images = IccImageResource.values();
+
+ int num = images.length;
+
+ String[] names = new String[num];
+ String[] abbrev = new String[num];
+ String[] descr = new String[num];
+
+ for (int i = 0; i < num; i++) {
+ names[i] = images[i].toString();
+ abbrev[i] = images[i].abbrev;
+ descr[i] = images[i].description;
+ }
+
+ Option list = new Option.ObjectList(grpOptionsRoot,
+ "Images", "Input Images",
+ names, images, abbrev, descr, 1);
+
+ return list;
+ }
+
+ public EmbeddedProfileTests(Group parent, String nodeName, String description) {
+ super(parent, nodeName, description);
+ addDependencies(grpOptionsRoot, true);
+ }
+
+ private static class Context {
+ URL input;
+
+ public Context(TestEnvironment env, Result res) {
+
+ IccImageResource icc_input = (IccImageResource)
+ env.getModifier(inputImages);
+
+ input = icc_input.url;
+ }
+ }
+
+ public Object initTest(TestEnvironment env, Result res) {
+ return new Context(env, res);
+ }
+
+ public void cleanupTest(TestEnvironment env, Object o) {
+ Context ctx = (Context)o;
+ ctx.input = null;
+ }
+
+ private static class ReadImageTest extends EmbeddedProfileTests {
+ public ReadImageTest() {
+ super(grpRoot, "embd_img_read", "ImageReader.read()");
+ }
+
+ public void runTest(Object octx, int numReps) {
+ final Context ctx = (Context)octx;
+ final URL url = ctx.input;
+ ImageInputStream iis = null;
+ ImageReader reader = null;
+
+ try {
+ iis = ImageIO.createImageInputStream(url.openStream());
+ reader = ImageIO.getImageReaders(iis).next();
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to run the becnhmark", e);
+ }
+
+ do {
+ try {
+ reader.setInput(iis);
+ BufferedImage img = reader.read(0);
+ reader.reset();
+
+ iis = ImageIO.createImageInputStream(url.openStream());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } while (--numReps >= 0);
+ }
+ }
+}
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c Tue Mar 05 17:18:55 2013 +0400
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c Thu Mar 07 14:05:21 2013 +0400
@@ -117,6 +117,7 @@
static jfieldID IL_nextRowOffset_fID;
static jfieldID IL_width_fID;
static jfieldID IL_height_fID;
+static jfieldID IL_imageAtOnce_fID;
static jfieldID PF_ID_fID;
JavaVM *javaVM;
@@ -237,7 +238,7 @@
* Method: loadProfile
* Signature: ([B)J
*/
-JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfile
+JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative
(JNIEnv *env, jobject obj, jbyteArray data)
{
jbyte* dataArray;
@@ -284,7 +285,7 @@
* Method: freeProfile
* Signature: (J)V
*/
-JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_freeProfile
+JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative
(JNIEnv *env, jobject obj, jlong id)
{
storeID_t sProf;
@@ -369,48 +370,22 @@
static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);
static cmsBool _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size);
-/*
- * Class: sun_java2d_cmm_lcms_LCMS
- * Method: getTagSize
- * Signature: (JI)I
- */
-JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagSize
- (JNIEnv *env, jobject obj, jlong id, jint tagSig)
-{
- storeID_t sProf;
- TagSignature_t sig;
- jint result = -1;
-
- sProf.j = id;
- sig.j = tagSig;
-
- if (tagSig == SigHead) {
- result = sizeof(cmsICCHeader);
- } else {
- if (cmsIsTag(sProf.pf, sig.cms)) {
- result = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0);
- } else {
- JNU_ThrowByName(env, "java/awt/color/CMMException",
- "ICC profile tag not found");
- }
- }
-
- return result;
-}
/*
* Class: sun_java2d_cmm_lcms_LCMS
* Method: getTagData
* Signature: (JI[B)V
*/
-JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData
- (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data)
+JNIEXPORT jbyteArray JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagNative
+ (JNIEnv *env, jobject obj, jlong id, jint tagSig)
{
storeID_t sProf;
TagSignature_t sig;
cmsInt32Number tagSize;
- jbyte* dataArray;
+ jbyte* dataArray = NULL;
+ jbyteArray data = NULL;
+
jint bufSize;
sProf.j = id;
@@ -419,12 +394,14 @@
if (tagSig == SigHead) {
cmsBool status;
- bufSize =(*env)->GetArrayLength(env, data);
+ // allocate java array
+ bufSize = sizeof(cmsICCHeader);
+ data = (*env)->NewByteArray(env, bufSize);
- if (bufSize < sizeof(cmsICCHeader)) {
- JNU_ThrowByName(env, "java/awt/color/CMMException",
- "Insufficient buffer capacity");
- return;
+ if (data == NULL) {
+ JNU_ThrowByName(env, "java/awt/color/CMMException",
+ "Unable to allocate buffer");
+ return NULL;
}
dataArray = (*env)->GetByteArrayElements (env, data, 0);
@@ -432,7 +409,7 @@
if (dataArray == NULL) {
JNU_ThrowByName(env, "java/awt/color/CMMException",
"Unable to get buffer");
- return;
+ return NULL;
}
status = _getHeaderInfo(sProf.pf, dataArray, bufSize);
@@ -442,9 +419,10 @@
if (!status) {
JNU_ThrowByName(env, "java/awt/color/CMMException",
"ICC Profile header not found");
+ return NULL;
}
- return;
+ return data;
}
if (cmsIsTag(sProf.pf, sig.cms)) {
@@ -452,16 +430,15 @@
} else {
JNU_ThrowByName(env, "java/awt/color/CMMException",
"ICC profile tag not found");
- return;
+ return NULL;
}
- // verify data buffer capacity
- bufSize = (*env)->GetArrayLength(env, data);
-
- if (tagSize < 0 || 0 > bufSize || tagSize > bufSize) {
+ // allocate java array
+ data = (*env)->NewByteArray(env, tagSize);
+ if (data == NULL) {
JNU_ThrowByName(env, "java/awt/color/CMMException",
- "Insufficient buffer capacity.");
- return;
+ "Unable to allocate buffer");
+ return NULL;
}
dataArray = (*env)->GetByteArrayElements (env, data, 0);
@@ -469,7 +446,7 @@
if (dataArray == NULL) {
JNU_ThrowByName(env, "java/awt/color/CMMException",
"Unable to get buffer");
- return;
+ return NULL;
}
bufSize = cmsReadRawTag(sProf.pf, sig.cms, dataArray, tagSize);
@@ -479,8 +456,9 @@
if (bufSize != tagSize) {
JNU_ThrowByName(env, "java/awt/color/CMMException",
"Can not get tag data.");
+ return NULL;
}
- return;
+ return data;
}
/*
@@ -488,7 +466,7 @@
* Method: setTagData
* Signature: (JI[B)V
*/
-JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagData
+JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative
(JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data)
{
storeID_t sProf;
@@ -586,6 +564,7 @@
char* inputRow;
char* outputRow;
jobject srcData, dstData;
+ jboolean srcAtOnce = JNI_FALSE, dstAtOnce = JNI_FALSE;
srcOffset = (*env)->GetIntField (env, src, IL_offset_fID);
srcNextRowOffset = (*env)->GetIntField (env, src, IL_nextRowOffset_fID);
@@ -594,6 +573,9 @@
width = (*env)->GetIntField (env, src, IL_width_fID);
height = (*env)->GetIntField (env, src, IL_height_fID);
+ srcAtOnce = (*env)->GetBooleanField(env, src, IL_imageAtOnce_fID);
+ dstAtOnce = (*env)->GetBooleanField(env, dst, IL_imageAtOnce_fID);
+
sTrans.j = (*env)->GetLongField (env, trans, Trans_ID_fID);
if (sTrans.xf == NULL) {
@@ -625,10 +607,14 @@
inputRow = (char*)inputBuffer + srcOffset;
outputRow = (char*)outputBuffer + dstOffset;
- for (i = 0; i < height; i++) {
- cmsDoTransform(sTrans.xf, inputRow, outputRow, width);
- inputRow += srcNextRowOffset;
- outputRow += dstNextRowOffset;
+ if (srcAtOnce && dstAtOnce) {
+ cmsDoTransform(sTrans.xf, inputRow, outputRow, width * height);
+ } else {
+ for (i = 0; i < height; i++) {
+ cmsDoTransform(sTrans.xf, inputRow, outputRow, width);
+ inputRow += srcNextRowOffset;
+ outputRow += dstNextRowOffset;
+ }
}
releaseILData(env, inputBuffer, srcDType, srcData);
@@ -670,6 +656,7 @@
IL_width_fID = (*env)->GetFieldID (env, IL, "width", "I");
IL_height_fID = (*env)->GetFieldID (env, IL, "height", "I");
IL_offset_fID = (*env)->GetFieldID (env, IL, "offset", "I");
+ IL_imageAtOnce_fID = (*env)->GetFieldID (env, IL, "imageAtOnce", "Z");
IL_nextRowOffset_fID = (*env)->GetFieldID (env, IL, "nextRowOffset", "I");
PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J");