176 lines
8.1 KiB
C++
Executable File
176 lines
8.1 KiB
C++
Executable File
/*
|
|
* 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.
|
|
*/
|
|
|
|
#undef LOG_TAG
|
|
#define LOG_TAG "HardwareBufferRenderer"
|
|
#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
|