/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2005-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.image.jai;
import java.awt.image.renderable.ContextualRenderedImageFactory;
import java.awt.image.renderable.RenderedImageFactory;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import javax.media.jai.JAI;
import javax.media.jai.OperationDescriptor;
import javax.media.jai.OperationRegistry;
import javax.media.jai.ParameterBlockJAI;
import javax.media.jai.registry.RIFRegistry;
import javax.media.jai.registry.RenderedRegistryMode;
import org.geotools.coverage.GridSampleDimension;
import org.geotools.coverage.grid.AbstractGridCoverage;
import org.geotools.resources.i18n.LoggingKeys;
import org.geotools.resources.i18n.Loggings;
import org.geotools.util.logging.Logging;
/**
* A set of static methods for managing JAI's {@linkplain OperationRegistry operation registry}.
*
* @since 2.2
*
* @source $URL$
* @version $Id$
* @author Martin Desruisseaux (IRD)
* @author Andrea Aime - GeoSolutions
*/
public final class Registry {
/**
* The JAITools product name (used to register operations in JAI)
*/
public static final String JAI_TOOLS_PRODUCT = "org.jaitools.media.jai";
/**
* The GeoTools product name (used to register operations in JAI)
*/
public static final String GEOTOOLS_PRODUCT = "org.geotools";
/**
* Do not allows instantiation of this class.
*/
private Registry() {
}
/**
* Allows or disallow native acceleration for the specified operation on the given JAI instance.
* By default, JAI uses hardware accelerated methods when available. For example, it make use of
* MMX instructions on Intel processors. Unfortunatly, some native method crash the Java Virtual
* Machine under some circonstances. For example on JAI 1.1.2, the {@code "Affine"} operation on
* an image with float data type, bilinear interpolation and an {@link javax.media.jai.ImageLayout}
* rendering hint cause an exception in medialib native code. Disabling the native acceleration
* (i.e using the pure Java version) is a convenient workaround until Sun fix the bug.
* <p>
* <strong>Implementation note:</strong> the current implementation assumes that factories for
* native implementations are declared in the {@code com.sun.media.jai.mlib} package, while
* factories for pure java implementations are declared in the {@code com.sun.media.jai.opimage}
* package. It work for Sun's 1.1.2 implementation, but may change in future versions. If this
* method doesn't recognize the package, it does nothing.
*
* @param operation The operation name (e.g. {@code "Affine"}).
* @param allowed {@code false} to disallow native acceleration.
* @param jai The instance of {@link JAI} we are going to work on. This argument can be
* omitted for the {@linkplain JAI#getDefaultInstance default JAI instance}.
*
* @see <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4906854">JAI bug report 4906854</a>
*
* @since 2.5
*/
public synchronized static void setNativeAccelerationAllowed(final String operation,
final boolean allowed,
final JAI jai)
{
final String product = "com.sun.media.jai";
final OperationRegistry registry = jai.getOperationRegistry();
// TODO: Check if we can remove SuppressWarnings with a future JAI version.
@SuppressWarnings("unchecked")
final List<RenderedImageFactory> factories = registry.getOrderedFactoryList(
RenderedRegistryMode.MODE_NAME, operation, product);
if (factories != null) {
RenderedImageFactory javaFactory = null;
RenderedImageFactory nativeFactory = null;
Boolean currentState = null;
for (final RenderedImageFactory factory : factories) {
final String pack = factory.getClass().getPackage().getName();
if (pack.equals("com.sun.media.jai.mlib")) {
nativeFactory = factory;
if (javaFactory != null) {
currentState = Boolean.FALSE;
}
}
if (pack.equals("com.sun.media.jai.opimage")) {
javaFactory = factory;
if (nativeFactory != null) {
currentState = Boolean.TRUE;
}
}
}
if (currentState!=null && currentState.booleanValue()!=allowed) {
RIFRegistry.unsetPreference(registry, operation, product,
allowed ? javaFactory : nativeFactory,
allowed ? nativeFactory : javaFactory);
RIFRegistry.setPreference(registry, operation, product,
allowed ? nativeFactory : javaFactory,
allowed ? javaFactory : nativeFactory);
final LogRecord record = Loggings.format(Level.CONFIG,
LoggingKeys.NATIVE_ACCELERATION_STATE_$2,
operation, Integer.valueOf(allowed ? 1 : 0));
log("setNativeAccelerationAllowed", record);
}
}
}
/**
* Allows or disallow native acceleration for the specified operation on the
* {@linkplain JAI#getDefaultInstance default JAI instance}. This method is
* a shortcut for <code>{@linkplain #setNativeAccelerationAllowed(String,boolean,JAI)
* setNativeAccelerationAllowed}(operation, allowed, JAI.getDefaultInstance())</code>.
*
* @see #setNativeAccelerationAllowed(String, boolean, JAI)
*/
public static void setNativeAccelerationAllowed(final String operation, final boolean allowed) {
setNativeAccelerationAllowed(operation, allowed, JAI.getDefaultInstance());
}
/**
* Register the "SampleTranscode" image operation to the operation registry
* of the specified JAI instance. This method is invoked by the static
* initializer of {@link GridSampleDimension}.
* @param jai is he {@link JAI} instance in which we ant to register this operation.
* @param descriptor is the {@link OperationDescriptor} for the JAI operation to register.
* @param name is the name of the operation to register.
* @param crif is the rendered image facotry for this operation.
* @return <code>true</code> if everything goes well, <code>false</code> otherwise.
*/
public static boolean registerRIF(
final JAI jai,
final OperationDescriptor descriptor,
final String name,
final ContextualRenderedImageFactory crif) {
final OperationRegistry registry = jai.getOperationRegistry();
try {
registry.registerDescriptor(descriptor);
registry.registerFactory(RenderedRegistryMode.MODE_NAME,
name, GEOTOOLS_PRODUCT,crif);
return true;
} catch (IllegalArgumentException exception) {
final LogRecord record = Loggings.format(Level.SEVERE,
LoggingKeys.CANT_REGISTER_JAI_OPERATION_$1, name);
// Note: GridSampleDimension is the public class that use this
// transcoder.
record.setSourceClassName(GridSampleDimension.class.getName());
record.setSourceMethodName("<classinit>");
record.setThrown(exception);
record.setLoggerName(AbstractGridCoverage.LOGGER.getName());
AbstractGridCoverage.LOGGER.log(record);
}
return false;
}
/**
* Forcefully registers the specified rendered operation in the JAI registry
*
* @param descriptor
* @param rif
* @param productName
* @return true if the registration succeded, false if the registration was not required
* as the operation was already available in the registry
*/
public static boolean registerRIF(final JAI jai, OperationDescriptor descriptor,
RenderedImageFactory rif, String productName) {
final OperationRegistry registry = jai.getOperationRegistry();
try {
// see if the operation is already registered, avoid registering it twice
new ParameterBlockJAI(descriptor.getName());
return false;
} catch (Exception e) {
registry.registerDescriptor(descriptor);
final String descName = descriptor.getName();
registry.registerFactory(RenderedRegistryMode.MODE_NAME, descName, productName,
rif);
return true;
}
}
/**
* Logs the specified record.
*/
private static void log(final String method, final LogRecord record) {
record.setSourceClassName(Registry.class.getName());
record.setSourceMethodName(method);
final Logger logger = Logging.getLogger(Registry.class);
record.setLoggerName(logger.getName());
logger.log(record);
}
}