blob: a952be020855384e7fcb331845cc688cca479394 [file] [log] [blame]
John Reck7beba3c2023-03-07 20:18:26 -05001#include <vector>
2
3#include "Gainmap.h"
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"
John Reck7beba3c2023-03-07 20:18:26 -050020#include "effects/GainmapRenderer.h"
Brian Osmanbc44fa02020-01-03 15:28:06 -050021#include "include/effects/SkRuntimeEffect.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022
Romain Guy06f96e22010-07-30 19:18:16 -070023using namespace android::uirenderer;
24
Derek Sollenberger669b15a2017-03-31 12:09:24 -040025/**
26 * By default Skia gradients will interpolate their colors in unpremul space
27 * and then premultiply each of the results. We must set this flag to preserve
Kevin Lubick1175dc02022-02-28 12:41:27 -050028 * backwards compatibility by premultiplying the colors of the gradient first,
Derek Sollenberger669b15a2017-03-31 12:09:24 -040029 * and then interpolating between them.
30 */
31static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;
32
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -050033#define ThrowIAE_IfNull(env, ptr) \
34 if (nullptr == ptr) { \
35 doThrowIAE(env); \
36 return 0; \
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038
Ashok Bhat36bef0b2014-01-20 20:08:01 +000039static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040{
41 SkScalar hsv[3];
42 SkRGBToHSV(red, green, blue, hsv);
43
44 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
45 float* values = autoHSV.ptr();
46 for (int i = 0; i < 3; i++) {
47 values[i] = SkScalarToFloat(hsv[i]);
48 }
49}
Elliott Hughes4cb17532011-04-12 16:10:26 -070050
Ashok Bhat36bef0b2014-01-20 20:08:01 +000051static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052{
53 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
Kevin Lubickdd1e5ef2023-02-16 19:50:00 +000054 SkScalar* hsv = autoHSV.ptr();
Ashok Bhat36bef0b2014-01-20 20:08:01 +000055 return static_cast<jint>(SkHSVToColor(alpha, hsv));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056}
57
58///////////////////////////////////////////////////////////////////////////////////////////////
59
Nader Jawad5bed1f52020-09-25 00:27:29 -070060static void Shader_safeUnref(SkShader* shader) {
Derek Sollenberger6062c592011-02-22 13:55:04 -050061 SkSafeUnref(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062}
63
John Reck8bde0be2017-05-19 10:55:20 -070064static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) {
65 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
66}
67
John Reck992c5f82023-09-21 09:12:17 -040068///////////////////////////////////////////////////////////////////////////////////////////////
69
70static SkGainmapInfo sNoOpGainmap = {
71 .fGainmapRatioMin = {1.f, 1.f, 1.f, 1.0},
72 .fGainmapRatioMax = {1.f, 1.f, 1.f, 1.0},
73 .fGainmapGamma = {1.f, 1.f, 1.f, 1.f},
74 .fEpsilonSdr = {0.f, 0.f, 0.f, 1.0},
75 .fEpsilonHdr = {0.f, 0.f, 0.f, 1.0},
76 .fDisplayRatioSdr = 1.f,
77 .fDisplayRatioHdr = 1.f,
78};
79
80static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
81 jint tileModeX, jint tileModeY, jint maxAniso, bool filter,
82 bool isDirectSampled, jlong overrideGainmapPtr) {
83 SkSamplingOptions sampling = maxAniso > 0 ? SkSamplingOptions::Aniso(static_cast<int>(maxAniso))
84 : SkSamplingOptions(filter ? SkFilterMode::kLinear
85 : SkFilterMode::kNearest,
86 SkMipmapMode::kNone);
Chris Craikb581e672017-03-07 15:27:36 -080087 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
John Reck992c5f82023-09-21 09:12:17 -040088 const Gainmap* gainmap = reinterpret_cast<Gainmap*>(overrideGainmapPtr);
Stan Iliev7bc3bc62017-05-24 13:28:36 -040089 sk_sp<SkImage> image;
Leon Scroggins III71fae622019-03-26 16:28:41 -040090 if (bitmapHandle) {
Chris Craikb786bbd2015-06-10 16:58:42 -070091 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
92 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
John Reck7beba3c2023-03-07 20:18:26 -050093 auto& bitmap = android::bitmap::toBitmap(bitmapHandle);
94 image = bitmap.makeImage();
John Reck992c5f82023-09-21 09:12:17 -040095 if (!gainmap && bitmap.hasGainmap()) {
96 gainmap = bitmap.gainmap().get();
97 }
John Reck7beba3c2023-03-07 20:18:26 -050098
John Reck992c5f82023-09-21 09:12:17 -040099 if (!isDirectSampled && gainmap && gainmap->info != sNoOpGainmap) {
100 sk_sp<SkShader> gainmapShader =
101 MakeGainmapShader(image, gainmap->bitmap->makeImage(), gainmap->info,
102 (SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
John Reck7beba3c2023-03-07 20:18:26 -0500103 if (gainmapShader) {
104 if (matrix) {
105 gainmapShader = gainmapShader->makeWithLocalMatrix(*matrix);
106 }
107 return reinterpret_cast<jlong>(gainmapShader.release());
108 }
109 }
Chris Craikb786bbd2015-06-10 16:58:42 -0700110 }
Romain Guy06f96e22010-07-30 19:18:16 -0700111
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400112 if (!image.get()) {
113 SkBitmap bitmap;
114 image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
115 }
Nader Jawad2a499342023-02-08 11:56:37 -0800116
Derek Sollenberger4d3df822022-01-11 17:58:29 +0000117 sk_sp<SkShader> shader;
118 if (isDirectSampled) {
119 shader = image->makeRawShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
120 } else {
121 shader = image->makeShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
122 }
Nader Jawad5bed1f52020-09-25 00:27:29 -0700123 ThrowIAE_IfNull(env, shader.get());
Derek Sollenberger450756a2016-11-07 15:55:47 -0500124
Nader Jawad5bed1f52020-09-25 00:27:29 -0700125 if (matrix) {
126 shader = shader->makeWithLocalMatrix(*matrix);
127 }
ztenghuib244fb52017-04-04 17:33:40 -0700128
Nader Jawad5bed1f52020-09-25 00:27:29 -0700129 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130}
Romain Guy06f96e22010-07-30 19:18:16 -0700131
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132///////////////////////////////////////////////////////////////////////////////////////////////
133
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500134static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) {
135 const size_t count = env->GetArrayLength(colorArray);
136 const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500138 std::vector<SkColor4f> colors(count);
139 for (size_t i = 0; i < count; ++i) {
140 colors[i] = GraphicsJNI::convertColorLong(colorValues[i]);
ztenghuib244fb52017-04-04 17:33:40 -0700141 }
Romain Guy06f96e22010-07-30 19:18:16 -0700142
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500143 env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT);
144 return colors;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145}
146
147///////////////////////////////////////////////////////////////////////////////////////////////
148
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500149static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
150 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray,
Leon Scroggins III2befe1d2019-01-31 13:19:26 -0500151 jfloatArray posArray, jint tileMode, jlong colorSpaceHandle) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500152 SkPoint pts[2];
153 pts[0].set(x0, y0);
154 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500156 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500158 AutoJavaFloatArray autoPos(env, posArray, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400159 SkScalar* pos = autoPos.ptr();
Elliott Hughes4cb17532011-04-12 16:10:26 -0700160
Nader Jawad5bed1f52020-09-25 00:27:29 -0700161 sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
162 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
163 static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr));
164 ThrowIAE_IfNull(env, shader);
ztenghuib244fb52017-04-04 17:33:40 -0700165
Nader Jawad5bed1f52020-09-25 00:27:29 -0700166 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
167 if (matrix) {
168 shader = shader->makeWithLocalMatrix(*matrix);
169 }
170
171 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172}
173
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500174///////////////////////////////////////////////////////////////////////////////////////////////
175
Nader Jawade7ab8412020-10-16 18:00:04 -0700176static jlong RadialGradient_create(JNIEnv* env,
177 jobject,
178 jlong matrixPtr,
179 jfloat startX,
180 jfloat startY,
181 jfloat startRadius,
182 jfloat endX,
183 jfloat endY,
184 jfloat endRadius,
185 jlongArray colorArray,
186 jfloatArray posArray,
187 jint tileMode,
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500188 jlong colorSpaceHandle) {
Nader Jawade7ab8412020-10-16 18:00:04 -0700189
190 SkPoint start;
191 start.set(startX, startY);
192
193 SkPoint end;
194 end.set(endX, endY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500196 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500198 AutoJavaFloatArray autoPos(env, posArray, colors.size());
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500199 SkScalar* pos = autoPos.ptr();
ztenghuib244fb52017-04-04 17:33:40 -0700200
Nader Jawade7ab8412020-10-16 18:00:04 -0700201 auto colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
202 auto skTileMode = static_cast<SkTileMode>(tileMode);
203 sk_sp<SkShader> shader = SkGradientShader::MakeTwoPointConical(start, startRadius, end,
204 endRadius, &colors[0], std::move(colorSpace), pos, colors.size(), skTileMode,
205 sGradientShaderFlags, nullptr);
Nader Jawad5bed1f52020-09-25 00:27:29 -0700206 ThrowIAE_IfNull(env, shader);
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500207
Nader Jawade7ab8412020-10-16 18:00:04 -0700208 // Explicitly create a new shader with the specified matrix to match existing behavior.
209 // Passing in the matrix in the instantiation above can throw exceptions for non-invertible
210 // matrices. However, makeWithLocalMatrix will still allow for the shader to be created
211 // and skia handles null-shaders internally (i.e. is ignored)
Nader Jawad5bed1f52020-09-25 00:27:29 -0700212 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
213 if (matrix) {
214 shader = shader->makeWithLocalMatrix(*matrix);
215 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500216
Nader Jawad5bed1f52020-09-25 00:27:29 -0700217 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218}
219
220///////////////////////////////////////////////////////////////////////////////
221
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500222static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
223 jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) {
224 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700225
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500226 AutoJavaFloatArray autoPos(env, jpositions, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400227 SkScalar* pos = autoPos.ptr();
Elliott Hughes4cb17532011-04-12 16:10:26 -0700228
Nader Jawad5bed1f52020-09-25 00:27:29 -0700229 sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
230 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
231 sGradientShaderFlags, nullptr);
232 ThrowIAE_IfNull(env, shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233
Nader Jawad5bed1f52020-09-25 00:27:29 -0700234 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
235 if (matrix) {
236 shader = shader->makeWithLocalMatrix(*matrix);
237 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500238
Nader Jawad5bed1f52020-09-25 00:27:29 -0700239 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240}
241
242///////////////////////////////////////////////////////////////////////////////////////////////
243
Chris Craikb581e672017-03-07 15:27:36 -0800244static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
245 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
Nader Jawad5bed1f52020-09-25 00:27:29 -0700246 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
247 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
248 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
249 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
250 sk_sp<SkShader> baseShader(SkShaders::Blend(mode,
251 sk_ref_sp(shaderA), sk_ref_sp(shaderB)));
Chris Craikb581e672017-03-07 15:27:36 -0800252
Nader Jawad5bed1f52020-09-25 00:27:29 -0700253 SkShader* shader;
Chris Craikb581e672017-03-07 15:27:36 -0800254
Nader Jawad5bed1f52020-09-25 00:27:29 -0700255 if (matrix) {
256 shader = baseShader->makeWithLocalMatrix(*matrix).release();
257 } else {
258 shader = baseShader.release();
259 }
260 return reinterpret_cast<jlong>(shader);
Nader Jawad322cb9c2020-08-17 17:15:54 -0700261}
262
263///////////////////////////////////////////////////////////////////////////////////////////////
264
Stan Iliev6867fc82019-11-22 18:00:01 -0500265///////////////////////////////////////////////////////////////////////////////////////////////
266
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500267static jlong RuntimeShader_createShaderBuilder(JNIEnv* env, jobject, jstring sksl) {
Stan Iliev6867fc82019-11-22 18:00:01 -0500268 ScopedUtfChars strSksl(env, sksl);
Brian Osman75567772021-04-20 19:46:39 +0000269 auto result = SkRuntimeEffect::MakeForShader(SkString(strSksl.c_str()),
270 SkRuntimeEffect::Options{});
John Stiles5f2f3e42021-02-10 16:58:04 +0000271 if (result.effect.get() == nullptr) {
272 doThrowIAE(env, result.errorText.c_str());
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500273 return 0;
John Reckc784d9a2020-08-03 10:45:39 -0700274 }
John Stiles5f2f3e42021-02-10 16:58:04 +0000275 return reinterpret_cast<jlong>(new SkRuntimeShaderBuilder(std::move(result.effect)));
Stan Iliev6867fc82019-11-22 18:00:01 -0500276}
277
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500278static void SkRuntimeShaderBuilder_delete(SkRuntimeShaderBuilder* builder) {
279 delete builder;
Nader Jawad5bed1f52020-09-25 00:27:29 -0700280}
281
Stan Iliev6867fc82019-11-22 18:00:01 -0500282static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500283 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SkRuntimeShaderBuilder_delete));
284}
285
Derek Sollenberger7843e512022-02-03 15:50:09 +0000286static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500287 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
288 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Brian Osmanbb7c43d2022-02-03 14:48:12 -0500289 sk_sp<SkShader> shader = builder->makeShader(matrix);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500290 ThrowIAE_IfNull(env, shader);
291 return reinterpret_cast<jlong>(shader.release());
292}
293
294static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) {
295 va_list args;
296 va_start(args, fmt);
Greg Kaiser9c1f79f2021-01-19 07:35:49 -0800297 int ret = jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", fmt, args);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500298 va_end(args);
Greg Kaiser9c1f79f2021-01-19 07:35:49 -0800299 return ret;
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500300}
301
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000302static bool isIntUniformType(const SkRuntimeEffect::Uniform::Type& type) {
303 switch (type) {
304 case SkRuntimeEffect::Uniform::Type::kFloat:
305 case SkRuntimeEffect::Uniform::Type::kFloat2:
306 case SkRuntimeEffect::Uniform::Type::kFloat3:
307 case SkRuntimeEffect::Uniform::Type::kFloat4:
308 case SkRuntimeEffect::Uniform::Type::kFloat2x2:
309 case SkRuntimeEffect::Uniform::Type::kFloat3x3:
310 case SkRuntimeEffect::Uniform::Type::kFloat4x4:
311 return false;
312 case SkRuntimeEffect::Uniform::Type::kInt:
313 case SkRuntimeEffect::Uniform::Type::kInt2:
314 case SkRuntimeEffect::Uniform::Type::kInt3:
315 case SkRuntimeEffect::Uniform::Type::kInt4:
316 return true;
317 }
318}
319
320static void UpdateFloatUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder,
321 const char* uniformName, const float values[], int count,
322 bool isColor) {
323 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
324 if (uniform.fVar == nullptr) {
325 ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
326 } else if (isColor != ((uniform.fVar->flags & SkRuntimeEffect::Uniform::kColor_Flag) != 0)) {
327 if (isColor) {
328 jniThrowExceptionFmt(
329 env, "java/lang/IllegalArgumentException",
330 "attempting to set a color uniform using the non-color specific APIs: %s %x",
331 uniformName, uniform.fVar->flags);
332 } else {
333 ThrowIAEFmt(env,
334 "attempting to set a non-color uniform using the setColorUniform APIs: %s",
335 uniformName);
336 }
337 } else if (isIntUniformType(uniform.fVar->type)) {
338 ThrowIAEFmt(env, "attempting to set a int uniform using the setUniform APIs: %s",
339 uniformName);
340 } else if (!uniform.set<float>(values, count)) {
341 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
342 uniform.fVar->sizeInBytes(), sizeof(float) * count);
343 }
344}
345
346static void RuntimeShader_updateFloatUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
347 jstring jUniformName, jfloat value1, jfloat value2,
348 jfloat value3, jfloat value4, jint count) {
349 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
350 ScopedUtfChars name(env, jUniformName);
351 const float values[4] = {value1, value2, value3, value4};
352 UpdateFloatUniforms(env, builder, name.c_str(), values, count, false);
353}
354
355static void RuntimeShader_updateFloatArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
356 jstring jUniformName, jfloatArray jvalues,
357 jboolean isColor) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500358 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
359 ScopedUtfChars name(env, jUniformName);
360 AutoJavaFloatArray autoValues(env, jvalues, 0, kRO_JNIAccess);
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000361 UpdateFloatUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length(), isColor);
362}
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500363
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000364static void UpdateIntUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder, const char* uniformName,
365 const int values[], int count) {
366 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500367 if (uniform.fVar == nullptr) {
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000368 ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
369 } else if (!isIntUniformType(uniform.fVar->type)) {
370 ThrowIAEFmt(env, "attempting to set a non-int uniform using the setIntUniform APIs: %s",
371 uniformName);
372 } else if (!uniform.set<int>(values, count)) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500373 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000374 uniform.fVar->sizeInBytes(), sizeof(float) * count);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500375 }
376}
377
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000378static void RuntimeShader_updateIntUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
379 jstring jUniformName, jint value1, jint value2,
380 jint value3, jint value4, jint count) {
381 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
382 ScopedUtfChars name(env, jUniformName);
383 const int values[4] = {value1, value2, value3, value4};
384 UpdateIntUniforms(env, builder, name.c_str(), values, count);
385}
386
387static void RuntimeShader_updateIntArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
388 jstring jUniformName, jintArray jvalues) {
389 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
390 ScopedUtfChars name(env, jUniformName);
391 AutoJavaIntArray autoValues(env, jvalues, 0);
392 UpdateIntUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length());
393}
394
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500395static void RuntimeShader_updateShader(JNIEnv* env, jobject, jlong shaderBuilder,
396 jstring jUniformName, jlong shaderHandle) {
397 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
398 ScopedUtfChars name(env, jUniformName);
399 SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
400
401 SkRuntimeShaderBuilder::BuilderChild child = builder->child(name.c_str());
Brian Osman2a1308f2021-06-02 17:24:58 +0000402 if (child.fChild == nullptr) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500403 ThrowIAEFmt(env, "unable to find shader named %s", name.c_str());
404 return;
405 }
406
407 builder->child(name.c_str()) = sk_ref_sp(shader);
Stan Iliev6867fc82019-11-22 18:00:01 -0500408}
409
410///////////////////////////////////////////////////////////////////////////////////////////////
411
Daniel Micay76f6a862015-09-19 17:31:01 -0400412static const JNINativeMethod gColorMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800413 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
414 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415};
416
Daniel Micay76f6a862015-09-19 17:31:01 -0400417static const JNINativeMethod gShaderMethods[] = {
John Reck8bde0be2017-05-19 10:55:20 -0700418 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419};
420
Daniel Micay76f6a862015-09-19 17:31:01 -0400421static const JNINativeMethod gBitmapShaderMethods[] = {
John Reck992c5f82023-09-21 09:12:17 -0400422 {"nativeCreate", "(JJIIIZZJ)J", (void*)BitmapShader_constructor},
Nader Jawad2a499342023-02-08 11:56:37 -0800423
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424};
425
Daniel Micay76f6a862015-09-19 17:31:01 -0400426static const JNINativeMethod gLinearGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500427 { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428};
429
Daniel Micay76f6a862015-09-19 17:31:01 -0400430static const JNINativeMethod gRadialGradientMethods[] = {
Nader Jawade7ab8412020-10-16 18:00:04 -0700431 { "nativeCreate", "(JFFFFFF[J[FIJ)J", (void*)RadialGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432};
433
Daniel Micay76f6a862015-09-19 17:31:01 -0400434static const JNINativeMethod gSweepGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500435 { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436};
437
Daniel Micay76f6a862015-09-19 17:31:01 -0400438static const JNINativeMethod gComposeShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800439 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440};
441
Stan Iliev6867fc82019-11-22 18:00:01 -0500442static const JNINativeMethod gRuntimeShaderMethods[] = {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500443 {"nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer},
Derek Sollenberger7843e512022-02-03 15:50:09 +0000444 {"nativeCreateShader", "(JJ)J", (void*)RuntimeShader_create},
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500445 {"nativeCreateBuilder", "(Ljava/lang/String;)J", (void*)RuntimeShader_createShaderBuilder},
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000446 {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V",
447 (void*)RuntimeShader_updateFloatArrayUniforms},
448 {"nativeUpdateUniforms", "(JLjava/lang/String;FFFFI)V",
449 (void*)RuntimeShader_updateFloatUniforms},
450 {"nativeUpdateUniforms", "(JLjava/lang/String;[I)V",
451 (void*)RuntimeShader_updateIntArrayUniforms},
452 {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
453 (void*)RuntimeShader_updateIntUniforms},
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500454 {"nativeUpdateShader", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateShader},
Stan Iliev6867fc82019-11-22 18:00:01 -0500455};
456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457int register_android_graphics_Shader(JNIEnv* env)
458{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800459 android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
460 NELEM(gColorMethods));
461 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
462 NELEM(gShaderMethods));
463 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
464 NELEM(gBitmapShaderMethods));
465 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
466 NELEM(gLinearGradientMethods));
467 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
468 NELEM(gRadialGradientMethods));
469 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
470 NELEM(gSweepGradientMethods));
471 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
472 NELEM(gComposeShaderMethods));
Stan Iliev6867fc82019-11-22 18:00:01 -0500473 android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods,
474 NELEM(gRuntimeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700475
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800476 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477}