blob: e3cdee6e7034a315b2fd7b6939bd509a685d7f78 [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define ATRACE_TAG ATRACE_TAG_VIEW
#include <GraphicsJNI.h>
#include <RootRenderNode.h>
#include <TreeInfo.h>
#include <android-base/unique_fd.h>
#include <android/native_window.h>
#include <nativehelper/JNIPlatformHelp.h>
#include <renderthread/CanvasContext.h>
#include <renderthread/RenderProxy.h>
#include <renderthread/RenderThread.h>
#include "HardwareBufferHelpers.h"
#include "JvmErrorReporter.h"
namespace android {
using namespace android::uirenderer;
using namespace android::uirenderer::renderthread;
struct {
jclass clazz;
jmethodID invokeRenderCallback;
} gHardwareBufferRendererClassInfo;
static RenderCallback createRenderCallback(JNIEnv* env, jobject releaseCallback) {
if (releaseCallback == nullptr) return nullptr;
JavaVM* vm = nullptr;
LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
auto globalCallbackRef =
std::make_shared<JGlobalRefHolder>(vm, env->NewGlobalRef(releaseCallback));
return [globalCallbackRef](android::base::unique_fd&& fd, int status) {
globalCallbackRef->env()->CallStaticVoidMethod(
gHardwareBufferRendererClassInfo.clazz,
gHardwareBufferRendererClassInfo.invokeRenderCallback, globalCallbackRef->object(),
reinterpret_cast<jint>(fd.release()), reinterpret_cast<jint>(status));
};
}
static long android_graphics_HardwareBufferRenderer_createRootNode(JNIEnv* env, jobject) {
auto* node = new RootRenderNode(std::make_unique<JvmErrorReporter>(env));
node->incStrong(nullptr);
node->setName("RootRenderNode");
return reinterpret_cast<jlong>(node);
}
static void android_graphics_hardwareBufferRenderer_destroyRootNode(JNIEnv*, jobject,
jlong renderNodePtr) {
auto* node = reinterpret_cast<RootRenderNode*>(renderNodePtr);
node->destroy();
}
static long android_graphics_HardwareBufferRenderer_create(JNIEnv* env, jobject, jobject buffer,
jlong renderNodePtr) {
auto* hardwareBuffer = HardwareBufferHelpers::AHardwareBuffer_fromHardwareBuffer(env, buffer);
auto* rootRenderNode = reinterpret_cast<RootRenderNode*>(renderNodePtr);
ContextFactoryImpl factory(rootRenderNode);
auto* proxy = new RenderProxy(false, rootRenderNode, &factory);
proxy->setHardwareBuffer(hardwareBuffer);
return (jlong)proxy;
}
static void HardwareBufferRenderer_destroy(jlong renderProxy) {
auto* proxy = reinterpret_cast<RenderProxy*>(renderProxy);
delete proxy;
}
static SkMatrix createMatrixFromBufferTransform(SkScalar width, SkScalar height, int transform) {
switch (transform) {
case ANATIVEWINDOW_TRANSFORM_ROTATE_90:
return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
case ANATIVEWINDOW_TRANSFORM_ROTATE_180:
return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
case ANATIVEWINDOW_TRANSFORM_ROTATE_270:
return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
default:
ALOGE("Invalid transform provided. Transform should be validated from"
"the java side. Leveraging identity transform as a fallback");
[[fallthrough]];
case ANATIVEWINDOW_TRANSFORM_IDENTITY:
return SkMatrix::I();
}
}
static int android_graphics_HardwareBufferRenderer_render(JNIEnv* env, jobject, jlong renderProxy,
jint transform, jint width, jint height,
jlong colorspacePtr, jobject consumer) {
auto* proxy = reinterpret_cast<RenderProxy*>(renderProxy);
auto skWidth = static_cast<SkScalar>(width);
auto skHeight = static_cast<SkScalar>(height);
auto matrix = createMatrixFromBufferTransform(skWidth, skHeight, transform);
auto colorSpace = GraphicsJNI::getNativeColorSpace(colorspacePtr);
proxy->setHardwareBufferRenderParams(HardwareBufferRenderParams(
width, height, matrix, colorSpace, createRenderCallback(env, consumer)));
nsecs_t vsync = systemTime(SYSTEM_TIME_MONOTONIC);
UiFrameInfoBuilder(proxy->frameInfo())
.setVsync(vsync, vsync, UiFrameInfoBuilder::INVALID_VSYNC_ID,
UiFrameInfoBuilder::UNKNOWN_DEADLINE,
UiFrameInfoBuilder::UNKNOWN_FRAME_INTERVAL)
.addFlag(FrameInfoFlags::SurfaceCanvas);
return proxy->syncAndDrawFrame();
}
static void android_graphics_HardwareBufferRenderer_setLightGeometry(JNIEnv*, jobject,
jlong renderProxyPtr,
jfloat lightX, jfloat lightY,
jfloat lightZ,
jfloat lightRadius) {
auto* proxy = reinterpret_cast<RenderProxy*>(renderProxyPtr);
proxy->setLightGeometry((Vector3){lightX, lightY, lightZ}, lightRadius);
}
static void android_graphics_HardwareBufferRenderer_setLightAlpha(JNIEnv* env, jobject,
jlong renderProxyPtr,
jfloat ambientShadowAlpha,
jfloat spotShadowAlpha) {
auto* proxy = reinterpret_cast<RenderProxy*>(renderProxyPtr);
proxy->setLightAlpha((uint8_t)(255 * ambientShadowAlpha), (uint8_t)(255 * spotShadowAlpha));
}
static jlong android_graphics_HardwareBufferRenderer_getFinalizer() {
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&HardwareBufferRenderer_destroy));
}
// ----------------------------------------------------------------------------
// JNI Glue
// ----------------------------------------------------------------------------
const char* const kClassPathName = "android/graphics/HardwareBufferRenderer";
static const JNINativeMethod gMethods[] = {
{"nCreateHardwareBufferRenderer", "(Landroid/hardware/HardwareBuffer;J)J",
(void*)android_graphics_HardwareBufferRenderer_create},
{"nRender", "(JIIIJLjava/util/function/Consumer;)I",
(void*)android_graphics_HardwareBufferRenderer_render},
{"nCreateRootRenderNode", "()J",
(void*)android_graphics_HardwareBufferRenderer_createRootNode},
{"nSetLightGeometry", "(JFFFF)V",
(void*)android_graphics_HardwareBufferRenderer_setLightGeometry},
{"nSetLightAlpha", "(JFF)V", (void*)android_graphics_HardwareBufferRenderer_setLightAlpha},
{"nGetFinalizer", "()J", (void*)android_graphics_HardwareBufferRenderer_getFinalizer},
{"nDestroyRootRenderNode", "(J)V",
(void*)android_graphics_hardwareBufferRenderer_destroyRootNode}};
int register_android_graphics_HardwareBufferRenderer(JNIEnv* env) {
jclass hardwareBufferRendererClazz =
FindClassOrDie(env, "android/graphics/HardwareBufferRenderer");
gHardwareBufferRendererClassInfo.clazz =
reinterpret_cast<jclass>(env->NewGlobalRef(hardwareBufferRendererClazz));
gHardwareBufferRendererClassInfo.invokeRenderCallback =
GetStaticMethodIDOrDie(env, hardwareBufferRendererClazz, "invokeRenderCallback",
"(Ljava/util/function/Consumer;II)V");
HardwareBufferHelpers::init();
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
} // namespace android