Merge "Add filtering and directSampling features for BitmapShader"

This commit is contained in:
Derek Sollenberger
2022-01-18 13:01:54 +00:00
committed by Android (Google) Code Review
4 changed files with 134 additions and 11 deletions

View File

@@ -15242,6 +15242,11 @@ package android.graphics {
public class BitmapShader extends android.graphics.Shader {
ctor public BitmapShader(@NonNull android.graphics.Bitmap, @NonNull android.graphics.Shader.TileMode, @NonNull android.graphics.Shader.TileMode);
method public int getFilterMode();
method public void setFilterMode(int);
field public static final int FILTER_MODE_DEFAULT = 0; // 0x0
field public static final int FILTER_MODE_LINEAR = 2; // 0x2
field public static final int FILTER_MODE_NEAREST = 1; // 0x1
}
public enum BlendMode {
@@ -16648,6 +16653,7 @@ package android.graphics {
method public void setFloatUniform(@NonNull String, float, float, float);
method public void setFloatUniform(@NonNull String, float, float, float, float);
method public void setFloatUniform(@NonNull String, @NonNull float[]);
method public void setInputBuffer(@NonNull String, @NonNull android.graphics.BitmapShader);
method public void setInputShader(@NonNull String, @NonNull android.graphics.Shader);
method public void setIntUniform(@NonNull String, int);
method public void setIntUniform(@NonNull String, int, int);

View File

@@ -16,8 +16,12 @@
package android.graphics;
import android.annotation.IntDef;
import android.annotation.NonNull;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Shader used to draw a bitmap as a texture. The bitmap can be repeated or
* mirrored by setting the tiling mode.
@@ -31,6 +35,47 @@ public class BitmapShader extends Shader {
private int mTileX;
private int mTileY;
/** @hide */
@IntDef(prefix = {"FILTER_MODE"}, value = {
FILTER_MODE_DEFAULT,
FILTER_MODE_NEAREST,
FILTER_MODE_LINEAR
})
@Retention(RetentionPolicy.SOURCE)
public @interface FilterMode {}
/**
* This FilterMode value will respect the value of the Paint#isFilterBitmap flag while the
* shader is attached to the Paint.
*
* <p>The exception to this rule is when a Shader is attached as input to a RuntimeShader. In
* that case this mode will default to FILTER_MODE_NEAREST.</p>
*
* @see #setFilterMode(int)
*/
public static final int FILTER_MODE_DEFAULT = 0;
/**
* This FilterMode value will cause the shader to sample from the nearest pixel to the requested
* sample point.
*
* <p>This value will override the effect of Paint#isFilterBitmap.</p>
*
* @see #setFilterMode(int)
*/
public static final int FILTER_MODE_NEAREST = 1;
/**
* This FilterMode value will cause the shader to interpolate the output of the shader from a
* 2x2 grid of pixels nearest to the sample point (i.e. bilinear interpolation).
*
* <p>This value will override the effect of Paint#isFilterBitmap.</p>
*
* @see #setFilterMode(int)
*/
public static final int FILTER_MODE_LINEAR = 2;
@FilterMode
private int mFilterMode;
/*
* This is cache of the last value from the Paint of bitmap-filtering.
* In the future, BitmapShaders will carry their own (expanded) data for this
@@ -48,6 +93,15 @@ public class BitmapShader extends Shader {
*/
private boolean mFilterFromPaint;
/**
* Stores whether or not the contents of this shader's bitmap will be sampled
* without modification or if the bitmap's properties, like colorspace and
* premultiplied alpha, will be respected when sampling from the bitmap's buffer.
*/
private boolean mIsDirectSampled;
private boolean mRequestDirectSampling;
/**
* Call this to create a new shader that will draw with a bitmap.
*
@@ -66,24 +120,60 @@ public class BitmapShader extends Shader {
mBitmap = bitmap;
mTileX = tileX;
mTileY = tileY;
mFilterMode = FILTER_MODE_DEFAULT;
mFilterFromPaint = false;
mIsDirectSampled = false;
mRequestDirectSampling = false;
}
/**
* Returns the filter mode used when sampling from this shader
*/
@FilterMode
public int getFilterMode() {
return mFilterMode;
}
/**
* Set the filter mode to be used when sampling from this shader
*/
public void setFilterMode(@FilterMode int mode) {
if (mode != mFilterMode) {
mFilterMode = mode;
discardNativeInstance();
}
}
/** @hide */
/* package */ synchronized long getNativeInstanceWithDirectSampling() {
mRequestDirectSampling = true;
return getNativeInstance();
}
/** @hide */
@Override
protected long createNativeInstance(long nativeMatrix, boolean filterFromPaint) {
mFilterFromPaint = filterFromPaint;
boolean enableLinearFilter = mFilterMode == FILTER_MODE_LINEAR;
if (mFilterMode == FILTER_MODE_DEFAULT) {
mFilterFromPaint = filterFromPaint;
enableLinearFilter = mFilterFromPaint;
}
mIsDirectSampled = mRequestDirectSampling;
mRequestDirectSampling = false;
return nativeCreate(nativeMatrix, mBitmap.getNativeInstance(), mTileX, mTileY,
mFilterFromPaint);
enableLinearFilter, mIsDirectSampled);
}
/** @hide */
@Override
protected boolean shouldDiscardNativeInstance(boolean filterFromPaint) {
return mFilterFromPaint != filterFromPaint;
return mIsDirectSampled != mRequestDirectSampling
|| (mFilterMode == FILTER_MODE_DEFAULT && mFilterFromPaint != filterFromPaint);
}
private static native long nativeCreate(long nativeMatrix, long bitmapHandle,
int shaderTileModeX, int shaderTileModeY, boolean filter);
int shaderTileModeX, int shaderTileModeY, boolean filter, boolean isDirectSampled);
}

View File

@@ -279,11 +279,11 @@ public class RuntimeShader extends Shader {
}
/**
* Sets the uniform shader that is declares as input to this shader. If the shader does not
* Assigns the uniform shader to the provided shader parameter. If the shader program does not
* have a uniform shader with that name then an IllegalArgumentException is thrown.
*
* @param shaderName name matching the uniform declared in the SKSL shader
* @param shader shader passed into the SKSL shader for sampling
* @param shaderName name matching the uniform declared in the AGSL shader program
* @param shader shader passed into the AGSL shader program for sampling
*/
public void setInputShader(@NonNull String shaderName, @NonNull Shader shader) {
if (shaderName == null) {
@@ -297,6 +297,28 @@ public class RuntimeShader extends Shader {
discardNativeInstance();
}
/**
* Assigns the uniform shader to the provided shader parameter. If the shader program does not
* have a uniform shader with that name then an IllegalArgumentException is thrown.
*
* Unlike setInputShader this method returns samples directly from the bitmap's buffer. This
* means that there will be no transformation of the sampled pixels, such as colorspace
* conversion or alpha premultiplication.
*/
public void setInputBuffer(@NonNull String shaderName, @NonNull BitmapShader shader) {
if (shaderName == null) {
throw new NullPointerException("The shaderName parameter must not be null");
}
if (shader == null) {
throw new NullPointerException("The shader parameter must not be null");
}
nativeUpdateShader(mNativeInstanceRuntimeShaderBuilder, shaderName,
shader.getNativeInstanceWithDirectSampling());
discardNativeInstance();
}
/** @hide */
@Override
protected long createNativeInstance(long nativeMatrix, boolean filterFromPaint) {

View File

@@ -64,7 +64,8 @@ static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) {
///////////////////////////////////////////////////////////////////////////////////////////////
static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
jint tileModeX, jint tileModeY, bool filter) {
jint tileModeX, jint tileModeY, bool filter,
bool isDirectSampled) {
const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
sk_sp<SkImage> image;
if (bitmapHandle) {
@@ -79,8 +80,12 @@ static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, j
}
SkSamplingOptions sampling(filter ? SkFilterMode::kLinear : SkFilterMode::kNearest,
SkMipmapMode::kNone);
sk_sp<SkShader> shader = image->makeShader(
(SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
sk_sp<SkShader> shader;
if (isDirectSampled) {
shader = image->makeRawShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
} else {
shader = image->makeShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
}
ThrowIAE_IfNull(env, shader.get());
if (matrix) {
@@ -393,7 +398,7 @@ static const JNINativeMethod gShaderMethods[] = {
};
static const JNINativeMethod gBitmapShaderMethods[] = {
{ "nativeCreate", "(JJIIZ)J", (void*)BitmapShader_constructor },
{"nativeCreate", "(JJIIZZ)J", (void*)BitmapShader_constructor},
};
static const JNINativeMethod gLinearGradientMethods[] = {