xref: /aosp_15_r20/frameworks/layoutlib/jni/android_view_LayoutlibRenderer.cpp (revision fc3927be90a325f95c74a9043993a80ef388dc46)
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