blob: 0bbd8a8cf97c68ad8e9d8e8dc2e9ac5c6dcabf93 [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,
Derek Sollenberger4d3df822022-01-11 17:58:29 +000067 jint tileModeX, jint tileModeY, bool filter,
68 bool isDirectSampled) {
Chris Craikb581e672017-03-07 15:27:36 -080069 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Stan Iliev7bc3bc62017-05-24 13:28:36 -040070 sk_sp<SkImage> image;
Leon Scroggins III71fae622019-03-26 16:28:41 -040071 if (bitmapHandle) {
Chris Craikb786bbd2015-06-10 16:58:42 -070072 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
73 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
Leon Scroggins III71fae622019-03-26 16:28:41 -040074 image = android::bitmap::toBitmap(bitmapHandle).makeImage();
Chris Craikb786bbd2015-06-10 16:58:42 -070075 }
Romain Guy06f96e22010-07-30 19:18:16 -070076
Stan Iliev7bc3bc62017-05-24 13:28:36 -040077 if (!image.get()) {
78 SkBitmap bitmap;
79 image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
80 }
Mike Reed3ed30892020-12-11 12:25:30 -050081 SkSamplingOptions sampling(filter ? SkFilterMode::kLinear : SkFilterMode::kNearest,
82 SkMipmapMode::kNone);
Derek Sollenberger4d3df822022-01-11 17:58:29 +000083 sk_sp<SkShader> shader;
84 if (isDirectSampled) {
85 shader = image->makeRawShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
86 } else {
87 shader = image->makeShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
88 }
Nader Jawad5bed1f52020-09-25 00:27:29 -070089 ThrowIAE_IfNull(env, shader.get());
Derek Sollenberger450756a2016-11-07 15:55:47 -050090
Nader Jawad5bed1f52020-09-25 00:27:29 -070091 if (matrix) {
92 shader = shader->makeWithLocalMatrix(*matrix);
93 }
ztenghuib244fb52017-04-04 17:33:40 -070094
Nader Jawad5bed1f52020-09-25 00:27:29 -070095 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096}
Romain Guy06f96e22010-07-30 19:18:16 -070097
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098///////////////////////////////////////////////////////////////////////////////////////////////
99
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500100static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) {
101 const size_t count = env->GetArrayLength(colorArray);
102 const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500104 std::vector<SkColor4f> colors(count);
105 for (size_t i = 0; i < count; ++i) {
106 colors[i] = GraphicsJNI::convertColorLong(colorValues[i]);
ztenghuib244fb52017-04-04 17:33:40 -0700107 }
Romain Guy06f96e22010-07-30 19:18:16 -0700108
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500109 env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT);
110 return colors;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111}
112
113///////////////////////////////////////////////////////////////////////////////////////////////
114
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500115static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
116 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray,
Leon Scroggins III2befe1d2019-01-31 13:19:26 -0500117 jfloatArray posArray, jint tileMode, jlong colorSpaceHandle) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500118 SkPoint pts[2];
119 pts[0].set(x0, y0);
120 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500122 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500124 AutoJavaFloatArray autoPos(env, posArray, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400125#ifdef SK_SCALAR_IS_FLOAT
126 SkScalar* pos = autoPos.ptr();
127#else
128 #error Need to convert float array to SkScalar array before calling the following function.
129#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700130
Nader Jawad5bed1f52020-09-25 00:27:29 -0700131 sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
132 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
133 static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr));
134 ThrowIAE_IfNull(env, shader);
ztenghuib244fb52017-04-04 17:33:40 -0700135
Nader Jawad5bed1f52020-09-25 00:27:29 -0700136 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
137 if (matrix) {
138 shader = shader->makeWithLocalMatrix(*matrix);
139 }
140
141 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142}
143
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500144///////////////////////////////////////////////////////////////////////////////////////////////
145
Nader Jawade7ab8412020-10-16 18:00:04 -0700146static jlong RadialGradient_create(JNIEnv* env,
147 jobject,
148 jlong matrixPtr,
149 jfloat startX,
150 jfloat startY,
151 jfloat startRadius,
152 jfloat endX,
153 jfloat endY,
154 jfloat endRadius,
155 jlongArray colorArray,
156 jfloatArray posArray,
157 jint tileMode,
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500158 jlong colorSpaceHandle) {
Nader Jawade7ab8412020-10-16 18:00:04 -0700159
160 SkPoint start;
161 start.set(startX, startY);
162
163 SkPoint end;
164 end.set(endX, endY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500166 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500168 AutoJavaFloatArray autoPos(env, posArray, colors.size());
169#ifdef SK_SCALAR_IS_FLOAT
170 SkScalar* pos = autoPos.ptr();
171#else
172 #error Need to convert float array to SkScalar array before calling the following function.
173#endif
ztenghuib244fb52017-04-04 17:33:40 -0700174
Nader Jawade7ab8412020-10-16 18:00:04 -0700175 auto colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
176 auto skTileMode = static_cast<SkTileMode>(tileMode);
177 sk_sp<SkShader> shader = SkGradientShader::MakeTwoPointConical(start, startRadius, end,
178 endRadius, &colors[0], std::move(colorSpace), pos, colors.size(), skTileMode,
179 sGradientShaderFlags, nullptr);
Nader Jawad5bed1f52020-09-25 00:27:29 -0700180 ThrowIAE_IfNull(env, shader);
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500181
Nader Jawade7ab8412020-10-16 18:00:04 -0700182 // Explicitly create a new shader with the specified matrix to match existing behavior.
183 // Passing in the matrix in the instantiation above can throw exceptions for non-invertible
184 // matrices. However, makeWithLocalMatrix will still allow for the shader to be created
185 // and skia handles null-shaders internally (i.e. is ignored)
Nader Jawad5bed1f52020-09-25 00:27:29 -0700186 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
187 if (matrix) {
188 shader = shader->makeWithLocalMatrix(*matrix);
189 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500190
Nader Jawad5bed1f52020-09-25 00:27:29 -0700191 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192}
193
194///////////////////////////////////////////////////////////////////////////////
195
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500196static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
197 jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) {
198 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700199
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500200 AutoJavaFloatArray autoPos(env, jpositions, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400201#ifdef SK_SCALAR_IS_FLOAT
202 SkScalar* pos = autoPos.ptr();
203#else
204 #error Need to convert float array to SkScalar array before calling the following function.
205#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700206
Nader Jawad5bed1f52020-09-25 00:27:29 -0700207 sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
208 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
209 sGradientShaderFlags, nullptr);
210 ThrowIAE_IfNull(env, shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211
Nader Jawad5bed1f52020-09-25 00:27:29 -0700212 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
213 if (matrix) {
214 shader = shader->makeWithLocalMatrix(*matrix);
215 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500216
Nader Jawad5bed1f52020-09-25 00:27:29 -0700217 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218}
219
220///////////////////////////////////////////////////////////////////////////////////////////////
221
Chris Craikb581e672017-03-07 15:27:36 -0800222static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
223 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
Nader Jawad5bed1f52020-09-25 00:27:29 -0700224 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
225 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
226 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
227 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
228 sk_sp<SkShader> baseShader(SkShaders::Blend(mode,
229 sk_ref_sp(shaderA), sk_ref_sp(shaderB)));
Chris Craikb581e672017-03-07 15:27:36 -0800230
Nader Jawad5bed1f52020-09-25 00:27:29 -0700231 SkShader* shader;
Chris Craikb581e672017-03-07 15:27:36 -0800232
Nader Jawad5bed1f52020-09-25 00:27:29 -0700233 if (matrix) {
234 shader = baseShader->makeWithLocalMatrix(*matrix).release();
235 } else {
236 shader = baseShader.release();
237 }
238 return reinterpret_cast<jlong>(shader);
Nader Jawad322cb9c2020-08-17 17:15:54 -0700239}
240
241///////////////////////////////////////////////////////////////////////////////////////////////
242
Stan Iliev6867fc82019-11-22 18:00:01 -0500243///////////////////////////////////////////////////////////////////////////////////////////////
244
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500245static jlong RuntimeShader_createShaderBuilder(JNIEnv* env, jobject, jstring sksl) {
Stan Iliev6867fc82019-11-22 18:00:01 -0500246 ScopedUtfChars strSksl(env, sksl);
Brian Osman75567772021-04-20 19:46:39 +0000247 auto result = SkRuntimeEffect::MakeForShader(SkString(strSksl.c_str()),
248 SkRuntimeEffect::Options{});
John Stiles5f2f3e42021-02-10 16:58:04 +0000249 if (result.effect.get() == nullptr) {
250 doThrowIAE(env, result.errorText.c_str());
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500251 return 0;
John Reckc784d9a2020-08-03 10:45:39 -0700252 }
John Stiles5f2f3e42021-02-10 16:58:04 +0000253 return reinterpret_cast<jlong>(new SkRuntimeShaderBuilder(std::move(result.effect)));
Stan Iliev6867fc82019-11-22 18:00:01 -0500254}
255
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500256static void SkRuntimeShaderBuilder_delete(SkRuntimeShaderBuilder* builder) {
257 delete builder;
Nader Jawad5bed1f52020-09-25 00:27:29 -0700258}
259
Stan Iliev6867fc82019-11-22 18:00:01 -0500260static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500261 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SkRuntimeShaderBuilder_delete));
262}
263
Derek Sollenberger7843e512022-02-03 15:50:09 +0000264static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500265 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
266 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Brian Osmanbb7c43d2022-02-03 14:48:12 -0500267 sk_sp<SkShader> shader = builder->makeShader(matrix);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500268 ThrowIAE_IfNull(env, shader);
269 return reinterpret_cast<jlong>(shader.release());
270}
271
272static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) {
273 va_list args;
274 va_start(args, fmt);
Greg Kaiser9c1f79f2021-01-19 07:35:49 -0800275 int ret = jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", fmt, args);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500276 va_end(args);
Greg Kaiser9c1f79f2021-01-19 07:35:49 -0800277 return ret;
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500278}
279
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000280static bool isIntUniformType(const SkRuntimeEffect::Uniform::Type& type) {
281 switch (type) {
282 case SkRuntimeEffect::Uniform::Type::kFloat:
283 case SkRuntimeEffect::Uniform::Type::kFloat2:
284 case SkRuntimeEffect::Uniform::Type::kFloat3:
285 case SkRuntimeEffect::Uniform::Type::kFloat4:
286 case SkRuntimeEffect::Uniform::Type::kFloat2x2:
287 case SkRuntimeEffect::Uniform::Type::kFloat3x3:
288 case SkRuntimeEffect::Uniform::Type::kFloat4x4:
289 return false;
290 case SkRuntimeEffect::Uniform::Type::kInt:
291 case SkRuntimeEffect::Uniform::Type::kInt2:
292 case SkRuntimeEffect::Uniform::Type::kInt3:
293 case SkRuntimeEffect::Uniform::Type::kInt4:
294 return true;
295 }
296}
297
298static void UpdateFloatUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder,
299 const char* uniformName, const float values[], int count,
300 bool isColor) {
301 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
302 if (uniform.fVar == nullptr) {
303 ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
304 } else if (isColor != ((uniform.fVar->flags & SkRuntimeEffect::Uniform::kColor_Flag) != 0)) {
305 if (isColor) {
306 jniThrowExceptionFmt(
307 env, "java/lang/IllegalArgumentException",
308 "attempting to set a color uniform using the non-color specific APIs: %s %x",
309 uniformName, uniform.fVar->flags);
310 } else {
311 ThrowIAEFmt(env,
312 "attempting to set a non-color uniform using the setColorUniform APIs: %s",
313 uniformName);
314 }
315 } else if (isIntUniformType(uniform.fVar->type)) {
316 ThrowIAEFmt(env, "attempting to set a int uniform using the setUniform APIs: %s",
317 uniformName);
318 } else if (!uniform.set<float>(values, count)) {
319 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
320 uniform.fVar->sizeInBytes(), sizeof(float) * count);
321 }
322}
323
324static void RuntimeShader_updateFloatUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
325 jstring jUniformName, jfloat value1, jfloat value2,
326 jfloat value3, jfloat value4, jint count) {
327 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
328 ScopedUtfChars name(env, jUniformName);
329 const float values[4] = {value1, value2, value3, value4};
330 UpdateFloatUniforms(env, builder, name.c_str(), values, count, false);
331}
332
333static void RuntimeShader_updateFloatArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
334 jstring jUniformName, jfloatArray jvalues,
335 jboolean isColor) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500336 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
337 ScopedUtfChars name(env, jUniformName);
338 AutoJavaFloatArray autoValues(env, jvalues, 0, kRO_JNIAccess);
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000339 UpdateFloatUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length(), isColor);
340}
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500341
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000342static void UpdateIntUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder, const char* uniformName,
343 const int values[], int count) {
344 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500345 if (uniform.fVar == nullptr) {
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000346 ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
347 } else if (!isIntUniformType(uniform.fVar->type)) {
348 ThrowIAEFmt(env, "attempting to set a non-int uniform using the setIntUniform APIs: %s",
349 uniformName);
350 } else if (!uniform.set<int>(values, count)) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500351 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000352 uniform.fVar->sizeInBytes(), sizeof(float) * count);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500353 }
354}
355
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000356static void RuntimeShader_updateIntUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
357 jstring jUniformName, jint value1, jint value2,
358 jint value3, jint value4, jint count) {
359 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
360 ScopedUtfChars name(env, jUniformName);
361 const int values[4] = {value1, value2, value3, value4};
362 UpdateIntUniforms(env, builder, name.c_str(), values, count);
363}
364
365static void RuntimeShader_updateIntArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
366 jstring jUniformName, jintArray jvalues) {
367 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
368 ScopedUtfChars name(env, jUniformName);
369 AutoJavaIntArray autoValues(env, jvalues, 0);
370 UpdateIntUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length());
371}
372
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500373static void RuntimeShader_updateShader(JNIEnv* env, jobject, jlong shaderBuilder,
374 jstring jUniformName, jlong shaderHandle) {
375 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
376 ScopedUtfChars name(env, jUniformName);
377 SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
378
379 SkRuntimeShaderBuilder::BuilderChild child = builder->child(name.c_str());
Brian Osman2a1308f2021-06-02 17:24:58 +0000380 if (child.fChild == nullptr) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500381 ThrowIAEFmt(env, "unable to find shader named %s", name.c_str());
382 return;
383 }
384
385 builder->child(name.c_str()) = sk_ref_sp(shader);
Stan Iliev6867fc82019-11-22 18:00:01 -0500386}
387
388///////////////////////////////////////////////////////////////////////////////////////////////
389
Daniel Micay76f6a862015-09-19 17:31:01 -0400390static const JNINativeMethod gColorMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800391 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
392 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393};
394
Daniel Micay76f6a862015-09-19 17:31:01 -0400395static const JNINativeMethod gShaderMethods[] = {
John Reck8bde0be2017-05-19 10:55:20 -0700396 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397};
398
Daniel Micay76f6a862015-09-19 17:31:01 -0400399static const JNINativeMethod gBitmapShaderMethods[] = {
Derek Sollenberger4d3df822022-01-11 17:58:29 +0000400 {"nativeCreate", "(JJIIZZ)J", (void*)BitmapShader_constructor},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401};
402
Daniel Micay76f6a862015-09-19 17:31:01 -0400403static const JNINativeMethod gLinearGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500404 { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405};
406
Daniel Micay76f6a862015-09-19 17:31:01 -0400407static const JNINativeMethod gRadialGradientMethods[] = {
Nader Jawade7ab8412020-10-16 18:00:04 -0700408 { "nativeCreate", "(JFFFFFF[J[FIJ)J", (void*)RadialGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409};
410
Daniel Micay76f6a862015-09-19 17:31:01 -0400411static const JNINativeMethod gSweepGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500412 { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413};
414
Daniel Micay76f6a862015-09-19 17:31:01 -0400415static const JNINativeMethod gComposeShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800416 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417};
418
Stan Iliev6867fc82019-11-22 18:00:01 -0500419static const JNINativeMethod gRuntimeShaderMethods[] = {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500420 {"nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer},
Derek Sollenberger7843e512022-02-03 15:50:09 +0000421 {"nativeCreateShader", "(JJ)J", (void*)RuntimeShader_create},
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500422 {"nativeCreateBuilder", "(Ljava/lang/String;)J", (void*)RuntimeShader_createShaderBuilder},
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000423 {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V",
424 (void*)RuntimeShader_updateFloatArrayUniforms},
425 {"nativeUpdateUniforms", "(JLjava/lang/String;FFFFI)V",
426 (void*)RuntimeShader_updateFloatUniforms},
427 {"nativeUpdateUniforms", "(JLjava/lang/String;[I)V",
428 (void*)RuntimeShader_updateIntArrayUniforms},
429 {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
430 (void*)RuntimeShader_updateIntUniforms},
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500431 {"nativeUpdateShader", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateShader},
Stan Iliev6867fc82019-11-22 18:00:01 -0500432};
433
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434int register_android_graphics_Shader(JNIEnv* env)
435{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800436 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
437 NELEM(gColorMethods));
438 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
439 NELEM(gShaderMethods));
440 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
441 NELEM(gBitmapShaderMethods));
442 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
443 NELEM(gLinearGradientMethods));
444 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
445 NELEM(gRadialGradientMethods));
446 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
447 NELEM(gSweepGradientMethods));
448 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
449 NELEM(gComposeShaderMethods));
Stan Iliev6867fc82019-11-22 18:00:01 -0500450 android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods,
451 NELEM(gRuntimeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700452
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800453 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454}