blob: 7fc37769d9adf36e3b3647ef2d148adf6ca6711f [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 Lubickcae0b212023-09-12 18:33:10 +000025#include <GrTypes.h>
Kevin Lubick1175dc02022-02-28 12:41:27 -050026#include <SkBitmap.h>
John Recke170fb62018-05-07 08:12:07 -070027#include <SkCanvas.h>
Greg Danielc0732522019-02-20 08:31:03 -050028#include <SkImage.h>
Kevin Lubickdd8b2ea2023-03-17 19:55:58 +000029#include <SkImageAndroid.h>
Kevin Lubick1175dc02022-02-28 12:41:27 -050030#include <SkImageInfo.h>
31#include <SkRefCnt.h>
rnleece9762b2021-05-21 15:40:53 -070032#include <gui/TraceUtils.h>
John Recke170fb62018-05-07 08:12:07 -070033#include <utils/GLUtils.h>
Alec Mouri45238012020-01-29 11:04:40 -080034#include <utils/NdkUtils.h>
John Recke170fb62018-05-07 08:12:07 -070035#include <utils/Trace.h>
Alec Mouri45238012020-01-29 11:04:40 -080036
John Recke170fb62018-05-07 08:12:07 -070037#include <thread>
38
Alec Mouri45238012020-01-29 11:04:40 -080039#include "hwui/Bitmap.h"
40#include "renderthread/EglManager.h"
41#include "renderthread/VulkanManager.h"
42#include "thread/ThreadBase.h"
43#include "utils/TimeUtils.h"
44
John Recke170fb62018-05-07 08:12:07 -070045namespace android::uirenderer {
46
John Reck5f66fb82022-09-23 17:49:23 -040047static constexpr auto kThreadTimeout = 60000_ms;
48
Greg Danielc0732522019-02-20 08:31:03 -050049class AHBUploader;
50// This helper uploader classes allows us to upload using either EGL or Vulkan using the same
51// interface.
52static sp<AHBUploader> sUploader = nullptr;
John Recke170fb62018-05-07 08:12:07 -070053
Greg Danielc0732522019-02-20 08:31:03 -050054struct FormatInfo {
Alec Mouri45238012020-01-29 11:04:40 -080055 AHardwareBuffer_Format bufferFormat;
Greg Danielc0732522019-02-20 08:31:03 -050056 GLint format, type;
57 VkFormat vkFormat;
58 bool isSupported = false;
59 bool valid = true;
60};
John Recke170fb62018-05-07 08:12:07 -070061
Greg Danielc0732522019-02-20 08:31:03 -050062class AHBUploader : public RefBase {
63public:
64 virtual ~AHBUploader() {}
John Recke170fb62018-05-07 08:12:07 -070065
Greg Danielc0732522019-02-20 08:31:03 -050066 void destroy() {
67 std::lock_guard _lock{mLock};
68 LOG_ALWAYS_FATAL_IF(mPendingUploads, "terminate called while uploads in progress");
69 if (mUploadThread) {
70 mUploadThread->requestExit();
71 mUploadThread->join();
72 mUploadThread = nullptr;
73 }
74 onDestroy();
John Recke170fb62018-05-07 08:12:07 -070075 }
76
Greg Danielc0732522019-02-20 08:31:03 -050077 bool uploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -080078 AHardwareBuffer* ahb) {
Greg Danielc0732522019-02-20 08:31:03 -050079 ATRACE_CALL();
80 beginUpload();
Alec Mouri45238012020-01-29 11:04:40 -080081 bool result = onUploadHardwareBitmap(bitmap, format, ahb);
Greg Danielc0732522019-02-20 08:31:03 -050082 endUpload();
83 return result;
84 }
85
86 void postIdleTimeoutCheck() {
John Reck5f66fb82022-09-23 17:49:23 -040087 mUploadThread->queue().postDelayed(kThreadTimeout, [this]() { this->idleTimeoutCheck(); });
Greg Danielc0732522019-02-20 08:31:03 -050088 }
89
90protected:
91 std::mutex mLock;
92 sp<ThreadBase> mUploadThread = nullptr;
93
94private:
Greg Danielc0732522019-02-20 08:31:03 -050095 virtual void onIdle() = 0;
96 virtual void onDestroy() = 0;
97
98 virtual bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -080099 AHardwareBuffer* ahb) = 0;
Greg Danielc0732522019-02-20 08:31:03 -0500100 virtual void onBeginUpload() = 0;
101
102 bool shouldTimeOutLocked() {
103 nsecs_t durationSince = systemTime() - mLastUpload;
John Reck5f66fb82022-09-23 17:49:23 -0400104 return durationSince > kThreadTimeout;
Greg Danielc0732522019-02-20 08:31:03 -0500105 }
106
107 void idleTimeoutCheck() {
108 std::lock_guard _lock{mLock};
109 if (mPendingUploads == 0 && shouldTimeOutLocked()) {
110 onIdle();
111 } else {
112 this->postIdleTimeoutCheck();
113 }
114 }
115
116 void beginUpload() {
117 std::lock_guard _lock{mLock};
118 mPendingUploads++;
119
120 if (!mUploadThread) {
121 mUploadThread = new ThreadBase{};
122 }
123 if (!mUploadThread->isRunning()) {
124 mUploadThread->start("GrallocUploadThread");
125 }
126
127 onBeginUpload();
128 }
129
130 void endUpload() {
131 std::lock_guard _lock{mLock};
132 mPendingUploads--;
133 mLastUpload = systemTime();
134 }
135
136 int mPendingUploads = 0;
137 nsecs_t mLastUpload = 0;
138};
139
140#define FENCE_TIMEOUT 2000000000
141
142class EGLUploader : public AHBUploader {
143private:
Greg Danielc0732522019-02-20 08:31:03 -0500144 void onDestroy() override {
145 mEglManager.destroy();
146 }
147 void onIdle() override {
148 mEglManager.destroy();
149 }
150
151 void onBeginUpload() override {
152 if (!mEglManager.hasEglContext()) {
153 mUploadThread->queue().runSync([this]() {
154 this->mEglManager.initialize();
155 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
156 });
157
158 this->postIdleTimeoutCheck();
159 }
160 }
161
162
163 EGLDisplay getUploadEglDisplay() {
164 std::lock_guard _lock{mLock};
165 LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(), "Forgot to begin an upload?");
166 return mEglManager.eglDisplay();
167 }
168
169 bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -0800170 AHardwareBuffer* ahb) override {
Greg Danielc0732522019-02-20 08:31:03 -0500171 ATRACE_CALL();
172
173 EGLDisplay display = getUploadEglDisplay();
174
175 LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
176 uirenderer::renderthread::EglManager::eglErrorString());
Alec Mouri45238012020-01-29 11:04:40 -0800177 // We use an EGLImage to access the content of the buffer
Greg Danielc0732522019-02-20 08:31:03 -0500178 // The EGL image is later bound to a 2D texture
Alec Mouri70463a62020-03-30 15:10:17 -0700179 const EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(ahb);
Greg Danielc0732522019-02-20 08:31:03 -0500180 AutoEglImage autoImage(display, clientBuffer);
181 if (autoImage.image == EGL_NO_IMAGE_KHR) {
182 ALOGW("Could not create EGL image, err =%s",
183 uirenderer::renderthread::EglManager::eglErrorString());
184 return false;
185 }
186
187 {
188 ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
189 EGLSyncKHR fence = mUploadThread->queue().runSync([&]() -> EGLSyncKHR {
190 AutoSkiaGlTexture glTexture;
191 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
John Reck996773a2020-02-03 16:30:56 -0800192 if (GLUtils::dumpGLErrors()) {
193 return EGL_NO_SYNC_KHR;
194 }
Greg Danielc0732522019-02-20 08:31:03 -0500195
196 // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
197 // provide.
198 // But asynchronous in sense that driver may upload texture onto hardware buffer
199 // when we first use it in drawing
200 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
201 format.format, format.type, bitmap.getPixels());
John Reck996773a2020-02-03 16:30:56 -0800202 if (GLUtils::dumpGLErrors()) {
203 return EGL_NO_SYNC_KHR;
204 }
Greg Danielc0732522019-02-20 08:31:03 -0500205
206 EGLSyncKHR uploadFence =
207 eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
John Reck996773a2020-02-03 16:30:56 -0800208 if (uploadFence == EGL_NO_SYNC_KHR) {
209 ALOGW("Could not create sync fence %#x", eglGetError());
210 };
Greg Danielc0732522019-02-20 08:31:03 -0500211 glFlush();
John Reck996773a2020-02-03 16:30:56 -0800212 GLUtils::dumpGLErrors();
Greg Danielc0732522019-02-20 08:31:03 -0500213 return uploadFence;
214 });
215
John Reck996773a2020-02-03 16:30:56 -0800216 if (fence == EGL_NO_SYNC_KHR) {
217 return false;
218 }
Greg Danielc0732522019-02-20 08:31:03 -0500219 EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
John Reck996773a2020-02-03 16:30:56 -0800220 ALOGE_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
221 "Failed to wait for the fence %#x", eglGetError());
Greg Danielc0732522019-02-20 08:31:03 -0500222
223 eglDestroySyncKHR(display, fence);
224 }
225 return true;
226 }
227
228 renderthread::EglManager mEglManager;
229};
230
231class VkUploader : public AHBUploader {
232private:
Greg Danielc0732522019-02-20 08:31:03 -0500233 void onDestroy() override {
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400234 std::lock_guard _lock{mVkLock};
Greg Danielc0732522019-02-20 08:31:03 -0500235 mGrContext.reset();
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400236 mVulkanManagerStrong.clear();
Greg Danielc0732522019-02-20 08:31:03 -0500237 }
238 void onIdle() override {
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400239 onDestroy();
Greg Danielc0732522019-02-20 08:31:03 -0500240 }
John Recke170fb62018-05-07 08:12:07 -0700241
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400242 void onBeginUpload() override {}
John Recke170fb62018-05-07 08:12:07 -0700243
Greg Danielc0732522019-02-20 08:31:03 -0500244 bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -0800245 AHardwareBuffer* ahb) override {
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400246 bool uploadSucceeded = false;
247 mUploadThread->queue().runSync([this, &uploadSucceeded, bitmap, ahb]() {
248 ATRACE_CALL();
249 std::lock_guard _lock{mVkLock};
Greg Danielc0732522019-02-20 08:31:03 -0500250
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400251 renderthread::VulkanManager* vkManager = getVulkanManager();
252 if (!vkManager->hasVkContext()) {
253 LOG_ALWAYS_FATAL_IF(mGrContext,
254 "GrContext exists with no VulkanManager for vulkan uploads");
255 vkManager->initialize();
256 }
Greg Danielc0732522019-02-20 08:31:03 -0500257
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400258 if (!mGrContext) {
259 GrContextOptions options;
260 mGrContext = vkManager->createContext(options,
261 renderthread::VulkanManager::ContextType::kUploadThread);
262 LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads");
263 this->postIdleTimeoutCheck();
264 }
265
266 sk_sp<SkImage> image =
Kevin Lubickdd8b2ea2023-03-17 19:55:58 +0000267 SkImages::TextureFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(),
268 ahb);
Kevin Lubickcae0b212023-09-12 18:33:10 +0000269 mGrContext->submit(GrSyncCpu::kYes);
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400270
271 uploadSucceeded = (image.get() != nullptr);
272 });
273 return uploadSucceeded;
274 }
275
276 /* must be called on the upload thread after the vkLock has been acquired */
277 renderthread::VulkanManager* getVulkanManager() {
278 if (!mVulkanManagerStrong) {
279 mVulkanManagerStrong = mVulkanManagerWeak.promote();
280
281 // create a new manager if we couldn't promote the weak ref
282 if (!mVulkanManagerStrong) {
283 mVulkanManagerStrong = renderthread::VulkanManager::getInstance();
284 mGrContext.reset();
285 mVulkanManagerWeak = mVulkanManagerStrong;
286 }
287 }
288
289 return mVulkanManagerStrong.get();
Greg Danielc0732522019-02-20 08:31:03 -0500290 }
291
Adlai Hollerf8c434e2020-07-27 11:42:45 -0400292 sk_sp<GrDirectContext> mGrContext;
Derek Sollenberger802fefa2020-08-13 16:53:30 -0400293 sp<renderthread::VulkanManager> mVulkanManagerStrong;
294 wp<renderthread::VulkanManager> mVulkanManagerWeak;
Greg Danielc0732522019-02-20 08:31:03 -0500295 std::mutex mVkLock;
296};
John Recke170fb62018-05-07 08:12:07 -0700297
Alec Mouri1efd0a52022-01-20 13:58:23 -0800298static bool checkSupport(AHardwareBuffer_Format format) {
299 AHardwareBuffer_Desc desc = {
300 .width = 1,
301 .height = 1,
302 .layers = 1,
303 .format = format,
304 .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
305 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
306 };
307 UniqueAHardwareBuffer buffer = allocateAHardwareBuffer(desc);
308 return buffer != nullptr;
309}
310
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500311bool HardwareBitmapUploader::hasFP16Support() {
Alec Mouri1efd0a52022-01-20 13:58:23 -0800312 static bool hasFP16Support = checkSupport(AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT);
John Recke170fb62018-05-07 08:12:07 -0700313 return hasFP16Support;
314}
315
Alec Mouri1efd0a52022-01-20 13:58:23 -0800316bool HardwareBitmapUploader::has1010102Support() {
317 static bool has101012Support = checkSupport(AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM);
318 return has101012Support;
319}
320
Greg Daniele77ab7a2024-09-04 15:29:52 +0000321bool HardwareBitmapUploader::has10101010Support() {
322 static bool has1010110Support = checkSupport(AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM);
323 return has1010110Support;
324}
325
Leon Scroggins IIIa008aa92022-03-10 16:25:30 -0500326bool HardwareBitmapUploader::hasAlpha8Support() {
327 static bool hasAlpha8Support = checkSupport(AHARDWAREBUFFER_FORMAT_R8_UNORM);
328 return hasAlpha8Support;
329}
330
Greg Danielc0732522019-02-20 08:31:03 -0500331static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
John Recke170fb62018-05-07 08:12:07 -0700332 FormatInfo formatInfo;
John Recke170fb62018-05-07 08:12:07 -0700333 switch (skBitmap.info().colorType()) {
334 case kRGBA_8888_SkColorType:
335 formatInfo.isSupported = true;
Colin Crossf4e74b82019-10-31 13:47:42 -0700336 [[fallthrough]];
John Recke170fb62018-05-07 08:12:07 -0700337 // ARGB_4444 is upconverted to RGBA_8888
338 case kARGB_4444_SkColorType:
Alec Mouri45238012020-01-29 11:04:40 -0800339 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700340 formatInfo.format = GL_RGBA;
341 formatInfo.type = GL_UNSIGNED_BYTE;
Greg Danielc0732522019-02-20 08:31:03 -0500342 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700343 break;
344 case kRGBA_F16_SkColorType:
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500345 formatInfo.isSupported = HardwareBitmapUploader::hasFP16Support();
John Recke170fb62018-05-07 08:12:07 -0700346 if (formatInfo.isSupported) {
347 formatInfo.type = GL_HALF_FLOAT;
Alec Mouri45238012020-01-29 11:04:40 -0800348 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
Greg Danielc0732522019-02-20 08:31:03 -0500349 formatInfo.vkFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
John Recke170fb62018-05-07 08:12:07 -0700350 } else {
351 formatInfo.type = GL_UNSIGNED_BYTE;
Alec Mouri45238012020-01-29 11:04:40 -0800352 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
Greg Danielc0732522019-02-20 08:31:03 -0500353 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700354 }
355 formatInfo.format = GL_RGBA;
356 break;
357 case kRGB_565_SkColorType:
358 formatInfo.isSupported = true;
Alec Mouri45238012020-01-29 11:04:40 -0800359 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700360 formatInfo.format = GL_RGB;
361 formatInfo.type = GL_UNSIGNED_SHORT_5_6_5;
Greg Danielc0732522019-02-20 08:31:03 -0500362 formatInfo.vkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;
John Recke170fb62018-05-07 08:12:07 -0700363 break;
364 case kGray_8_SkColorType:
Greg Danielc0732522019-02-20 08:31:03 -0500365 formatInfo.isSupported = usingGL;
Alec Mouri45238012020-01-29 11:04:40 -0800366 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700367 formatInfo.format = GL_LUMINANCE;
368 formatInfo.type = GL_UNSIGNED_BYTE;
Greg Danielc0732522019-02-20 08:31:03 -0500369 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700370 break;
Alec Mouri1efd0a52022-01-20 13:58:23 -0800371 case kRGBA_1010102_SkColorType:
372 formatInfo.isSupported = HardwareBitmapUploader::has1010102Support();
373 if (formatInfo.isSupported) {
374 formatInfo.type = GL_UNSIGNED_INT_2_10_10_10_REV;
375 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
376 formatInfo.vkFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
377 } else {
378 formatInfo.type = GL_UNSIGNED_BYTE;
379 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
380 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
381 }
382 formatInfo.format = GL_RGBA;
383 break;
Greg Daniele77ab7a2024-09-04 15:29:52 +0000384 case kRGBA_10x6_SkColorType:
385 formatInfo.isSupported = HardwareBitmapUploader::has10101010Support();
386 if (formatInfo.isSupported) {
387 formatInfo.type = 0; // Not supported in GL
388 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM;
389 formatInfo.vkFormat = VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16;
390 } else {
391 formatInfo.type = GL_UNSIGNED_BYTE;
392 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
393 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
394 }
395 formatInfo.format = 0; // Not supported in GL
396 break;
Leon Scroggins IIIa008aa92022-03-10 16:25:30 -0500397 case kAlpha_8_SkColorType:
398 formatInfo.isSupported = HardwareBitmapUploader::hasAlpha8Support();
John Reck41ed6712024-02-15 18:26:00 -0500399 if (formatInfo.isSupported) {
400 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8_UNORM;
401 formatInfo.format = GL_RED;
402 formatInfo.type = GL_UNSIGNED_BYTE;
403 formatInfo.vkFormat = VK_FORMAT_R8_UNORM;
404 } else {
405 formatInfo.type = GL_UNSIGNED_BYTE;
406 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
407 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
408 formatInfo.format = GL_RGBA;
409 }
Leon Scroggins IIIa008aa92022-03-10 16:25:30 -0500410 break;
John Recke170fb62018-05-07 08:12:07 -0700411 default:
412 ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
413 formatInfo.valid = false;
414 }
415 return formatInfo;
416}
417
418static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& source) {
419 if (format.isSupported) {
420 return source;
421 } else {
422 SkBitmap bitmap;
Mike Reed7994a312021-01-28 18:06:26 -0500423 bitmap.allocPixels(source.info().makeColorType(kN32_SkColorType));
424 bitmap.writePixels(source.pixmap());
John Recke170fb62018-05-07 08:12:07 -0700425 return bitmap;
426 }
427}
428
Greg Danielc0732522019-02-20 08:31:03 -0500429
430static void createUploader(bool usingGL) {
431 static std::mutex lock;
432 std::lock_guard _lock{lock};
433 if (!sUploader.get()) {
434 if (usingGL) {
435 sUploader = new EGLUploader();
436 } else {
437 sUploader = new VkUploader();
438 }
439 }
440}
John Recke170fb62018-05-07 08:12:07 -0700441
442sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sourceBitmap) {
443 ATRACE_CALL();
444
Greg Danielc0732522019-02-20 08:31:03 -0500445 bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
446 uirenderer::RenderPipelineType::SkiaGL;
447
448 FormatInfo format = determineFormat(sourceBitmap, usingGL);
John Recke170fb62018-05-07 08:12:07 -0700449 if (!format.valid) {
450 return nullptr;
451 }
452
John Recke170fb62018-05-07 08:12:07 -0700453 SkBitmap bitmap = makeHwCompatible(format, sourceBitmap);
Alec Mouri45238012020-01-29 11:04:40 -0800454 AHardwareBuffer_Desc desc = {
455 .width = static_cast<uint32_t>(bitmap.width()),
456 .height = static_cast<uint32_t>(bitmap.height()),
457 .layers = 1,
458 .format = format.bufferFormat,
459 .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
460 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
461 };
462 UniqueAHardwareBuffer ahb = allocateAHardwareBuffer(desc);
463 if (!ahb) {
464 ALOGW("allocateHardwareBitmap() failed in AHardwareBuffer_allocate()");
John Recke170fb62018-05-07 08:12:07 -0700465 return nullptr;
Alec Mouri45238012020-01-29 11:04:40 -0800466 };
John Recke170fb62018-05-07 08:12:07 -0700467
Greg Danielc0732522019-02-20 08:31:03 -0500468 createUploader(usingGL);
John Recke170fb62018-05-07 08:12:07 -0700469
Alec Mouri45238012020-01-29 11:04:40 -0800470 if (!sUploader->uploadHardwareBitmap(bitmap, format, ahb.get())) {
John Recke170fb62018-05-07 08:12:07 -0700471 return nullptr;
472 }
Alec Mouri45238012020-01-29 11:04:40 -0800473 return Bitmap::createFrom(ahb.get(), bitmap.colorType(), bitmap.refColorSpace(),
474 bitmap.alphaType(), Bitmap::computePalette(bitmap));
John Recke170fb62018-05-07 08:12:07 -0700475}
476
Greg Danielc0732522019-02-20 08:31:03 -0500477void HardwareBitmapUploader::initialize() {
478 bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
479 uirenderer::RenderPipelineType::SkiaGL;
480 createUploader(usingGL);
Greg Danielc0732522019-02-20 08:31:03 -0500481}
482
John Reck6104cea2019-01-10 14:37:17 -0800483void HardwareBitmapUploader::terminate() {
Greg Daniel78b7ddc2019-03-27 12:52:43 -0400484 if (sUploader) {
485 sUploader->destroy();
486 }
John Reck6104cea2019-01-10 14:37:17 -0800487}
488
Chris Blume7b8a8082018-11-30 15:51:58 -0800489} // namespace android::uirenderer