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