1 #undef LOG_TAG
2 #define LOG_TAG "ShaderJNI"
3
4 #include <vector>
5
6 #include "Gainmap.h"
7 #include "GraphicsJNI.h"
8 #include "SkBitmap.h"
9 #include "SkBlendMode.h"
10 #include "SkColor.h"
11 #include "SkColorFilter.h"
12 #include "SkGradientShader.h"
13 #include "SkImage.h"
14 #include "SkImagePriv.h"
15 #include "SkMatrix.h"
16 #include "SkPoint.h"
17 #include "SkRefCnt.h"
18 #include "SkSamplingOptions.h"
19 #include "SkScalar.h"
20 #include "SkShader.h"
21 #include "SkString.h"
22 #include "SkTileMode.h"
23 #include "effects/GainmapRenderer.h"
24 #include "include/effects/SkRuntimeEffect.h"
25
26 using namespace android::uirenderer;
27
28 /**
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
31 * backwards compatibility by premultiplying the colors of the gradient first,
32 * and then interpolating between them.
33 */
34 static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;
35
36 #define ThrowIAE_IfNull(env, ptr) \
37 if (nullptr == ptr) { \
38 doThrowIAE(env); \
39 return 0; \
40 }
41
Color_RGBToHSV(JNIEnv * env,jobject,jint red,jint green,jint blue,jfloatArray hsvArray)42 static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
43 {
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 }
53
Color_HSVToColor(JNIEnv * env,jobject,jint alpha,jfloatArray hsvArray)54 static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
55 {
56 AutoJavaFloatArray autoHSV(env, hsvArray, 3);
57 SkScalar* hsv = autoHSV.ptr();
58 return static_cast<jint>(SkHSVToColor(alpha, hsv));
59 }
60
61 ///////////////////////////////////////////////////////////////////////////////////////////////
62
Shader_safeUnref(SkShader * shader)63 static void Shader_safeUnref(SkShader* shader) {
64 SkSafeUnref(shader);
65 }
66
Shader_getNativeFinalizer(JNIEnv *,jobject)67 static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) {
68 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
69 }
70
createBitmapShaderHelper(JNIEnv * env,jobject o,jlong matrixPtr,jlong bitmapHandle,jint tileModeX,jint tileModeY,bool isDirectSampled,const SkSamplingOptions & sampling)71 static jlong createBitmapShaderHelper(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
72 jint tileModeX, jint tileModeY, bool isDirectSampled,
73 const SkSamplingOptions& sampling) {
74 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
75 sk_sp<SkImage> image;
76 if (bitmapHandle) {
77 // 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.
79 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 }
93 }
94
95 if (!image.get()) {
96 SkBitmap bitmap;
97 image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
98 }
99
100 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 }
106 ThrowIAE_IfNull(env, shader.get());
107
108 if (matrix) {
109 shader = shader->makeWithLocalMatrix(*matrix);
110 }
111
112 return reinterpret_cast<jlong>(shader.release());
113 }
114
115 ///////////////////////////////////////////////////////////////////////////////////////////////
116
BitmapShader_constructor(JNIEnv * env,jobject o,jlong matrixPtr,jlong bitmapHandle,jint tileModeX,jint tileModeY,bool filter,bool isDirectSampled)117 static 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
BitmapShader_constructorWithMaxAniso(JNIEnv * env,jobject o,jlong matrixPtr,jlong bitmapHandle,jint tileModeX,jint tileModeY,jint maxAniso,bool isDirectSampled)126 static 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
convertColorLongs(JNIEnv * env,jlongArray colorArray)137 static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) {
138 const size_t count = env->GetArrayLength(colorArray);
139 const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr);
140
141 std::vector<SkColor4f> colors(count);
142 for (size_t i = 0; i < count; ++i) {
143 colors[i] = GraphicsJNI::convertColorLong(colorValues[i]);
144 }
145
146 env->ReleaseLongArrayElements(colorArray, const_cast<jlong*>(colorValues), JNI_ABORT);
147 return colors;
148 }
149
150 ///////////////////////////////////////////////////////////////////////////////////////////////
151
LinearGradient_create(JNIEnv * env,jobject,jlong matrixPtr,jfloat x0,jfloat y0,jfloat x1,jfloat y1,jlongArray colorArray,jfloatArray posArray,jint tileMode,jlong colorSpaceHandle)152 static jlong LinearGradient_create(JNIEnv* env, jobject, jlong matrixPtr,
153 jfloat x0, jfloat y0, jfloat x1, jfloat y1, jlongArray colorArray,
154 jfloatArray posArray, jint tileMode, jlong colorSpaceHandle) {
155 SkPoint pts[2];
156 pts[0].set(x0, y0);
157 pts[1].set(x1, y1);
158
159 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
160
161 AutoJavaFloatArray autoPos(env, posArray, colors.size());
162 SkScalar* pos = autoPos.ptr();
163
164 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);
168
169 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());
175 }
176
177 ///////////////////////////////////////////////////////////////////////////////////////////////
178
RadialGradient_create(JNIEnv * env,jobject,jlong matrixPtr,jfloat startX,jfloat startY,jfloat startRadius,jfloat endX,jfloat endY,jfloat endRadius,jlongArray colorArray,jfloatArray posArray,jint tileMode,jlong colorSpaceHandle)179 static 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,
191 jlong colorSpaceHandle) {
192
193 SkPoint start;
194 start.set(startX, startY);
195
196 SkPoint end;
197 end.set(endX, endY);
198
199 std::vector<SkColor4f> colors = convertColorLongs(env, colorArray);
200
201 AutoJavaFloatArray autoPos(env, posArray, colors.size());
202 SkScalar* pos = autoPos.ptr();
203
204 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);
209 ThrowIAE_IfNull(env, shader);
210
211 // 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)
215 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
216 if (matrix) {
217 shader = shader->makeWithLocalMatrix(*matrix);
218 }
219
220 return reinterpret_cast<jlong>(shader.release());
221 }
222
223 ///////////////////////////////////////////////////////////////////////////////
224
SweepGradient_create(JNIEnv * env,jobject,jlong matrixPtr,jfloat x,jfloat y,jlongArray colorArray,jfloatArray jpositions,jlong colorSpaceHandle)225 static 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);
228
229 AutoJavaFloatArray autoPos(env, jpositions, colors.size());
230 SkScalar* pos = autoPos.ptr();
231
232 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);
236
237 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
238 if (matrix) {
239 shader = shader->makeWithLocalMatrix(*matrix);
240 }
241
242 return reinterpret_cast<jlong>(shader.release());
243 }
244
245 ///////////////////////////////////////////////////////////////////////////////////////////////
246
ComposeShader_create(JNIEnv * env,jobject o,jlong matrixPtr,jlong shaderAHandle,jlong shaderBHandle,jint xfermodeHandle)247 static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
248 jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle) {
249 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)));
255
256 SkShader* shader;
257
258 if (matrix) {
259 shader = baseShader->makeWithLocalMatrix(*matrix).release();
260 } else {
261 shader = baseShader.release();
262 }
263 return reinterpret_cast<jlong>(shader);
264 }
265
266 ///////////////////////////////////////////////////////////////////////////////////////////////
267
268 ///////////////////////////////////////////////////////////////////////////////////////////////
269
RuntimeShader_createShaderBuilder(JNIEnv * env,jobject,jstring sksl)270 static jlong RuntimeShader_createShaderBuilder(JNIEnv* env, jobject, jstring sksl) {
271 ScopedUtfChars strSksl(env, sksl);
272 auto result = SkRuntimeEffect::MakeForShader(SkString(strSksl.c_str()),
273 SkRuntimeEffect::Options{});
274 if (result.effect.get() == nullptr) {
275 doThrowIAE(env, result.errorText.c_str());
276 return 0;
277 }
278 return reinterpret_cast<jlong>(new SkRuntimeShaderBuilder(std::move(result.effect)));
279 }
280
SkRuntimeShaderBuilder_delete(SkRuntimeShaderBuilder * builder)281 static void SkRuntimeShaderBuilder_delete(SkRuntimeShaderBuilder* builder) {
282 delete builder;
283 }
284
RuntimeShader_getNativeFinalizer(JNIEnv *,jobject)285 static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
286 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SkRuntimeShaderBuilder_delete));
287 }
288
RuntimeShader_create(JNIEnv * env,jobject,jlong shaderBuilder,jlong matrixPtr)289 static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr) {
290 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
291 const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
292 sk_sp<SkShader> shader = builder->makeShader(matrix);
293 ThrowIAE_IfNull(env, shader);
294 return reinterpret_cast<jlong>(shader.release());
295 }
296
ThrowIAEFmt(JNIEnv * env,const char * fmt,...)297 static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) {
298 va_list args;
299 va_start(args, fmt);
300 int ret = jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", fmt, args);
301 va_end(args);
302 return ret;
303 }
304
isIntUniformType(const SkRuntimeEffect::Uniform::Type & type)305 static 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
UpdateFloatUniforms(JNIEnv * env,SkRuntimeShaderBuilder * builder,const char * uniformName,const float values[],int count,bool isColor)323 static 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
RuntimeShader_updateFloatUniforms(JNIEnv * env,jobject,jlong shaderBuilder,jstring jUniformName,jfloat value1,jfloat value2,jfloat value3,jfloat value4,jint count)349 static 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
RuntimeShader_updateFloatArrayUniforms(JNIEnv * env,jobject,jlong shaderBuilder,jstring jUniformName,jfloatArray jvalues,jboolean isColor)358 static void RuntimeShader_updateFloatArrayUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
359 jstring jUniformName, jfloatArray jvalues,
360 jboolean isColor) {
361 SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
362 ScopedUtfChars name(env, jUniformName);
363 AutoJavaFloatArray autoValues(env, jvalues, 0, kRO_JNIAccess);
364 UpdateFloatUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length(), isColor);
365 }
366
UpdateIntUniforms(JNIEnv * env,SkRuntimeShaderBuilder * builder,const char * uniformName,const int values[],int count)367 static void UpdateIntUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder, const char* uniformName,
368 const int values[], int count) {
369 SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
370 if (uniform.fVar == nullptr) {
371 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)) {
376 ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
377 uniform.fVar->sizeInBytes(), sizeof(float) * count);
378 }
379 }
380
RuntimeShader_updateIntUniforms(JNIEnv * env,jobject,jlong shaderBuilder,jstring jUniformName,jint value1,jint value2,jint value3,jint value4,jint count)381 static 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
RuntimeShader_updateIntArrayUniforms(JNIEnv * env,jobject,jlong shaderBuilder,jstring jUniformName,jintArray jvalues)390 static 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
RuntimeShader_updateShader(JNIEnv * env,jobject,jlong shaderBuilder,jstring jUniformName,jlong shaderHandle)398 static 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());
405 if (child.fChild == nullptr) {
406 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);
411 }
412
413 ///////////////////////////////////////////////////////////////////////////////////////////////
414
415 static const JNINativeMethod gColorMethods[] = {
416 { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV },
417 { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor }
418 };
419
420 static const JNINativeMethod gShaderMethods[] = {
421 { "nativeGetFinalizer", "()J", (void*)Shader_getNativeFinalizer },
422 };
423
424 static const JNINativeMethod gBitmapShaderMethods[] = {
425 {"nativeCreate", "(JJIIZZ)J", (void*)BitmapShader_constructor},
426 {"nativeCreateWithMaxAniso", "(JJIIIZ)J", (void*)BitmapShader_constructorWithMaxAniso},
427
428 };
429
430 static const JNINativeMethod gLinearGradientMethods[] = {
431 { "nativeCreate", "(JFFFF[J[FIJ)J", (void*)LinearGradient_create },
432 };
433
434 static const JNINativeMethod gRadialGradientMethods[] = {
435 { "nativeCreate", "(JFFFFFF[J[FIJ)J", (void*)RadialGradient_create },
436 };
437
438 static const JNINativeMethod gSweepGradientMethods[] = {
439 { "nativeCreate", "(JFF[J[FJ)J", (void*)SweepGradient_create },
440 };
441
442 static const JNINativeMethod gComposeShaderMethods[] = {
443 { "nativeCreate", "(JJJI)J", (void*)ComposeShader_create },
444 };
445
446 static const JNINativeMethod gRuntimeShaderMethods[] = {
447 {"nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer},
448 {"nativeCreateShader", "(JJ)J", (void*)RuntimeShader_create},
449 {"nativeCreateBuilder", "(Ljava/lang/String;)J", (void*)RuntimeShader_createShaderBuilder},
450 {"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},
458 {"nativeUpdateShader", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateShader},
459 };
460
register_android_graphics_Shader(JNIEnv * env)461 int register_android_graphics_Shader(JNIEnv* env)
462 {
463 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));
477 android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods,
478 NELEM(gRuntimeShaderMethods));
479
480 return 0;
481 }
482