blob: 8a0db1c91d4647699f2b6b9294d7833adc18fced [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
Nader Jawad2a499342023-02-08 11:56:37 -080074static jlong createBitmapShaderHelper(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
75 jint tileModeX, jint tileModeY, bool isDirectSampled,
76 const SkSamplingOptions& sampling) {
Chris Craikb581e672017-03-07 15:27:36 -080077 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Stan Iliev7bc3bc62017-05-24 13:28:36 -040078 sk_sp<SkImage> image;
Leon Scroggins III71fae622019-03-26 16:28:41 -040079 if (bitmapHandle) {
Chris Craikb786bbd2015-06-10 16:58:42 -070080 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
81 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
Leon Scroggins III71fae622019-03-26 16:28:41 -040082 image = android::bitmap::toBitmap(bitmapHandle).makeImage();
Chris Craikb786bbd2015-06-10 16:58:42 -070083 }
Romain Guy06f96e22010-07-30 19:18:16 -070084
Stan Iliev7bc3bc62017-05-24 13:28:36 -040085 if (!image.get()) {
86 SkBitmap bitmap;
87 image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
88 }
Nader Jawad2a499342023-02-08 11:56:37 -080089
Derek Sollenberger4d3df822022-01-11 17:58:29 +000090 sk_sp<SkShader> shader;
91 if (isDirectSampled) {
92 shader = image->makeRawShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
93 } else {
94 shader = image->makeShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
95 }
Nader Jawad5bed1f52020-09-25 00:27:29 -070096 ThrowIAE_IfNull(env, shader.get());
Derek Sollenberger450756a2016-11-07 15:55:47 -050097
Nader Jawad5bed1f52020-09-25 00:27:29 -070098 if (matrix) {
99 shader = shader->makeWithLocalMatrix(*matrix);
100 }
ztenghuib244fb52017-04-04 17:33:40 -0700101
Nader Jawad5bed1f52020-09-25 00:27:29 -0700102 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103}
Romain Guy06f96e22010-07-30 19:18:16 -0700104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105///////////////////////////////////////////////////////////////////////////////////////////////
106
Nader Jawad2a499342023-02-08 11:56:37 -0800107static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
108 jint tileModeX, jint tileModeY, bool filter,
109 bool isDirectSampled) {
110 SkSamplingOptions sampling(filter ? SkFilterMode::kLinear : SkFilterMode::kNearest,
111 SkMipmapMode::kNone);
112 return createBitmapShaderHelper(env, o, matrixPtr, bitmapHandle, tileModeX, tileModeY,
113 isDirectSampled, sampling);
114}
115
116static jlong BitmapShader_constructorWithMaxAniso(JNIEnv* env, jobject o, jlong matrixPtr,
117 jlong bitmapHandle, jint tileModeX,
118 jint tileModeY, jint maxAniso,
119 bool isDirectSampled) {
120 auto sampling = SkSamplingOptions::Aniso(static_cast<int>(maxAniso));
121 return createBitmapShaderHelper(env, o, matrixPtr, bitmapHandle, tileModeX, tileModeY,
122 isDirectSampled, sampling);
123}
124
125///////////////////////////////////////////////////////////////////////////////////////////////
126
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500127static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) {
128 const size_t count = env->GetArrayLength(colorArray);
129 const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500131 std::vector<SkColor4f> colors(count);
132 for (size_t i = 0; i < count; ++i) {
133 colors[i] = GraphicsJNI::convertColorLong(colorValues[i]);
ztenghuib244fb52017-04-04 17:33:40 -0700134 }
Romain Guy06f96e22010-07-30 19:18:16 -0700135
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500136 env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT);
137 return colors;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138}
139
140///////////////////////////////////////////////////////////////////////////////////////////////
141
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500142static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
143 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray,
Leon Scroggins III2befe1d2019-01-31 13:19:26 -0500144 jfloatArray posArray, jint tileMode, jlong colorSpaceHandle) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500145 SkPoint pts[2];
146 pts[0].set(x0, y0);
147 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500149 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500151 AutoJavaFloatArray autoPos(env, posArray, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400152#ifdef SK_SCALAR_IS_FLOAT
153 SkScalar* pos = autoPos.ptr();
154#else
155 #error Need to convert float array to SkScalar array before calling the following function.
156#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700157
Nader Jawad5bed1f52020-09-25 00:27:29 -0700158 sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
159 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
160 static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr));
161 ThrowIAE_IfNull(env, shader);
ztenghuib244fb52017-04-04 17:33:40 -0700162
Nader Jawad5bed1f52020-09-25 00:27:29 -0700163 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
164 if (matrix) {
165 shader = shader->makeWithLocalMatrix(*matrix);
166 }
167
168 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169}
170
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500171///////////////////////////////////////////////////////////////////////////////////////////////
172
Nader Jawade7ab8412020-10-16 18:00:04 -0700173static jlong RadialGradient_create(JNIEnv* env,
174 jobject,
175 jlong matrixPtr,
176 jfloat startX,
177 jfloat startY,
178 jfloat startRadius,
179 jfloat endX,
180 jfloat endY,
181 jfloat endRadius,
182 jlongArray colorArray,
183 jfloatArray posArray,
184 jint tileMode,
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500185 jlong colorSpaceHandle) {
Nader Jawade7ab8412020-10-16 18:00:04 -0700186
187 SkPoint start;
188 start.set(startX, startY);
189
190 SkPoint end;
191 end.set(endX, endY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500193 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500195 AutoJavaFloatArray autoPos(env, posArray, colors.size());
196#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
ztenghuib244fb52017-04-04 17:33:40 -0700201
Nader Jawade7ab8412020-10-16 18:00:04 -0700202 auto colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
203 auto skTileMode = static_cast<SkTileMode>(tileMode);
204 sk_sp<SkShader> shader = SkGradientShader::MakeTwoPointConical(start, startRadius, end,
205 endRadius, &colors[0], std::move(colorSpace), pos, colors.size(), skTileMode,
206 sGradientShaderFlags, nullptr);
Nader Jawad5bed1f52020-09-25 00:27:29 -0700207 ThrowIAE_IfNull(env, shader);
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500208
Nader Jawade7ab8412020-10-16 18:00:04 -0700209 // Explicitly create a new shader with the specified matrix to match existing behavior.
210 // Passing in the matrix in the instantiation above can throw exceptions for non-invertible
211 // matrices. However, makeWithLocalMatrix will still allow for the shader to be created
212 // and skia handles null-shaders internally (i.e. is ignored)
Nader Jawad5bed1f52020-09-25 00:27:29 -0700213 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
214 if (matrix) {
215 shader = shader->makeWithLocalMatrix(*matrix);
216 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500217
Nader Jawad5bed1f52020-09-25 00:27:29 -0700218 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219}
220
221///////////////////////////////////////////////////////////////////////////////
222
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500223static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
224 jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) {
225 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700226
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500227 AutoJavaFloatArray autoPos(env, jpositions, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400228#ifdef SK_SCALAR_IS_FLOAT
229 SkScalar* pos = autoPos.ptr();
230#else
231 #error Need to convert float array to SkScalar array before calling the following function.
232#endif
Elliott Hughes4cb17532011-04-12 16:10:26 -0700233
Nader Jawad5bed1f52020-09-25 00:27:29 -0700234 sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
235 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
236 sGradientShaderFlags, nullptr);
237 ThrowIAE_IfNull(env, shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238
Nader Jawad5bed1f52020-09-25 00:27:29 -0700239 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
240 if (matrix) {
241 shader = shader->makeWithLocalMatrix(*matrix);
242 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500243
Nader Jawad5bed1f52020-09-25 00:27:29 -0700244 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245}
246
247///////////////////////////////////////////////////////////////////////////////////////////////
248
Chris Craikb581e672017-03-07 15:27:36 -0800249static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
250 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
Nader Jawad5bed1f52020-09-25 00:27:29 -0700251 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
252 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
253 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
254 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
255 sk_sp<SkShader> baseShader(SkShaders::Blend(mode,
256 sk_ref_sp(shaderA), sk_ref_sp(shaderB)));
Chris Craikb581e672017-03-07 15:27:36 -0800257
Nader Jawad5bed1f52020-09-25 00:27:29 -0700258 SkShader* shader;
Chris Craikb581e672017-03-07 15:27:36 -0800259
Nader Jawad5bed1f52020-09-25 00:27:29 -0700260 if (matrix) {
261 shader = baseShader->makeWithLocalMatrix(*matrix).release();
262 } else {
263 shader = baseShader.release();
264 }
265 return reinterpret_cast<jlong>(shader);
Nader Jawad322cb9c2020-08-17 17:15:54 -0700266}
267
268///////////////////////////////////////////////////////////////////////////////////////////////
269
Stan Iliev6867fc82019-11-22 18:00:01 -0500270///////////////////////////////////////////////////////////////////////////////////////////////
271
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500272static jlong RuntimeShader_createShaderBuilder(JNIEnv* env, jobject, jstring sksl) {
Stan Iliev6867fc82019-11-22 18:00:01 -0500273 ScopedUtfChars strSksl(env, sksl);
Brian Osman75567772021-04-20 19:46:39 +0000274 auto result = SkRuntimeEffect::MakeForShader(SkString(strSksl.c_str()),
275 SkRuntimeEffect::Options{});
John Stiles5f2f3e42021-02-10 16:58:04 +0000276 if (result.effect.get() == nullptr) {
277 doThrowIAE(env, result.errorText.c_str());
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500278 return 0;
John Reckc784d9a2020-08-03 10:45:39 -0700279 }
John Stiles5f2f3e42021-02-10 16:58:04 +0000280 return reinterpret_cast<jlong>(new SkRuntimeShaderBuilder(std::move(result.effect)));
Stan Iliev6867fc82019-11-22 18:00:01 -0500281}
282
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500283static void SkRuntimeShaderBuilder_delete(SkRuntimeShaderBuilder* builder) {
284 delete builder;
Nader Jawad5bed1f52020-09-25 00:27:29 -0700285}
286
Stan Iliev6867fc82019-11-22 18:00:01 -0500287static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500288 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SkRuntimeShaderBuilder_delete));
289}
290
Derek Sollenberger7843e512022-02-03 15:50:09 +0000291static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500292 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
293 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Brian Osmanbb7c43d2022-02-03 14:48:12 -0500294 sk_sp<SkShader> shader = builder->makeShader(matrix);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500295 ThrowIAE_IfNull(env, shader);
296 return reinterpret_cast<jlong>(shader.release());
297}
298
299static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) {
300 va_list args;
301 va_start(args, fmt);
Greg Kaiser9c1f79f2021-01-19 07:35:49 -0800302 int ret = jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", fmt, args);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500303 va_end(args);
Greg Kaiser9c1f79f2021-01-19 07:35:49 -0800304 return ret;
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500305}
306
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000307static bool isIntUniformType(const SkRuntimeEffect::Uniform::Type& type) {
308 switch (type) {
309 case SkRuntimeEffect::Uniform::Type::kFloat:
310 case SkRuntimeEffect::Uniform::Type::kFloat2:
311 case SkRuntimeEffect::Uniform::Type::kFloat3:
312 case SkRuntimeEffect::Uniform::Type::kFloat4:
313 case SkRuntimeEffect::Uniform::Type::kFloat2x2:
314 case SkRuntimeEffect::Uniform::Type::kFloat3x3:
315 case SkRuntimeEffect::Uniform::Type::kFloat4x4:
316 return false;
317 case SkRuntimeEffect::Uniform::Type::kInt:
318 case SkRuntimeEffect::Uniform::Type::kInt2:
319 case SkRuntimeEffect::Uniform::Type::kInt3:
320 case SkRuntimeEffect::Uniform::Type::kInt4:
321 return true;
322 }
323}
324
325static void UpdateFloatUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder,
326 const char* uniformName, const float values[], int count,
327 bool isColor) {
328 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
329 if (uniform.fVar == nullptr) {
330 ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
331 } else if (isColor != ((uniform.fVar->flags & SkRuntimeEffect::Uniform::kColor_Flag) != 0)) {
332 if (isColor) {
333 jniThrowExceptionFmt(
334 env, "java/lang/IllegalArgumentException",
335 "attempting to set a color uniform using the non-color specific APIs: %s %x",
336 uniformName, uniform.fVar->flags);
337 } else {
338 ThrowIAEFmt(env,
339 "attempting to set a non-color uniform using the setColorUniform APIs: %s",
340 uniformName);
341 }
342 } else if (isIntUniformType(uniform.fVar->type)) {
343 ThrowIAEFmt(env, "attempting to set a int uniform using the setUniform APIs: %s",
344 uniformName);
345 } else if (!uniform.set<float>(values, count)) {
346 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
347 uniform.fVar->sizeInBytes(), sizeof(float) * count);
348 }
349}
350
351static void RuntimeShader_updateFloatUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
352 jstring jUniformName, jfloat value1, jfloat value2,
353 jfloat value3, jfloat value4, jint count) {
354 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
355 ScopedUtfChars name(env, jUniformName);
356 const float values[4] = {value1, value2, value3, value4};
357 UpdateFloatUniforms(env, builder, name.c_str(), values, count, false);
358}
359
360static void RuntimeShader_updateFloatArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
361 jstring jUniformName, jfloatArray jvalues,
362 jboolean isColor) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500363 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
364 ScopedUtfChars name(env, jUniformName);
365 AutoJavaFloatArray autoValues(env, jvalues, 0, kRO_JNIAccess);
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000366 UpdateFloatUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length(), isColor);
367}
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500368
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000369static void UpdateIntUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder, const char* uniformName,
370 const int values[], int count) {
371 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500372 if (uniform.fVar == nullptr) {
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000373 ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
374 } else if (!isIntUniformType(uniform.fVar->type)) {
375 ThrowIAEFmt(env, "attempting to set a non-int uniform using the setIntUniform APIs: %s",
376 uniformName);
377 } else if (!uniform.set<int>(values, count)) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500378 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000379 uniform.fVar->sizeInBytes(), sizeof(float) * count);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500380 }
381}
382
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000383static void RuntimeShader_updateIntUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
384 jstring jUniformName, jint value1, jint value2,
385 jint value3, jint value4, jint count) {
386 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
387 ScopedUtfChars name(env, jUniformName);
388 const int values[4] = {value1, value2, value3, value4};
389 UpdateIntUniforms(env, builder, name.c_str(), values, count);
390}
391
392static void RuntimeShader_updateIntArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
393 jstring jUniformName, jintArray jvalues) {
394 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
395 ScopedUtfChars name(env, jUniformName);
396 AutoJavaIntArray autoValues(env, jvalues, 0);
397 UpdateIntUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length());
398}
399
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500400static void RuntimeShader_updateShader(JNIEnv* env, jobject, jlong shaderBuilder,
401 jstring jUniformName, jlong shaderHandle) {
402 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
403 ScopedUtfChars name(env, jUniformName);
404 SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
405
406 SkRuntimeShaderBuilder::BuilderChild child = builder->child(name.c_str());
Brian Osman2a1308f2021-06-02 17:24:58 +0000407 if (child.fChild == nullptr) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500408 ThrowIAEFmt(env, "unable to find shader named %s", name.c_str());
409 return;
410 }
411
412 builder->child(name.c_str()) = sk_ref_sp(shader);
Stan Iliev6867fc82019-11-22 18:00:01 -0500413}
414
415///////////////////////////////////////////////////////////////////////////////////////////////
416
Daniel Micay76f6a862015-09-19 17:31:01 -0400417static const JNINativeMethod gColorMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800418 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
419 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420};
421
Daniel Micay76f6a862015-09-19 17:31:01 -0400422static const JNINativeMethod gShaderMethods[] = {
John Reck8bde0be2017-05-19 10:55:20 -0700423 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424};
425
Daniel Micay76f6a862015-09-19 17:31:01 -0400426static const JNINativeMethod gBitmapShaderMethods[] = {
Derek Sollenberger4d3df822022-01-11 17:58:29 +0000427 {"nativeCreate", "(JJIIZZ)J", (void*)BitmapShader_constructor},
Nader Jawad2a499342023-02-08 11:56:37 -0800428 {"nativeCreateWithMaxAniso", "(JJIIIZ)J", (void*)BitmapShader_constructorWithMaxAniso},
429
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430};
431
Daniel Micay76f6a862015-09-19 17:31:01 -0400432static const JNINativeMethod gLinearGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500433 { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434};
435
Daniel Micay76f6a862015-09-19 17:31:01 -0400436static const JNINativeMethod gRadialGradientMethods[] = {
Nader Jawade7ab8412020-10-16 18:00:04 -0700437 { "nativeCreate", "(JFFFFFF[J[FIJ)J", (void*)RadialGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438};
439
Daniel Micay76f6a862015-09-19 17:31:01 -0400440static const JNINativeMethod gSweepGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500441 { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442};
443
Daniel Micay76f6a862015-09-19 17:31:01 -0400444static const JNINativeMethod gComposeShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800445 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446};
447
Stan Iliev6867fc82019-11-22 18:00:01 -0500448static const JNINativeMethod gRuntimeShaderMethods[] = {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500449 {"nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer},
Derek Sollenberger7843e512022-02-03 15:50:09 +0000450 {"nativeCreateShader", "(JJ)J", (void*)RuntimeShader_create},
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500451 {"nativeCreateBuilder", "(Ljava/lang/String;)J", (void*)RuntimeShader_createShaderBuilder},
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000452 {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V",
453 (void*)RuntimeShader_updateFloatArrayUniforms},
454 {"nativeUpdateUniforms", "(JLjava/lang/String;FFFFI)V",
455 (void*)RuntimeShader_updateFloatUniforms},
456 {"nativeUpdateUniforms", "(JLjava/lang/String;[I)V",
457 (void*)RuntimeShader_updateIntArrayUniforms},
458 {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
459 (void*)RuntimeShader_updateIntUniforms},
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500460 {"nativeUpdateShader", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateShader},
Stan Iliev6867fc82019-11-22 18:00:01 -0500461};
462
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463int register_android_graphics_Shader(JNIEnv* env)
464{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800465 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
466 NELEM(gColorMethods));
467 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
468 NELEM(gShaderMethods));
469 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
470 NELEM(gBitmapShaderMethods));
471 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
472 NELEM(gLinearGradientMethods));
473 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
474 NELEM(gRadialGradientMethods));
475 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
476 NELEM(gSweepGradientMethods));
477 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
478 NELEM(gComposeShaderMethods));
Stan Iliev6867fc82019-11-22 18:00:01 -0500479 android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods,
480 NELEM(gRuntimeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700481
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800482 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483}