blob: c24cabb287de17ea78c02c53137c9d5f6b2cf094 [file] [log] [blame]
John Recke170fb62018-05-07 08:12:07 -07001/*
2 * Copyright (C) 2018 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 "HardwareBitmapUploader.h"
18
Alec Mouri45238012020-01-29 11:04:40 -080019#include <EGL/egl.h>
John Recke170fb62018-05-07 08:12:07 -070020#include <EGL/eglext.h>
21#include <GLES2/gl2.h>
22#include <GLES2/gl2ext.h>
23#include <GLES3/gl3.h>
Adlai Hollerf8c434e2020-07-27 11:42:45 -040024#include <GrDirectContext.h>
John Recke170fb62018-05-07 08:12:07 -070025#include <SkCanvas.h>
Greg Danielc0732522019-02-20 08:31:03 -050026#include <SkImage.h>
rnleece9762b2021-05-21 15:40:53 -070027#include <gui/TraceUtils.h>
John Recke170fb62018-05-07 08:12:07 -070028#include <utils/GLUtils.h>
Alec Mouri45238012020-01-29 11:04:40 -080029#include <utils/NdkUtils.h>
John Recke170fb62018-05-07 08:12:07 -070030#include <utils/Trace.h>
Alec Mouri45238012020-01-29 11:04:40 -080031
John Recke170fb62018-05-07 08:12:07 -070032#include <thread>
33
Alec Mouri45238012020-01-29 11:04:40 -080034#include "hwui/Bitmap.h"
35#include "renderthread/EglManager.h"
36#include "renderthread/VulkanManager.h"
37#include "thread/ThreadBase.h"
38#include "utils/TimeUtils.h"
39
John Recke170fb62018-05-07 08:12:07 -070040namespace android::uirenderer {
41
Greg Danielc0732522019-02-20 08:31:03 -050042class AHBUploader;
43// This helper uploader classes allows us to upload using either EGL or Vulkan using the same
44// interface.
45static sp<AHBUploader> sUploader = nullptr;
John Recke170fb62018-05-07 08:12:07 -070046
Greg Danielc0732522019-02-20 08:31:03 -050047struct FormatInfo {
Alec Mouri45238012020-01-29 11:04:40 -080048 AHardwareBuffer_Format bufferFormat;
Greg Danielc0732522019-02-20 08:31:03 -050049 GLint format, type;
50 VkFormat vkFormat;
51 bool isSupported = false;
52 bool valid = true;
53};
John Recke170fb62018-05-07 08:12:07 -070054
Greg Danielc0732522019-02-20 08:31:03 -050055class AHBUploader : public RefBase {
56public:
57 virtual ~AHBUploader() {}
John Recke170fb62018-05-07 08:12:07 -070058
Greg Danielc0732522019-02-20 08:31:03 -050059 void destroy() {
60 std::lock_guard _lock{mLock};
61 LOG_ALWAYS_FATAL_IF(mPendingUploads, "terminate called while uploads in progress");
62 if (mUploadThread) {
63 mUploadThread->requestExit();
64 mUploadThread->join();
65 mUploadThread = nullptr;
66 }
67 onDestroy();
John Recke170fb62018-05-07 08:12:07 -070068 }
69
Greg Danielc0732522019-02-20 08:31:03 -050070 bool uploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -080071 AHardwareBuffer* ahb) {
Greg Danielc0732522019-02-20 08:31:03 -050072 ATRACE_CALL();
73 beginUpload();
Alec Mouri45238012020-01-29 11:04:40 -080074 bool result = onUploadHardwareBitmap(bitmap, format, ahb);
Greg Danielc0732522019-02-20 08:31:03 -050075 endUpload();
76 return result;
77 }
78
79 void postIdleTimeoutCheck() {
80 mUploadThread->queue().postDelayed(5000_ms, [this](){ this->idleTimeoutCheck(); });
81 }
82
83protected:
84 std::mutex mLock;
85 sp<ThreadBase> mUploadThread = nullptr;
86
87private:
Greg Danielc0732522019-02-20 08:31:03 -050088 virtual void onIdle() = 0;
89 virtual void onDestroy() = 0;
90
91 virtual bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -080092 AHardwareBuffer* ahb) = 0;
Greg Danielc0732522019-02-20 08:31:03 -050093 virtual void onBeginUpload() = 0;
94
95 bool shouldTimeOutLocked() {
96 nsecs_t durationSince = systemTime() - mLastUpload;
97 return durationSince > 2000_ms;
98 }
99
100 void idleTimeoutCheck() {
101 std::lock_guard _lock{mLock};
102 if (mPendingUploads == 0 && shouldTimeOutLocked()) {
103 onIdle();
104 } else {
105 this->postIdleTimeoutCheck();
106 }
107 }
108
109 void beginUpload() {
110 std::lock_guard _lock{mLock};
111 mPendingUploads++;
112
113 if (!mUploadThread) {
114 mUploadThread = new ThreadBase{};
115 }
116 if (!mUploadThread->isRunning()) {
117 mUploadThread->start("GrallocUploadThread");
118 }
119
120 onBeginUpload();
121 }
122
123 void endUpload() {
124 std::lock_guard _lock{mLock};
125 mPendingUploads--;
126 mLastUpload = systemTime();
127 }
128
129 int mPendingUploads = 0;
130 nsecs_t mLastUpload = 0;
131};
132
133#define FENCE_TIMEOUT 2000000000
134
135class EGLUploader : public AHBUploader {
136private:
Greg Danielc0732522019-02-20 08:31:03 -0500137 void onDestroy() override {
138 mEglManager.destroy();
139 }
140 void onIdle() override {
141 mEglManager.destroy();
142 }
143
144 void onBeginUpload() override {
145 if (!mEglManager.hasEglContext()) {
146 mUploadThread->queue().runSync([this]() {
147 this->mEglManager.initialize();
148 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
149 });
150
151 this->postIdleTimeoutCheck();
152 }
153 }
154
155
156 EGLDisplay getUploadEglDisplay() {
157 std::lock_guard _lock{mLock};
158 LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(), "Forgot to begin an upload?");
159 return mEglManager.eglDisplay();
160 }
161
162 bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -0800163 AHardwareBuffer* ahb) override {
Greg Danielc0732522019-02-20 08:31:03 -0500164 ATRACE_CALL();
165
166 EGLDisplay display = getUploadEglDisplay();
167
168 LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
169 uirenderer::renderthread::EglManager::eglErrorString());
Alec Mouri45238012020-01-29 11:04:40 -0800170 // We use an EGLImage to access the content of the buffer
Greg Danielc0732522019-02-20 08:31:03 -0500171 // The EGL image is later bound to a 2D texture
Alec Mouri70463a62020-03-30 15:10:17 -0700172 const EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(ahb);
Greg Danielc0732522019-02-20 08:31:03 -0500173 AutoEglImage autoImage(display, clientBuffer);
174 if (autoImage.image == EGL_NO_IMAGE_KHR) {
175 ALOGW("Could not create EGL image, err =%s",
176 uirenderer::renderthread::EglManager::eglErrorString());
177 return false;
178 }
179
180 {
181 ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
182 EGLSyncKHR fence = mUploadThread->queue().runSync([&]() -> EGLSyncKHR {
183 AutoSkiaGlTexture glTexture;
184 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
John Reck996773a2020-02-03 16:30:56 -0800185 if (GLUtils::dumpGLErrors()) {
186 return EGL_NO_SYNC_KHR;
187 }
Greg Danielc0732522019-02-20 08:31:03 -0500188
189 // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
190 // provide.
191 // But asynchronous in sense that driver may upload texture onto hardware buffer
192 // when we first use it in drawing
193 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
194 format.format, format.type, bitmap.getPixels());
John Reck996773a2020-02-03 16:30:56 -0800195 if (GLUtils::dumpGLErrors()) {
196 return EGL_NO_SYNC_KHR;
197 }
Greg Danielc0732522019-02-20 08:31:03 -0500198
199 EGLSyncKHR uploadFence =
200 eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
John Reck996773a2020-02-03 16:30:56 -0800201 if (uploadFence == EGL_NO_SYNC_KHR) {
202 ALOGW("Could not create sync fence %#x", eglGetError());
203 };
Greg Danielc0732522019-02-20 08:31:03 -0500204 glFlush();
John Reck996773a2020-02-03 16:30:56 -0800205 GLUtils::dumpGLErrors();
Greg Danielc0732522019-02-20 08:31:03 -0500206 return uploadFence;
207 });
208
John Reck996773a2020-02-03 16:30:56 -0800209 if (fence == EGL_NO_SYNC_KHR) {
210 return false;
211 }
Greg Danielc0732522019-02-20 08:31:03 -0500212 EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
John Reck996773a2020-02-03 16:30:56 -0800213 ALOGE_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
214 "Failed to wait for the fence %#x", eglGetError());
Greg Danielc0732522019-02-20 08:31:03 -0500215
216 eglDestroySyncKHR(display, fence);
217 }
218 return true;
219 }
220
221 renderthread::EglManager mEglManager;
222};
223
224class VkUploader : public AHBUploader {
225private:
Greg Danielc0732522019-02-20 08:31:03 -0500226 void onDestroy() override {
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400227 std::lock_guard _lock{mVkLock};
Greg Danielc0732522019-02-20 08:31:03 -0500228 mGrContext.reset();
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400229 mVulkanManagerStrong.clear();
Greg Danielc0732522019-02-20 08:31:03 -0500230 }
231 void onIdle() override {
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400232 onDestroy();
Greg Danielc0732522019-02-20 08:31:03 -0500233 }
John Recke170fb62018-05-07 08:12:07 -0700234
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400235 void onBeginUpload() override {}
John Recke170fb62018-05-07 08:12:07 -0700236
Greg Danielc0732522019-02-20 08:31:03 -0500237 bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -0800238 AHardwareBuffer* ahb) override {
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400239 bool uploadSucceeded = false;
240 mUploadThread->queue().runSync([this, &uploadSucceeded, bitmap, ahb]() {
241 ATRACE_CALL();
242 std::lock_guard _lock{mVkLock};
Greg Danielc0732522019-02-20 08:31:03 -0500243
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400244 renderthread::VulkanManager* vkManager = getVulkanManager();
245 if (!vkManager->hasVkContext()) {
246 LOG_ALWAYS_FATAL_IF(mGrContext,
247 "GrContext exists with no VulkanManager for vulkan uploads");
248 vkManager->initialize();
249 }
Greg Danielc0732522019-02-20 08:31:03 -0500250
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400251 if (!mGrContext) {
252 GrContextOptions options;
253 mGrContext = vkManager->createContext(options,
254 renderthread::VulkanManager::ContextType::kUploadThread);
255 LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads");
256 this->postIdleTimeoutCheck();
257 }
258
259 sk_sp<SkImage> image =
260 SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(), ahb);
261 mGrContext->submit(true);
262
263 uploadSucceeded = (image.get() != nullptr);
264 });
265 return uploadSucceeded;
266 }
267
268 /* must be called on the upload thread after the vkLock has been acquired */
269 renderthread::VulkanManager* getVulkanManager() {
270 if (!mVulkanManagerStrong) {
271 mVulkanManagerStrong = mVulkanManagerWeak.promote();
272
273 // create a new manager if we couldn't promote the weak ref
274 if (!mVulkanManagerStrong) {
275 mVulkanManagerStrong = renderthread::VulkanManager::getInstance();
276 mGrContext.reset();
277 mVulkanManagerWeak = mVulkanManagerStrong;
278 }
279 }
280
281 return mVulkanManagerStrong.get();
Greg Danielc0732522019-02-20 08:31:03 -0500282 }
283
Adlai Hollerf8c434e2020-07-27 11:42:45 -0400284 sk_sp<GrDirectContext> mGrContext;
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400285 sp<renderthread::VulkanManager> mVulkanManagerStrong;
286 wp<renderthread::VulkanManager> mVulkanManagerWeak;
Greg Danielc0732522019-02-20 08:31:03 -0500287 std::mutex mVkLock;
288};
John Recke170fb62018-05-07 08:12:07 -0700289
Alec Mouri1efd0a52022-01-20 13:58:23 -0800290static bool checkSupport(AHardwareBuffer_Format format) {
291 AHardwareBuffer_Desc desc = {
292 .width = 1,
293 .height = 1,
294 .layers = 1,
295 .format = format,
296 .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
297 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
298 };
299 UniqueAHardwareBuffer buffer = allocateAHardwareBuffer(desc);
300 return buffer != nullptr;
301}
302
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500303bool HardwareBitmapUploader::hasFP16Support() {
Alec Mouri1efd0a52022-01-20 13:58:23 -0800304 static bool hasFP16Support = checkSupport(AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT);
John Recke170fb62018-05-07 08:12:07 -0700305 return hasFP16Support;
306}
307
Alec Mouri1efd0a52022-01-20 13:58:23 -0800308bool HardwareBitmapUploader::has1010102Support() {
309 static bool has101012Support = checkSupport(AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM);
310 return has101012Support;
311}
312
Leon Scroggins IIIa008aa92022-03-10 16:25:30 -0500313bool HardwareBitmapUploader::hasAlpha8Support() {
314 static bool hasAlpha8Support = checkSupport(AHARDWAREBUFFER_FORMAT_R8_UNORM);
315 return hasAlpha8Support;
316}
317
Greg Danielc0732522019-02-20 08:31:03 -0500318static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
John Recke170fb62018-05-07 08:12:07 -0700319 FormatInfo formatInfo;
John Recke170fb62018-05-07 08:12:07 -0700320 switch (skBitmap.info().colorType()) {
321 case kRGBA_8888_SkColorType:
322 formatInfo.isSupported = true;
Colin Crossf4e74b82019-10-31 13:47:42 -0700323 [[fallthrough]];
John Recke170fb62018-05-07 08:12:07 -0700324 // ARGB_4444 is upconverted to RGBA_8888
325 case kARGB_4444_SkColorType:
Alec Mouri45238012020-01-29 11:04:40 -0800326 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700327 formatInfo.format = GL_RGBA;
328 formatInfo.type = GL_UNSIGNED_BYTE;
Greg Danielc0732522019-02-20 08:31:03 -0500329 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700330 break;
331 case kRGBA_F16_SkColorType:
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500332 formatInfo.isSupported = HardwareBitmapUploader::hasFP16Support();
John Recke170fb62018-05-07 08:12:07 -0700333 if (formatInfo.isSupported) {
334 formatInfo.type = GL_HALF_FLOAT;
Alec Mouri45238012020-01-29 11:04:40 -0800335 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
Greg Danielc0732522019-02-20 08:31:03 -0500336 formatInfo.vkFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
John Recke170fb62018-05-07 08:12:07 -0700337 } else {
338 formatInfo.type = GL_UNSIGNED_BYTE;
Alec Mouri45238012020-01-29 11:04:40 -0800339 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
Greg Danielc0732522019-02-20 08:31:03 -0500340 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700341 }
342 formatInfo.format = GL_RGBA;
343 break;
344 case kRGB_565_SkColorType:
345 formatInfo.isSupported = true;
Alec Mouri45238012020-01-29 11:04:40 -0800346 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700347 formatInfo.format = GL_RGB;
348 formatInfo.type = GL_UNSIGNED_SHORT_5_6_5;
Greg Danielc0732522019-02-20 08:31:03 -0500349 formatInfo.vkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;
John Recke170fb62018-05-07 08:12:07 -0700350 break;
351 case kGray_8_SkColorType:
Greg Danielc0732522019-02-20 08:31:03 -0500352 formatInfo.isSupported = usingGL;
Alec Mouri45238012020-01-29 11:04:40 -0800353 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700354 formatInfo.format = GL_LUMINANCE;
355 formatInfo.type = GL_UNSIGNED_BYTE;
Greg Danielc0732522019-02-20 08:31:03 -0500356 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700357 break;
Alec Mouri1efd0a52022-01-20 13:58:23 -0800358 case kRGBA_1010102_SkColorType:
359 formatInfo.isSupported = HardwareBitmapUploader::has1010102Support();
360 if (formatInfo.isSupported) {
361 formatInfo.type = GL_UNSIGNED_INT_2_10_10_10_REV;
362 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
363 formatInfo.vkFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
364 } else {
365 formatInfo.type = GL_UNSIGNED_BYTE;
366 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
367 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
368 }
369 formatInfo.format = GL_RGBA;
370 break;
Leon Scroggins IIIa008aa92022-03-10 16:25:30 -0500371 case kAlpha_8_SkColorType:
372 formatInfo.isSupported = HardwareBitmapUploader::hasAlpha8Support();
373 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8_UNORM;
374 formatInfo.format = GL_R8;
375 formatInfo.type = GL_UNSIGNED_BYTE;
376 formatInfo.vkFormat = VK_FORMAT_R8_UNORM;
377 break;
John Recke170fb62018-05-07 08:12:07 -0700378 default:
379 ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
380 formatInfo.valid = false;
381 }
382 return formatInfo;
383}
384
385static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& source) {
386 if (format.isSupported) {
387 return source;
388 } else {
389 SkBitmap bitmap;
Mike Reed7994a312021-01-28 18:06:26 -0500390 bitmap.allocPixels(source.info().makeColorType(kN32_SkColorType));
391 bitmap.writePixels(source.pixmap());
John Recke170fb62018-05-07 08:12:07 -0700392 return bitmap;
393 }
394}
395
Greg Danielc0732522019-02-20 08:31:03 -0500396
397static void createUploader(bool usingGL) {
398 static std::mutex lock;
399 std::lock_guard _lock{lock};
400 if (!sUploader.get()) {
401 if (usingGL) {
402 sUploader = new EGLUploader();
403 } else {
404 sUploader = new VkUploader();
405 }
406 }
407}
John Recke170fb62018-05-07 08:12:07 -0700408
409sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sourceBitmap) {
410 ATRACE_CALL();
411
Greg Danielc0732522019-02-20 08:31:03 -0500412 bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
413 uirenderer::RenderPipelineType::SkiaGL;
414
415 FormatInfo format = determineFormat(sourceBitmap, usingGL);
John Recke170fb62018-05-07 08:12:07 -0700416 if (!format.valid) {
417 return nullptr;
418 }
419
John Recke170fb62018-05-07 08:12:07 -0700420 SkBitmap bitmap = makeHwCompatible(format, sourceBitmap);
Alec Mouri45238012020-01-29 11:04:40 -0800421 AHardwareBuffer_Desc desc = {
422 .width = static_cast<uint32_t>(bitmap.width()),
423 .height = static_cast<uint32_t>(bitmap.height()),
424 .layers = 1,
425 .format = format.bufferFormat,
426 .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
427 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
428 };
429 UniqueAHardwareBuffer ahb = allocateAHardwareBuffer(desc);
430 if (!ahb) {
431 ALOGW("allocateHardwareBitmap() failed in AHardwareBuffer_allocate()");
John Recke170fb62018-05-07 08:12:07 -0700432 return nullptr;
Alec Mouri45238012020-01-29 11:04:40 -0800433 };
John Recke170fb62018-05-07 08:12:07 -0700434
Greg Danielc0732522019-02-20 08:31:03 -0500435 createUploader(usingGL);
John Recke170fb62018-05-07 08:12:07 -0700436
Alec Mouri45238012020-01-29 11:04:40 -0800437 if (!sUploader->uploadHardwareBitmap(bitmap, format, ahb.get())) {
John Recke170fb62018-05-07 08:12:07 -0700438 return nullptr;
439 }
Alec Mouri45238012020-01-29 11:04:40 -0800440 return Bitmap::createFrom(ahb.get(), bitmap.colorType(), bitmap.refColorSpace(),
441 bitmap.alphaType(), Bitmap::computePalette(bitmap));
John Recke170fb62018-05-07 08:12:07 -0700442}
443
Greg Danielc0732522019-02-20 08:31:03 -0500444void HardwareBitmapUploader::initialize() {
445 bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
446 uirenderer::RenderPipelineType::SkiaGL;
447 createUploader(usingGL);
Greg Danielc0732522019-02-20 08:31:03 -0500448}
449
John Reck6104cea2019-01-10 14:37:17 -0800450void HardwareBitmapUploader::terminate() {
Greg Daniel78b7ddc2019-03-27 12:52:43 -0400451 if (sUploader) {
452 sUploader->destroy();
453 }
John Reck6104cea2019-01-10 14:37:17 -0800454}
455
Chris Blume7b8a8082018-11-30 15:51:58 -0800456} // namespace android::uirenderer