blob: c505b53b2df1d6ba40d0d60f0c1d558dd228fe90 [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
264static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr,
265 jboolean isOpaque) {
266 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
267 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
268 sk_sp<SkShader> shader = builder->makeShader(matrix, isOpaque == JNI_TRUE);
269 ThrowIAE_IfNull(env, shader);
270 return reinterpret_cast<jlong>(shader.release());
271}
272
273static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) {
274 va_list args;
275 va_start(args, fmt);
Greg Kaiser9c1f79f2021-01-19 07:35:49 -0800276 int ret = jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", fmt, args);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500277 va_end(args);
Greg Kaiser9c1f79f2021-01-19 07:35:49 -0800278 return ret;
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500279}
280
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000281static bool isIntUniformType(const SkRuntimeEffect::Uniform::Type& type) {
282 switch (type) {
283 case SkRuntimeEffect::Uniform::Type::kFloat:
284 case SkRuntimeEffect::Uniform::Type::kFloat2:
285 case SkRuntimeEffect::Uniform::Type::kFloat3:
286 case SkRuntimeEffect::Uniform::Type::kFloat4:
287 case SkRuntimeEffect::Uniform::Type::kFloat2x2:
288 case SkRuntimeEffect::Uniform::Type::kFloat3x3:
289 case SkRuntimeEffect::Uniform::Type::kFloat4x4:
290 return false;
291 case SkRuntimeEffect::Uniform::Type::kInt:
292 case SkRuntimeEffect::Uniform::Type::kInt2:
293 case SkRuntimeEffect::Uniform::Type::kInt3:
294 case SkRuntimeEffect::Uniform::Type::kInt4:
295 return true;
296 }
297}
298
299static void UpdateFloatUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder,
300 const char* uniformName, const float values[], int count,
301 bool isColor) {
302 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
303 if (uniform.fVar == nullptr) {
304 ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
305 } else if (isColor != ((uniform.fVar->flags & SkRuntimeEffect::Uniform::kColor_Flag) != 0)) {
306 if (isColor) {
307 jniThrowExceptionFmt(
308 env, "java/lang/IllegalArgumentException",
309 "attempting to set a color uniform using the non-color specific APIs: %s %x",
310 uniformName, uniform.fVar->flags);
311 } else {
312 ThrowIAEFmt(env,
313 "attempting to set a non-color uniform using the setColorUniform APIs: %s",
314 uniformName);
315 }
316 } else if (isIntUniformType(uniform.fVar->type)) {
317 ThrowIAEFmt(env, "attempting to set a int uniform using the setUniform APIs: %s",
318 uniformName);
319 } else if (!uniform.set<float>(values, count)) {
320 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
321 uniform.fVar->sizeInBytes(), sizeof(float) * count);
322 }
323}
324
325static void RuntimeShader_updateFloatUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
326 jstring jUniformName, jfloat value1, jfloat value2,
327 jfloat value3, jfloat value4, jint count) {
328 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
329 ScopedUtfChars name(env, jUniformName);
330 const float values[4] = {value1, value2, value3, value4};
331 UpdateFloatUniforms(env, builder, name.c_str(), values, count, false);
332}
333
334static void RuntimeShader_updateFloatArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
335 jstring jUniformName, jfloatArray jvalues,
336 jboolean isColor) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500337 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
338 ScopedUtfChars name(env, jUniformName);
339 AutoJavaFloatArray autoValues(env, jvalues, 0, kRO_JNIAccess);
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000340 UpdateFloatUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length(), isColor);
341}
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500342
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000343static void UpdateIntUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder, const char* uniformName,
344 const int values[], int count) {
345 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500346 if (uniform.fVar == nullptr) {
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000347 ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
348 } else if (!isIntUniformType(uniform.fVar->type)) {
349 ThrowIAEFmt(env, "attempting to set a non-int uniform using the setIntUniform APIs: %s",
350 uniformName);
351 } else if (!uniform.set<int>(values, count)) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500352 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000353 uniform.fVar->sizeInBytes(), sizeof(float) * count);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500354 }
355}
356
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000357static void RuntimeShader_updateIntUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
358 jstring jUniformName, jint value1, jint value2,
359 jint value3, jint value4, jint count) {
360 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
361 ScopedUtfChars name(env, jUniformName);
362 const int values[4] = {value1, value2, value3, value4};
363 UpdateIntUniforms(env, builder, name.c_str(), values, count);
364}
365
366static void RuntimeShader_updateIntArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
367 jstring jUniformName, jintArray jvalues) {
368 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
369 ScopedUtfChars name(env, jUniformName);
370 AutoJavaIntArray autoValues(env, jvalues, 0);
371 UpdateIntUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length());
372}
373
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500374static void RuntimeShader_updateShader(JNIEnv* env, jobject, jlong shaderBuilder,
375 jstring jUniformName, jlong shaderHandle) {
376 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
377 ScopedUtfChars name(env, jUniformName);
378 SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
379
380 SkRuntimeShaderBuilder::BuilderChild child = builder->child(name.c_str());
Brian Osman2a1308f2021-06-02 17:24:58 +0000381 if (child.fChild == nullptr) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500382 ThrowIAEFmt(env, "unable to find shader named %s", name.c_str());
383 return;
384 }
385
386 builder->child(name.c_str()) = sk_ref_sp(shader);
Stan Iliev6867fc82019-11-22 18:00:01 -0500387}
388
389///////////////////////////////////////////////////////////////////////////////////////////////
390
Daniel Micay76f6a862015-09-19 17:31:01 -0400391static const JNINativeMethod gColorMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800392 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
393 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394};
395
Daniel Micay76f6a862015-09-19 17:31:01 -0400396static const JNINativeMethod gShaderMethods[] = {
John Reck8bde0be2017-05-19 10:55:20 -0700397 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398};
399
Daniel Micay76f6a862015-09-19 17:31:01 -0400400static const JNINativeMethod gBitmapShaderMethods[] = {
Derek Sollenberger4d3df822022-01-11 17:58:29 +0000401 {"nativeCreate", "(JJIIZZ)J", (void*)BitmapShader_constructor},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402};
403
Daniel Micay76f6a862015-09-19 17:31:01 -0400404static const JNINativeMethod gLinearGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500405 { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406};
407
Daniel Micay76f6a862015-09-19 17:31:01 -0400408static const JNINativeMethod gRadialGradientMethods[] = {
Nader Jawade7ab8412020-10-16 18:00:04 -0700409 { "nativeCreate", "(JFFFFFF[J[FIJ)J", (void*)RadialGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410};
411
Daniel Micay76f6a862015-09-19 17:31:01 -0400412static const JNINativeMethod gSweepGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500413 { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414};
415
Daniel Micay76f6a862015-09-19 17:31:01 -0400416static const JNINativeMethod gComposeShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800417 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418};
419
Stan Iliev6867fc82019-11-22 18:00:01 -0500420static const JNINativeMethod gRuntimeShaderMethods[] = {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500421 {"nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer},
422 {"nativeCreateShader", "(JJZ)J", (void*)RuntimeShader_create},
423 {"nativeCreateBuilder", "(Ljava/lang/String;)J", (void*)RuntimeShader_createShaderBuilder},
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000424 {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V",
425 (void*)RuntimeShader_updateFloatArrayUniforms},
426 {"nativeUpdateUniforms", "(JLjava/lang/String;FFFFI)V",
427 (void*)RuntimeShader_updateFloatUniforms},
428 {"nativeUpdateUniforms", "(JLjava/lang/String;[I)V",
429 (void*)RuntimeShader_updateIntArrayUniforms},
430 {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
431 (void*)RuntimeShader_updateIntUniforms},
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500432 {"nativeUpdateShader", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateShader},
Stan Iliev6867fc82019-11-22 18:00:01 -0500433};
434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435int register_android_graphics_Shader(JNIEnv* env)
436{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800437 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
438 NELEM(gColorMethods));
439 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
440 NELEM(gShaderMethods));
441 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
442 NELEM(gBitmapShaderMethods));
443 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
444 NELEM(gLinearGradientMethods));
445 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
446 NELEM(gRadialGradientMethods));
447 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
448 NELEM(gSweepGradientMethods));
449 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
450 NELEM(gComposeShaderMethods));
Stan Iliev6867fc82019-11-22 18:00:01 -0500451 android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods,
452 NELEM(gRuntimeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700453
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800454 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455}