blob: 75d45e5bd8aa394723bea16a0afc04f9559ea2de [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);
Kevin Lubickdd1e5ef2023-02-16 19:50:00 +000055 SkScalar* hsv = autoHSV.ptr();
Ashok Bhat36bef0b2014-01-20 20:08:01 +000056 return static_cast<jint>(SkHSVToColor(alpha, hsv));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057}
58
59///////////////////////////////////////////////////////////////////////////////////////////////
60
Nader Jawad5bed1f52020-09-25 00:27:29 -070061static void Shader_safeUnref(SkShader* shader) {
Derek Sollenberger6062c592011-02-22 13:55:04 -050062 SkSafeUnref(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063}
64
John Reck8bde0be2017-05-19 10:55:20 -070065static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) {
66 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
67}
68
Nader Jawad2a499342023-02-08 11:56:37 -080069static jlong createBitmapShaderHelper(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
70 jint tileModeX, jint tileModeY, bool isDirectSampled,
71 const SkSamplingOptions& sampling) {
Chris Craikb581e672017-03-07 15:27:36 -080072 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Stan Iliev7bc3bc62017-05-24 13:28:36 -040073 sk_sp<SkImage> image;
Leon Scroggins III71fae622019-03-26 16:28:41 -040074 if (bitmapHandle) {
Chris Craikb786bbd2015-06-10 16:58:42 -070075 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
76 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
Leon Scroggins III71fae622019-03-26 16:28:41 -040077 image = android::bitmap::toBitmap(bitmapHandle).makeImage();
Chris Craikb786bbd2015-06-10 16:58:42 -070078 }
Romain Guy06f96e22010-07-30 19:18:16 -070079
Stan Iliev7bc3bc62017-05-24 13:28:36 -040080 if (!image.get()) {
81 SkBitmap bitmap;
82 image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
83 }
Nader Jawad2a499342023-02-08 11:56:37 -080084
Derek Sollenberger4d3df822022-01-11 17:58:29 +000085 sk_sp<SkShader> shader;
86 if (isDirectSampled) {
87 shader = image->makeRawShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
88 } else {
89 shader = image->makeShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
90 }
Nader Jawad5bed1f52020-09-25 00:27:29 -070091 ThrowIAE_IfNull(env, shader.get());
Derek Sollenberger450756a2016-11-07 15:55:47 -050092
Nader Jawad5bed1f52020-09-25 00:27:29 -070093 if (matrix) {
94 shader = shader->makeWithLocalMatrix(*matrix);
95 }
ztenghuib244fb52017-04-04 17:33:40 -070096
Nader Jawad5bed1f52020-09-25 00:27:29 -070097 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098}
Romain Guy06f96e22010-07-30 19:18:16 -070099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100///////////////////////////////////////////////////////////////////////////////////////////////
101
Nader Jawad2a499342023-02-08 11:56:37 -0800102static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
103 jint tileModeX, jint tileModeY, bool filter,
104 bool isDirectSampled) {
105 SkSamplingOptions sampling(filter ? SkFilterMode::kLinear : SkFilterMode::kNearest,
106 SkMipmapMode::kNone);
107 return createBitmapShaderHelper(env, o, matrixPtr, bitmapHandle, tileModeX, tileModeY,
108 isDirectSampled, sampling);
109}
110
111static jlong BitmapShader_constructorWithMaxAniso(JNIEnv* env, jobject o, jlong matrixPtr,
112 jlong bitmapHandle, jint tileModeX,
113 jint tileModeY, jint maxAniso,
114 bool isDirectSampled) {
115 auto sampling = SkSamplingOptions::Aniso(static_cast<int>(maxAniso));
116 return createBitmapShaderHelper(env, o, matrixPtr, bitmapHandle, tileModeX, tileModeY,
117 isDirectSampled, sampling);
118}
119
120///////////////////////////////////////////////////////////////////////////////////////////////
121
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500122static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) {
123 const size_t count = env->GetArrayLength(colorArray);
124 const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500126 std::vector<SkColor4f> colors(count);
127 for (size_t i = 0; i < count; ++i) {
128 colors[i] = GraphicsJNI::convertColorLong(colorValues[i]);
ztenghuib244fb52017-04-04 17:33:40 -0700129 }
Romain Guy06f96e22010-07-30 19:18:16 -0700130
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500131 env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT);
132 return colors;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133}
134
135///////////////////////////////////////////////////////////////////////////////////////////////
136
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500137static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
138 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray,
Leon Scroggins III2befe1d2019-01-31 13:19:26 -0500139 jfloatArray posArray, jint tileMode, jlong colorSpaceHandle) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500140 SkPoint pts[2];
141 pts[0].set(x0, y0);
142 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500144 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500146 AutoJavaFloatArray autoPos(env, posArray, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400147 SkScalar* pos = autoPos.ptr();
Elliott Hughes4cb17532011-04-12 16:10:26 -0700148
Nader Jawad5bed1f52020-09-25 00:27:29 -0700149 sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
150 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
151 static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr));
152 ThrowIAE_IfNull(env, shader);
ztenghuib244fb52017-04-04 17:33:40 -0700153
Nader Jawad5bed1f52020-09-25 00:27:29 -0700154 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
155 if (matrix) {
156 shader = shader->makeWithLocalMatrix(*matrix);
157 }
158
159 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160}
161
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500162///////////////////////////////////////////////////////////////////////////////////////////////
163
Nader Jawade7ab8412020-10-16 18:00:04 -0700164static jlong RadialGradient_create(JNIEnv* env,
165 jobject,
166 jlong matrixPtr,
167 jfloat startX,
168 jfloat startY,
169 jfloat startRadius,
170 jfloat endX,
171 jfloat endY,
172 jfloat endRadius,
173 jlongArray colorArray,
174 jfloatArray posArray,
175 jint tileMode,
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500176 jlong colorSpaceHandle) {
Nader Jawade7ab8412020-10-16 18:00:04 -0700177
178 SkPoint start;
179 start.set(startX, startY);
180
181 SkPoint end;
182 end.set(endX, endY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500184 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500186 AutoJavaFloatArray autoPos(env, posArray, colors.size());
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500187 SkScalar* pos = autoPos.ptr();
ztenghuib244fb52017-04-04 17:33:40 -0700188
Nader Jawade7ab8412020-10-16 18:00:04 -0700189 auto colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
190 auto skTileMode = static_cast<SkTileMode>(tileMode);
191 sk_sp<SkShader> shader = SkGradientShader::MakeTwoPointConical(start, startRadius, end,
192 endRadius, &colors[0], std::move(colorSpace), pos, colors.size(), skTileMode,
193 sGradientShaderFlags, nullptr);
Nader Jawad5bed1f52020-09-25 00:27:29 -0700194 ThrowIAE_IfNull(env, shader);
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500195
Nader Jawade7ab8412020-10-16 18:00:04 -0700196 // Explicitly create a new shader with the specified matrix to match existing behavior.
197 // Passing in the matrix in the instantiation above can throw exceptions for non-invertible
198 // matrices. However, makeWithLocalMatrix will still allow for the shader to be created
199 // and skia handles null-shaders internally (i.e. is ignored)
Nader Jawad5bed1f52020-09-25 00:27:29 -0700200 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
201 if (matrix) {
202 shader = shader->makeWithLocalMatrix(*matrix);
203 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500204
Nader Jawad5bed1f52020-09-25 00:27:29 -0700205 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206}
207
208///////////////////////////////////////////////////////////////////////////////
209
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500210static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
211 jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) {
212 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700213
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500214 AutoJavaFloatArray autoPos(env, jpositions, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400215 SkScalar* pos = autoPos.ptr();
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},
Nader Jawad2a499342023-02-08 11:56:37 -0800411 {"nativeCreateWithMaxAniso", "(JJIIIZ)J", (void*)BitmapShader_constructorWithMaxAniso},
412
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413};
414
Daniel Micay76f6a862015-09-19 17:31:01 -0400415static const JNINativeMethod gLinearGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500416 { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417};
418
Daniel Micay76f6a862015-09-19 17:31:01 -0400419static const JNINativeMethod gRadialGradientMethods[] = {
Nader Jawade7ab8412020-10-16 18:00:04 -0700420 { "nativeCreate", "(JFFFFFF[J[FIJ)J", (void*)RadialGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421};
422
Daniel Micay76f6a862015-09-19 17:31:01 -0400423static const JNINativeMethod gSweepGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500424 { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425};
426
Daniel Micay76f6a862015-09-19 17:31:01 -0400427static const JNINativeMethod gComposeShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800428 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429};
430
Stan Iliev6867fc82019-11-22 18:00:01 -0500431static const JNINativeMethod gRuntimeShaderMethods[] = {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500432 {"nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer},
Derek Sollenberger7843e512022-02-03 15:50:09 +0000433 {"nativeCreateShader", "(JJ)J", (void*)RuntimeShader_create},
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500434 {"nativeCreateBuilder", "(Ljava/lang/String;)J", (void*)RuntimeShader_createShaderBuilder},
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000435 {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V",
436 (void*)RuntimeShader_updateFloatArrayUniforms},
437 {"nativeUpdateUniforms", "(JLjava/lang/String;FFFFI)V",
438 (void*)RuntimeShader_updateFloatUniforms},
439 {"nativeUpdateUniforms", "(JLjava/lang/String;[I)V",
440 (void*)RuntimeShader_updateIntArrayUniforms},
441 {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
442 (void*)RuntimeShader_updateIntUniforms},
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500443 {"nativeUpdateShader", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateShader},
Stan Iliev6867fc82019-11-22 18:00:01 -0500444};
445
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446int register_android_graphics_Shader(JNIEnv* env)
447{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800448 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
449 NELEM(gColorMethods));
450 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
451 NELEM(gShaderMethods));
452 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
453 NELEM(gBitmapShaderMethods));
454 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
455 NELEM(gLinearGradientMethods));
456 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
457 NELEM(gRadialGradientMethods));
458 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
459 NELEM(gSweepGradientMethods));
460 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
461 NELEM(gComposeShaderMethods));
Stan Iliev6867fc82019-11-22 18:00:01 -0500462 android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods,
463 NELEM(gRuntimeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700464
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800465 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466}