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