blob: fa8e2e79c831ac4449bc7a5ad01db149a691a0b0 [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"
Kevin Lubick1175dc02022-02-28 12:41:27 -05005#include "SkBitmap.h"
6#include "SkBlendMode.h"
7#include "SkColor.h"
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -04008#include "SkColorFilter.h"
Ben Wagner60126ef2015-08-07 12:13:48 -04009#include "SkGradientShader.h"
Kevin Lubick1175dc02022-02-28 12:41:27 -050010#include "SkImage.h"
Matt Sarett62feb3a2016-09-20 10:34:11 -040011#include "SkImagePriv.h"
Kevin Lubick1175dc02022-02-28 12:41:27 -050012#include "SkMatrix.h"
13#include "SkPoint.h"
14#include "SkRefCnt.h"
15#include "SkSamplingOptions.h"
16#include "SkScalar.h"
Ben Wagner60126ef2015-08-07 12:13:48 -040017#include "SkShader.h"
Kevin Lubick1175dc02022-02-28 12:41:27 -050018#include "SkString.h"
19#include "SkTileMode.h"
Brian Osmanbc44fa02020-01-03 15:28:06 -050020#include "include/effects/SkRuntimeEffect.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050022#include <vector>
23
Romain Guy06f96e22010-07-30 19:18:16 -070024using namespace android::uirenderer;
25
Derek Sollenberger669b15a2017-03-31 12:09:24 -040026/**
27 * By default Skia gradients will interpolate their colors in unpremul space
28 * and then premultiply each of the results. We must set this flag to preserve
Kevin Lubick1175dc02022-02-28 12:41:27 -050029 * backwards compatibility by premultiplying the colors of the gradient first,
Derek Sollenberger669b15a2017-03-31 12:09:24 -040030 * and then interpolating between them.
31 */
32static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;
33
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050034#define ThrowIAE_IfNull(env, ptr) \
35 if (nullptr == ptr) { \
36 doThrowIAE(env); \
37 return 0; \
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039
Ashok Bhat36bef0b2014-01-20 20:08:01 +000040static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041{
42 SkScalar hsv[3];
43 SkRGBToHSV(red, green, blue, hsv);
44
45 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
46 float* values = autoHSV.ptr();
47 for (int i = 0; i < 3; i++) {
48 values[i] = SkScalarToFloat(hsv[i]);
49 }
50}
Elliott Hughes4cb17532011-04-12 16:10:26 -070051
Ashok Bhat36bef0b2014-01-20 20:08:01 +000052static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053{
54 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
Leon Scroggins III2e0103e2014-04-04 17:05:24 -040055#ifdef SK_SCALAR_IS_FLOAT
56 SkScalar* hsv = autoHSV.ptr();
57#else
58 #error Need to convert float array to SkScalar array before calling the following function.
59#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -070060
Ashok Bhat36bef0b2014-01-20 20:08:01 +000061 return static_cast<jint>(SkHSVToColor(alpha, hsv));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062}
63
64///////////////////////////////////////////////////////////////////////////////////////////////
65
Nader Jawad5bed1f52020-09-25 00:27:29 -070066static void Shader_safeUnref(SkShader* shader) {
Derek Sollenberger6062c592011-02-22 13:55:04 -050067 SkSafeUnref(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068}
69
John Reck8bde0be2017-05-19 10:55:20 -070070static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) {
71 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
72}
73
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074///////////////////////////////////////////////////////////////////////////////////////////////
75
Leon Scroggins III71fae622019-03-26 16:28:41 -040076static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
Derek Sollenberger4d3df822022-01-11 17:58:29 +000077 jint tileModeX, jint tileModeY, bool filter,
78 bool isDirectSampled) {
Chris Craikb581e672017-03-07 15:27:36 -080079 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Stan Iliev7bc3bc62017-05-24 13:28:36 -040080 sk_sp<SkImage> image;
Leon Scroggins III71fae622019-03-26 16:28:41 -040081 if (bitmapHandle) {
Chris Craikb786bbd2015-06-10 16:58:42 -070082 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
83 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
Leon Scroggins III71fae622019-03-26 16:28:41 -040084 image = android::bitmap::toBitmap(bitmapHandle).makeImage();
Chris Craikb786bbd2015-06-10 16:58:42 -070085 }
Romain Guy06f96e22010-07-30 19:18:16 -070086
Stan Iliev7bc3bc62017-05-24 13:28:36 -040087 if (!image.get()) {
88 SkBitmap bitmap;
89 image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
90 }
Mike Reed3ed30892020-12-11 12:25:30 -050091 SkSamplingOptions sampling(filter ? SkFilterMode::kLinear : SkFilterMode::kNearest,
92 SkMipmapMode::kNone);
Derek Sollenberger4d3df822022-01-11 17:58:29 +000093 sk_sp<SkShader> shader;
94 if (isDirectSampled) {
95 shader = image->makeRawShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
96 } else {
97 shader = image->makeShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
98 }
Nader Jawad5bed1f52020-09-25 00:27:29 -070099 ThrowIAE_IfNull(env, shader.get());
Derek Sollenberger450756a2016-11-07 15:55:47 -0500100
Nader Jawad5bed1f52020-09-25 00:27:29 -0700101 if (matrix) {
102 shader = shader->makeWithLocalMatrix(*matrix);
103 }
ztenghuib244fb52017-04-04 17:33:40 -0700104
Nader Jawad5bed1f52020-09-25 00:27:29 -0700105 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106}
Romain Guy06f96e22010-07-30 19:18:16 -0700107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108///////////////////////////////////////////////////////////////////////////////////////////////
109
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500110static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) {
111 const size_t count = env->GetArrayLength(colorArray);
112 const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500114 std::vector<SkColor4f> colors(count);
115 for (size_t i = 0; i < count; ++i) {
116 colors[i] = GraphicsJNI::convertColorLong(colorValues[i]);
ztenghuib244fb52017-04-04 17:33:40 -0700117 }
Romain Guy06f96e22010-07-30 19:18:16 -0700118
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500119 env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT);
120 return colors;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121}
122
123///////////////////////////////////////////////////////////////////////////////////////////////
124
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500125static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
126 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray,
Leon Scroggins III2befe1d2019-01-31 13:19:26 -0500127 jfloatArray posArray, jint tileMode, jlong colorSpaceHandle) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500128 SkPoint pts[2];
129 pts[0].set(x0, y0);
130 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500132 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500134 AutoJavaFloatArray autoPos(env, posArray, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400135#ifdef SK_SCALAR_IS_FLOAT
136 SkScalar* pos = autoPos.ptr();
137#else
138 #error Need to convert float array to SkScalar array before calling the following function.
139#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700140
Nader Jawad5bed1f52020-09-25 00:27:29 -0700141 sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
142 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
143 static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr));
144 ThrowIAE_IfNull(env, shader);
ztenghuib244fb52017-04-04 17:33:40 -0700145
Nader Jawad5bed1f52020-09-25 00:27:29 -0700146 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
147 if (matrix) {
148 shader = shader->makeWithLocalMatrix(*matrix);
149 }
150
151 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152}
153
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500154///////////////////////////////////////////////////////////////////////////////////////////////
155
Nader Jawade7ab8412020-10-16 18:00:04 -0700156static jlong RadialGradient_create(JNIEnv* env,
157 jobject,
158 jlong matrixPtr,
159 jfloat startX,
160 jfloat startY,
161 jfloat startRadius,
162 jfloat endX,
163 jfloat endY,
164 jfloat endRadius,
165 jlongArray colorArray,
166 jfloatArray posArray,
167 jint tileMode,
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500168 jlong colorSpaceHandle) {
Nader Jawade7ab8412020-10-16 18:00:04 -0700169
170 SkPoint start;
171 start.set(startX, startY);
172
173 SkPoint end;
174 end.set(endX, endY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500176 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500178 AutoJavaFloatArray autoPos(env, posArray, colors.size());
179#ifdef SK_SCALAR_IS_FLOAT
180 SkScalar* pos = autoPos.ptr();
181#else
182 #error Need to convert float array to SkScalar array before calling the following function.
183#endif
ztenghuib244fb52017-04-04 17:33:40 -0700184
Nader Jawade7ab8412020-10-16 18:00:04 -0700185 auto colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
186 auto skTileMode = static_cast<SkTileMode>(tileMode);
187 sk_sp<SkShader> shader = SkGradientShader::MakeTwoPointConical(start, startRadius, end,
188 endRadius, &colors[0], std::move(colorSpace), pos, colors.size(), skTileMode,
189 sGradientShaderFlags, nullptr);
Nader Jawad5bed1f52020-09-25 00:27:29 -0700190 ThrowIAE_IfNull(env, shader);
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500191
Nader Jawade7ab8412020-10-16 18:00:04 -0700192 // Explicitly create a new shader with the specified matrix to match existing behavior.
193 // Passing in the matrix in the instantiation above can throw exceptions for non-invertible
194 // matrices. However, makeWithLocalMatrix will still allow for the shader to be created
195 // and skia handles null-shaders internally (i.e. is ignored)
Nader Jawad5bed1f52020-09-25 00:27:29 -0700196 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
197 if (matrix) {
198 shader = shader->makeWithLocalMatrix(*matrix);
199 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500200
Nader Jawad5bed1f52020-09-25 00:27:29 -0700201 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202}
203
204///////////////////////////////////////////////////////////////////////////////
205
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500206static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
207 jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) {
208 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700209
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500210 AutoJavaFloatArray autoPos(env, jpositions, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400211#ifdef SK_SCALAR_IS_FLOAT
212 SkScalar* pos = autoPos.ptr();
213#else
214 #error Need to convert float array to SkScalar array before calling the following function.
215#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700216
Nader Jawad5bed1f52020-09-25 00:27:29 -0700217 sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
218 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
219 sGradientShaderFlags, nullptr);
220 ThrowIAE_IfNull(env, shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221
Nader Jawad5bed1f52020-09-25 00:27:29 -0700222 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
223 if (matrix) {
224 shader = shader->makeWithLocalMatrix(*matrix);
225 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500226
Nader Jawad5bed1f52020-09-25 00:27:29 -0700227 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228}
229
230///////////////////////////////////////////////////////////////////////////////////////////////
231
Chris Craikb581e672017-03-07 15:27:36 -0800232static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
233 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
Nader Jawad5bed1f52020-09-25 00:27:29 -0700234 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
235 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
236 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
237 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
238 sk_sp<SkShader> baseShader(SkShaders::Blend(mode,
239 sk_ref_sp(shaderA), sk_ref_sp(shaderB)));
Chris Craikb581e672017-03-07 15:27:36 -0800240
Nader Jawad5bed1f52020-09-25 00:27:29 -0700241 SkShader* shader;
Chris Craikb581e672017-03-07 15:27:36 -0800242
Nader Jawad5bed1f52020-09-25 00:27:29 -0700243 if (matrix) {
244 shader = baseShader->makeWithLocalMatrix(*matrix).release();
245 } else {
246 shader = baseShader.release();
247 }
248 return reinterpret_cast<jlong>(shader);
Nader Jawad322cb9c2020-08-17 17:15:54 -0700249}
250
251///////////////////////////////////////////////////////////////////////////////////////////////
252
Stan Iliev6867fc82019-11-22 18:00:01 -0500253///////////////////////////////////////////////////////////////////////////////////////////////
254
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500255static jlong RuntimeShader_createShaderBuilder(JNIEnv* env, jobject, jstring sksl) {
Stan Iliev6867fc82019-11-22 18:00:01 -0500256 ScopedUtfChars strSksl(env, sksl);
Brian Osman75567772021-04-20 19:46:39 +0000257 auto result = SkRuntimeEffect::MakeForShader(SkString(strSksl.c_str()),
258 SkRuntimeEffect::Options{});
John Stiles5f2f3e42021-02-10 16:58:04 +0000259 if (result.effect.get() == nullptr) {
260 doThrowIAE(env, result.errorText.c_str());
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500261 return 0;
John Reckc784d9a2020-08-03 10:45:39 -0700262 }
John Stiles5f2f3e42021-02-10 16:58:04 +0000263 return reinterpret_cast<jlong>(new SkRuntimeShaderBuilder(std::move(result.effect)));
Stan Iliev6867fc82019-11-22 18:00:01 -0500264}
265
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500266static void SkRuntimeShaderBuilder_delete(SkRuntimeShaderBuilder* builder) {
267 delete builder;
Nader Jawad5bed1f52020-09-25 00:27:29 -0700268}
269
Stan Iliev6867fc82019-11-22 18:00:01 -0500270static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500271 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SkRuntimeShaderBuilder_delete));
272}
273
Derek Sollenberger7843e512022-02-03 15:50:09 +0000274static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500275 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
276 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Brian Osmanbb7c43d2022-02-03 14:48:12 -0500277 sk_sp<SkShader> shader = builder->makeShader(matrix);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500278 ThrowIAE_IfNull(env, shader);
279 return reinterpret_cast<jlong>(shader.release());
280}
281
282static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) {
283 va_list args;
284 va_start(args, fmt);
Greg Kaiser9c1f79f2021-01-19 07:35:49 -0800285 int ret = jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", fmt, args);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500286 va_end(args);
Greg Kaiser9c1f79f2021-01-19 07:35:49 -0800287 return ret;
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500288}
289
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000290static bool isIntUniformType(const SkRuntimeEffect::Uniform::Type& type) {
291 switch (type) {
292 case SkRuntimeEffect::Uniform::Type::kFloat:
293 case SkRuntimeEffect::Uniform::Type::kFloat2:
294 case SkRuntimeEffect::Uniform::Type::kFloat3:
295 case SkRuntimeEffect::Uniform::Type::kFloat4:
296 case SkRuntimeEffect::Uniform::Type::kFloat2x2:
297 case SkRuntimeEffect::Uniform::Type::kFloat3x3:
298 case SkRuntimeEffect::Uniform::Type::kFloat4x4:
299 return false;
300 case SkRuntimeEffect::Uniform::Type::kInt:
301 case SkRuntimeEffect::Uniform::Type::kInt2:
302 case SkRuntimeEffect::Uniform::Type::kInt3:
303 case SkRuntimeEffect::Uniform::Type::kInt4:
304 return true;
305 }
306}
307
308static void UpdateFloatUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder,
309 const char* uniformName, const float values[], int count,
310 bool isColor) {
311 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
312 if (uniform.fVar == nullptr) {
313 ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
314 } else if (isColor != ((uniform.fVar->flags & SkRuntimeEffect::Uniform::kColor_Flag) != 0)) {
315 if (isColor) {
316 jniThrowExceptionFmt(
317 env, "java/lang/IllegalArgumentException",
318 "attempting to set a color uniform using the non-color specific APIs: %s %x",
319 uniformName, uniform.fVar->flags);
320 } else {
321 ThrowIAEFmt(env,
322 "attempting to set a non-color uniform using the setColorUniform APIs: %s",
323 uniformName);
324 }
325 } else if (isIntUniformType(uniform.fVar->type)) {
326 ThrowIAEFmt(env, "attempting to set a int uniform using the setUniform APIs: %s",
327 uniformName);
328 } else if (!uniform.set<float>(values, count)) {
329 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
330 uniform.fVar->sizeInBytes(), sizeof(float) * count);
331 }
332}
333
334static void RuntimeShader_updateFloatUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
335 jstring jUniformName, jfloat value1, jfloat value2,
336 jfloat value3, jfloat value4, jint count) {
337 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
338 ScopedUtfChars name(env, jUniformName);
339 const float values[4] = {value1, value2, value3, value4};
340 UpdateFloatUniforms(env, builder, name.c_str(), values, count, false);
341}
342
343static void RuntimeShader_updateFloatArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
344 jstring jUniformName, jfloatArray jvalues,
345 jboolean isColor) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500346 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
347 ScopedUtfChars name(env, jUniformName);
348 AutoJavaFloatArray autoValues(env, jvalues, 0, kRO_JNIAccess);
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000349 UpdateFloatUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length(), isColor);
350}
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500351
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000352static void UpdateIntUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder, const char* uniformName,
353 const int values[], int count) {
354 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500355 if (uniform.fVar == nullptr) {
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000356 ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
357 } else if (!isIntUniformType(uniform.fVar->type)) {
358 ThrowIAEFmt(env, "attempting to set a non-int uniform using the setIntUniform APIs: %s",
359 uniformName);
360 } else if (!uniform.set<int>(values, count)) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500361 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000362 uniform.fVar->sizeInBytes(), sizeof(float) * count);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500363 }
364}
365
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000366static void RuntimeShader_updateIntUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
367 jstring jUniformName, jint value1, jint value2,
368 jint value3, jint value4, jint count) {
369 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
370 ScopedUtfChars name(env, jUniformName);
371 const int values[4] = {value1, value2, value3, value4};
372 UpdateIntUniforms(env, builder, name.c_str(), values, count);
373}
374
375static void RuntimeShader_updateIntArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
376 jstring jUniformName, jintArray jvalues) {
377 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
378 ScopedUtfChars name(env, jUniformName);
379 AutoJavaIntArray autoValues(env, jvalues, 0);
380 UpdateIntUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length());
381}
382
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500383static void RuntimeShader_updateShader(JNIEnv* env, jobject, jlong shaderBuilder,
384 jstring jUniformName, jlong shaderHandle) {
385 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
386 ScopedUtfChars name(env, jUniformName);
387 SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
388
389 SkRuntimeShaderBuilder::BuilderChild child = builder->child(name.c_str());
Brian Osman2a1308f2021-06-02 17:24:58 +0000390 if (child.fChild == nullptr) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500391 ThrowIAEFmt(env, "unable to find shader named %s", name.c_str());
392 return;
393 }
394
395 builder->child(name.c_str()) = sk_ref_sp(shader);
Stan Iliev6867fc82019-11-22 18:00:01 -0500396}
397
398///////////////////////////////////////////////////////////////////////////////////////////////
399
Daniel Micay76f6a862015-09-19 17:31:01 -0400400static const JNINativeMethod gColorMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800401 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
402 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403};
404
Daniel Micay76f6a862015-09-19 17:31:01 -0400405static const JNINativeMethod gShaderMethods[] = {
John Reck8bde0be2017-05-19 10:55:20 -0700406 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407};
408
Daniel Micay76f6a862015-09-19 17:31:01 -0400409static const JNINativeMethod gBitmapShaderMethods[] = {
Derek Sollenberger4d3df822022-01-11 17:58:29 +0000410 {"nativeCreate", "(JJIIZZ)J", (void*)BitmapShader_constructor},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411};
412
Daniel Micay76f6a862015-09-19 17:31:01 -0400413static const JNINativeMethod gLinearGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500414 { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415};
416
Daniel Micay76f6a862015-09-19 17:31:01 -0400417static const JNINativeMethod gRadialGradientMethods[] = {
Nader Jawade7ab8412020-10-16 18:00:04 -0700418 { "nativeCreate", "(JFFFFFF[J[FIJ)J", (void*)RadialGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419};
420
Daniel Micay76f6a862015-09-19 17:31:01 -0400421static const JNINativeMethod gSweepGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500422 { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423};
424
Daniel Micay76f6a862015-09-19 17:31:01 -0400425static const JNINativeMethod gComposeShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800426 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427};
428
Stan Iliev6867fc82019-11-22 18:00:01 -0500429static const JNINativeMethod gRuntimeShaderMethods[] = {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500430 {"nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer},
Derek Sollenberger7843e512022-02-03 15:50:09 +0000431 {"nativeCreateShader", "(JJ)J", (void*)RuntimeShader_create},
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500432 {"nativeCreateBuilder", "(Ljava/lang/String;)J", (void*)RuntimeShader_createShaderBuilder},
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000433 {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V",
434 (void*)RuntimeShader_updateFloatArrayUniforms},
435 {"nativeUpdateUniforms", "(JLjava/lang/String;FFFFI)V",
436 (void*)RuntimeShader_updateFloatUniforms},
437 {"nativeUpdateUniforms", "(JLjava/lang/String;[I)V",
438 (void*)RuntimeShader_updateIntArrayUniforms},
439 {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
440 (void*)RuntimeShader_updateIntUniforms},
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500441 {"nativeUpdateShader", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateShader},
Stan Iliev6867fc82019-11-22 18:00:01 -0500442};
443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444int register_android_graphics_Shader(JNIEnv* env)
445{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800446 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
447 NELEM(gColorMethods));
448 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
449 NELEM(gShaderMethods));
450 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
451 NELEM(gBitmapShaderMethods));
452 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
453 NELEM(gLinearGradientMethods));
454 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
455 NELEM(gRadialGradientMethods));
456 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
457 NELEM(gSweepGradientMethods));
458 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
459 NELEM(gComposeShaderMethods));
Stan Iliev6867fc82019-11-22 18:00:01 -0500460 android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods,
461 NELEM(gRuntimeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700462
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800463 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464}