blob: 2a057e7a4cdc08a4136a309ee6ec6d481d855324 [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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039///////////////////////////////////////////////////////////////////////////////////////////////
40
Nader Jawad5bed1f52020-09-25 00:27:29 -070041static void Shader_safeUnref(SkShader* shader) {
Derek Sollenberger6062c592011-02-22 13:55:04 -050042 SkSafeUnref(shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043}
44
John Reck8bde0be2017-05-19 10:55:20 -070045static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) {
46 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
47}
48
John Reck992c5f82023-09-21 09:12:17 -040049///////////////////////////////////////////////////////////////////////////////////////////////
50
51static SkGainmapInfo sNoOpGainmap = {
52 .fGainmapRatioMin = {1.f, 1.f, 1.f, 1.0},
53 .fGainmapRatioMax = {1.f, 1.f, 1.f, 1.0},
54 .fGainmapGamma = {1.f, 1.f, 1.f, 1.f},
55 .fEpsilonSdr = {0.f, 0.f, 0.f, 1.0},
56 .fEpsilonHdr = {0.f, 0.f, 0.f, 1.0},
57 .fDisplayRatioSdr = 1.f,
58 .fDisplayRatioHdr = 1.f,
59};
60
61static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
62 jint tileModeX, jint tileModeY, jint maxAniso, bool filter,
63 bool isDirectSampled, jlong overrideGainmapPtr) {
64 SkSamplingOptions sampling = maxAniso > 0 ? SkSamplingOptions::Aniso(static_cast<int>(maxAniso))
65 : SkSamplingOptions(filter ? SkFilterMode::kLinear
66 : SkFilterMode::kNearest,
67 SkMipmapMode::kNone);
Chris Craikb581e672017-03-07 15:27:36 -080068 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
John Reck992c5f82023-09-21 09:12:17 -040069 const Gainmap* gainmap = reinterpret_cast<Gainmap*>(overrideGainmapPtr);
Stan Iliev7bc3bc62017-05-24 13:28:36 -040070 sk_sp<SkImage> image;
Leon Scroggins III71fae622019-03-26 16:28:41 -040071 if (bitmapHandle) {
Chris Craikb786bbd2015-06-10 16:58:42 -070072 // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
73 // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
John Reck7beba3c2023-03-07 20:18:26 -050074 auto& bitmap = android::bitmap::toBitmap(bitmapHandle);
75 image = bitmap.makeImage();
John Reck992c5f82023-09-21 09:12:17 -040076 if (!gainmap && bitmap.hasGainmap()) {
77 gainmap = bitmap.gainmap().get();
78 }
John Reck7beba3c2023-03-07 20:18:26 -050079
John Reck992c5f82023-09-21 09:12:17 -040080 if (!isDirectSampled && gainmap && gainmap->info != sNoOpGainmap) {
81 sk_sp<SkShader> gainmapShader =
82 MakeGainmapShader(image, gainmap->bitmap->makeImage(), gainmap->info,
83 (SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
John Reck7beba3c2023-03-07 20:18:26 -050084 if (gainmapShader) {
85 if (matrix) {
86 gainmapShader = gainmapShader->makeWithLocalMatrix(*matrix);
87 }
88 return reinterpret_cast<jlong>(gainmapShader.release());
89 }
90 }
Chris Craikb786bbd2015-06-10 16:58:42 -070091 }
Romain Guy06f96e22010-07-30 19:18:16 -070092
Stan Iliev7bc3bc62017-05-24 13:28:36 -040093 if (!image.get()) {
94 SkBitmap bitmap;
95 image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
96 }
Nader Jawad2a499342023-02-08 11:56:37 -080097
Derek Sollenberger4d3df822022-01-11 17:58:29 +000098 sk_sp<SkShader> shader;
99 if (isDirectSampled) {
100 shader = image->makeRawShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
101 } else {
102 shader = image->makeShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
103 }
Nader Jawad5bed1f52020-09-25 00:27:29 -0700104 ThrowIAE_IfNull(env, shader.get());
Derek Sollenberger450756a2016-11-07 15:55:47 -0500105
Nader Jawad5bed1f52020-09-25 00:27:29 -0700106 if (matrix) {
107 shader = shader->makeWithLocalMatrix(*matrix);
108 }
ztenghuib244fb52017-04-04 17:33:40 -0700109
Nader Jawad5bed1f52020-09-25 00:27:29 -0700110 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111}
Romain Guy06f96e22010-07-30 19:18:16 -0700112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113///////////////////////////////////////////////////////////////////////////////////////////////
114
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500115static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) {
116 const size_t count = env->GetArrayLength(colorArray);
117 const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500119 std::vector<SkColor4f> colors(count);
120 for (size_t i = 0; i < count; ++i) {
121 colors[i] = GraphicsJNI::convertColorLong(colorValues[i]);
ztenghuib244fb52017-04-04 17:33:40 -0700122 }
Romain Guy06f96e22010-07-30 19:18:16 -0700123
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500124 env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT);
125 return colors;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126}
127
128///////////////////////////////////////////////////////////////////////////////////////////////
129
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500130static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
131 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray,
Leon Scroggins III2befe1d2019-01-31 13:19:26 -0500132 jfloatArray posArray, jint tileMode, jlong colorSpaceHandle) {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500133 SkPoint pts[2];
134 pts[0].set(x0, y0);
135 pts[1].set(x1, y1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500137 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500139 AutoJavaFloatArray autoPos(env, posArray, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400140 SkScalar* pos = autoPos.ptr();
Elliott Hughes4cb17532011-04-12 16:10:26 -0700141
Nader Jawad5bed1f52020-09-25 00:27:29 -0700142 sk_sp<SkShader> shader(SkGradientShader::MakeLinear(pts, &colors[0],
143 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
144 static_cast<SkTileMode>(tileMode), sGradientShaderFlags, nullptr));
145 ThrowIAE_IfNull(env, shader);
ztenghuib244fb52017-04-04 17:33:40 -0700146
Nader Jawad5bed1f52020-09-25 00:27:29 -0700147 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
148 if (matrix) {
149 shader = shader->makeWithLocalMatrix(*matrix);
150 }
151
152 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153}
154
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500155///////////////////////////////////////////////////////////////////////////////////////////////
156
Nader Jawade7ab8412020-10-16 18:00:04 -0700157static jlong RadialGradient_create(JNIEnv* env,
158 jobject,
159 jlong matrixPtr,
160 jfloat startX,
161 jfloat startY,
162 jfloat startRadius,
163 jfloat endX,
164 jfloat endY,
165 jfloat endRadius,
166 jlongArray colorArray,
167 jfloatArray posArray,
168 jint tileMode,
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500169 jlong colorSpaceHandle) {
Nader Jawade7ab8412020-10-16 18:00:04 -0700170
171 SkPoint start;
172 start.set(startX, startY);
173
174 SkPoint end;
175 end.set(endX, endY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500177 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500179 AutoJavaFloatArray autoPos(env, posArray, colors.size());
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500180 SkScalar* pos = autoPos.ptr();
ztenghuib244fb52017-04-04 17:33:40 -0700181
Nader Jawade7ab8412020-10-16 18:00:04 -0700182 auto colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
183 auto skTileMode = static_cast<SkTileMode>(tileMode);
184 sk_sp<SkShader> shader = SkGradientShader::MakeTwoPointConical(start, startRadius, end,
185 endRadius, &colors[0], std::move(colorSpace), pos, colors.size(), skTileMode,
186 sGradientShaderFlags, nullptr);
Nader Jawad5bed1f52020-09-25 00:27:29 -0700187 ThrowIAE_IfNull(env, shader);
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500188
Nader Jawade7ab8412020-10-16 18:00:04 -0700189 // Explicitly create a new shader with the specified matrix to match existing behavior.
190 // Passing in the matrix in the instantiation above can throw exceptions for non-invertible
191 // matrices. However, makeWithLocalMatrix will still allow for the shader to be created
192 // and skia handles null-shaders internally (i.e. is ignored)
Nader Jawad5bed1f52020-09-25 00:27:29 -0700193 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
194 if (matrix) {
195 shader = shader->makeWithLocalMatrix(*matrix);
196 }
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500197
Nader Jawad5bed1f52020-09-25 00:27:29 -0700198 return reinterpret_cast<jlong>(shader.release());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199}
200
201///////////////////////////////////////////////////////////////////////////////
202
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500203static jlong SweepGradient_create(JNIEnv* env, jobject, jlong matrixPtr, jfloat x, jfloat y,
204 jlongArray colorArray, jfloatArray jpositions, jlong colorSpaceHandle) {
205 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700206
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500207 AutoJavaFloatArray autoPos(env, jpositions, colors.size());
Leon Scroggins III2e0103e2014-04-04 17:05:24 -0400208 SkScalar* pos = autoPos.ptr();
Elliott Hughes4cb17532011-04-12 16:10:26 -0700209
Nader Jawad5bed1f52020-09-25 00:27:29 -0700210 sk_sp<SkShader> shader = SkGradientShader::MakeSweep(x, y, &colors[0],
211 GraphicsJNI::getNativeColorSpace(colorSpaceHandle), pos, colors.size(),
212 sGradientShaderFlags, nullptr);
213 ThrowIAE_IfNull(env, shader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214
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
Chris Craikb581e672017-03-07 15:27:36 -0800225static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
226 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
Nader Jawad5bed1f52020-09-25 00:27:29 -0700227 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
228 SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
229 SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
230 SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
231 sk_sp<SkShader> baseShader(SkShaders::Blend(mode,
232 sk_ref_sp(shaderA), sk_ref_sp(shaderB)));
Chris Craikb581e672017-03-07 15:27:36 -0800233
Nader Jawad5bed1f52020-09-25 00:27:29 -0700234 SkShader* shader;
Chris Craikb581e672017-03-07 15:27:36 -0800235
Nader Jawad5bed1f52020-09-25 00:27:29 -0700236 if (matrix) {
237 shader = baseShader->makeWithLocalMatrix(*matrix).release();
238 } else {
239 shader = baseShader.release();
240 }
241 return reinterpret_cast<jlong>(shader);
Nader Jawad322cb9c2020-08-17 17:15:54 -0700242}
243
244///////////////////////////////////////////////////////////////////////////////////////////////
245
Stan Iliev6867fc82019-11-22 18:00:01 -0500246///////////////////////////////////////////////////////////////////////////////////////////////
247
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500248static jlong RuntimeShader_createShaderBuilder(JNIEnv* env, jobject, jstring sksl) {
Stan Iliev6867fc82019-11-22 18:00:01 -0500249 ScopedUtfChars strSksl(env, sksl);
Brian Osman75567772021-04-20 19:46:39 +0000250 auto result = SkRuntimeEffect::MakeForShader(SkString(strSksl.c_str()),
251 SkRuntimeEffect::Options{});
John Stiles5f2f3e42021-02-10 16:58:04 +0000252 if (result.effect.get() == nullptr) {
253 doThrowIAE(env, result.errorText.c_str());
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500254 return 0;
John Reckc784d9a2020-08-03 10:45:39 -0700255 }
John Stiles5f2f3e42021-02-10 16:58:04 +0000256 return reinterpret_cast<jlong>(new SkRuntimeShaderBuilder(std::move(result.effect)));
Stan Iliev6867fc82019-11-22 18:00:01 -0500257}
258
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500259static void SkRuntimeShaderBuilder_delete(SkRuntimeShaderBuilder* builder) {
260 delete builder;
Nader Jawad5bed1f52020-09-25 00:27:29 -0700261}
262
Stan Iliev6867fc82019-11-22 18:00:01 -0500263static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500264 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SkRuntimeShaderBuilder_delete));
265}
266
Derek Sollenberger7843e512022-02-03 15:50:09 +0000267static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500268 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
269 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
Brian Osmanbb7c43d2022-02-03 14:48:12 -0500270 sk_sp<SkShader> shader = builder->makeShader(matrix);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500271 ThrowIAE_IfNull(env, shader);
272 return reinterpret_cast<jlong>(shader.release());
273}
274
275static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) {
276 va_list args;
277 va_start(args, fmt);
Greg Kaiser9c1f79f2021-01-19 07:35:49 -0800278 int ret = jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", fmt, args);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500279 va_end(args);
Greg Kaiser9c1f79f2021-01-19 07:35:49 -0800280 return ret;
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500281}
282
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000283static bool isIntUniformType(const SkRuntimeEffect::Uniform::Type& type) {
284 switch (type) {
285 case SkRuntimeEffect::Uniform::Type::kFloat:
286 case SkRuntimeEffect::Uniform::Type::kFloat2:
287 case SkRuntimeEffect::Uniform::Type::kFloat3:
288 case SkRuntimeEffect::Uniform::Type::kFloat4:
289 case SkRuntimeEffect::Uniform::Type::kFloat2x2:
290 case SkRuntimeEffect::Uniform::Type::kFloat3x3:
291 case SkRuntimeEffect::Uniform::Type::kFloat4x4:
292 return false;
293 case SkRuntimeEffect::Uniform::Type::kInt:
294 case SkRuntimeEffect::Uniform::Type::kInt2:
295 case SkRuntimeEffect::Uniform::Type::kInt3:
296 case SkRuntimeEffect::Uniform::Type::kInt4:
297 return true;
298 }
299}
300
301static void UpdateFloatUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder,
302 const char* uniformName, const float values[], int count,
303 bool isColor) {
304 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
305 if (uniform.fVar == nullptr) {
306 ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
307 } else if (isColor != ((uniform.fVar->flags & SkRuntimeEffect::Uniform::kColor_Flag) != 0)) {
308 if (isColor) {
309 jniThrowExceptionFmt(
310 env, "java/lang/IllegalArgumentException",
311 "attempting to set a color uniform using the non-color specific APIs: %s %x",
312 uniformName, uniform.fVar->flags);
313 } else {
314 ThrowIAEFmt(env,
315 "attempting to set a non-color uniform using the setColorUniform APIs: %s",
316 uniformName);
317 }
318 } else if (isIntUniformType(uniform.fVar->type)) {
319 ThrowIAEFmt(env, "attempting to set a int uniform using the setUniform APIs: %s",
320 uniformName);
321 } else if (!uniform.set<float>(values, count)) {
322 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
323 uniform.fVar->sizeInBytes(), sizeof(float) * count);
324 }
325}
326
327static void RuntimeShader_updateFloatUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
328 jstring jUniformName, jfloat value1, jfloat value2,
329 jfloat value3, jfloat value4, jint count) {
330 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
331 ScopedUtfChars name(env, jUniformName);
332 const float values[4] = {value1, value2, value3, value4};
333 UpdateFloatUniforms(env, builder, name.c_str(), values, count, false);
334}
335
336static void RuntimeShader_updateFloatArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
337 jstring jUniformName, jfloatArray jvalues,
338 jboolean isColor) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500339 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
340 ScopedUtfChars name(env, jUniformName);
341 AutoJavaFloatArray autoValues(env, jvalues, 0, kRO_JNIAccess);
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000342 UpdateFloatUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length(), isColor);
343}
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500344
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000345static void UpdateIntUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder, const char* uniformName,
346 const int values[], int count) {
347 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500348 if (uniform.fVar == nullptr) {
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000349 ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
350 } else if (!isIntUniformType(uniform.fVar->type)) {
351 ThrowIAEFmt(env, "attempting to set a non-int uniform using the setIntUniform APIs: %s",
352 uniformName);
353 } else if (!uniform.set<int>(values, count)) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500354 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000355 uniform.fVar->sizeInBytes(), sizeof(float) * count);
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500356 }
357}
358
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000359static void RuntimeShader_updateIntUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
360 jstring jUniformName, jint value1, jint value2,
361 jint value3, jint value4, jint count) {
362 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
363 ScopedUtfChars name(env, jUniformName);
364 const int values[4] = {value1, value2, value3, value4};
365 UpdateIntUniforms(env, builder, name.c_str(), values, count);
366}
367
368static void RuntimeShader_updateIntArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
369 jstring jUniformName, jintArray jvalues) {
370 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
371 ScopedUtfChars name(env, jUniformName);
372 AutoJavaIntArray autoValues(env, jvalues, 0);
373 UpdateIntUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length());
374}
375
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500376static void RuntimeShader_updateShader(JNIEnv* env, jobject, jlong shaderBuilder,
377 jstring jUniformName, jlong shaderHandle) {
378 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
379 ScopedUtfChars name(env, jUniformName);
380 SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
381
382 SkRuntimeShaderBuilder::BuilderChild child = builder->child(name.c_str());
Brian Osman2a1308f2021-06-02 17:24:58 +0000383 if (child.fChild == nullptr) {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500384 ThrowIAEFmt(env, "unable to find shader named %s", name.c_str());
385 return;
386 }
387
388 builder->child(name.c_str()) = sk_ref_sp(shader);
Stan Iliev6867fc82019-11-22 18:00:01 -0500389}
390
391///////////////////////////////////////////////////////////////////////////////////////////////
392
Daniel Micay76f6a862015-09-19 17:31:01 -0400393static const JNINativeMethod gShaderMethods[] = {
John Reck8bde0be2017-05-19 10:55:20 -0700394 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395};
396
Daniel Micay76f6a862015-09-19 17:31:01 -0400397static const JNINativeMethod gBitmapShaderMethods[] = {
John Reck992c5f82023-09-21 09:12:17 -0400398 {"nativeCreate", "(JJIIIZZJ)J", (void*)BitmapShader_constructor},
Nader Jawad2a499342023-02-08 11:56:37 -0800399
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400};
401
Daniel Micay76f6a862015-09-19 17:31:01 -0400402static const JNINativeMethod gLinearGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500403 { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404};
405
Daniel Micay76f6a862015-09-19 17:31:01 -0400406static const JNINativeMethod gRadialGradientMethods[] = {
Nader Jawade7ab8412020-10-16 18:00:04 -0700407 { "nativeCreate", "(JFFFFFF[J[FIJ)J", (void*)RadialGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408};
409
Daniel Micay76f6a862015-09-19 17:31:01 -0400410static const JNINativeMethod gSweepGradientMethods[] = {
Leon Scroggins IIIb0aecc22019-01-18 11:09:59 -0500411 { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412};
413
Daniel Micay76f6a862015-09-19 17:31:01 -0400414static const JNINativeMethod gComposeShaderMethods[] = {
Chris Craikb581e672017-03-07 15:27:36 -0800415 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416};
417
Stan Iliev6867fc82019-11-22 18:00:01 -0500418static const JNINativeMethod gRuntimeShaderMethods[] = {
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500419 {"nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer},
Derek Sollenberger7843e512022-02-03 15:50:09 +0000420 {"nativeCreateShader", "(JJ)J", (void*)RuntimeShader_create},
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500421 {"nativeCreateBuilder", "(Ljava/lang/String;)J", (void*)RuntimeShader_createShaderBuilder},
Derek Sollenbergere09fbee2021-10-22 14:45:36 +0000422 {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V",
423 (void*)RuntimeShader_updateFloatArrayUniforms},
424 {"nativeUpdateUniforms", "(JLjava/lang/String;FFFFI)V",
425 (void*)RuntimeShader_updateFloatUniforms},
426 {"nativeUpdateUniforms", "(JLjava/lang/String;[I)V",
427 (void*)RuntimeShader_updateIntArrayUniforms},
428 {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
429 (void*)RuntimeShader_updateIntUniforms},
Derek Sollenberger783e5ae2021-01-11 15:44:46 -0500430 {"nativeUpdateShader", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateShader},
Stan Iliev6867fc82019-11-22 18:00:01 -0500431};
432
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433int register_android_graphics_Shader(JNIEnv* env)
434{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800435 android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
436 NELEM(gShaderMethods));
437 android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
438 NELEM(gBitmapShaderMethods));
439 android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
440 NELEM(gLinearGradientMethods));
441 android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
442 NELEM(gRadialGradientMethods));
443 android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
444 NELEM(gSweepGradientMethods));
445 android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
446 NELEM(gComposeShaderMethods));
Stan Iliev6867fc82019-11-22 18:00:01 -0500447 android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods,
448 NELEM(gRuntimeShaderMethods));
Elliott Hughes4cb17532011-04-12 16:10:26 -0700449
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800450 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451}