modules/graphics/src/main/java/com/sun/scenario/effect/impl/state/LinearConvolveKernel.java
Print this page
*** 23,111 ****
* questions.
*/
package com.sun.scenario.effect.impl.state;
- import java.nio.FloatBuffer;
import com.sun.javafx.geom.Rectangle;
import com.sun.javafx.geom.transform.BaseTransform;
- import com.sun.scenario.effect.Color4f;
- import com.sun.scenario.effect.Effect;
- import com.sun.scenario.effect.FilterContext;
- import com.sun.scenario.effect.ImageData;
- import com.sun.scenario.effect.impl.EffectPeer;
- import com.sun.scenario.effect.impl.Renderer;
/**
* The helper class for defining a 1 dimensional linear convolution kernel
* for either the LinearConvolve or LinearConvolveShadow shaders.
* This class is abstract and must be subclassed for specific linear
* convolutions.
*/
public abstract class LinearConvolveKernel {
- public static final int MAX_KERNEL_SIZE = 128;
-
- public enum PassType {
- /**
- * The kernel on this pass will be applied horizontally with
- * the kernel centered symmetrically around each pixel.
- * The specific conditions indicated by this type are:
- * <ul>
- * <li>The kernel is an odd size {@code (2*k+1)}
- * <li>The data for destination pixel {@code (x,y)} is taken from
- * pixels {@code x-k,y} through {@code (x+k,y)} with the weights
- * applied in that same order.
- * <li>If the bounds of the source image are {@code (x,y,w,h)} then
- * the bounds of the destination will be {@code (x-k,y,w+2*k,h)}.
- * </ul>
- */
- HORIZONTAL_CENTERED,
-
- /**
- * The kernel on this pass will be applied vertically with
- * the kernel centered symmetrically around each pixel.
- * The specific conditions indicated by this type are:
- * <ul>
- * <li>The kernel is an odd size {@code (2*k+1)}
- * <li>The data for destination pixel {@code (x,y)} is taken from
- * pixels {@code x,y-k} through {@code (x,y+k)} with the weights
- * applied in that same order.
- * <li>If the bounds of the source image are {@code (x,y,w,h)} then
- * the bounds of the destination will be {@code (x,y-k,w,h+2*k)}.
- * </ul>
- */
- VERTICAL_CENTERED,
-
- /**
- * The kernel on this pass can be applied in any direction or with
- * any kind of offset.
- * No assumptions are made about the offset and delta of the kernel
- * vector.
- */
- GENERAL_VECTOR,
- };
-
- /**
- * Returns the peer sample count for a given kernel size. There are
- * only a few peers defined to operate on specific sizes of convolution
- * kernel. If there are peers defined only for kernel sizes of 8 and 16
- * and a given effect has a linear convolution kernel with 5 weights,
- * then the peer for size 8 will be used and the buffer of weights must
- * be padded out to the appropriate size with 0s so that the shader
- * constant pool will be fully initialized and the extra unneeded
- * convolution samples will be ignored by the 0 weights.
- *
- * @param ksize the number of computed convolution kernel weights
- * @return the number of convolution weights which will be applied by
- * the associated peer.
- */
- public static int getPeerSize(int ksize) {
- if (ksize < 32) return ((ksize + 3) & (~3));
- if (ksize <= MAX_KERNEL_SIZE) return ((ksize + 31) & (~31));
- throw new RuntimeException("No peer available for kernel size: "+ksize);
- }
-
/**
* Returns true if this is a LinearConvolveShadow operation, or false
* if the operation is a regular LinearConvolve.
*
* @return true if this is a Shadow operation
--- 23,42 ----
*** 113,428 ****
public boolean isShadow() {
return false;
}
/**
- * Returns the number of linear convolution passes the algorithm must make
- * to complete its work. Most subclasses will use only 1 or 2 passes
- * (typically broken down into a horizontal pass and a vertical pass as
- * necessary).
- *
- * @return the number of passes to be made
- */
- public abstract int getNumberOfPasses();
-
- /**
* Returns true if the entire operation of this linear convolution
* would have no effect on the source data.
*
* @return true if the operation is a NOP
*/
public boolean isNop() {
return false;
}
/**
- * Returns true if the operation of a particular pass of this linear
- * convolution would have no effect on the source data.
- *
- * @param pass the algorithm pass being performed
- * @return true if the given pass is a NOP
- */
- public boolean isNop(int pass) {
- return false;
- }
-
- /**
- * Returns the {@link PassType} that indicates the assumptions that
- * can be made in optimizing the application of the kernel on this
- * pass.
- *
- * @param pass the algorithm pass being performed
- * @return the {@link PassType} that describes the kernel vector for
- * this pass
- */
- public PassType getPassType(int pass) {
- return PassType.GENERAL_VECTOR;
- }
-
- /**
* Returns the size of the output image needed for a given input
* image dimensions and a given pass of the algorithm.
*
* @param srcdimension the bounds of the input image
* @param pass the algorithm pass being performed
* @return the bounds of the result image
*/
public abstract Rectangle getResultBounds(Rectangle srcdimension, int pass);
/**
- * Returns the size of the scaled result image needed to hold the output
- * for a given input image dimensions and a given pass of the algorithm.
- * The image may be further scaled after the shader operation is through
- * to obtain the final result bounds.
- * This value is only of use to the actual shader to understand exactly
- * how much room to allocate for the shader result.
- *
- * @param srcdimension the bounds of the input image
- * @param pass the algorithm pass being performed
- * @return the bounds of the result image
- */
- public Rectangle getScaledResultBounds(Rectangle srcdimension, int pass) {
- return getResultBounds(srcdimension, pass);
- }
-
- /**
- * Returns an array of 4 floats used to initialize a float4 Shader
- * constant with the relative starting location of the first weight
- * in the convolution kernel and the incremental offset between each
- * sample to be weighted and convolved. The values are stored in
- * the array in the following order:
- * <pre>
- * shadervec.x = vector[0] = incdx // X offset between subsequent samples
- * shadervec.y = vector[1] = incdy // Y offset between subsequent samples
- * shadervec.z = vector[2] = startdx // X offset to first convolution sample
- * shadervec.w = vector[3] = startdy // Y offset to first convolution sample
- * </pre>
- * These values are used in the shader loop as follows:
- * <pre>
- * samplelocation = outputpixellocation.xy + shadervec.zw;
- * for (each weight) {
- * sum += weight * sample(samplelocation.xy);
- * samplelocation.xy += shadervec.xy;
- * }
- *
- * @param srcnativedimensions the native dimensions (including unused
- * padding) of the input source
- * @param pass the pass of the algorithm being performed
- * @return an array of 4 floats representing
- * {@code [ incdx, incdy, startdx, startdy ]}
- */
- public abstract float[] getVector(Rectangle srcnativedimensions,
- BaseTransform transform, int pass);
-
- /**
* Returns the size of the kernel for a given pass.
*
* @param pass the pass of the algorithm being performed
* @return the size of the kernel for the given pass
*/
public abstract int getKernelSize(int pass);
! /**
! * Returns the size of the kernel used in the shader for a given pass,
! * taking into account the scaling specified by the getPow2ScaleXY methods.
! *
! * @param pass the pass of the algorithm being performed
! * @return the size of the kernel for the scaled operation
! */
! public int getScaledKernelSize(int pass) {
! return getKernelSize(pass);
! }
!
! /**
! * Returns the number of power of 2 scales along the X axis.
! * Positive numbers mean to scale the image larger by the indicated
! * factors of 2.0.
! * Negative numbers mean to scale the image smaller by the indicated
! * factors of 0.5.
! * Overall the image will be scaled by {@code pow(2.0, getPow2ScaleX())}.
! * <p>
! * The kernel specified by the {@link #getWeights()} method will be
! * relative to the scale factor recommended by this method.
! * This scaling allows larger kernels to be reduced in size to save
! * computation if the resolution reduction will not alter the quality
! * of the convolution (eg. for blur convolutions).
! *
! * @return the power of 2.0 by which to scale the source image along the
! * X axis.
! */
! public int getPow2ScaleX() {
! return 0;
! }
!
! /**
! * Returns the number of power of 2 scales along the Y axis.
! * Positive numbers mean to scale the image larger by the indicated
! * factors of 2.0.
! * Negative numbers mean to scale the image smaller by the indicated
! * factors of 0.5.
! * Overall the image will be scaled by {@code pow(2.0, getPow2ScaleY())}.
! * <p>
! * The kernel specified by the {@link #getWeights()} method will be
! * relative to the scale factor recommended by this method.
! * This scaling allows larger kernels to be reduced in size to save
! * computation if the resolution reduction will not alter the quality
! * of the convolution (eg. for blur convolutions).
! *
! * @return the power of 2.0 by which to scale the source image along the
! * Y axis.
! */
! public int getPow2ScaleY() {
! return 0;
! }
!
! /**
! * A {@link FloatBuffer} padded out to the required size as specified by
! * the {@link #getPeerSize()} method.
! *
! * @param pass the pass of the algorithm being performed
! * @return a {@code FloatBuffer} containing the kernel convolution weights
! */
! public abstract FloatBuffer getWeights(int pass);
!
! /**
! * Returns the maximum number of valid float4 elements that should be
! * referenced from the buffer returned by getWeights() for the given pass.
! *
! * @param pass the pass of the algorithm being performed
! * @return the maximum number of valid float4 elements in the weights buffer
! */
! public int getWeightsArrayLength(int pass) {
! int ksize = getScaledKernelSize(pass);
! int psize = getPeerSize(ksize);
! return psize / 4;
! }
!
! final static float[] BLACK_COMPONENTS =
! Color4f.BLACK.getPremultipliedRGBComponents();
!
! /**
! * Returns the color components to be used for a linearly convolved shadow.
! * Only the LinearConvolveShadow shader uses this method. State
! * subclasses that are only intended to be used with the LinearConvolve
! * shader do not need to override this method.
! *
! * @param pass the pass of the algorithm being performed
! * @return the color components for the shadow color for the given pass
! */
! public float[] getShadowColorComponents(int pass) {
! return BLACK_COMPONENTS;
! }
!
! public EffectPeer getPeer(Renderer r, FilterContext fctx, int pass) {
! if (isNop(pass)) {
! return null;
! }
! int ksize = getScaledKernelSize(pass);
! int psize = getPeerSize(ksize);
! String opname = isShadow() ? "LinearConvolveShadow" : "LinearConvolve";
! return r.getPeerInstance(fctx, opname, psize);
! }
!
! public Rectangle transform(Rectangle clip,
! int xpow2scales, int ypow2scales)
! {
! // Modeled after Renderer.transform(fctx, img, hscale, vscale)
! if (clip == null || (xpow2scales | ypow2scales) == 0) {
! return clip;
! }
! clip = new Rectangle(clip);
! if (xpow2scales < 0) {
! xpow2scales = -xpow2scales;
! clip.width = (clip.width + (1 << xpow2scales) - 1) >> xpow2scales;
! clip.x >>= xpow2scales;
! } else if (xpow2scales > 0) {
! clip.width = clip.width << xpow2scales;
! clip.x <<= xpow2scales;
! }
! if (ypow2scales < 0) {
! ypow2scales = -ypow2scales;
! clip.height = (clip.height + (1 << ypow2scales) - 1) >> ypow2scales;
! clip.y >>= ypow2scales;
! } else if (ypow2scales > 0) {
! clip.height = clip.height << ypow2scales;
! clip.y <<= ypow2scales;
! }
! return clip;
! }
!
! public ImageData filterImageDatas(Effect effect,
! FilterContext fctx,
! BaseTransform transform,
! Rectangle outputClip,
! ImageData... inputs)
! {
! ImageData src = inputs[0];
! src.addref();
! if (isNop()) {
! return src;
! }
! Rectangle approxBounds = inputs[0].getUntransformedBounds();
! int approxW = approxBounds.width;
! int approxH = approxBounds.height;
! Renderer r = Renderer.getRenderer(fctx, effect, approxW, approxH);
! EffectPeer peer0 = getPeer(r, fctx, 0);
! EffectPeer peer1 = getPeer(r, fctx, 1);
! int hscale = 0;
! int vscale = 0;
! if (peer0 instanceof LinearConvolvePeer) {
! hscale = ((LinearConvolvePeer) peer0).getPow2ScaleX(this);
! }
! if (peer1 instanceof LinearConvolvePeer) {
! vscale = ((LinearConvolvePeer) peer1).getPow2ScaleY(this);
! }
! Rectangle filterClip = outputClip;
! if ((hscale | vscale) != 0) {
! src = r.transform(fctx, src, hscale, vscale);
! if (!src.validate(fctx)) {
! src.unref();
! return src;
! }
! filterClip = transform(outputClip, hscale, vscale);
! }
! if (filterClip != null) {
! // The inputClip was already grown by the padding when the
! // inputs were filtered, but now we need to make sure that
! // the peers pass out padded results from the already padded
! // input data, so we grow the clip here by the size of the
! // scaled kernel padding.
! int hgrow = getScaledKernelSize(0) / 2;
! int vgrow = getScaledKernelSize(1) / 2;
! if ((hgrow | vgrow) != 0) {
! if (filterClip == outputClip) {
! filterClip = new Rectangle(outputClip);
! }
! filterClip.grow(hgrow, vgrow);
! }
! }
! if (peer0 != null) {
! peer0.setPass(0);
! ImageData res = peer0.filter(effect, transform, filterClip, src);
! src.unref();
! src = res;
! if (!src.validate(fctx)) {
! src.unref();
! return src;
! }
! }
!
! if (peer1 != null) {
! peer1.setPass(1);
! ImageData res = peer1.filter(effect, transform, filterClip, src);
! src.unref();
! src = res;
! if (!src.validate(fctx)) {
! src.unref();
! return src;
! }
! }
!
! if ((hscale | vscale) != 0) {
! src = r.transform(fctx, src, -hscale, -vscale);
! }
! return src;
! }
}
--- 44,77 ----
public boolean isShadow() {
return false;
}
/**
* Returns true if the entire operation of this linear convolution
* would have no effect on the source data.
*
* @return true if the operation is a NOP
*/
public boolean isNop() {
return false;
}
/**
* Returns the size of the output image needed for a given input
* image dimensions and a given pass of the algorithm.
*
* @param srcdimension the bounds of the input image
* @param pass the algorithm pass being performed
* @return the bounds of the result image
*/
public abstract Rectangle getResultBounds(Rectangle srcdimension, int pass);
/**
* Returns the size of the kernel for a given pass.
*
* @param pass the pass of the algorithm being performed
* @return the size of the kernel for the given pass
*/
public abstract int getKernelSize(int pass);
! public abstract LinearConvolveRenderState getRenderState(BaseTransform filtertx);
}