blob: b7e99994355c10ebed29dff321dd79b62799ac0b [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
John Reck5f66fb82022-09-23 17:49:23 -040045static constexpr auto kThreadTimeout = 60000_ms;
46
Greg Danielc0732522019-02-20 08:31:03 -050047class AHBUploader;
48// This helper uploader classes allows us to upload using either EGL or Vulkan using the same
49// interface.
50static sp<AHBUploader> sUploader = nullptr;
John Recke170fb62018-05-07 08:12:07 -070051
Greg Danielc0732522019-02-20 08:31:03 -050052struct FormatInfo {
Alec Mouri45238012020-01-29 11:04:40 -080053 AHardwareBuffer_Format bufferFormat;
Greg Danielc0732522019-02-20 08:31:03 -050054 GLint format, type;
55 VkFormat vkFormat;
56 bool isSupported = false;
57 bool valid = true;
58};
John Recke170fb62018-05-07 08:12:07 -070059
Greg Danielc0732522019-02-20 08:31:03 -050060class AHBUploader : public RefBase {
61public:
62 virtual ~AHBUploader() {}
John Recke170fb62018-05-07 08:12:07 -070063
Greg Danielc0732522019-02-20 08:31:03 -050064 void destroy() {
65 std::lock_guard _lock{mLock};
66 LOG_ALWAYS_FATAL_IF(mPendingUploads, "terminate called while uploads in progress");
67 if (mUploadThread) {
68 mUploadThread->requestExit();
69 mUploadThread->join();
70 mUploadThread = nullptr;
71 }
72 onDestroy();
John Recke170fb62018-05-07 08:12:07 -070073 }
74
Greg Danielc0732522019-02-20 08:31:03 -050075 bool uploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -080076 AHardwareBuffer* ahb) {
Greg Danielc0732522019-02-20 08:31:03 -050077 ATRACE_CALL();
78 beginUpload();
Alec Mouri45238012020-01-29 11:04:40 -080079 bool result = onUploadHardwareBitmap(bitmap, format, ahb);
Greg Danielc0732522019-02-20 08:31:03 -050080 endUpload();
81 return result;
82 }
83
84 void postIdleTimeoutCheck() {
John Reck5f66fb82022-09-23 17:49:23 -040085 mUploadThread->queue().postDelayed(kThreadTimeout, [this]() { this->idleTimeoutCheck(); });
Greg Danielc0732522019-02-20 08:31:03 -050086 }
87
88protected:
89 std::mutex mLock;
90 sp<ThreadBase> mUploadThread = nullptr;
91
92private:
Greg Danielc0732522019-02-20 08:31:03 -050093 virtual void onIdle() = 0;
94 virtual void onDestroy() = 0;
95
96 virtual bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -080097 AHardwareBuffer* ahb) = 0;
Greg Danielc0732522019-02-20 08:31:03 -050098 virtual void onBeginUpload() = 0;
99
100 bool shouldTimeOutLocked() {
101 nsecs_t durationSince = systemTime() - mLastUpload;
John Reck5f66fb82022-09-23 17:49:23 -0400102 return durationSince > kThreadTimeout;
Greg Danielc0732522019-02-20 08:31:03 -0500103 }
104
105 void idleTimeoutCheck() {
106 std::lock_guard _lock{mLock};
107 if (mPendingUploads == 0 && shouldTimeOutLocked()) {
108 onIdle();
109 } else {
110 this->postIdleTimeoutCheck();
111 }
112 }
113
114 void beginUpload() {
115 std::lock_guard _lock{mLock};
116 mPendingUploads++;
117
118 if (!mUploadThread) {
119 mUploadThread = new ThreadBase{};
120 }
121 if (!mUploadThread->isRunning()) {
122 mUploadThread->start("GrallocUploadThread");
123 }
124
125 onBeginUpload();
126 }
127
128 void endUpload() {
129 std::lock_guard _lock{mLock};
130 mPendingUploads--;
131 mLastUpload = systemTime();
132 }
133
134 int mPendingUploads = 0;
135 nsecs_t mLastUpload = 0;
136};
137
138#define FENCE_TIMEOUT 2000000000
139
140class EGLUploader : public AHBUploader {
141private:
Greg Danielc0732522019-02-20 08:31:03 -0500142 void onDestroy() override {
143 mEglManager.destroy();
144 }
145 void onIdle() override {
146 mEglManager.destroy();
147 }
148
149 void onBeginUpload() override {
150 if (!mEglManager.hasEglContext()) {
151 mUploadThread->queue().runSync([this]() {
152 this->mEglManager.initialize();
153 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
154 });
155
156 this->postIdleTimeoutCheck();
157 }
158 }
159
160
161 EGLDisplay getUploadEglDisplay() {
162 std::lock_guard _lock{mLock};
163 LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(), "Forgot to begin an upload?");
164 return mEglManager.eglDisplay();
165 }
166
167 bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -0800168 AHardwareBuffer* ahb) override {
Greg Danielc0732522019-02-20 08:31:03 -0500169 ATRACE_CALL();
170
171 EGLDisplay display = getUploadEglDisplay();
172
173 LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
174 uirenderer::renderthread::EglManager::eglErrorString());
Alec Mouri45238012020-01-29 11:04:40 -0800175 // We use an EGLImage to access the content of the buffer
Greg Danielc0732522019-02-20 08:31:03 -0500176 // The EGL image is later bound to a 2D texture
Alec Mouri70463a62020-03-30 15:10:17 -0700177 const EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(ahb);
Greg Danielc0732522019-02-20 08:31:03 -0500178 AutoEglImage autoImage(display, clientBuffer);
179 if (autoImage.image == EGL_NO_IMAGE_KHR) {
180 ALOGW("Could not create EGL image, err =%s",
181 uirenderer::renderthread::EglManager::eglErrorString());
182 return false;
183 }
184
185 {
186 ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
187 EGLSyncKHR fence = mUploadThread->queue().runSync([&]() -> EGLSyncKHR {
188 AutoSkiaGlTexture glTexture;
189 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
John Reck996773a2020-02-03 16:30:56 -0800190 if (GLUtils::dumpGLErrors()) {
191 return EGL_NO_SYNC_KHR;
192 }
Greg Danielc0732522019-02-20 08:31:03 -0500193
194 // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
195 // provide.
196 // But asynchronous in sense that driver may upload texture onto hardware buffer
197 // when we first use it in drawing
198 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
199 format.format, format.type, bitmap.getPixels());
John Reck996773a2020-02-03 16:30:56 -0800200 if (GLUtils::dumpGLErrors()) {
201 return EGL_NO_SYNC_KHR;
202 }
Greg Danielc0732522019-02-20 08:31:03 -0500203
204 EGLSyncKHR uploadFence =
205 eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
John Reck996773a2020-02-03 16:30:56 -0800206 if (uploadFence == EGL_NO_SYNC_KHR) {
207 ALOGW("Could not create sync fence %#x", eglGetError());
208 };
Greg Danielc0732522019-02-20 08:31:03 -0500209 glFlush();
John Reck996773a2020-02-03 16:30:56 -0800210 GLUtils::dumpGLErrors();
Greg Danielc0732522019-02-20 08:31:03 -0500211 return uploadFence;
212 });
213
John Reck996773a2020-02-03 16:30:56 -0800214 if (fence == EGL_NO_SYNC_KHR) {
215 return false;
216 }
Greg Danielc0732522019-02-20 08:31:03 -0500217 EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
John Reck996773a2020-02-03 16:30:56 -0800218 ALOGE_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
219 "Failed to wait for the fence %#x", eglGetError());
Greg Danielc0732522019-02-20 08:31:03 -0500220
221 eglDestroySyncKHR(display, fence);
222 }
223 return true;
224 }
225
226 renderthread::EglManager mEglManager;
227};
228
229class VkUploader : public AHBUploader {
230private:
Greg Danielc0732522019-02-20 08:31:03 -0500231 void onDestroy() override {
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400232 std::lock_guard _lock{mVkLock};
Greg Danielc0732522019-02-20 08:31:03 -0500233 mGrContext.reset();
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400234 mVulkanManagerStrong.clear();
Greg Danielc0732522019-02-20 08:31:03 -0500235 }
236 void onIdle() override {
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400237 onDestroy();
Greg Danielc0732522019-02-20 08:31:03 -0500238 }
John Recke170fb62018-05-07 08:12:07 -0700239
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400240 void onBeginUpload() override {}
John Recke170fb62018-05-07 08:12:07 -0700241
Greg Danielc0732522019-02-20 08:31:03 -0500242 bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -0800243 AHardwareBuffer* ahb) override {
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400244 bool uploadSucceeded = false;
245 mUploadThread->queue().runSync([this, &uploadSucceeded, bitmap, ahb]() {
246 ATRACE_CALL();
247 std::lock_guard _lock{mVkLock};
Greg Danielc0732522019-02-20 08:31:03 -0500248
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400249 renderthread::VulkanManager* vkManager = getVulkanManager();
250 if (!vkManager->hasVkContext()) {
251 LOG_ALWAYS_FATAL_IF(mGrContext,
252 "GrContext exists with no VulkanManager for vulkan uploads");
253 vkManager->initialize();
254 }
Greg Danielc0732522019-02-20 08:31:03 -0500255
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400256 if (!mGrContext) {
257 GrContextOptions options;
258 mGrContext = vkManager->createContext(options,
259 renderthread::VulkanManager::ContextType::kUploadThread);
260 LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads");
261 this->postIdleTimeoutCheck();
262 }
263
264 sk_sp<SkImage> image =
265 SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(), ahb);
266 mGrContext->submit(true);
267
268 uploadSucceeded = (image.get() != nullptr);
269 });
270 return uploadSucceeded;
271 }
272
273 /* must be called on the upload thread after the vkLock has been acquired */
274 renderthread::VulkanManager* getVulkanManager() {
275 if (!mVulkanManagerStrong) {
276 mVulkanManagerStrong = mVulkanManagerWeak.promote();
277
278 // create a new manager if we couldn't promote the weak ref
279 if (!mVulkanManagerStrong) {
280 mVulkanManagerStrong = renderthread::VulkanManager::getInstance();
281 mGrContext.reset();
282 mVulkanManagerWeak = mVulkanManagerStrong;
283 }
284 }
285
286 return mVulkanManagerStrong.get();
Greg Danielc0732522019-02-20 08:31:03 -0500287 }
288
Adlai Hollerf8c434e2020-07-27 11:42:45 -0400289 sk_sp<GrDirectContext> mGrContext;
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400290 sp<renderthread::VulkanManager> mVulkanManagerStrong;
291 wp<renderthread::VulkanManager> mVulkanManagerWeak;
Greg Danielc0732522019-02-20 08:31:03 -0500292 std::mutex mVkLock;
293};
John Recke170fb62018-05-07 08:12:07 -0700294
Alec Mouri1efd0a52022-01-20 13:58:23 -0800295static bool checkSupport(AHardwareBuffer_Format format) {
296 AHardwareBuffer_Desc desc = {
297 .width = 1,
298 .height = 1,
299 .layers = 1,
300 .format = format,
301 .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
302 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
303 };
304 UniqueAHardwareBuffer buffer = allocateAHardwareBuffer(desc);
305 return buffer != nullptr;
306}
307
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500308bool HardwareBitmapUploader::hasFP16Support() {
Alec Mouri1efd0a52022-01-20 13:58:23 -0800309 static bool hasFP16Support = checkSupport(AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT);
John Recke170fb62018-05-07 08:12:07 -0700310 return hasFP16Support;
311}
312
Alec Mouri1efd0a52022-01-20 13:58:23 -0800313bool HardwareBitmapUploader::has1010102Support() {
314 static bool has101012Support = checkSupport(AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM);
315 return has101012Support;
316}
317
Leon Scroggins IIIa008aa92022-03-10 16:25:30 -0500318bool HardwareBitmapUploader::hasAlpha8Support() {
319 static bool hasAlpha8Support = checkSupport(AHARDWAREBUFFER_FORMAT_R8_UNORM);
320 return hasAlpha8Support;
321}
322
Greg Danielc0732522019-02-20 08:31:03 -0500323static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
John Recke170fb62018-05-07 08:12:07 -0700324 FormatInfo formatInfo;
John Recke170fb62018-05-07 08:12:07 -0700325 switch (skBitmap.info().colorType()) {
326 case kRGBA_8888_SkColorType:
327 formatInfo.isSupported = true;
Colin Crossf4e74b82019-10-31 13:47:42 -0700328 [[fallthrough]];
John Recke170fb62018-05-07 08:12:07 -0700329 // ARGB_4444 is upconverted to RGBA_8888
330 case kARGB_4444_SkColorType:
Alec Mouri45238012020-01-29 11:04:40 -0800331 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700332 formatInfo.format = GL_RGBA;
333 formatInfo.type = GL_UNSIGNED_BYTE;
Greg Danielc0732522019-02-20 08:31:03 -0500334 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700335 break;
336 case kRGBA_F16_SkColorType:
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500337 formatInfo.isSupported = HardwareBitmapUploader::hasFP16Support();
John Recke170fb62018-05-07 08:12:07 -0700338 if (formatInfo.isSupported) {
339 formatInfo.type = GL_HALF_FLOAT;
Alec Mouri45238012020-01-29 11:04:40 -0800340 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
Greg Danielc0732522019-02-20 08:31:03 -0500341 formatInfo.vkFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
John Recke170fb62018-05-07 08:12:07 -0700342 } else {
343 formatInfo.type = GL_UNSIGNED_BYTE;
Alec Mouri45238012020-01-29 11:04:40 -0800344 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
Greg Danielc0732522019-02-20 08:31:03 -0500345 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700346 }
347 formatInfo.format = GL_RGBA;
348 break;
349 case kRGB_565_SkColorType:
350 formatInfo.isSupported = true;
Alec Mouri45238012020-01-29 11:04:40 -0800351 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700352 formatInfo.format = GL_RGB;
353 formatInfo.type = GL_UNSIGNED_SHORT_5_6_5;
Greg Danielc0732522019-02-20 08:31:03 -0500354 formatInfo.vkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;
John Recke170fb62018-05-07 08:12:07 -0700355 break;
356 case kGray_8_SkColorType:
Greg Danielc0732522019-02-20 08:31:03 -0500357 formatInfo.isSupported = usingGL;
Alec Mouri45238012020-01-29 11:04:40 -0800358 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700359 formatInfo.format = GL_LUMINANCE;
360 formatInfo.type = GL_UNSIGNED_BYTE;
Greg Danielc0732522019-02-20 08:31:03 -0500361 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700362 break;
Alec Mouri1efd0a52022-01-20 13:58:23 -0800363 case kRGBA_1010102_SkColorType:
364 formatInfo.isSupported = HardwareBitmapUploader::has1010102Support();
365 if (formatInfo.isSupported) {
366 formatInfo.type = GL_UNSIGNED_INT_2_10_10_10_REV;
367 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
368 formatInfo.vkFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
369 } else {
370 formatInfo.type = GL_UNSIGNED_BYTE;
371 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
372 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
373 }
374 formatInfo.format = GL_RGBA;
375 break;
Leon Scroggins IIIa008aa92022-03-10 16:25:30 -0500376 case kAlpha_8_SkColorType:
377 formatInfo.isSupported = HardwareBitmapUploader::hasAlpha8Support();
378 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8_UNORM;
379 formatInfo.format = GL_R8;
380 formatInfo.type = GL_UNSIGNED_BYTE;
381 formatInfo.vkFormat = VK_FORMAT_R8_UNORM;
382 break;
John Recke170fb62018-05-07 08:12:07 -0700383 default:
384 ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
385 formatInfo.valid = false;
386 }
387 return formatInfo;
388}
389
390static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& source) {
391 if (format.isSupported) {
392 return source;
393 } else {
394 SkBitmap bitmap;
Mike Reed7994a312021-01-28 18:06:26 -0500395 bitmap.allocPixels(source.info().makeColorType(kN32_SkColorType));
396 bitmap.writePixels(source.pixmap());
John Recke170fb62018-05-07 08:12:07 -0700397 return bitmap;
398 }
399}
400
Greg Danielc0732522019-02-20 08:31:03 -0500401
402static void createUploader(bool usingGL) {
403 static std::mutex lock;
404 std::lock_guard _lock{lock};
405 if (!sUploader.get()) {
406 if (usingGL) {
407 sUploader = new EGLUploader();
408 } else {
409 sUploader = new VkUploader();
410 }
411 }
412}
John Recke170fb62018-05-07 08:12:07 -0700413
414sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sourceBitmap) {
415 ATRACE_CALL();
416
Greg Danielc0732522019-02-20 08:31:03 -0500417 bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
418 uirenderer::RenderPipelineType::SkiaGL;
419
420 FormatInfo format = determineFormat(sourceBitmap, usingGL);
John Recke170fb62018-05-07 08:12:07 -0700421 if (!format.valid) {
422 return nullptr;
423 }
424
John Recke170fb62018-05-07 08:12:07 -0700425 SkBitmap bitmap = makeHwCompatible(format, sourceBitmap);
Alec Mouri45238012020-01-29 11:04:40 -0800426 AHardwareBuffer_Desc desc = {
427 .width = static_cast<uint32_t>(bitmap.width()),
428 .height = static_cast<uint32_t>(bitmap.height()),
429 .layers = 1,
430 .format = format.bufferFormat,
431 .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
432 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
433 };
434 UniqueAHardwareBuffer ahb = allocateAHardwareBuffer(desc);
435 if (!ahb) {
436 ALOGW("allocateHardwareBitmap() failed in AHardwareBuffer_allocate()");
John Recke170fb62018-05-07 08:12:07 -0700437 return nullptr;
Alec Mouri45238012020-01-29 11:04:40 -0800438 };
John Recke170fb62018-05-07 08:12:07 -0700439
Greg Danielc0732522019-02-20 08:31:03 -0500440 createUploader(usingGL);
John Recke170fb62018-05-07 08:12:07 -0700441
Alec Mouri45238012020-01-29 11:04:40 -0800442 if (!sUploader->uploadHardwareBitmap(bitmap, format, ahb.get())) {
John Recke170fb62018-05-07 08:12:07 -0700443 return nullptr;
444 }
Alec Mouri45238012020-01-29 11:04:40 -0800445 return Bitmap::createFrom(ahb.get(), bitmap.colorType(), bitmap.refColorSpace(),
446 bitmap.alphaType(), Bitmap::computePalette(bitmap));
John Recke170fb62018-05-07 08:12:07 -0700447}
448
Greg Danielc0732522019-02-20 08:31:03 -0500449void HardwareBitmapUploader::initialize() {
450 bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
451 uirenderer::RenderPipelineType::SkiaGL;
452 createUploader(usingGL);
Greg Danielc0732522019-02-20 08:31:03 -0500453}
454
John Reck6104cea2019-01-10 14:37:17 -0800455void HardwareBitmapUploader::terminate() {
Greg Daniel78b7ddc2019-03-27 12:52:43 -0400456 if (sUploader) {
457 sUploader->destroy();
458 }
John Reck6104cea2019-01-10 14:37:17 -0800459}
460
Chris Blume7b8a8082018-11-30 15:51:58 -0800461} // namespace android::uirenderer