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