blob: c4366f756a21899be8af2ec3a9bf3d9e9a55c757 [file] [log] [blame]
Derek Sollenberger783e5ae2021-01-11 15:44:46 -05001#undef LOG_TAG
2#define LOG_TAG "ShaderJNI"
3
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004#include "GraphicsJNI.h"
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -04005#include "SkColorFilter.h"
Ben Wagner60126ef2015-08-07 12:13:48 -04006#include "SkGradientShader.h"
Matt Sarett62feb3a2016-09-20 10:34:11 -04007#include "SkImagePriv.h"
Ben Wagner60126ef2015-08-07 12:13:48 -04008#include "SkShader.h"
Mike Reedc2f31df2016-10-28 17:21:45 -04009#include "SkBlendMode.h"
Brian Osmanbc44fa02020-01-03 15:28:06 -050010#include "include/effects/SkRuntimeEffect.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050012#include <vector>
13
Romain Guy06f96e22010-07-30 19:18:16 -070014using namespace android::uirenderer;
15
Derek Sollenberger669b15a2017-03-31 12:09:24 -040016/**
17 * By default Skia gradients will interpolate their colors in unpremul space
18 * and then premultiply each of the results. We must set this flag to preserve
19 * backwards compatiblity by premultiplying the colors of the gradient first,
20 * and then interpolating between them.
21 */
22static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;
23
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050024#define ThrowIAE_IfNull(env, ptr) \
25 if (nullptr == ptr) { \
26 doThrowIAE(env); \
27 return 0; \
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029
Ashok Bhat36bef0b2014-01-20 20:08:01 +000030static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031{
32 SkScalar hsv[3];
33 SkRGBToHSV(red, green, blue, hsv);
34
35 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
36 float* values = autoHSV.ptr();
37 for (int i = 0; i < 3; i++) {
38 values[i] = SkScalarToFloat(hsv[i]);
39 }
40}
Elliott Hughes4cb17532011-04-12 16:10:26 -070041
Ashok Bhat36bef0b2014-01-20 20:08:01 +000042static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043{
44 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
Leon Scroggins III2e0103e2014-04-04 17:05:24 -040045#ifdef SK_SCALAR_IS_FLOAT
46 SkScalar* hsv = autoHSV.ptr();
47#else
48 #error Need to convert float array to SkScalar array before calling the following function.
49#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -070050
Ashok Bhat36bef0b2014-01-20 20:08:01 +000051 return static_cast<jint>(SkHSVToColor(alpha, hsv));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052}
53
54///////////////////////////////////////////////////////////////////////////////////////////////
55
Nader Jawad5bed1f52020-09-25 00:27:29 -070056static void Shader_safeUnref(SkShader* shader) {
Derek Sollenberger6062c592011-02-22 13:55:04 -050057 SkSafeUnref(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058}
59
John Reck8bde0be2017-05-19 10:55:20 -070060static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) {
61 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
62}
63
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064///////////////////////////////////////////////////////////////////////////////////////////////
65
Leon Scroggins III71fae622019-03-26 16:28:41 -040066static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
Mike Reed3ed30892020-12-11 12:25:30 -050067 jint tileModeX, jint tileModeY, bool filter) {
Chris Craikb581e672017-03-07 15:27:36 -080068 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Stan Iliev7bc3bc62017-05-24 13:28:36 -040069 sk_sp<SkImage> image;
Leon Scroggins III71fae622019-03-26 16:28:41 -040070 if (bitmapHandle) {
Chris Craikb786bbd2015-06-10 16:58:42 -070071 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
72 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
Leon Scroggins III71fae622019-03-26 16:28:41 -040073 image = android::bitmap::toBitmap(bitmapHandle).makeImage();
Chris Craikb786bbd2015-06-10 16:58:42 -070074 }
Romain Guy06f96e22010-07-30 19:18:16 -070075
Stan Iliev7bc3bc62017-05-24 13:28:36 -040076 if (!image.get()) {
77 SkBitmap bitmap;
78 image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
79 }
Mike Reed3ed30892020-12-11 12:25:30 -050080 SkSamplingOptions sampling(filter ? SkFilterMode::kLinear : SkFilterMode::kNearest,
81 SkMipmapMode::kNone);
Nader Jawad5bed1f52020-09-25 00:27:29 -070082 sk_sp<SkShader> shader = image->makeShader(
Mike Reed3ed30892020-12-11 12:25:30 -050083 (SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
Nader Jawad5bed1f52020-09-25 00:27:29 -070084 ThrowIAE_IfNull(env, shader.get());
Derek Sollenberger450756a2016-11-07 15:55:47 -050085
Nader Jawad5bed1f52020-09-25 00:27:29 -070086 if (matrix) {
87 shader = shader->makeWithLocalMatrix(*matrix);
88 }
ztenghuib244fb52017-04-04 17:33:40 -070089
Nader Jawad5bed1f52020-09-25 00:27:29 -070090 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091}
Romain Guy06f96e22010-07-30 19:18:16 -070092
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093///////////////////////////////////////////////////////////////////////////////////////////////
94
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050095static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) {
96 const size_t count = env->GetArrayLength(colorArray);
97 const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050099 std::vector<SkColor4f> colors(count);
100 for (size_t i = 0; i < count; ++i) {
101 colors[i] = GraphicsJNI::convertColorLong(colorValues[i]);
ztenghuib244fb52017-04-04 17:33:40 -0700102 }
Romain Guy06f96e22010-07-30 19:18:16 -0700103
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500104 env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT);
105 return colors;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106}
107
108///////////////////////////////////////////////////////////////////////////////////////////////
109
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500110static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
111 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray,
Leon Scroggins III2befe1d2019-01-31 13:19:26 -0500112 jfloatArray posArray, jint tileMode, jlong colorSpaceHandle) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500113 SkPoint pts[2];
114 pts[0].set(x0, y0);
115 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500117 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500119 AutoJavaFloatArray autoPos(env, posArray, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400120#ifdef SK_SCALAR_IS_FLOAT
121 SkScalar* pos = autoPos.ptr();
122#else
123 #error Need to convert float array to SkScalar array before calling the following function.
124#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700125
Nader Jawad5bed1f52020-09-25 00:27:29 -0700126 sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
127 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
128 static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr));
129 ThrowIAE_IfNull(env, shader);
ztenghuib244fb52017-04-04 17:33:40 -0700130
Nader Jawad5bed1f52020-09-25 00:27:29 -0700131 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
132 if (matrix) {
133 shader = shader->makeWithLocalMatrix(*matrix);
134 }
135
136 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137}
138
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500139///////////////////////////////////////////////////////////////////////////////////////////////
140
Nader Jawade7ab8412020-10-16 18:00:04 -0700141static jlong RadialGradient_create(JNIEnv* env,
142 jobject,
143 jlong matrixPtr,
144 jfloat startX,
145 jfloat startY,
146 jfloat startRadius,
147 jfloat endX,
148 jfloat endY,
149 jfloat endRadius,
150 jlongArray colorArray,
151 jfloatArray posArray,
152 jint tileMode,
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500153 jlong colorSpaceHandle) {
Nader Jawade7ab8412020-10-16 18:00:04 -0700154
155 SkPoint start;
156 start.set(startX, startY);
157
158 SkPoint end;
159 end.set(endX, endY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500161 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500163 AutoJavaFloatArray autoPos(env, posArray, colors.size());
164#ifdef SK_SCALAR_IS_FLOAT
165 SkScalar* pos = autoPos.ptr();
166#else
167 #error Need to convert float array to SkScalar array before calling the following function.
168#endif
ztenghuib244fb52017-04-04 17:33:40 -0700169
Nader Jawade7ab8412020-10-16 18:00:04 -0700170 auto colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
171 auto skTileMode = static_cast<SkTileMode>(tileMode);
172 sk_sp<SkShader> shader = SkGradientShader::MakeTwoPointConical(start, startRadius, end,
173 endRadius, &colors[0], std::move(colorSpace), pos, colors.size(), skTileMode,
174 sGradientShaderFlags, nullptr);
Nader Jawad5bed1f52020-09-25 00:27:29 -0700175 ThrowIAE_IfNull(env, shader);
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500176
Nader Jawade7ab8412020-10-16 18:00:04 -0700177 // Explicitly create a new shader with the specified matrix to match existing behavior.
178 // Passing in the matrix in the instantiation above can throw exceptions for non-invertible
179 // matrices. However, makeWithLocalMatrix will still allow for the shader to be created
180 // and skia handles null-shaders internally (i.e. is ignored)
Nader Jawad5bed1f52020-09-25 00:27:29 -0700181 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
182 if (matrix) {
183 shader = shader->makeWithLocalMatrix(*matrix);
184 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500185
Nader Jawad5bed1f52020-09-25 00:27:29 -0700186 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187}
188
189///////////////////////////////////////////////////////////////////////////////
190
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500191static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
192 jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) {
193 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700194
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500195 AutoJavaFloatArray autoPos(env, jpositions, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400196#ifdef SK_SCALAR_IS_FLOAT
197 SkScalar* pos = autoPos.ptr();
198#else
199 #error Need to convert float array to SkScalar array before calling the following function.
200#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700201
Nader Jawad5bed1f52020-09-25 00:27:29 -0700202 sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
203 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
204 sGradientShaderFlags, nullptr);
205 ThrowIAE_IfNull(env, shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206
Nader Jawad5bed1f52020-09-25 00:27:29 -0700207 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
208 if (matrix) {
209 shader = shader->makeWithLocalMatrix(*matrix);
210 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500211
Nader Jawad5bed1f52020-09-25 00:27:29 -0700212 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213}
214
215///////////////////////////////////////////////////////////////////////////////////////////////
216
Chris Craikb581e672017-03-07 15:27:36 -0800217static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
218 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
Nader Jawad5bed1f52020-09-25 00:27:29 -0700219 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
220 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
221 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
222 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
223 sk_sp<SkShader> baseShader(SkShaders::Blend(mode,
224 sk_ref_sp(shaderA), sk_ref_sp(shaderB)));
Chris Craikb581e672017-03-07 15:27:36 -0800225
Nader Jawad5bed1f52020-09-25 00:27:29 -0700226 SkShader* shader;
Chris Craikb581e672017-03-07 15:27:36 -0800227
Nader Jawad5bed1f52020-09-25 00:27:29 -0700228 if (matrix) {
229 shader = baseShader->makeWithLocalMatrix(*matrix).release();
230 } else {
231 shader = baseShader.release();
232 }
233 return reinterpret_cast<jlong>(shader);
Nader Jawad322cb9c2020-08-17 17:15:54 -0700234}
235
236///////////////////////////////////////////////////////////////////////////////////////////////
237
Stan Iliev6867fc82019-11-22 18:00:01 -0500238///////////////////////////////////////////////////////////////////////////////////////////////
239
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500240static jlong RuntimeShader_createShaderBuilder(JNIEnv* env, jobject, jstring sksl) {
Stan Iliev6867fc82019-11-22 18:00:01 -0500241 ScopedUtfChars strSksl(env, sksl);
Brian Osman75567772021-04-20 19:46:39 +0000242 auto result = SkRuntimeEffect::MakeForShader(SkString(strSksl.c_str()),
243 SkRuntimeEffect::Options{});
John Stiles5f2f3e42021-02-10 16:58:04 +0000244 if (result.effect.get() == nullptr) {
245 doThrowIAE(env, result.errorText.c_str());
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500246 return 0;
John Reckc784d9a2020-08-03 10:45:39 -0700247 }
John Stiles5f2f3e42021-02-10 16:58:04 +0000248 return reinterpret_cast<jlong>(new SkRuntimeShaderBuilder(std::move(result.effect)));
Stan Iliev6867fc82019-11-22 18:00:01 -0500249}
250
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500251static void SkRuntimeShaderBuilder_delete(SkRuntimeShaderBuilder* builder) {
252 delete builder;
Nader Jawad5bed1f52020-09-25 00:27:29 -0700253}
254
Stan Iliev6867fc82019-11-22 18:00:01 -0500255static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500256 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SkRuntimeShaderBuilder_delete));
257}
258
259static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr,
260 jboolean isOpaque) {
261 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
262 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
263 sk_sp<SkShader> shader = builder->makeShader(matrix, isOpaque == JNI_TRUE);
264 ThrowIAE_IfNull(env, shader);
265 return reinterpret_cast<jlong>(shader.release());
266}
267
268static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) {
269 va_list args;
270 va_start(args, fmt);
Greg Kaiser9c1f79f2021-01-19 07:35:49 -0800271 int ret = jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", fmt, args);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500272 va_end(args);
Greg Kaiser9c1f79f2021-01-19 07:35:49 -0800273 return ret;
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500274}
275
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000276static bool isIntUniformType(const SkRuntimeEffect::Uniform::Type& type) {
277 switch (type) {
278 case SkRuntimeEffect::Uniform::Type::kFloat:
279 case SkRuntimeEffect::Uniform::Type::kFloat2:
280 case SkRuntimeEffect::Uniform::Type::kFloat3:
281 case SkRuntimeEffect::Uniform::Type::kFloat4:
282 case SkRuntimeEffect::Uniform::Type::kFloat2x2:
283 case SkRuntimeEffect::Uniform::Type::kFloat3x3:
284 case SkRuntimeEffect::Uniform::Type::kFloat4x4:
285 return false;
286 case SkRuntimeEffect::Uniform::Type::kInt:
287 case SkRuntimeEffect::Uniform::Type::kInt2:
288 case SkRuntimeEffect::Uniform::Type::kInt3:
289 case SkRuntimeEffect::Uniform::Type::kInt4:
290 return true;
291 }
292}
293
294static void UpdateFloatUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder,
295 const char* uniformName, const float values[], int count,
296 bool isColor) {
297 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
298 if (uniform.fVar == nullptr) {
299 ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
300 } else if (isColor != ((uniform.fVar->flags & SkRuntimeEffect::Uniform::kColor_Flag) != 0)) {
301 if (isColor) {
302 jniThrowExceptionFmt(
303 env, "java/lang/IllegalArgumentException",
304 "attempting to set a color uniform using the non-color specific APIs: %s %x",
305 uniformName, uniform.fVar->flags);
306 } else {
307 ThrowIAEFmt(env,
308 "attempting to set a non-color uniform using the setColorUniform APIs: %s",
309 uniformName);
310 }
311 } else if (isIntUniformType(uniform.fVar->type)) {
312 ThrowIAEFmt(env, "attempting to set a int uniform using the setUniform APIs: %s",
313 uniformName);
314 } else if (!uniform.set<float>(values, count)) {
315 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
316 uniform.fVar->sizeInBytes(), sizeof(float) * count);
317 }
318}
319
320static void RuntimeShader_updateFloatUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
321 jstring jUniformName, jfloat value1, jfloat value2,
322 jfloat value3, jfloat value4, jint count) {
323 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
324 ScopedUtfChars name(env, jUniformName);
325 const float values[4] = {value1, value2, value3, value4};
326 UpdateFloatUniforms(env, builder, name.c_str(), values, count, false);
327}
328
329static void RuntimeShader_updateFloatArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
330 jstring jUniformName, jfloatArray jvalues,
331 jboolean isColor) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500332 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
333 ScopedUtfChars name(env, jUniformName);
334 AutoJavaFloatArray autoValues(env, jvalues, 0, kRO_JNIAccess);
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000335 UpdateFloatUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length(), isColor);
336}
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500337
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000338static void UpdateIntUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder, const char* uniformName,
339 const int values[], int count) {
340 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500341 if (uniform.fVar == nullptr) {
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000342 ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
343 } else if (!isIntUniformType(uniform.fVar->type)) {
344 ThrowIAEFmt(env, "attempting to set a non-int uniform using the setIntUniform APIs: %s",
345 uniformName);
346 } else if (!uniform.set<int>(values, count)) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500347 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000348 uniform.fVar->sizeInBytes(), sizeof(float) * count);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500349 }
350}
351
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000352static void RuntimeShader_updateIntUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
353 jstring jUniformName, jint value1, jint value2,
354 jint value3, jint value4, jint count) {
355 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
356 ScopedUtfChars name(env, jUniformName);
357 const int values[4] = {value1, value2, value3, value4};
358 UpdateIntUniforms(env, builder, name.c_str(), values, count);
359}
360
361static void RuntimeShader_updateIntArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
362 jstring jUniformName, jintArray jvalues) {
363 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
364 ScopedUtfChars name(env, jUniformName);
365 AutoJavaIntArray autoValues(env, jvalues, 0);
366 UpdateIntUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length());
367}
368
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500369static void RuntimeShader_updateShader(JNIEnv* env, jobject, jlong shaderBuilder,
370 jstring jUniformName, jlong shaderHandle) {
371 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
372 ScopedUtfChars name(env, jUniformName);
373 SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
374
375 SkRuntimeShaderBuilder::BuilderChild child = builder->child(name.c_str());
Brian Osman2a1308f2021-06-02 17:24:58 +0000376 if (child.fChild == nullptr) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500377 ThrowIAEFmt(env, "unable to find shader named %s", name.c_str());
378 return;
379 }
380
381 builder->child(name.c_str()) = sk_ref_sp(shader);
Stan Iliev6867fc82019-11-22 18:00:01 -0500382}
383
384///////////////////////////////////////////////////////////////////////////////////////////////
385
Daniel Micay76f6a862015-09-19 17:31:01 -0400386static const JNINativeMethod gColorMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800387 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
388 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389};
390
Daniel Micay76f6a862015-09-19 17:31:01 -0400391static const JNINativeMethod gShaderMethods[] = {
John Reck8bde0be2017-05-19 10:55:20 -0700392 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393};
394
Daniel Micay76f6a862015-09-19 17:31:01 -0400395static const JNINativeMethod gBitmapShaderMethods[] = {
Mike Reed3ed30892020-12-11 12:25:30 -0500396 { "nativeCreate", "(JJIIZ)J", (void*)BitmapShader_constructor },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397};
398
Daniel Micay76f6a862015-09-19 17:31:01 -0400399static const JNINativeMethod gLinearGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500400 { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401};
402
Daniel Micay76f6a862015-09-19 17:31:01 -0400403static const JNINativeMethod gRadialGradientMethods[] = {
Nader Jawade7ab8412020-10-16 18:00:04 -0700404 { "nativeCreate", "(JFFFFFF[J[FIJ)J", (void*)RadialGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405};
406
Daniel Micay76f6a862015-09-19 17:31:01 -0400407static const JNINativeMethod gSweepGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500408 { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409};
410
Daniel Micay76f6a862015-09-19 17:31:01 -0400411static const JNINativeMethod gComposeShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800412 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413};
414
Stan Iliev6867fc82019-11-22 18:00:01 -0500415static const JNINativeMethod gRuntimeShaderMethods[] = {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500416 {"nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer},
417 {"nativeCreateShader", "(JJZ)J", (void*)RuntimeShader_create},
418 {"nativeCreateBuilder", "(Ljava/lang/String;)J", (void*)RuntimeShader_createShaderBuilder},
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000419 {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V",
420 (void*)RuntimeShader_updateFloatArrayUniforms},
421 {"nativeUpdateUniforms", "(JLjava/lang/String;FFFFI)V",
422 (void*)RuntimeShader_updateFloatUniforms},
423 {"nativeUpdateUniforms", "(JLjava/lang/String;[I)V",
424 (void*)RuntimeShader_updateIntArrayUniforms},
425 {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
426 (void*)RuntimeShader_updateIntUniforms},
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500427 {"nativeUpdateShader", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateShader},
Stan Iliev6867fc82019-11-22 18:00:01 -0500428};
429
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430int register_android_graphics_Shader(JNIEnv* env)
431{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800432 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
433 NELEM(gColorMethods));
434 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
435 NELEM(gShaderMethods));
436 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
437 NELEM(gBitmapShaderMethods));
438 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
439 NELEM(gLinearGradientMethods));
440 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
441 NELEM(gRadialGradientMethods));
442 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
443 NELEM(gSweepGradientMethods));
444 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
445 NELEM(gComposeShaderMethods));
Stan Iliev6867fc82019-11-22 18:00:01 -0500446 android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods,
447 NELEM(gRuntimeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700448
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800449 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450}