blob: 7291cab364e2847a47fa63573991c98eaf4d5c30 [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>
Kevin Lubick1175dc02022-02-28 12:41:27 -050025#include <SkBitmap.h>
John Recke170fb62018-05-07 08:12:07 -070026#include <SkCanvas.h>
Greg Danielc0732522019-02-20 08:31:03 -050027#include <SkImage.h>
Kevin Lubick1175dc02022-02-28 12:41:27 -050028#include <SkImageInfo.h>
29#include <SkRefCnt.h>
rnleece9762b2021-05-21 15:40:53 -070030#include <gui/TraceUtils.h>
John Recke170fb62018-05-07 08:12:07 -070031#include <utils/GLUtils.h>
Alec Mouri45238012020-01-29 11:04:40 -080032#include <utils/NdkUtils.h>
John Recke170fb62018-05-07 08:12:07 -070033#include <utils/Trace.h>
Alec Mouri45238012020-01-29 11:04:40 -080034
John Recke170fb62018-05-07 08:12:07 -070035#include <thread>
36
Alec Mouri45238012020-01-29 11:04:40 -080037#include "hwui/Bitmap.h"
38#include "renderthread/EglManager.h"
39#include "renderthread/VulkanManager.h"
40#include "thread/ThreadBase.h"
41#include "utils/TimeUtils.h"
42
John Recke170fb62018-05-07 08:12:07 -070043namespace android::uirenderer {
44
Greg Danielc0732522019-02-20 08:31:03 -050045class AHBUploader;
46// This helper uploader classes allows us to upload using either EGL or Vulkan using the same
47// interface.
48static sp<AHBUploader> sUploader = nullptr;
John Recke170fb62018-05-07 08:12:07 -070049
Greg Danielc0732522019-02-20 08:31:03 -050050struct FormatInfo {
Alec Mouri45238012020-01-29 11:04:40 -080051 AHardwareBuffer_Format bufferFormat;
Greg Danielc0732522019-02-20 08:31:03 -050052 GLint format, type;
53 VkFormat vkFormat;
54 bool isSupported = false;
55 bool valid = true;
56};
John Recke170fb62018-05-07 08:12:07 -070057
Greg Danielc0732522019-02-20 08:31:03 -050058class AHBUploader : public RefBase {
59public:
60 virtual ~AHBUploader() {}
John Recke170fb62018-05-07 08:12:07 -070061
Greg Danielc0732522019-02-20 08:31:03 -050062 void destroy() {
63 std::lock_guard _lock{mLock};
64 LOG_ALWAYS_FATAL_IF(mPendingUploads, "terminate called while uploads in progress");
65 if (mUploadThread) {
66 mUploadThread->requestExit();
67 mUploadThread->join();
68 mUploadThread = nullptr;
69 }
70 onDestroy();
John Recke170fb62018-05-07 08:12:07 -070071 }
72
Greg Danielc0732522019-02-20 08:31:03 -050073 bool uploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -080074 AHardwareBuffer* ahb) {
Greg Danielc0732522019-02-20 08:31:03 -050075 ATRACE_CALL();
76 beginUpload();
Alec Mouri45238012020-01-29 11:04:40 -080077 bool result = onUploadHardwareBitmap(bitmap, format, ahb);
Greg Danielc0732522019-02-20 08:31:03 -050078 endUpload();
79 return result;
80 }
81
82 void postIdleTimeoutCheck() {
83 mUploadThread->queue().postDelayed(5000_ms, [this](){ this->idleTimeoutCheck(); });
84 }
85
86protected:
87 std::mutex mLock;
88 sp<ThreadBase> mUploadThread = nullptr;
89
90private:
Greg Danielc0732522019-02-20 08:31:03 -050091 virtual void onIdle() = 0;
92 virtual void onDestroy() = 0;
93
94 virtual bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -080095 AHardwareBuffer* ahb) = 0;
Greg Danielc0732522019-02-20 08:31:03 -050096 virtual void onBeginUpload() = 0;
97
98 bool shouldTimeOutLocked() {
99 nsecs_t durationSince = systemTime() - mLastUpload;
100 return durationSince > 2000_ms;
101 }
102
103 void idleTimeoutCheck() {
104 std::lock_guard _lock{mLock};
105 if (mPendingUploads == 0 && shouldTimeOutLocked()) {
106 onIdle();
107 } else {
108 this->postIdleTimeoutCheck();
109 }
110 }
111
112 void beginUpload() {
113 std::lock_guard _lock{mLock};
114 mPendingUploads++;
115
116 if (!mUploadThread) {
117 mUploadThread = new ThreadBase{};
118 }
119 if (!mUploadThread->isRunning()) {
120 mUploadThread->start("GrallocUploadThread");
121 }
122
123 onBeginUpload();
124 }
125
126 void endUpload() {
127 std::lock_guard _lock{mLock};
128 mPendingUploads--;
129 mLastUpload = systemTime();
130 }
131
132 int mPendingUploads = 0;
133 nsecs_t mLastUpload = 0;
134};
135
136#define FENCE_TIMEOUT 2000000000
137
138class EGLUploader : public AHBUploader {
139private:
Greg Danielc0732522019-02-20 08:31:03 -0500140 void onDestroy() override {
141 mEglManager.destroy();
142 }
143 void onIdle() override {
144 mEglManager.destroy();
145 }
146
147 void onBeginUpload() override {
148 if (!mEglManager.hasEglContext()) {
149 mUploadThread->queue().runSync([this]() {
150 this->mEglManager.initialize();
151 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
152 });
153
154 this->postIdleTimeoutCheck();
155 }
156 }
157
158
159 EGLDisplay getUploadEglDisplay() {
160 std::lock_guard _lock{mLock};
161 LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(), "Forgot to begin an upload?");
162 return mEglManager.eglDisplay();
163 }
164
165 bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -0800166 AHardwareBuffer* ahb) override {
Greg Danielc0732522019-02-20 08:31:03 -0500167 ATRACE_CALL();
168
169 EGLDisplay display = getUploadEglDisplay();
170
171 LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
172 uirenderer::renderthread::EglManager::eglErrorString());
Alec Mouri45238012020-01-29 11:04:40 -0800173 // We use an EGLImage to access the content of the buffer
Greg Danielc0732522019-02-20 08:31:03 -0500174 // The EGL image is later bound to a 2D texture
Alec Mouri70463a62020-03-30 15:10:17 -0700175 const EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(ahb);
Greg Danielc0732522019-02-20 08:31:03 -0500176 AutoEglImage autoImage(display, clientBuffer);
177 if (autoImage.image == EGL_NO_IMAGE_KHR) {
178 ALOGW("Could not create EGL image, err =%s",
179 uirenderer::renderthread::EglManager::eglErrorString());
180 return false;
181 }
182
183 {
184 ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
185 EGLSyncKHR fence = mUploadThread->queue().runSync([&]() -> EGLSyncKHR {
186 AutoSkiaGlTexture glTexture;
187 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
John Reck996773a2020-02-03 16:30:56 -0800188 if (GLUtils::dumpGLErrors()) {
189 return EGL_NO_SYNC_KHR;
190 }
Greg Danielc0732522019-02-20 08:31:03 -0500191
192 // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
193 // provide.
194 // But asynchronous in sense that driver may upload texture onto hardware buffer
195 // when we first use it in drawing
196 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
197 format.format, format.type, bitmap.getPixels());
John Reck996773a2020-02-03 16:30:56 -0800198 if (GLUtils::dumpGLErrors()) {
199 return EGL_NO_SYNC_KHR;
200 }
Greg Danielc0732522019-02-20 08:31:03 -0500201
202 EGLSyncKHR uploadFence =
203 eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
John Reck996773a2020-02-03 16:30:56 -0800204 if (uploadFence == EGL_NO_SYNC_KHR) {
205 ALOGW("Could not create sync fence %#x", eglGetError());
206 };
Greg Danielc0732522019-02-20 08:31:03 -0500207 glFlush();
John Reck996773a2020-02-03 16:30:56 -0800208 GLUtils::dumpGLErrors();
Greg Danielc0732522019-02-20 08:31:03 -0500209 return uploadFence;
210 });
211
John Reck996773a2020-02-03 16:30:56 -0800212 if (fence == EGL_NO_SYNC_KHR) {
213 return false;
214 }
Greg Danielc0732522019-02-20 08:31:03 -0500215 EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
John Reck996773a2020-02-03 16:30:56 -0800216 ALOGE_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
217 "Failed to wait for the fence %#x", eglGetError());
Greg Danielc0732522019-02-20 08:31:03 -0500218
219 eglDestroySyncKHR(display, fence);
220 }
221 return true;
222 }
223
224 renderthread::EglManager mEglManager;
225};
226
227class VkUploader : public AHBUploader {
228private:
Greg Danielc0732522019-02-20 08:31:03 -0500229 void onDestroy() override {
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400230 std::lock_guard _lock{mVkLock};
Greg Danielc0732522019-02-20 08:31:03 -0500231 mGrContext.reset();
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400232 mVulkanManagerStrong.clear();
Greg Danielc0732522019-02-20 08:31:03 -0500233 }
234 void onIdle() override {
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400235 onDestroy();
Greg Danielc0732522019-02-20 08:31:03 -0500236 }
John Recke170fb62018-05-07 08:12:07 -0700237
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400238 void onBeginUpload() override {}
John Recke170fb62018-05-07 08:12:07 -0700239
Greg Danielc0732522019-02-20 08:31:03 -0500240 bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -0800241 AHardwareBuffer* ahb) override {
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400242 bool uploadSucceeded = false;
243 mUploadThread->queue().runSync([this, &uploadSucceeded, bitmap, ahb]() {
244 ATRACE_CALL();
245 std::lock_guard _lock{mVkLock};
Greg Danielc0732522019-02-20 08:31:03 -0500246
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400247 renderthread::VulkanManager* vkManager = getVulkanManager();
248 if (!vkManager->hasVkContext()) {
249 LOG_ALWAYS_FATAL_IF(mGrContext,
250 "GrContext exists with no VulkanManager for vulkan uploads");
251 vkManager->initialize();
252 }
Greg Danielc0732522019-02-20 08:31:03 -0500253
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400254 if (!mGrContext) {
255 GrContextOptions options;
256 mGrContext = vkManager->createContext(options,
257 renderthread::VulkanManager::ContextType::kUploadThread);
258 LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads");
259 this->postIdleTimeoutCheck();
260 }
261
262 sk_sp<SkImage> image =
263 SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(), ahb);
264 mGrContext->submit(true);
265
266 uploadSucceeded = (image.get() != nullptr);
267 });
268 return uploadSucceeded;
269 }
270
271 /* must be called on the upload thread after the vkLock has been acquired */
272 renderthread::VulkanManager* getVulkanManager() {
273 if (!mVulkanManagerStrong) {
274 mVulkanManagerStrong = mVulkanManagerWeak.promote();
275
276 // create a new manager if we couldn't promote the weak ref
277 if (!mVulkanManagerStrong) {
278 mVulkanManagerStrong = renderthread::VulkanManager::getInstance();
279 mGrContext.reset();
280 mVulkanManagerWeak = mVulkanManagerStrong;
281 }
282 }
283
284 return mVulkanManagerStrong.get();
Greg Danielc0732522019-02-20 08:31:03 -0500285 }
286
Adlai Hollerf8c434e2020-07-27 11:42:45 -0400287 sk_sp<GrDirectContext> mGrContext;
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400288 sp<renderthread::VulkanManager> mVulkanManagerStrong;
289 wp<renderthread::VulkanManager> mVulkanManagerWeak;
Greg Danielc0732522019-02-20 08:31:03 -0500290 std::mutex mVkLock;
291};
John Recke170fb62018-05-07 08:12:07 -0700292
Alec Mouri1efd0a52022-01-20 13:58:23 -0800293static bool checkSupport(AHardwareBuffer_Format format) {
294 AHardwareBuffer_Desc desc = {
295 .width = 1,
296 .height = 1,
297 .layers = 1,
298 .format = format,
299 .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
300 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
301 };
302 UniqueAHardwareBuffer buffer = allocateAHardwareBuffer(desc);
303 return buffer != nullptr;
304}
305
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500306bool HardwareBitmapUploader::hasFP16Support() {
Alec Mouri1efd0a52022-01-20 13:58:23 -0800307 static bool hasFP16Support = checkSupport(AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT);
John Recke170fb62018-05-07 08:12:07 -0700308 return hasFP16Support;
309}
310
Alec Mouri1efd0a52022-01-20 13:58:23 -0800311bool HardwareBitmapUploader::has1010102Support() {
312 static bool has101012Support = checkSupport(AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM);
313 return has101012Support;
314}
315
Leon Scroggins IIIa008aa92022-03-10 16:25:30 -0500316bool HardwareBitmapUploader::hasAlpha8Support() {
317 static bool hasAlpha8Support = checkSupport(AHARDWAREBUFFER_FORMAT_R8_UNORM);
318 return hasAlpha8Support;
319}
320
Greg Danielc0732522019-02-20 08:31:03 -0500321static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
John Recke170fb62018-05-07 08:12:07 -0700322 FormatInfo formatInfo;
John Recke170fb62018-05-07 08:12:07 -0700323 switch (skBitmap.info().colorType()) {
324 case kRGBA_8888_SkColorType:
325 formatInfo.isSupported = true;
Colin Crossf4e74b82019-10-31 13:47:42 -0700326 [[fallthrough]];
John Recke170fb62018-05-07 08:12:07 -0700327 // ARGB_4444 is upconverted to RGBA_8888
328 case kARGB_4444_SkColorType:
Alec Mouri45238012020-01-29 11:04:40 -0800329 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700330 formatInfo.format = GL_RGBA;
331 formatInfo.type = GL_UNSIGNED_BYTE;
Greg Danielc0732522019-02-20 08:31:03 -0500332 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700333 break;
334 case kRGBA_F16_SkColorType:
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500335 formatInfo.isSupported = HardwareBitmapUploader::hasFP16Support();
John Recke170fb62018-05-07 08:12:07 -0700336 if (formatInfo.isSupported) {
337 formatInfo.type = GL_HALF_FLOAT;
Alec Mouri45238012020-01-29 11:04:40 -0800338 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
Greg Danielc0732522019-02-20 08:31:03 -0500339 formatInfo.vkFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
John Recke170fb62018-05-07 08:12:07 -0700340 } else {
341 formatInfo.type = GL_UNSIGNED_BYTE;
Alec Mouri45238012020-01-29 11:04:40 -0800342 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
Greg Danielc0732522019-02-20 08:31:03 -0500343 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700344 }
345 formatInfo.format = GL_RGBA;
346 break;
347 case kRGB_565_SkColorType:
348 formatInfo.isSupported = true;
Alec Mouri45238012020-01-29 11:04:40 -0800349 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700350 formatInfo.format = GL_RGB;
351 formatInfo.type = GL_UNSIGNED_SHORT_5_6_5;
Greg Danielc0732522019-02-20 08:31:03 -0500352 formatInfo.vkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;
John Recke170fb62018-05-07 08:12:07 -0700353 break;
354 case kGray_8_SkColorType:
Greg Danielc0732522019-02-20 08:31:03 -0500355 formatInfo.isSupported = usingGL;
Alec Mouri45238012020-01-29 11:04:40 -0800356 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700357 formatInfo.format = GL_LUMINANCE;
358 formatInfo.type = GL_UNSIGNED_BYTE;
Greg Danielc0732522019-02-20 08:31:03 -0500359 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700360 break;
Alec Mouri1efd0a52022-01-20 13:58:23 -0800361 case kRGBA_1010102_SkColorType:
362 formatInfo.isSupported = HardwareBitmapUploader::has1010102Support();
363 if (formatInfo.isSupported) {
364 formatInfo.type = GL_UNSIGNED_INT_2_10_10_10_REV;
365 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
366 formatInfo.vkFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
367 } else {
368 formatInfo.type = GL_UNSIGNED_BYTE;
369 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
370 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
371 }
372 formatInfo.format = GL_RGBA;
373 break;
Leon Scroggins IIIa008aa92022-03-10 16:25:30 -0500374 case kAlpha_8_SkColorType:
375 formatInfo.isSupported = HardwareBitmapUploader::hasAlpha8Support();
376 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8_UNORM;
377 formatInfo.format = GL_R8;
378 formatInfo.type = GL_UNSIGNED_BYTE;
379 formatInfo.vkFormat = VK_FORMAT_R8_UNORM;
380 break;
John Recke170fb62018-05-07 08:12:07 -0700381 default:
382 ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
383 formatInfo.valid = false;
384 }
385 return formatInfo;
386}
387
388static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& source) {
389 if (format.isSupported) {
390 return source;
391 } else {
392 SkBitmap bitmap;
Mike Reed7994a312021-01-28 18:06:26 -0500393 bitmap.allocPixels(source.info().makeColorType(kN32_SkColorType));
394 bitmap.writePixels(source.pixmap());
John Recke170fb62018-05-07 08:12:07 -0700395 return bitmap;
396 }
397}
398
Greg Danielc0732522019-02-20 08:31:03 -0500399
400static void createUploader(bool usingGL) {
401 static std::mutex lock;
402 std::lock_guard _lock{lock};
403 if (!sUploader.get()) {
404 if (usingGL) {
405 sUploader = new EGLUploader();
406 } else {
407 sUploader = new VkUploader();
408 }
409 }
410}
John Recke170fb62018-05-07 08:12:07 -0700411
412sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sourceBitmap) {
413 ATRACE_CALL();
414
Greg Danielc0732522019-02-20 08:31:03 -0500415 bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
416 uirenderer::RenderPipelineType::SkiaGL;
417
418 FormatInfo format = determineFormat(sourceBitmap, usingGL);
John Recke170fb62018-05-07 08:12:07 -0700419 if (!format.valid) {
420 return nullptr;
421 }
422
John Recke170fb62018-05-07 08:12:07 -0700423 SkBitmap bitmap = makeHwCompatible(format, sourceBitmap);
Alec Mouri45238012020-01-29 11:04:40 -0800424 AHardwareBuffer_Desc desc = {
425 .width = static_cast<uint32_t>(bitmap.width()),
426 .height = static_cast<uint32_t>(bitmap.height()),
427 .layers = 1,
428 .format = format.bufferFormat,
429 .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
430 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
431 };
432 UniqueAHardwareBuffer ahb = allocateAHardwareBuffer(desc);
433 if (!ahb) {
434 ALOGW("allocateHardwareBitmap() failed in AHardwareBuffer_allocate()");
John Recke170fb62018-05-07 08:12:07 -0700435 return nullptr;
Alec Mouri45238012020-01-29 11:04:40 -0800436 };
John Recke170fb62018-05-07 08:12:07 -0700437
Greg Danielc0732522019-02-20 08:31:03 -0500438 createUploader(usingGL);
John Recke170fb62018-05-07 08:12:07 -0700439
Alec Mouri45238012020-01-29 11:04:40 -0800440 if (!sUploader->uploadHardwareBitmap(bitmap, format, ahb.get())) {
John Recke170fb62018-05-07 08:12:07 -0700441 return nullptr;
442 }
Alec Mouri45238012020-01-29 11:04:40 -0800443 return Bitmap::createFrom(ahb.get(), bitmap.colorType(), bitmap.refColorSpace(),
444 bitmap.alphaType(), Bitmap::computePalette(bitmap));
John Recke170fb62018-05-07 08:12:07 -0700445}
446
Greg Danielc0732522019-02-20 08:31:03 -0500447void HardwareBitmapUploader::initialize() {
448 bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
449 uirenderer::RenderPipelineType::SkiaGL;
450 createUploader(usingGL);
Greg Danielc0732522019-02-20 08:31:03 -0500451}
452
John Reck6104cea2019-01-10 14:37:17 -0800453void HardwareBitmapUploader::terminate() {
Greg Daniel78b7ddc2019-03-27 12:52:43 -0400454 if (sUploader) {
455 sUploader->destroy();
456 }
John Reck6104cea2019-01-10 14:37:17 -0800457}
458
Chris Blume7b8a8082018-11-30 15:51:58 -0800459} // namespace android::uirenderer