1*fc3927beSAndroid Build Coastguard Worker /*
2*fc3927beSAndroid Build Coastguard Worker * Copyright 2024 The Android Open Source Project
3*fc3927beSAndroid Build Coastguard Worker *
4*fc3927beSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*fc3927beSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*fc3927beSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*fc3927beSAndroid Build Coastguard Worker *
8*fc3927beSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*fc3927beSAndroid Build Coastguard Worker *
10*fc3927beSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*fc3927beSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*fc3927beSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*fc3927beSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*fc3927beSAndroid Build Coastguard Worker * limitations under the License.
15*fc3927beSAndroid Build Coastguard Worker */
16*fc3927beSAndroid Build Coastguard Worker
17*fc3927beSAndroid Build Coastguard Worker #include <gui/BufferQueue.h>
18*fc3927beSAndroid Build Coastguard Worker #include <gui/IGraphicBufferConsumer.h>
19*fc3927beSAndroid Build Coastguard Worker #include <gui/IGraphicBufferProducer.h>
20*fc3927beSAndroid Build Coastguard Worker #include <ui/GraphicBuffer.h>
21*fc3927beSAndroid Build Coastguard Worker
22*fc3927beSAndroid Build Coastguard Worker #include "android_runtime/android_view_Surface.h"
23*fc3927beSAndroid Build Coastguard Worker #include "core_jni_helpers.h"
24*fc3927beSAndroid Build Coastguard Worker #include "jni.h"
25*fc3927beSAndroid Build Coastguard Worker
26*fc3927beSAndroid Build Coastguard Worker namespace android {
27*fc3927beSAndroid Build Coastguard Worker
28*fc3927beSAndroid Build Coastguard Worker jfieldID gNativeContextFieldId;
29*fc3927beSAndroid Build Coastguard Worker
30*fc3927beSAndroid Build Coastguard Worker /**
31*fc3927beSAndroid Build Coastguard Worker * Class to store information needed by the Layoutlib renderer
32*fc3927beSAndroid Build Coastguard Worker */
33*fc3927beSAndroid Build Coastguard Worker class JNILayoutlibRendererContext : public RefBase {
34*fc3927beSAndroid Build Coastguard Worker public:
~JNILayoutlibRendererContext()35*fc3927beSAndroid Build Coastguard Worker ~JNILayoutlibRendererContext() override {
36*fc3927beSAndroid Build Coastguard Worker if (mBufferConsumer != nullptr) {
37*fc3927beSAndroid Build Coastguard Worker mBufferConsumer.clear();
38*fc3927beSAndroid Build Coastguard Worker }
39*fc3927beSAndroid Build Coastguard Worker }
40*fc3927beSAndroid Build Coastguard Worker
setBufferConsumer(const sp<IGraphicBufferConsumer> & consumer)41*fc3927beSAndroid Build Coastguard Worker void setBufferConsumer(const sp<IGraphicBufferConsumer>& consumer) {
42*fc3927beSAndroid Build Coastguard Worker mBufferConsumer = consumer;
43*fc3927beSAndroid Build Coastguard Worker }
44*fc3927beSAndroid Build Coastguard Worker
getBufferConsumer()45*fc3927beSAndroid Build Coastguard Worker IGraphicBufferConsumer* getBufferConsumer() {
46*fc3927beSAndroid Build Coastguard Worker return mBufferConsumer.get();
47*fc3927beSAndroid Build Coastguard Worker }
48*fc3927beSAndroid Build Coastguard Worker
49*fc3927beSAndroid Build Coastguard Worker private:
50*fc3927beSAndroid Build Coastguard Worker sp<IGraphicBufferConsumer> mBufferConsumer;
51*fc3927beSAndroid Build Coastguard Worker };
52*fc3927beSAndroid Build Coastguard Worker
android_view_LayoutlibRenderer_createSurface(JNIEnv * env,jobject thiz)53*fc3927beSAndroid Build Coastguard Worker static jobject android_view_LayoutlibRenderer_createSurface(JNIEnv* env, jobject thiz) {
54*fc3927beSAndroid Build Coastguard Worker sp<IGraphicBufferProducer> gbProducer;
55*fc3927beSAndroid Build Coastguard Worker sp<IGraphicBufferConsumer> gbConsumer;
56*fc3927beSAndroid Build Coastguard Worker BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
57*fc3927beSAndroid Build Coastguard Worker
58*fc3927beSAndroid Build Coastguard Worker // Save the IGraphicBufferConsumer in the context so that it can be reused for buffer creation
59*fc3927beSAndroid Build Coastguard Worker sp<JNILayoutlibRendererContext> newCtx = sp<JNILayoutlibRendererContext>::make();
60*fc3927beSAndroid Build Coastguard Worker newCtx->setBufferConsumer(gbConsumer);
61*fc3927beSAndroid Build Coastguard Worker auto* const currentCtx = reinterpret_cast<JNILayoutlibRendererContext*>(
62*fc3927beSAndroid Build Coastguard Worker env->GetLongField(thiz, gNativeContextFieldId));
63*fc3927beSAndroid Build Coastguard Worker if (newCtx != nullptr) {
64*fc3927beSAndroid Build Coastguard Worker // Create a strong reference to the new context to avoid it being destroyed
65*fc3927beSAndroid Build Coastguard Worker newCtx->incStrong((void*)android_view_LayoutlibRenderer_createSurface);
66*fc3927beSAndroid Build Coastguard Worker }
67*fc3927beSAndroid Build Coastguard Worker if (currentCtx != nullptr) {
68*fc3927beSAndroid Build Coastguard Worker // Delete the reference to the previous context as it is not needed and can be destroyed
69*fc3927beSAndroid Build Coastguard Worker currentCtx->decStrong((void*)android_view_LayoutlibRenderer_createSurface);
70*fc3927beSAndroid Build Coastguard Worker }
71*fc3927beSAndroid Build Coastguard Worker env->SetLongField(thiz, gNativeContextFieldId, reinterpret_cast<jlong>(newCtx.get()));
72*fc3927beSAndroid Build Coastguard Worker
73*fc3927beSAndroid Build Coastguard Worker return android_view_Surface_createFromIGraphicBufferProducer(env, gbProducer);
74*fc3927beSAndroid Build Coastguard Worker }
75*fc3927beSAndroid Build Coastguard Worker
android_view_LayoutlibRenderer_createBuffer(JNIEnv * env,jobject thiz,jint width,jint height)76*fc3927beSAndroid Build Coastguard Worker static jobject android_view_LayoutlibRenderer_createBuffer(JNIEnv* env, jobject thiz, jint width,
77*fc3927beSAndroid Build Coastguard Worker jint height) {
78*fc3927beSAndroid Build Coastguard Worker auto* ctx = reinterpret_cast<JNILayoutlibRendererContext*>(
79*fc3927beSAndroid Build Coastguard Worker env->GetLongField(thiz, gNativeContextFieldId));
80*fc3927beSAndroid Build Coastguard Worker if (ctx == nullptr) {
81*fc3927beSAndroid Build Coastguard Worker jniThrowException(env, "java/lang/IllegalStateException", "No surface has been created");
82*fc3927beSAndroid Build Coastguard Worker return nullptr;
83*fc3927beSAndroid Build Coastguard Worker }
84*fc3927beSAndroid Build Coastguard Worker
85*fc3927beSAndroid Build Coastguard Worker IGraphicBufferConsumer* bufferConsumer = ctx->getBufferConsumer();
86*fc3927beSAndroid Build Coastguard Worker bufferConsumer->setDefaultBufferSize(width, height);
87*fc3927beSAndroid Build Coastguard Worker auto* bufferItem = new BufferItem();
88*fc3927beSAndroid Build Coastguard Worker bufferConsumer->acquireBuffer(bufferItem, 0);
89*fc3927beSAndroid Build Coastguard Worker sp<GraphicBuffer> buffer = bufferItem->mGraphicBuffer;
90*fc3927beSAndroid Build Coastguard Worker delete bufferItem;
91*fc3927beSAndroid Build Coastguard Worker
92*fc3927beSAndroid Build Coastguard Worker int bytesPerPixel = 4;
93*fc3927beSAndroid Build Coastguard Worker uint32_t dataSize = buffer->getStride() * buffer->getHeight() * bytesPerPixel;
94*fc3927beSAndroid Build Coastguard Worker
95*fc3927beSAndroid Build Coastguard Worker void* pData = nullptr;
96*fc3927beSAndroid Build Coastguard Worker buffer->lockAsync(0, Rect::EMPTY_RECT, &pData, 0);
97*fc3927beSAndroid Build Coastguard Worker
98*fc3927beSAndroid Build Coastguard Worker jobject byteBuffer = env->NewDirectByteBuffer(pData, dataSize);
99*fc3927beSAndroid Build Coastguard Worker return byteBuffer;
100*fc3927beSAndroid Build Coastguard Worker }
101*fc3927beSAndroid Build Coastguard Worker
102*fc3927beSAndroid Build Coastguard Worker static const JNINativeMethod gMethods[] = {
103*fc3927beSAndroid Build Coastguard Worker {"nativeCreateSurface", "()Landroid/view/Surface;",
104*fc3927beSAndroid Build Coastguard Worker (void*)android_view_LayoutlibRenderer_createSurface},
105*fc3927beSAndroid Build Coastguard Worker {"nativeCreateBuffer", "(II)Ljava/nio/ByteBuffer;",
106*fc3927beSAndroid Build Coastguard Worker (void*)android_view_LayoutlibRenderer_createBuffer},
107*fc3927beSAndroid Build Coastguard Worker };
108*fc3927beSAndroid Build Coastguard Worker
register_android_view_LayoutlibRenderer(JNIEnv * env)109*fc3927beSAndroid Build Coastguard Worker int register_android_view_LayoutlibRenderer(JNIEnv* env) {
110*fc3927beSAndroid Build Coastguard Worker jclass layoutlibRendererClass = FindClassOrDie(env, "android/view/LayoutlibRenderer");
111*fc3927beSAndroid Build Coastguard Worker gNativeContextFieldId = GetFieldIDOrDie(env, layoutlibRendererClass, "mNativeContext", "J");
112*fc3927beSAndroid Build Coastguard Worker
113*fc3927beSAndroid Build Coastguard Worker return RegisterMethodsOrDie(env, "android/view/LayoutlibRenderer", gMethods, NELEM(gMethods));
114*fc3927beSAndroid Build Coastguard Worker }
115*fc3927beSAndroid Build Coastguard Worker
116*fc3927beSAndroid Build Coastguard Worker } // namespace android