blob: 7eb79be6f55bf239646d1537a2261f3201ee40f2 [file] [log] [blame]
Derek Sollenberger783e5ae2021-01-11 15:44:46 -05001#undef LOG_TAG
2#define LOG_TAG "ShaderJNI"
3
John Reck7beba3c2023-03-07 20:18:26 -05004#include <vector>
5
6#include "Gainmap.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007#include "GraphicsJNI.h"
Kevin Lubick1175dc02022-02-28 12:41:27 -05008#include "SkBitmap.h"
9#include "SkBlendMode.h"
10#include "SkColor.h"
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -040011#include "SkColorFilter.h"
Ben Wagner60126ef2015-08-07 12:13:48 -040012#include "SkGradientShader.h"
Kevin Lubick1175dc02022-02-28 12:41:27 -050013#include "SkImage.h"
Matt Sarett62feb3a2016-09-20 10:34:11 -040014#include "SkImagePriv.h"
Kevin Lubick1175dc02022-02-28 12:41:27 -050015#include "SkMatrix.h"
16#include "SkPoint.h"
17#include "SkRefCnt.h"
18#include "SkSamplingOptions.h"
19#include "SkScalar.h"
Ben Wagner60126ef2015-08-07 12:13:48 -040020#include "SkShader.h"
Kevin Lubick1175dc02022-02-28 12:41:27 -050021#include "SkString.h"
22#include "SkTileMode.h"
John Reck7beba3c2023-03-07 20:18:26 -050023#include "effects/GainmapRenderer.h"
Brian Osmanbc44fa02020-01-03 15:28:06 -050024#include "include/effects/SkRuntimeEffect.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025
Romain Guy06f96e22010-07-30 19:18:16 -070026using namespace android::uirenderer;
27
Derek Sollenberger669b15a2017-03-31 12:09:24 -040028/**
29 * By default Skia gradients will interpolate their colors in unpremul space
30 * and then premultiply each of the results. We must set this flag to preserve
Kevin Lubick1175dc02022-02-28 12:41:27 -050031 * backwards compatibility by premultiplying the colors of the gradient first,
Derek Sollenberger669b15a2017-03-31 12:09:24 -040032 * and then interpolating between them.
33 */
34static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;
35
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050036#define ThrowIAE_IfNull(env, ptr) \
37 if (nullptr == ptr) { \
38 doThrowIAE(env); \
39 return 0; \
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041
Ashok Bhat36bef0b2014-01-20 20:08:01 +000042static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043{
44 SkScalar hsv[3];
45 SkRGBToHSV(red, green, blue, hsv);
46
47 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
48 float* values = autoHSV.ptr();
49 for (int i = 0; i < 3; i++) {
50 values[i] = SkScalarToFloat(hsv[i]);
51 }
52}
Elliott Hughes4cb17532011-04-12 16:10:26 -070053
Ashok Bhat36bef0b2014-01-20 20:08:01 +000054static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055{
56 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
Kevin Lubickdd1e5ef2023-02-16 19:50:00 +000057 SkScalar* hsv = autoHSV.ptr();
Ashok Bhat36bef0b2014-01-20 20:08:01 +000058 return static_cast<jint>(SkHSVToColor(alpha, hsv));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059}
60
61///////////////////////////////////////////////////////////////////////////////////////////////
62
Nader Jawad5bed1f52020-09-25 00:27:29 -070063static void Shader_safeUnref(SkShader* shader) {
Derek Sollenberger6062c592011-02-22 13:55:04 -050064 SkSafeUnref(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065}
66
John Reck8bde0be2017-05-19 10:55:20 -070067static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) {
68 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
69}
70
Nader Jawad2a499342023-02-08 11:56:37 -080071static jlong createBitmapShaderHelper(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
72 jint tileModeX, jint tileModeY, bool isDirectSampled,
73 const SkSamplingOptions& sampling) {
Chris Craikb581e672017-03-07 15:27:36 -080074 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Stan Iliev7bc3bc62017-05-24 13:28:36 -040075 sk_sp<SkImage> image;
Leon Scroggins III71fae622019-03-26 16:28:41 -040076 if (bitmapHandle) {
Chris Craikb786bbd2015-06-10 16:58:42 -070077 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
78 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
John Reck7beba3c2023-03-07 20:18:26 -050079 auto& bitmap = android::bitmap::toBitmap(bitmapHandle);
80 image = bitmap.makeImage();
81
82 if (!isDirectSampled && bitmap.hasGainmap()) {
83 sk_sp<SkShader> gainmapShader = MakeGainmapShader(
84 image, bitmap.gainmap()->bitmap->makeImage(), bitmap.gainmap()->info,
85 (SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
86 if (gainmapShader) {
87 if (matrix) {
88 gainmapShader = gainmapShader->makeWithLocalMatrix(*matrix);
89 }
90 return reinterpret_cast<jlong>(gainmapShader.release());
91 }
92 }
Chris Craikb786bbd2015-06-10 16:58:42 -070093 }
Romain Guy06f96e22010-07-30 19:18:16 -070094
Stan Iliev7bc3bc62017-05-24 13:28:36 -040095 if (!image.get()) {
96 SkBitmap bitmap;
97 image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
98 }
Nader Jawad2a499342023-02-08 11:56:37 -080099
Derek Sollenberger4d3df822022-01-11 17:58:29 +0000100 sk_sp<SkShader> shader;
101 if (isDirectSampled) {
102 shader = image->makeRawShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
103 } else {
104 shader = image->makeShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
105 }
Nader Jawad5bed1f52020-09-25 00:27:29 -0700106 ThrowIAE_IfNull(env, shader.get());
Derek Sollenberger450756a2016-11-07 15:55:47 -0500107
Nader Jawad5bed1f52020-09-25 00:27:29 -0700108 if (matrix) {
109 shader = shader->makeWithLocalMatrix(*matrix);
110 }
ztenghuib244fb52017-04-04 17:33:40 -0700111
Nader Jawad5bed1f52020-09-25 00:27:29 -0700112 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113}
Romain Guy06f96e22010-07-30 19:18:16 -0700114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115///////////////////////////////////////////////////////////////////////////////////////////////
116
Nader Jawad2a499342023-02-08 11:56:37 -0800117static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
118 jint tileModeX, jint tileModeY, bool filter,
119 bool isDirectSampled) {
120 SkSamplingOptions sampling(filter ? SkFilterMode::kLinear : SkFilterMode::kNearest,
121 SkMipmapMode::kNone);
122 return createBitmapShaderHelper(env, o, matrixPtr, bitmapHandle, tileModeX, tileModeY,
123 isDirectSampled, sampling);
124}
125
126static jlong BitmapShader_constructorWithMaxAniso(JNIEnv* env, jobject o, jlong matrixPtr,
127 jlong bitmapHandle, jint tileModeX,
128 jint tileModeY, jint maxAniso,
129 bool isDirectSampled) {
130 auto sampling = SkSamplingOptions::Aniso(static_cast<int>(maxAniso));
131 return createBitmapShaderHelper(env, o, matrixPtr, bitmapHandle, tileModeX, tileModeY,
132 isDirectSampled, sampling);
133}
134
135///////////////////////////////////////////////////////////////////////////////////////////////
136
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500137static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) {
138 const size_t count = env->GetArrayLength(colorArray);
139 const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500141 std::vector<SkColor4f> colors(count);
142 for (size_t i = 0; i < count; ++i) {
143 colors[i] = GraphicsJNI::convertColorLong(colorValues[i]);
ztenghuib244fb52017-04-04 17:33:40 -0700144 }
Romain Guy06f96e22010-07-30 19:18:16 -0700145
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500146 env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT);
147 return colors;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148}
149
150///////////////////////////////////////////////////////////////////////////////////////////////
151
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500152static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
153 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray,
Leon Scroggins III2befe1d2019-01-31 13:19:26 -0500154 jfloatArray posArray, jint tileMode, jlong colorSpaceHandle) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500155 SkPoint pts[2];
156 pts[0].set(x0, y0);
157 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500159 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500161 AutoJavaFloatArray autoPos(env, posArray, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400162 SkScalar* pos = autoPos.ptr();
Elliott Hughes4cb17532011-04-12 16:10:26 -0700163
Nader Jawad5bed1f52020-09-25 00:27:29 -0700164 sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
165 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
166 static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr));
167 ThrowIAE_IfNull(env, shader);
ztenghuib244fb52017-04-04 17:33:40 -0700168
Nader Jawad5bed1f52020-09-25 00:27:29 -0700169 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
170 if (matrix) {
171 shader = shader->makeWithLocalMatrix(*matrix);
172 }
173
174 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175}
176
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500177///////////////////////////////////////////////////////////////////////////////////////////////
178
Nader Jawade7ab8412020-10-16 18:00:04 -0700179static jlong RadialGradient_create(JNIEnv* env,
180 jobject,
181 jlong matrixPtr,
182 jfloat startX,
183 jfloat startY,
184 jfloat startRadius,
185 jfloat endX,
186 jfloat endY,
187 jfloat endRadius,
188 jlongArray colorArray,
189 jfloatArray posArray,
190 jint tileMode,
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500191 jlong colorSpaceHandle) {
Nader Jawade7ab8412020-10-16 18:00:04 -0700192
193 SkPoint start;
194 start.set(startX, startY);
195
196 SkPoint end;
197 end.set(endX, endY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500199 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500201 AutoJavaFloatArray autoPos(env, posArray, colors.size());
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500202 SkScalar* pos = autoPos.ptr();
ztenghuib244fb52017-04-04 17:33:40 -0700203
Nader Jawade7ab8412020-10-16 18:00:04 -0700204 auto colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
205 auto skTileMode = static_cast<SkTileMode>(tileMode);
206 sk_sp<SkShader> shader = SkGradientShader::MakeTwoPointConical(start, startRadius, end,
207 endRadius, &colors[0], std::move(colorSpace), pos, colors.size(), skTileMode,
208 sGradientShaderFlags, nullptr);
Nader Jawad5bed1f52020-09-25 00:27:29 -0700209 ThrowIAE_IfNull(env, shader);
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500210
Nader Jawade7ab8412020-10-16 18:00:04 -0700211 // Explicitly create a new shader with the specified matrix to match existing behavior.
212 // Passing in the matrix in the instantiation above can throw exceptions for non-invertible
213 // matrices. However, makeWithLocalMatrix will still allow for the shader to be created
214 // and skia handles null-shaders internally (i.e. is ignored)
Nader Jawad5bed1f52020-09-25 00:27:29 -0700215 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
216 if (matrix) {
217 shader = shader->makeWithLocalMatrix(*matrix);
218 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500219
Nader Jawad5bed1f52020-09-25 00:27:29 -0700220 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221}
222
223///////////////////////////////////////////////////////////////////////////////
224
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500225static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
226 jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) {
227 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700228
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500229 AutoJavaFloatArray autoPos(env, jpositions, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400230 SkScalar* pos = autoPos.ptr();
Elliott Hughes4cb17532011-04-12 16:10:26 -0700231
Nader Jawad5bed1f52020-09-25 00:27:29 -0700232 sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
233 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
234 sGradientShaderFlags, nullptr);
235 ThrowIAE_IfNull(env, shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236
Nader Jawad5bed1f52020-09-25 00:27:29 -0700237 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
238 if (matrix) {
239 shader = shader->makeWithLocalMatrix(*matrix);
240 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500241
Nader Jawad5bed1f52020-09-25 00:27:29 -0700242 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243}
244
245///////////////////////////////////////////////////////////////////////////////////////////////
246
Chris Craikb581e672017-03-07 15:27:36 -0800247static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
248 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
Nader Jawad5bed1f52020-09-25 00:27:29 -0700249 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
250 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
251 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
252 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
253 sk_sp<SkShader> baseShader(SkShaders::Blend(mode,
254 sk_ref_sp(shaderA), sk_ref_sp(shaderB)));
Chris Craikb581e672017-03-07 15:27:36 -0800255
Nader Jawad5bed1f52020-09-25 00:27:29 -0700256 SkShader* shader;
Chris Craikb581e672017-03-07 15:27:36 -0800257
Nader Jawad5bed1f52020-09-25 00:27:29 -0700258 if (matrix) {
259 shader = baseShader->makeWithLocalMatrix(*matrix).release();
260 } else {
261 shader = baseShader.release();
262 }
263 return reinterpret_cast<jlong>(shader);
Nader Jawad322cb9c2020-08-17 17:15:54 -0700264}
265
266///////////////////////////////////////////////////////////////////////////////////////////////
267
Stan Iliev6867fc82019-11-22 18:00:01 -0500268///////////////////////////////////////////////////////////////////////////////////////////////
269
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500270static jlong RuntimeShader_createShaderBuilder(JNIEnv* env, jobject, jstring sksl) {
Stan Iliev6867fc82019-11-22 18:00:01 -0500271 ScopedUtfChars strSksl(env, sksl);
Brian Osman75567772021-04-20 19:46:39 +0000272 auto result = SkRuntimeEffect::MakeForShader(SkString(strSksl.c_str()),
273 SkRuntimeEffect::Options{});
John Stiles5f2f3e42021-02-10 16:58:04 +0000274 if (result.effect.get() == nullptr) {
275 doThrowIAE(env, result.errorText.c_str());
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500276 return 0;
John Reckc784d9a2020-08-03 10:45:39 -0700277 }
John Stiles5f2f3e42021-02-10 16:58:04 +0000278 return reinterpret_cast<jlong>(new SkRuntimeShaderBuilder(std::move(result.effect)));
Stan Iliev6867fc82019-11-22 18:00:01 -0500279}
280
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500281static void SkRuntimeShaderBuilder_delete(SkRuntimeShaderBuilder* builder) {
282 delete builder;
Nader Jawad5bed1f52020-09-25 00:27:29 -0700283}
284
Stan Iliev6867fc82019-11-22 18:00:01 -0500285static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500286 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SkRuntimeShaderBuilder_delete));
287}
288
Derek Sollenberger7843e512022-02-03 15:50:09 +0000289static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500290 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
291 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Brian Osmanbb7c43d2022-02-03 14:48:12 -0500292 sk_sp<SkShader> shader = builder->makeShader(matrix);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500293 ThrowIAE_IfNull(env, shader);
294 return reinterpret_cast<jlong>(shader.release());
295}
296
297static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) {
298 va_list args;
299 va_start(args, fmt);
Greg Kaiser9c1f79f2021-01-19 07:35:49 -0800300 int ret = jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", fmt, args);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500301 va_end(args);
Greg Kaiser9c1f79f2021-01-19 07:35:49 -0800302 return ret;
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500303}
304
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000305static bool isIntUniformType(const SkRuntimeEffect::Uniform::Type& type) {
306 switch (type) {
307 case SkRuntimeEffect::Uniform::Type::kFloat:
308 case SkRuntimeEffect::Uniform::Type::kFloat2:
309 case SkRuntimeEffect::Uniform::Type::kFloat3:
310 case SkRuntimeEffect::Uniform::Type::kFloat4:
311 case SkRuntimeEffect::Uniform::Type::kFloat2x2:
312 case SkRuntimeEffect::Uniform::Type::kFloat3x3:
313 case SkRuntimeEffect::Uniform::Type::kFloat4x4:
314 return false;
315 case SkRuntimeEffect::Uniform::Type::kInt:
316 case SkRuntimeEffect::Uniform::Type::kInt2:
317 case SkRuntimeEffect::Uniform::Type::kInt3:
318 case SkRuntimeEffect::Uniform::Type::kInt4:
319 return true;
320 }
321}
322
323static void UpdateFloatUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder,
324 const char* uniformName, const float values[], int count,
325 bool isColor) {
326 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
327 if (uniform.fVar == nullptr) {
328 ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
329 } else if (isColor != ((uniform.fVar->flags & SkRuntimeEffect::Uniform::kColor_Flag) != 0)) {
330 if (isColor) {
331 jniThrowExceptionFmt(
332 env, "java/lang/IllegalArgumentException",
333 "attempting to set a color uniform using the non-color specific APIs: %s %x",
334 uniformName, uniform.fVar->flags);
335 } else {
336 ThrowIAEFmt(env,
337 "attempting to set a non-color uniform using the setColorUniform APIs: %s",
338 uniformName);
339 }
340 } else if (isIntUniformType(uniform.fVar->type)) {
341 ThrowIAEFmt(env, "attempting to set a int uniform using the setUniform APIs: %s",
342 uniformName);
343 } else if (!uniform.set<float>(values, count)) {
344 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
345 uniform.fVar->sizeInBytes(), sizeof(float) * count);
346 }
347}
348
349static void RuntimeShader_updateFloatUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
350 jstring jUniformName, jfloat value1, jfloat value2,
351 jfloat value3, jfloat value4, jint count) {
352 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
353 ScopedUtfChars name(env, jUniformName);
354 const float values[4] = {value1, value2, value3, value4};
355 UpdateFloatUniforms(env, builder, name.c_str(), values, count, false);
356}
357
358static void RuntimeShader_updateFloatArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
359 jstring jUniformName, jfloatArray jvalues,
360 jboolean isColor) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500361 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
362 ScopedUtfChars name(env, jUniformName);
363 AutoJavaFloatArray autoValues(env, jvalues, 0, kRO_JNIAccess);
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000364 UpdateFloatUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length(), isColor);
365}
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500366
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000367static void UpdateIntUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder, const char* uniformName,
368 const int values[], int count) {
369 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500370 if (uniform.fVar == nullptr) {
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000371 ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
372 } else if (!isIntUniformType(uniform.fVar->type)) {
373 ThrowIAEFmt(env, "attempting to set a non-int uniform using the setIntUniform APIs: %s",
374 uniformName);
375 } else if (!uniform.set<int>(values, count)) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500376 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000377 uniform.fVar->sizeInBytes(), sizeof(float) * count);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500378 }
379}
380
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000381static void RuntimeShader_updateIntUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
382 jstring jUniformName, jint value1, jint value2,
383 jint value3, jint value4, jint count) {
384 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
385 ScopedUtfChars name(env, jUniformName);
386 const int values[4] = {value1, value2, value3, value4};
387 UpdateIntUniforms(env, builder, name.c_str(), values, count);
388}
389
390static void RuntimeShader_updateIntArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
391 jstring jUniformName, jintArray jvalues) {
392 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
393 ScopedUtfChars name(env, jUniformName);
394 AutoJavaIntArray autoValues(env, jvalues, 0);
395 UpdateIntUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length());
396}
397
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500398static void RuntimeShader_updateShader(JNIEnv* env, jobject, jlong shaderBuilder,
399 jstring jUniformName, jlong shaderHandle) {
400 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
401 ScopedUtfChars name(env, jUniformName);
402 SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
403
404 SkRuntimeShaderBuilder::BuilderChild child = builder->child(name.c_str());
Brian Osman2a1308f2021-06-02 17:24:58 +0000405 if (child.fChild == nullptr) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500406 ThrowIAEFmt(env, "unable to find shader named %s", name.c_str());
407 return;
408 }
409
410 builder->child(name.c_str()) = sk_ref_sp(shader);
Stan Iliev6867fc82019-11-22 18:00:01 -0500411}
412
413///////////////////////////////////////////////////////////////////////////////////////////////
414
Daniel Micay76f6a862015-09-19 17:31:01 -0400415static const JNINativeMethod gColorMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800416 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
417 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418};
419
Daniel Micay76f6a862015-09-19 17:31:01 -0400420static const JNINativeMethod gShaderMethods[] = {
John Reck8bde0be2017-05-19 10:55:20 -0700421 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422};
423
Daniel Micay76f6a862015-09-19 17:31:01 -0400424static const JNINativeMethod gBitmapShaderMethods[] = {
Derek Sollenberger4d3df822022-01-11 17:58:29 +0000425 {"nativeCreate", "(JJIIZZ)J", (void*)BitmapShader_constructor},
Nader Jawad2a499342023-02-08 11:56:37 -0800426 {"nativeCreateWithMaxAniso", "(JJIIIZ)J", (void*)BitmapShader_constructorWithMaxAniso},
427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428};
429
Daniel Micay76f6a862015-09-19 17:31:01 -0400430static const JNINativeMethod gLinearGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500431 { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432};
433
Daniel Micay76f6a862015-09-19 17:31:01 -0400434static const JNINativeMethod gRadialGradientMethods[] = {
Nader Jawade7ab8412020-10-16 18:00:04 -0700435 { "nativeCreate", "(JFFFFFF[J[FIJ)J", (void*)RadialGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436};
437
Daniel Micay76f6a862015-09-19 17:31:01 -0400438static const JNINativeMethod gSweepGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500439 { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440};
441
Daniel Micay76f6a862015-09-19 17:31:01 -0400442static const JNINativeMethod gComposeShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800443 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444};
445
Stan Iliev6867fc82019-11-22 18:00:01 -0500446static const JNINativeMethod gRuntimeShaderMethods[] = {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500447 {"nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer},
Derek Sollenberger7843e512022-02-03 15:50:09 +0000448 {"nativeCreateShader", "(JJ)J", (void*)RuntimeShader_create},
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500449 {"nativeCreateBuilder", "(Ljava/lang/String;)J", (void*)RuntimeShader_createShaderBuilder},
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000450 {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V",
451 (void*)RuntimeShader_updateFloatArrayUniforms},
452 {"nativeUpdateUniforms", "(JLjava/lang/String;FFFFI)V",
453 (void*)RuntimeShader_updateFloatUniforms},
454 {"nativeUpdateUniforms", "(JLjava/lang/String;[I)V",
455 (void*)RuntimeShader_updateIntArrayUniforms},
456 {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
457 (void*)RuntimeShader_updateIntUniforms},
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500458 {"nativeUpdateShader", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateShader},
Stan Iliev6867fc82019-11-22 18:00:01 -0500459};
460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461int register_android_graphics_Shader(JNIEnv* env)
462{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800463 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
464 NELEM(gColorMethods));
465 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
466 NELEM(gShaderMethods));
467 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
468 NELEM(gBitmapShaderMethods));
469 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
470 NELEM(gLinearGradientMethods));
471 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
472 NELEM(gRadialGradientMethods));
473 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
474 NELEM(gSweepGradientMethods));
475 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
476 NELEM(gComposeShaderMethods));
Stan Iliev6867fc82019-11-22 18:00:01 -0500477 android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods,
478 NELEM(gRuntimeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700479
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800480 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800481}