• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 #include "BufferUtils.h"
17 
18 #include "graphics_jni_helpers.h"
19 
copyToVector(std::vector<uint8_t> & dst,const void * src,size_t srcSize)20 static void copyToVector(std::vector<uint8_t>& dst, const void* src, size_t srcSize) {
21     if (src) {
22         dst.resize(srcSize);
23         memcpy(dst.data(), src, srcSize);
24     }
25 }
26 
27 /**
28  * This code is taken and modified from com_google_android_gles_jni_GLImpl.cpp to extract data
29  * from a java.nio.Buffer.
30  */
getDirectBufferPointer(JNIEnv * env,jobject buffer)31 static void* getDirectBufferPointer(JNIEnv* env, jobject buffer) {
32     if (buffer == nullptr) {
33         return nullptr;
34     }
35 
36     jint position;
37     jint limit;
38     jint elementSizeShift;
39     jlong pointer;
40     pointer = jniGetNioBufferFields(env, buffer, &position, &limit, &elementSizeShift);
41     if (pointer == 0) {
42         jniThrowException(env, "java/lang/IllegalArgumentException",
43                           "Must use a native order direct Buffer");
44         return nullptr;
45     }
46     pointer += position << elementSizeShift;
47     return reinterpret_cast<void*>(pointer);
48 }
49 
releasePointer(JNIEnv * env,jarray array,void * data,jboolean commit)50 static void releasePointer(JNIEnv* env, jarray array, void* data, jboolean commit) {
51     env->ReleasePrimitiveArrayCritical(array, data, commit ? 0 : JNI_ABORT);
52 }
53 
getPointer(JNIEnv * env,jobject buffer,jarray * array,jint * remaining,jint * offset)54 static void* getPointer(JNIEnv* env, jobject buffer, jarray* array, jint* remaining, jint* offset) {
55     jint position;
56     jint limit;
57     jint elementSizeShift;
58 
59     jlong pointer;
60     pointer = jniGetNioBufferFields(env, buffer, &position, &limit, &elementSizeShift);
61     *remaining = (limit - position) << elementSizeShift;
62     if (pointer != 0L) {
63         *array = nullptr;
64         pointer += position << elementSizeShift;
65         return reinterpret_cast<void*>(pointer);
66     }
67 
68     *array = jniGetNioBufferBaseArray(env, buffer);
69     *offset = jniGetNioBufferBaseArrayOffset(env, buffer);
70     return nullptr;
71 }
72 
73 /**
74  * This is a copy of
75  * static void android_glBufferData__IILjava_nio_Buffer_2I
76  * from com_google_android_gles_jni_GLImpl.cpp
77  */
setIndirectData(JNIEnv * env,size_t size,jobject data_buf,std::vector<uint8_t> & result)78 static void setIndirectData(JNIEnv* env, size_t size, jobject data_buf,
79                             std::vector<uint8_t>& result) {
80     jint exception = 0;
81     const char* exceptionType = nullptr;
82     const char* exceptionMessage = nullptr;
83     jarray array = nullptr;
84     jint bufferOffset = 0;
85     jint remaining;
86     void* data = 0;
87     char* dataBase = nullptr;
88 
89     if (data_buf) {
90         data = getPointer(env, data_buf, (jarray*)&array, &remaining, &bufferOffset);
91         if (remaining < size) {
92             exception = 1;
93             exceptionType = "java/lang/IllegalArgumentException";
94             exceptionMessage = "remaining() < size < needed";
95             goto exit;
96         }
97     }
98     if (data_buf && data == nullptr) {
99         dataBase = (char*)env->GetPrimitiveArrayCritical(array, (jboolean*)0);
100         data = (void*)(dataBase + bufferOffset);
101     }
102 
103     copyToVector(result, data, size);
104 
105 exit:
106     if (array) {
107         releasePointer(env, array, (void*)dataBase, JNI_FALSE);
108     }
109     if (exception) {
110         jniThrowException(env, exceptionType, exceptionMessage);
111     }
112 }
113 
copyJavaNioBufferToVector(JNIEnv * env,jobject buffer,size_t size,jboolean isDirect)114 std::vector<uint8_t> copyJavaNioBufferToVector(JNIEnv* env, jobject buffer, size_t size,
115                                                jboolean isDirect) {
116     std::vector<uint8_t> data;
117     if (buffer == nullptr) {
118         jniThrowNullPointerException(env);
119     } else {
120         if (isDirect) {
121             void* directBufferPtr = getDirectBufferPointer(env, buffer);
122             if (directBufferPtr) {
123                 copyToVector(data, directBufferPtr, size);
124             }
125         } else {
126             setIndirectData(env, size, buffer, data);
127         }
128     }
129     return data;
130 }
131