xref: /aosp_15_r20/frameworks/base/libs/hwui/HardwareBitmapUploader.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker #include "HardwareBitmapUploader.h"
18*d57664e9SAndroid Build Coastguard Worker 
19*d57664e9SAndroid Build Coastguard Worker #include <EGL/egl.h>
20*d57664e9SAndroid Build Coastguard Worker #include <EGL/eglext.h>
21*d57664e9SAndroid Build Coastguard Worker #include <GLES2/gl2.h>
22*d57664e9SAndroid Build Coastguard Worker #include <GLES2/gl2ext.h>
23*d57664e9SAndroid Build Coastguard Worker #include <GLES3/gl3.h>
24*d57664e9SAndroid Build Coastguard Worker #include <SkBitmap.h>
25*d57664e9SAndroid Build Coastguard Worker #include <SkCanvas.h>
26*d57664e9SAndroid Build Coastguard Worker #include <SkImage.h>
27*d57664e9SAndroid Build Coastguard Worker #include <SkImageAndroid.h>
28*d57664e9SAndroid Build Coastguard Worker #include <SkImageInfo.h>
29*d57664e9SAndroid Build Coastguard Worker #include <SkRefCnt.h>
30*d57664e9SAndroid Build Coastguard Worker #include <gui/TraceUtils.h>
31*d57664e9SAndroid Build Coastguard Worker #include <include/gpu/ganesh/GrDirectContext.h>
32*d57664e9SAndroid Build Coastguard Worker #include <include/gpu/ganesh/GrTypes.h>
33*d57664e9SAndroid Build Coastguard Worker #include <utils/GLUtils.h>
34*d57664e9SAndroid Build Coastguard Worker #include <utils/NdkUtils.h>
35*d57664e9SAndroid Build Coastguard Worker #include <utils/Trace.h>
36*d57664e9SAndroid Build Coastguard Worker 
37*d57664e9SAndroid Build Coastguard Worker #include <thread>
38*d57664e9SAndroid Build Coastguard Worker 
39*d57664e9SAndroid Build Coastguard Worker #include "hwui/Bitmap.h"
40*d57664e9SAndroid Build Coastguard Worker #include "renderthread/EglManager.h"
41*d57664e9SAndroid Build Coastguard Worker #include "renderthread/VulkanManager.h"
42*d57664e9SAndroid Build Coastguard Worker #include "thread/ThreadBase.h"
43*d57664e9SAndroid Build Coastguard Worker #include "utils/TimeUtils.h"
44*d57664e9SAndroid Build Coastguard Worker 
45*d57664e9SAndroid Build Coastguard Worker namespace android::uirenderer {
46*d57664e9SAndroid Build Coastguard Worker 
47*d57664e9SAndroid Build Coastguard Worker static constexpr auto kThreadTimeout = 60000_ms;
48*d57664e9SAndroid Build Coastguard Worker 
49*d57664e9SAndroid Build Coastguard Worker class AHBUploader;
50*d57664e9SAndroid Build Coastguard Worker // This helper uploader classes allows us to upload using either EGL or Vulkan using the same
51*d57664e9SAndroid Build Coastguard Worker // interface.
52*d57664e9SAndroid Build Coastguard Worker static sp<AHBUploader> sUploader = nullptr;
53*d57664e9SAndroid Build Coastguard Worker 
54*d57664e9SAndroid Build Coastguard Worker struct FormatInfo {
55*d57664e9SAndroid Build Coastguard Worker     AHardwareBuffer_Format bufferFormat;
56*d57664e9SAndroid Build Coastguard Worker     GLint format, type;
57*d57664e9SAndroid Build Coastguard Worker     VkFormat vkFormat;
58*d57664e9SAndroid Build Coastguard Worker     bool isSupported = false;
59*d57664e9SAndroid Build Coastguard Worker     bool valid = true;
60*d57664e9SAndroid Build Coastguard Worker };
61*d57664e9SAndroid Build Coastguard Worker 
62*d57664e9SAndroid Build Coastguard Worker class AHBUploader : public RefBase {
63*d57664e9SAndroid Build Coastguard Worker public:
~AHBUploader()64*d57664e9SAndroid Build Coastguard Worker     virtual ~AHBUploader() {}
65*d57664e9SAndroid Build Coastguard Worker 
destroy()66*d57664e9SAndroid Build Coastguard Worker     void destroy() {
67*d57664e9SAndroid Build Coastguard Worker         std::lock_guard _lock{mLock};
68*d57664e9SAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(mPendingUploads, "terminate called while uploads in progress");
69*d57664e9SAndroid Build Coastguard Worker         if (mUploadThread) {
70*d57664e9SAndroid Build Coastguard Worker             mUploadThread->requestExit();
71*d57664e9SAndroid Build Coastguard Worker             mUploadThread->join();
72*d57664e9SAndroid Build Coastguard Worker             mUploadThread = nullptr;
73*d57664e9SAndroid Build Coastguard Worker         }
74*d57664e9SAndroid Build Coastguard Worker         onDestroy();
75*d57664e9SAndroid Build Coastguard Worker     }
76*d57664e9SAndroid Build Coastguard Worker 
uploadHardwareBitmap(const SkBitmap & bitmap,const FormatInfo & format,AHardwareBuffer * ahb)77*d57664e9SAndroid Build Coastguard Worker     bool uploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
78*d57664e9SAndroid Build Coastguard Worker                               AHardwareBuffer* ahb) {
79*d57664e9SAndroid Build Coastguard Worker         ATRACE_CALL();
80*d57664e9SAndroid Build Coastguard Worker         beginUpload();
81*d57664e9SAndroid Build Coastguard Worker         bool result = onUploadHardwareBitmap(bitmap, format, ahb);
82*d57664e9SAndroid Build Coastguard Worker         endUpload();
83*d57664e9SAndroid Build Coastguard Worker         return result;
84*d57664e9SAndroid Build Coastguard Worker     }
85*d57664e9SAndroid Build Coastguard Worker 
postIdleTimeoutCheck()86*d57664e9SAndroid Build Coastguard Worker     void postIdleTimeoutCheck() {
87*d57664e9SAndroid Build Coastguard Worker         mUploadThread->queue().postDelayed(kThreadTimeout, [this]() { this->idleTimeoutCheck(); });
88*d57664e9SAndroid Build Coastguard Worker     }
89*d57664e9SAndroid Build Coastguard Worker 
90*d57664e9SAndroid Build Coastguard Worker protected:
91*d57664e9SAndroid Build Coastguard Worker     std::mutex mLock;
92*d57664e9SAndroid Build Coastguard Worker     sp<ThreadBase> mUploadThread = nullptr;
93*d57664e9SAndroid Build Coastguard Worker 
94*d57664e9SAndroid Build Coastguard Worker private:
95*d57664e9SAndroid Build Coastguard Worker     virtual void onIdle() = 0;
96*d57664e9SAndroid Build Coastguard Worker     virtual void onDestroy() = 0;
97*d57664e9SAndroid Build Coastguard Worker 
98*d57664e9SAndroid Build Coastguard Worker     virtual bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
99*d57664e9SAndroid Build Coastguard Worker                                         AHardwareBuffer* ahb) = 0;
100*d57664e9SAndroid Build Coastguard Worker     virtual void onBeginUpload() = 0;
101*d57664e9SAndroid Build Coastguard Worker 
shouldTimeOutLocked()102*d57664e9SAndroid Build Coastguard Worker     bool shouldTimeOutLocked() {
103*d57664e9SAndroid Build Coastguard Worker         nsecs_t durationSince = systemTime() - mLastUpload;
104*d57664e9SAndroid Build Coastguard Worker         return durationSince > kThreadTimeout;
105*d57664e9SAndroid Build Coastguard Worker     }
106*d57664e9SAndroid Build Coastguard Worker 
idleTimeoutCheck()107*d57664e9SAndroid Build Coastguard Worker     void idleTimeoutCheck() {
108*d57664e9SAndroid Build Coastguard Worker         std::lock_guard _lock{mLock};
109*d57664e9SAndroid Build Coastguard Worker         if (mPendingUploads == 0 && shouldTimeOutLocked()) {
110*d57664e9SAndroid Build Coastguard Worker             onIdle();
111*d57664e9SAndroid Build Coastguard Worker         } else {
112*d57664e9SAndroid Build Coastguard Worker             this->postIdleTimeoutCheck();
113*d57664e9SAndroid Build Coastguard Worker         }
114*d57664e9SAndroid Build Coastguard Worker     }
115*d57664e9SAndroid Build Coastguard Worker 
beginUpload()116*d57664e9SAndroid Build Coastguard Worker     void beginUpload() {
117*d57664e9SAndroid Build Coastguard Worker         std::lock_guard _lock{mLock};
118*d57664e9SAndroid Build Coastguard Worker         mPendingUploads++;
119*d57664e9SAndroid Build Coastguard Worker 
120*d57664e9SAndroid Build Coastguard Worker         if (!mUploadThread) {
121*d57664e9SAndroid Build Coastguard Worker             mUploadThread = new ThreadBase{};
122*d57664e9SAndroid Build Coastguard Worker         }
123*d57664e9SAndroid Build Coastguard Worker         if (!mUploadThread->isRunning()) {
124*d57664e9SAndroid Build Coastguard Worker             mUploadThread->start("GrallocUploadThread");
125*d57664e9SAndroid Build Coastguard Worker         }
126*d57664e9SAndroid Build Coastguard Worker 
127*d57664e9SAndroid Build Coastguard Worker         onBeginUpload();
128*d57664e9SAndroid Build Coastguard Worker     }
129*d57664e9SAndroid Build Coastguard Worker 
endUpload()130*d57664e9SAndroid Build Coastguard Worker     void endUpload() {
131*d57664e9SAndroid Build Coastguard Worker         std::lock_guard _lock{mLock};
132*d57664e9SAndroid Build Coastguard Worker         mPendingUploads--;
133*d57664e9SAndroid Build Coastguard Worker         mLastUpload = systemTime();
134*d57664e9SAndroid Build Coastguard Worker     }
135*d57664e9SAndroid Build Coastguard Worker 
136*d57664e9SAndroid Build Coastguard Worker     int mPendingUploads = 0;
137*d57664e9SAndroid Build Coastguard Worker     nsecs_t mLastUpload = 0;
138*d57664e9SAndroid Build Coastguard Worker };
139*d57664e9SAndroid Build Coastguard Worker 
140*d57664e9SAndroid Build Coastguard Worker #define FENCE_TIMEOUT 2000000000
141*d57664e9SAndroid Build Coastguard Worker 
142*d57664e9SAndroid Build Coastguard Worker class EGLUploader : public AHBUploader {
143*d57664e9SAndroid Build Coastguard Worker private:
onDestroy()144*d57664e9SAndroid Build Coastguard Worker     void onDestroy() override {
145*d57664e9SAndroid Build Coastguard Worker         mEglManager.destroy();
146*d57664e9SAndroid Build Coastguard Worker     }
onIdle()147*d57664e9SAndroid Build Coastguard Worker     void onIdle() override {
148*d57664e9SAndroid Build Coastguard Worker         mEglManager.destroy();
149*d57664e9SAndroid Build Coastguard Worker     }
150*d57664e9SAndroid Build Coastguard Worker 
onBeginUpload()151*d57664e9SAndroid Build Coastguard Worker     void onBeginUpload() override {
152*d57664e9SAndroid Build Coastguard Worker         if (!mEglManager.hasEglContext()) {
153*d57664e9SAndroid Build Coastguard Worker             mUploadThread->queue().runSync([this]() {
154*d57664e9SAndroid Build Coastguard Worker                 this->mEglManager.initialize();
155*d57664e9SAndroid Build Coastguard Worker                 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
156*d57664e9SAndroid Build Coastguard Worker             });
157*d57664e9SAndroid Build Coastguard Worker 
158*d57664e9SAndroid Build Coastguard Worker             this->postIdleTimeoutCheck();
159*d57664e9SAndroid Build Coastguard Worker         }
160*d57664e9SAndroid Build Coastguard Worker     }
161*d57664e9SAndroid Build Coastguard Worker 
162*d57664e9SAndroid Build Coastguard Worker 
getUploadEglDisplay()163*d57664e9SAndroid Build Coastguard Worker     EGLDisplay getUploadEglDisplay() {
164*d57664e9SAndroid Build Coastguard Worker         std::lock_guard _lock{mLock};
165*d57664e9SAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(), "Forgot to begin an upload?");
166*d57664e9SAndroid Build Coastguard Worker         return mEglManager.eglDisplay();
167*d57664e9SAndroid Build Coastguard Worker     }
168*d57664e9SAndroid Build Coastguard Worker 
onUploadHardwareBitmap(const SkBitmap & bitmap,const FormatInfo & format,AHardwareBuffer * ahb)169*d57664e9SAndroid Build Coastguard Worker     bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
170*d57664e9SAndroid Build Coastguard Worker                                 AHardwareBuffer* ahb) override {
171*d57664e9SAndroid Build Coastguard Worker         ATRACE_CALL();
172*d57664e9SAndroid Build Coastguard Worker 
173*d57664e9SAndroid Build Coastguard Worker         EGLDisplay display = getUploadEglDisplay();
174*d57664e9SAndroid Build Coastguard Worker 
175*d57664e9SAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
176*d57664e9SAndroid Build Coastguard Worker                             uirenderer::renderthread::EglManager::eglErrorString());
177*d57664e9SAndroid Build Coastguard Worker         // We use an EGLImage to access the content of the buffer
178*d57664e9SAndroid Build Coastguard Worker         // The EGL image is later bound to a 2D texture
179*d57664e9SAndroid Build Coastguard Worker         const EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(ahb);
180*d57664e9SAndroid Build Coastguard Worker         AutoEglImage autoImage(display, clientBuffer);
181*d57664e9SAndroid Build Coastguard Worker         if (autoImage.image == EGL_NO_IMAGE_KHR) {
182*d57664e9SAndroid Build Coastguard Worker             ALOGW("Could not create EGL image, err =%s",
183*d57664e9SAndroid Build Coastguard Worker                   uirenderer::renderthread::EglManager::eglErrorString());
184*d57664e9SAndroid Build Coastguard Worker             return false;
185*d57664e9SAndroid Build Coastguard Worker         }
186*d57664e9SAndroid Build Coastguard Worker 
187*d57664e9SAndroid Build Coastguard Worker         {
188*d57664e9SAndroid Build Coastguard Worker             ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
189*d57664e9SAndroid Build Coastguard Worker             EGLSyncKHR fence = mUploadThread->queue().runSync([&]() -> EGLSyncKHR {
190*d57664e9SAndroid Build Coastguard Worker                 AutoSkiaGlTexture glTexture;
191*d57664e9SAndroid Build Coastguard Worker                 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
192*d57664e9SAndroid Build Coastguard Worker                 if (GLUtils::dumpGLErrors()) {
193*d57664e9SAndroid Build Coastguard Worker                     return EGL_NO_SYNC_KHR;
194*d57664e9SAndroid Build Coastguard Worker                 }
195*d57664e9SAndroid Build Coastguard Worker 
196*d57664e9SAndroid Build Coastguard Worker                 // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
197*d57664e9SAndroid Build Coastguard Worker                 // provide.
198*d57664e9SAndroid Build Coastguard Worker                 // But asynchronous in sense that driver may upload texture onto hardware buffer
199*d57664e9SAndroid Build Coastguard Worker                 // when we first use it in drawing
200*d57664e9SAndroid Build Coastguard Worker                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
201*d57664e9SAndroid Build Coastguard Worker                                 format.format, format.type, bitmap.getPixels());
202*d57664e9SAndroid Build Coastguard Worker                 if (GLUtils::dumpGLErrors()) {
203*d57664e9SAndroid Build Coastguard Worker                     return EGL_NO_SYNC_KHR;
204*d57664e9SAndroid Build Coastguard Worker                 }
205*d57664e9SAndroid Build Coastguard Worker 
206*d57664e9SAndroid Build Coastguard Worker                 EGLSyncKHR uploadFence =
207*d57664e9SAndroid Build Coastguard Worker                         eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
208*d57664e9SAndroid Build Coastguard Worker                 if (uploadFence == EGL_NO_SYNC_KHR) {
209*d57664e9SAndroid Build Coastguard Worker                     ALOGW("Could not create sync fence %#x", eglGetError());
210*d57664e9SAndroid Build Coastguard Worker                 };
211*d57664e9SAndroid Build Coastguard Worker                 glFlush();
212*d57664e9SAndroid Build Coastguard Worker                 GLUtils::dumpGLErrors();
213*d57664e9SAndroid Build Coastguard Worker                 return uploadFence;
214*d57664e9SAndroid Build Coastguard Worker             });
215*d57664e9SAndroid Build Coastguard Worker 
216*d57664e9SAndroid Build Coastguard Worker             if (fence == EGL_NO_SYNC_KHR) {
217*d57664e9SAndroid Build Coastguard Worker                 return false;
218*d57664e9SAndroid Build Coastguard Worker             }
219*d57664e9SAndroid Build Coastguard Worker             EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
220*d57664e9SAndroid Build Coastguard Worker             ALOGE_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
221*d57664e9SAndroid Build Coastguard Worker                     "Failed to wait for the fence %#x", eglGetError());
222*d57664e9SAndroid Build Coastguard Worker 
223*d57664e9SAndroid Build Coastguard Worker             eglDestroySyncKHR(display, fence);
224*d57664e9SAndroid Build Coastguard Worker         }
225*d57664e9SAndroid Build Coastguard Worker         return true;
226*d57664e9SAndroid Build Coastguard Worker     }
227*d57664e9SAndroid Build Coastguard Worker 
228*d57664e9SAndroid Build Coastguard Worker     renderthread::EglManager mEglManager;
229*d57664e9SAndroid Build Coastguard Worker };
230*d57664e9SAndroid Build Coastguard Worker 
231*d57664e9SAndroid Build Coastguard Worker class VkUploader : public AHBUploader {
232*d57664e9SAndroid Build Coastguard Worker private:
onDestroy()233*d57664e9SAndroid Build Coastguard Worker     void onDestroy() override {
234*d57664e9SAndroid Build Coastguard Worker         std::lock_guard _lock{mVkLock};
235*d57664e9SAndroid Build Coastguard Worker         mGrContext.reset();
236*d57664e9SAndroid Build Coastguard Worker         mVulkanManagerStrong.clear();
237*d57664e9SAndroid Build Coastguard Worker     }
onIdle()238*d57664e9SAndroid Build Coastguard Worker     void onIdle() override {
239*d57664e9SAndroid Build Coastguard Worker         onDestroy();
240*d57664e9SAndroid Build Coastguard Worker     }
241*d57664e9SAndroid Build Coastguard Worker 
onBeginUpload()242*d57664e9SAndroid Build Coastguard Worker     void onBeginUpload() override {}
243*d57664e9SAndroid Build Coastguard Worker 
onUploadHardwareBitmap(const SkBitmap & bitmap,const FormatInfo & format,AHardwareBuffer * ahb)244*d57664e9SAndroid Build Coastguard Worker     bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
245*d57664e9SAndroid Build Coastguard Worker                                 AHardwareBuffer* ahb) override {
246*d57664e9SAndroid Build Coastguard Worker         bool uploadSucceeded = false;
247*d57664e9SAndroid Build Coastguard Worker         mUploadThread->queue().runSync([this, &uploadSucceeded, bitmap, ahb]() {
248*d57664e9SAndroid Build Coastguard Worker           ATRACE_CALL();
249*d57664e9SAndroid Build Coastguard Worker           std::lock_guard _lock{mVkLock};
250*d57664e9SAndroid Build Coastguard Worker 
251*d57664e9SAndroid Build Coastguard Worker           renderthread::VulkanManager* vkManager = getVulkanManager();
252*d57664e9SAndroid Build Coastguard Worker           if (!vkManager->hasVkContext()) {
253*d57664e9SAndroid Build Coastguard Worker               LOG_ALWAYS_FATAL_IF(mGrContext,
254*d57664e9SAndroid Build Coastguard Worker                                   "GrContext exists with no VulkanManager for vulkan uploads");
255*d57664e9SAndroid Build Coastguard Worker               vkManager->initialize();
256*d57664e9SAndroid Build Coastguard Worker           }
257*d57664e9SAndroid Build Coastguard Worker 
258*d57664e9SAndroid Build Coastguard Worker           if (!mGrContext) {
259*d57664e9SAndroid Build Coastguard Worker               GrContextOptions options;
260*d57664e9SAndroid Build Coastguard Worker               mGrContext = vkManager->createContext(options,
261*d57664e9SAndroid Build Coastguard Worker                       renderthread::VulkanManager::ContextType::kUploadThread);
262*d57664e9SAndroid Build Coastguard Worker               LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads");
263*d57664e9SAndroid Build Coastguard Worker               this->postIdleTimeoutCheck();
264*d57664e9SAndroid Build Coastguard Worker           }
265*d57664e9SAndroid Build Coastguard Worker 
266*d57664e9SAndroid Build Coastguard Worker           sk_sp<SkImage> image =
267*d57664e9SAndroid Build Coastguard Worker               SkImages::TextureFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(),
268*d57664e9SAndroid Build Coastguard Worker                                                            ahb);
269*d57664e9SAndroid Build Coastguard Worker           mGrContext->submit(GrSyncCpu::kYes);
270*d57664e9SAndroid Build Coastguard Worker 
271*d57664e9SAndroid Build Coastguard Worker           uploadSucceeded = (image.get() != nullptr);
272*d57664e9SAndroid Build Coastguard Worker         });
273*d57664e9SAndroid Build Coastguard Worker         return uploadSucceeded;
274*d57664e9SAndroid Build Coastguard Worker     }
275*d57664e9SAndroid Build Coastguard Worker 
276*d57664e9SAndroid Build Coastguard Worker     /* must be called on the upload thread after the vkLock has been acquired  */
getVulkanManager()277*d57664e9SAndroid Build Coastguard Worker     renderthread::VulkanManager* getVulkanManager() {
278*d57664e9SAndroid Build Coastguard Worker         if (!mVulkanManagerStrong) {
279*d57664e9SAndroid Build Coastguard Worker             mVulkanManagerStrong = mVulkanManagerWeak.promote();
280*d57664e9SAndroid Build Coastguard Worker 
281*d57664e9SAndroid Build Coastguard Worker             // create a new manager if we couldn't promote the weak ref
282*d57664e9SAndroid Build Coastguard Worker             if (!mVulkanManagerStrong) {
283*d57664e9SAndroid Build Coastguard Worker                 mVulkanManagerStrong = renderthread::VulkanManager::getInstance();
284*d57664e9SAndroid Build Coastguard Worker                 mGrContext.reset();
285*d57664e9SAndroid Build Coastguard Worker                 mVulkanManagerWeak = mVulkanManagerStrong;
286*d57664e9SAndroid Build Coastguard Worker             }
287*d57664e9SAndroid Build Coastguard Worker         }
288*d57664e9SAndroid Build Coastguard Worker 
289*d57664e9SAndroid Build Coastguard Worker         return mVulkanManagerStrong.get();
290*d57664e9SAndroid Build Coastguard Worker     }
291*d57664e9SAndroid Build Coastguard Worker 
292*d57664e9SAndroid Build Coastguard Worker     sk_sp<GrDirectContext> mGrContext;
293*d57664e9SAndroid Build Coastguard Worker     sp<renderthread::VulkanManager> mVulkanManagerStrong;
294*d57664e9SAndroid Build Coastguard Worker     wp<renderthread::VulkanManager> mVulkanManagerWeak;
295*d57664e9SAndroid Build Coastguard Worker     std::mutex mVkLock;
296*d57664e9SAndroid Build Coastguard Worker };
297*d57664e9SAndroid Build Coastguard Worker 
checkSupport(AHardwareBuffer_Format format)298*d57664e9SAndroid Build Coastguard Worker static bool checkSupport(AHardwareBuffer_Format format) {
299*d57664e9SAndroid Build Coastguard Worker     AHardwareBuffer_Desc desc = {
300*d57664e9SAndroid Build Coastguard Worker             .width = 1,
301*d57664e9SAndroid Build Coastguard Worker             .height = 1,
302*d57664e9SAndroid Build Coastguard Worker             .layers = 1,
303*d57664e9SAndroid Build Coastguard Worker             .format = format,
304*d57664e9SAndroid Build Coastguard Worker             .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
305*d57664e9SAndroid Build Coastguard Worker                      AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
306*d57664e9SAndroid Build Coastguard Worker     };
307*d57664e9SAndroid Build Coastguard Worker     UniqueAHardwareBuffer buffer = allocateAHardwareBuffer(desc);
308*d57664e9SAndroid Build Coastguard Worker     return buffer != nullptr;
309*d57664e9SAndroid Build Coastguard Worker }
310*d57664e9SAndroid Build Coastguard Worker 
hasFP16Support()311*d57664e9SAndroid Build Coastguard Worker bool HardwareBitmapUploader::hasFP16Support() {
312*d57664e9SAndroid Build Coastguard Worker     static bool hasFP16Support = checkSupport(AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT);
313*d57664e9SAndroid Build Coastguard Worker     return hasFP16Support;
314*d57664e9SAndroid Build Coastguard Worker }
315*d57664e9SAndroid Build Coastguard Worker 
has1010102Support()316*d57664e9SAndroid Build Coastguard Worker bool HardwareBitmapUploader::has1010102Support() {
317*d57664e9SAndroid Build Coastguard Worker     static bool has101012Support = checkSupport(AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM);
318*d57664e9SAndroid Build Coastguard Worker     return has101012Support;
319*d57664e9SAndroid Build Coastguard Worker }
320*d57664e9SAndroid Build Coastguard Worker 
has10101010Support()321*d57664e9SAndroid Build Coastguard Worker bool HardwareBitmapUploader::has10101010Support() {
322*d57664e9SAndroid Build Coastguard Worker     static bool has1010110Support = checkSupport(AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM);
323*d57664e9SAndroid Build Coastguard Worker     return has1010110Support;
324*d57664e9SAndroid Build Coastguard Worker }
325*d57664e9SAndroid Build Coastguard Worker 
hasAlpha8Support()326*d57664e9SAndroid Build Coastguard Worker bool HardwareBitmapUploader::hasAlpha8Support() {
327*d57664e9SAndroid Build Coastguard Worker     static bool hasAlpha8Support = checkSupport(AHARDWAREBUFFER_FORMAT_R8_UNORM);
328*d57664e9SAndroid Build Coastguard Worker     return hasAlpha8Support;
329*d57664e9SAndroid Build Coastguard Worker }
330*d57664e9SAndroid Build Coastguard Worker 
determineFormat(const SkBitmap & skBitmap,bool usingGL)331*d57664e9SAndroid Build Coastguard Worker static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
332*d57664e9SAndroid Build Coastguard Worker     FormatInfo formatInfo;
333*d57664e9SAndroid Build Coastguard Worker     switch (skBitmap.info().colorType()) {
334*d57664e9SAndroid Build Coastguard Worker         case kRGBA_8888_SkColorType:
335*d57664e9SAndroid Build Coastguard Worker             formatInfo.isSupported = true;
336*d57664e9SAndroid Build Coastguard Worker             [[fallthrough]];
337*d57664e9SAndroid Build Coastguard Worker         // ARGB_4444 is upconverted to RGBA_8888
338*d57664e9SAndroid Build Coastguard Worker         case kARGB_4444_SkColorType:
339*d57664e9SAndroid Build Coastguard Worker             formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
340*d57664e9SAndroid Build Coastguard Worker             formatInfo.format = GL_RGBA;
341*d57664e9SAndroid Build Coastguard Worker             formatInfo.type = GL_UNSIGNED_BYTE;
342*d57664e9SAndroid Build Coastguard Worker             formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
343*d57664e9SAndroid Build Coastguard Worker             break;
344*d57664e9SAndroid Build Coastguard Worker         case kRGBA_F16_SkColorType:
345*d57664e9SAndroid Build Coastguard Worker             formatInfo.isSupported = HardwareBitmapUploader::hasFP16Support();
346*d57664e9SAndroid Build Coastguard Worker             if (formatInfo.isSupported) {
347*d57664e9SAndroid Build Coastguard Worker                 formatInfo.type = GL_HALF_FLOAT;
348*d57664e9SAndroid Build Coastguard Worker                 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
349*d57664e9SAndroid Build Coastguard Worker                 formatInfo.vkFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
350*d57664e9SAndroid Build Coastguard Worker             } else {
351*d57664e9SAndroid Build Coastguard Worker                 formatInfo.type = GL_UNSIGNED_BYTE;
352*d57664e9SAndroid Build Coastguard Worker                 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
353*d57664e9SAndroid Build Coastguard Worker                 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
354*d57664e9SAndroid Build Coastguard Worker             }
355*d57664e9SAndroid Build Coastguard Worker             formatInfo.format = GL_RGBA;
356*d57664e9SAndroid Build Coastguard Worker             break;
357*d57664e9SAndroid Build Coastguard Worker         case kRGB_565_SkColorType:
358*d57664e9SAndroid Build Coastguard Worker             formatInfo.isSupported = true;
359*d57664e9SAndroid Build Coastguard Worker             formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
360*d57664e9SAndroid Build Coastguard Worker             formatInfo.format = GL_RGB;
361*d57664e9SAndroid Build Coastguard Worker             formatInfo.type = GL_UNSIGNED_SHORT_5_6_5;
362*d57664e9SAndroid Build Coastguard Worker             formatInfo.vkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;
363*d57664e9SAndroid Build Coastguard Worker             break;
364*d57664e9SAndroid Build Coastguard Worker         case kGray_8_SkColorType:
365*d57664e9SAndroid Build Coastguard Worker             formatInfo.isSupported = usingGL;
366*d57664e9SAndroid Build Coastguard Worker             formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
367*d57664e9SAndroid Build Coastguard Worker             formatInfo.format = GL_LUMINANCE;
368*d57664e9SAndroid Build Coastguard Worker             formatInfo.type = GL_UNSIGNED_BYTE;
369*d57664e9SAndroid Build Coastguard Worker             formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
370*d57664e9SAndroid Build Coastguard Worker             break;
371*d57664e9SAndroid Build Coastguard Worker         case kRGBA_1010102_SkColorType:
372*d57664e9SAndroid Build Coastguard Worker             formatInfo.isSupported = HardwareBitmapUploader::has1010102Support();
373*d57664e9SAndroid Build Coastguard Worker             if (formatInfo.isSupported) {
374*d57664e9SAndroid Build Coastguard Worker                 formatInfo.type = GL_UNSIGNED_INT_2_10_10_10_REV;
375*d57664e9SAndroid Build Coastguard Worker                 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
376*d57664e9SAndroid Build Coastguard Worker                 formatInfo.vkFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
377*d57664e9SAndroid Build Coastguard Worker             } else {
378*d57664e9SAndroid Build Coastguard Worker                 formatInfo.type = GL_UNSIGNED_BYTE;
379*d57664e9SAndroid Build Coastguard Worker                 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
380*d57664e9SAndroid Build Coastguard Worker                 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
381*d57664e9SAndroid Build Coastguard Worker             }
382*d57664e9SAndroid Build Coastguard Worker             formatInfo.format = GL_RGBA;
383*d57664e9SAndroid Build Coastguard Worker             break;
384*d57664e9SAndroid Build Coastguard Worker         case kRGBA_10x6_SkColorType:
385*d57664e9SAndroid Build Coastguard Worker             formatInfo.isSupported = HardwareBitmapUploader::has10101010Support();
386*d57664e9SAndroid Build Coastguard Worker             if (formatInfo.isSupported) {
387*d57664e9SAndroid Build Coastguard Worker                 formatInfo.type = 0;  // Not supported in GL
388*d57664e9SAndroid Build Coastguard Worker                 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM;
389*d57664e9SAndroid Build Coastguard Worker                 formatInfo.vkFormat = VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16;
390*d57664e9SAndroid Build Coastguard Worker             } else {
391*d57664e9SAndroid Build Coastguard Worker                 formatInfo.type = GL_UNSIGNED_BYTE;
392*d57664e9SAndroid Build Coastguard Worker                 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
393*d57664e9SAndroid Build Coastguard Worker                 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
394*d57664e9SAndroid Build Coastguard Worker             }
395*d57664e9SAndroid Build Coastguard Worker             formatInfo.format = 0;  // Not supported in GL
396*d57664e9SAndroid Build Coastguard Worker             break;
397*d57664e9SAndroid Build Coastguard Worker         case kAlpha_8_SkColorType:
398*d57664e9SAndroid Build Coastguard Worker             formatInfo.isSupported = HardwareBitmapUploader::hasAlpha8Support();
399*d57664e9SAndroid Build Coastguard Worker             if (formatInfo.isSupported) {
400*d57664e9SAndroid Build Coastguard Worker                 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8_UNORM;
401*d57664e9SAndroid Build Coastguard Worker                 formatInfo.format = GL_RED;
402*d57664e9SAndroid Build Coastguard Worker                 formatInfo.type = GL_UNSIGNED_BYTE;
403*d57664e9SAndroid Build Coastguard Worker                 formatInfo.vkFormat = VK_FORMAT_R8_UNORM;
404*d57664e9SAndroid Build Coastguard Worker             } else {
405*d57664e9SAndroid Build Coastguard Worker                 formatInfo.type = GL_UNSIGNED_BYTE;
406*d57664e9SAndroid Build Coastguard Worker                 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
407*d57664e9SAndroid Build Coastguard Worker                 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
408*d57664e9SAndroid Build Coastguard Worker                 formatInfo.format = GL_RGBA;
409*d57664e9SAndroid Build Coastguard Worker             }
410*d57664e9SAndroid Build Coastguard Worker             break;
411*d57664e9SAndroid Build Coastguard Worker         default:
412*d57664e9SAndroid Build Coastguard Worker             ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
413*d57664e9SAndroid Build Coastguard Worker             formatInfo.valid = false;
414*d57664e9SAndroid Build Coastguard Worker     }
415*d57664e9SAndroid Build Coastguard Worker     return formatInfo;
416*d57664e9SAndroid Build Coastguard Worker }
417*d57664e9SAndroid Build Coastguard Worker 
makeHwCompatible(const FormatInfo & format,const SkBitmap & source)418*d57664e9SAndroid Build Coastguard Worker static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& source) {
419*d57664e9SAndroid Build Coastguard Worker     if (format.isSupported) {
420*d57664e9SAndroid Build Coastguard Worker         return source;
421*d57664e9SAndroid Build Coastguard Worker     } else {
422*d57664e9SAndroid Build Coastguard Worker         SkBitmap bitmap;
423*d57664e9SAndroid Build Coastguard Worker         bitmap.allocPixels(source.info().makeColorType(kN32_SkColorType));
424*d57664e9SAndroid Build Coastguard Worker         bitmap.writePixels(source.pixmap());
425*d57664e9SAndroid Build Coastguard Worker         return bitmap;
426*d57664e9SAndroid Build Coastguard Worker     }
427*d57664e9SAndroid Build Coastguard Worker }
428*d57664e9SAndroid Build Coastguard Worker 
429*d57664e9SAndroid Build Coastguard Worker 
createUploader(bool usingGL)430*d57664e9SAndroid Build Coastguard Worker static void createUploader(bool usingGL) {
431*d57664e9SAndroid Build Coastguard Worker     static std::mutex lock;
432*d57664e9SAndroid Build Coastguard Worker     std::lock_guard _lock{lock};
433*d57664e9SAndroid Build Coastguard Worker     if (!sUploader.get()) {
434*d57664e9SAndroid Build Coastguard Worker         if (usingGL) {
435*d57664e9SAndroid Build Coastguard Worker             sUploader = new EGLUploader();
436*d57664e9SAndroid Build Coastguard Worker         } else {
437*d57664e9SAndroid Build Coastguard Worker             sUploader = new VkUploader();
438*d57664e9SAndroid Build Coastguard Worker         }
439*d57664e9SAndroid Build Coastguard Worker     }
440*d57664e9SAndroid Build Coastguard Worker }
441*d57664e9SAndroid Build Coastguard Worker 
allocateHardwareBitmap(const SkBitmap & sourceBitmap)442*d57664e9SAndroid Build Coastguard Worker sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sourceBitmap) {
443*d57664e9SAndroid Build Coastguard Worker     ATRACE_CALL();
444*d57664e9SAndroid Build Coastguard Worker 
445*d57664e9SAndroid Build Coastguard Worker     bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
446*d57664e9SAndroid Build Coastguard Worker             uirenderer::RenderPipelineType::SkiaGL;
447*d57664e9SAndroid Build Coastguard Worker 
448*d57664e9SAndroid Build Coastguard Worker     FormatInfo format = determineFormat(sourceBitmap, usingGL);
449*d57664e9SAndroid Build Coastguard Worker     if (!format.valid) {
450*d57664e9SAndroid Build Coastguard Worker         return nullptr;
451*d57664e9SAndroid Build Coastguard Worker     }
452*d57664e9SAndroid Build Coastguard Worker 
453*d57664e9SAndroid Build Coastguard Worker     SkBitmap bitmap = makeHwCompatible(format, sourceBitmap);
454*d57664e9SAndroid Build Coastguard Worker     AHardwareBuffer_Desc desc = {
455*d57664e9SAndroid Build Coastguard Worker             .width = static_cast<uint32_t>(bitmap.width()),
456*d57664e9SAndroid Build Coastguard Worker             .height = static_cast<uint32_t>(bitmap.height()),
457*d57664e9SAndroid Build Coastguard Worker             .layers = 1,
458*d57664e9SAndroid Build Coastguard Worker             .format = format.bufferFormat,
459*d57664e9SAndroid Build Coastguard Worker             .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
460*d57664e9SAndroid Build Coastguard Worker                      AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
461*d57664e9SAndroid Build Coastguard Worker     };
462*d57664e9SAndroid Build Coastguard Worker     UniqueAHardwareBuffer ahb = allocateAHardwareBuffer(desc);
463*d57664e9SAndroid Build Coastguard Worker     if (!ahb) {
464*d57664e9SAndroid Build Coastguard Worker         ALOGW("allocateHardwareBitmap() failed in AHardwareBuffer_allocate()");
465*d57664e9SAndroid Build Coastguard Worker         return nullptr;
466*d57664e9SAndroid Build Coastguard Worker     };
467*d57664e9SAndroid Build Coastguard Worker 
468*d57664e9SAndroid Build Coastguard Worker     createUploader(usingGL);
469*d57664e9SAndroid Build Coastguard Worker 
470*d57664e9SAndroid Build Coastguard Worker     if (!sUploader->uploadHardwareBitmap(bitmap, format, ahb.get())) {
471*d57664e9SAndroid Build Coastguard Worker         return nullptr;
472*d57664e9SAndroid Build Coastguard Worker     }
473*d57664e9SAndroid Build Coastguard Worker     return Bitmap::createFrom(ahb.get(), bitmap.colorType(), bitmap.refColorSpace(),
474*d57664e9SAndroid Build Coastguard Worker                               bitmap.alphaType(), Bitmap::computePalette(bitmap));
475*d57664e9SAndroid Build Coastguard Worker }
476*d57664e9SAndroid Build Coastguard Worker 
initialize()477*d57664e9SAndroid Build Coastguard Worker void HardwareBitmapUploader::initialize() {
478*d57664e9SAndroid Build Coastguard Worker     bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
479*d57664e9SAndroid Build Coastguard Worker             uirenderer::RenderPipelineType::SkiaGL;
480*d57664e9SAndroid Build Coastguard Worker     createUploader(usingGL);
481*d57664e9SAndroid Build Coastguard Worker }
482*d57664e9SAndroid Build Coastguard Worker 
terminate()483*d57664e9SAndroid Build Coastguard Worker void HardwareBitmapUploader::terminate() {
484*d57664e9SAndroid Build Coastguard Worker     if (sUploader) {
485*d57664e9SAndroid Build Coastguard Worker         sUploader->destroy();
486*d57664e9SAndroid Build Coastguard Worker     }
487*d57664e9SAndroid Build Coastguard Worker }
488*d57664e9SAndroid Build Coastguard Worker 
489*d57664e9SAndroid Build Coastguard Worker }  // namespace android::uirenderer
490