blob: be8f852ecf1b436cd7092dfc2894ffc00e72dd27 [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>
Greg Danielc0732522019-02-20 08:31:03 -050024#include <GrContext.h>
John Recke170fb62018-05-07 08:12:07 -070025#include <SkCanvas.h>
Greg Danielc0732522019-02-20 08:31:03 -050026#include <SkImage.h>
Alec Mouri45238012020-01-29 11:04:40 -080027#include <private/android/AHardwareBufferHelpers.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>
31#include <utils/TraceUtils.h>
Alec Mouri45238012020-01-29 11:04:40 -080032
John Recke170fb62018-05-07 08:12:07 -070033#include <thread>
34
Alec Mouri45238012020-01-29 11:04:40 -080035#include "hwui/Bitmap.h"
36#include "renderthread/EglManager.h"
37#include "renderthread/VulkanManager.h"
38#include "thread/ThreadBase.h"
39#include "utils/TimeUtils.h"
40
John Recke170fb62018-05-07 08:12:07 -070041namespace android::uirenderer {
42
Greg Danielc0732522019-02-20 08:31:03 -050043class AHBUploader;
44// This helper uploader classes allows us to upload using either EGL or Vulkan using the same
45// interface.
46static sp<AHBUploader> sUploader = nullptr;
John Recke170fb62018-05-07 08:12:07 -070047
Greg Danielc0732522019-02-20 08:31:03 -050048struct FormatInfo {
Alec Mouri45238012020-01-29 11:04:40 -080049 AHardwareBuffer_Format bufferFormat;
Greg Danielc0732522019-02-20 08:31:03 -050050 GLint format, type;
51 VkFormat vkFormat;
52 bool isSupported = false;
53 bool valid = true;
54};
John Recke170fb62018-05-07 08:12:07 -070055
Greg Danielc0732522019-02-20 08:31:03 -050056class AHBUploader : public RefBase {
57public:
58 virtual ~AHBUploader() {}
John Recke170fb62018-05-07 08:12:07 -070059
Greg Danielc0732522019-02-20 08:31:03 -050060 // Called to start creation of the Vulkan and EGL contexts on another thread before we actually
61 // need to do an upload.
62 void initialize() {
63 onInitialize();
John Recke170fb62018-05-07 08:12:07 -070064 }
65
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() {
87 mUploadThread->queue().postDelayed(5000_ms, [this](){ this->idleTimeoutCheck(); });
88 }
89
90protected:
91 std::mutex mLock;
92 sp<ThreadBase> mUploadThread = nullptr;
93
94private:
95 virtual void onInitialize() = 0;
96 virtual void onIdle() = 0;
97 virtual void onDestroy() = 0;
98
99 virtual bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -0800100 AHardwareBuffer* ahb) = 0;
Greg Danielc0732522019-02-20 08:31:03 -0500101 virtual void onBeginUpload() = 0;
102
103 bool shouldTimeOutLocked() {
104 nsecs_t durationSince = systemTime() - mLastUpload;
105 return durationSince > 2000_ms;
106 }
107
108 void idleTimeoutCheck() {
109 std::lock_guard _lock{mLock};
110 if (mPendingUploads == 0 && shouldTimeOutLocked()) {
111 onIdle();
112 } else {
113 this->postIdleTimeoutCheck();
114 }
115 }
116
117 void beginUpload() {
118 std::lock_guard _lock{mLock};
119 mPendingUploads++;
120
121 if (!mUploadThread) {
122 mUploadThread = new ThreadBase{};
123 }
124 if (!mUploadThread->isRunning()) {
125 mUploadThread->start("GrallocUploadThread");
126 }
127
128 onBeginUpload();
129 }
130
131 void endUpload() {
132 std::lock_guard _lock{mLock};
133 mPendingUploads--;
134 mLastUpload = systemTime();
135 }
136
137 int mPendingUploads = 0;
138 nsecs_t mLastUpload = 0;
139};
140
141#define FENCE_TIMEOUT 2000000000
142
143class EGLUploader : public AHBUploader {
144private:
145 void onInitialize() override {}
146 void onDestroy() override {
147 mEglManager.destroy();
148 }
149 void onIdle() override {
150 mEglManager.destroy();
151 }
152
153 void onBeginUpload() override {
154 if (!mEglManager.hasEglContext()) {
155 mUploadThread->queue().runSync([this]() {
156 this->mEglManager.initialize();
157 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
158 });
159
160 this->postIdleTimeoutCheck();
161 }
162 }
163
164
165 EGLDisplay getUploadEglDisplay() {
166 std::lock_guard _lock{mLock};
167 LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(), "Forgot to begin an upload?");
168 return mEglManager.eglDisplay();
169 }
170
171 bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -0800172 AHardwareBuffer* ahb) override {
Greg Danielc0732522019-02-20 08:31:03 -0500173 ATRACE_CALL();
174
175 EGLDisplay display = getUploadEglDisplay();
176
177 LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
178 uirenderer::renderthread::EglManager::eglErrorString());
Alec Mouri45238012020-01-29 11:04:40 -0800179 // We use an EGLImage to access the content of the buffer
Greg Danielc0732522019-02-20 08:31:03 -0500180 // The EGL image is later bound to a 2D texture
Alec Mouri45238012020-01-29 11:04:40 -0800181 EGLClientBuffer clientBuffer = (EGLClientBuffer)AHardwareBuffer_to_ANativeWindowBuffer(ahb);
Greg Danielc0732522019-02-20 08:31:03 -0500182 AutoEglImage autoImage(display, clientBuffer);
183 if (autoImage.image == EGL_NO_IMAGE_KHR) {
184 ALOGW("Could not create EGL image, err =%s",
185 uirenderer::renderthread::EglManager::eglErrorString());
186 return false;
187 }
188
189 {
190 ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
191 EGLSyncKHR fence = mUploadThread->queue().runSync([&]() -> EGLSyncKHR {
192 AutoSkiaGlTexture glTexture;
193 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
John Reck996773a2020-02-03 16:30:56 -0800194 if (GLUtils::dumpGLErrors()) {
195 return EGL_NO_SYNC_KHR;
196 }
Greg Danielc0732522019-02-20 08:31:03 -0500197
198 // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
199 // provide.
200 // But asynchronous in sense that driver may upload texture onto hardware buffer
201 // when we first use it in drawing
202 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
203 format.format, format.type, bitmap.getPixels());
John Reck996773a2020-02-03 16:30:56 -0800204 if (GLUtils::dumpGLErrors()) {
205 return EGL_NO_SYNC_KHR;
206 }
Greg Danielc0732522019-02-20 08:31:03 -0500207
208 EGLSyncKHR uploadFence =
209 eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
John Reck996773a2020-02-03 16:30:56 -0800210 if (uploadFence == EGL_NO_SYNC_KHR) {
211 ALOGW("Could not create sync fence %#x", eglGetError());
212 };
Greg Danielc0732522019-02-20 08:31:03 -0500213 glFlush();
John Reck996773a2020-02-03 16:30:56 -0800214 GLUtils::dumpGLErrors();
Greg Danielc0732522019-02-20 08:31:03 -0500215 return uploadFence;
216 });
217
John Reck996773a2020-02-03 16:30:56 -0800218 if (fence == EGL_NO_SYNC_KHR) {
219 return false;
220 }
Greg Danielc0732522019-02-20 08:31:03 -0500221 EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
John Reck996773a2020-02-03 16:30:56 -0800222 ALOGE_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
223 "Failed to wait for the fence %#x", eglGetError());
Greg Danielc0732522019-02-20 08:31:03 -0500224
225 eglDestroySyncKHR(display, fence);
226 }
227 return true;
228 }
229
230 renderthread::EglManager mEglManager;
231};
232
233class VkUploader : public AHBUploader {
234private:
235 void onInitialize() override {
236 std::lock_guard _lock{mLock};
237 if (!mUploadThread) {
238 mUploadThread = new ThreadBase{};
239 }
240 if (!mUploadThread->isRunning()) {
241 mUploadThread->start("GrallocUploadThread");
242 }
243
244 mUploadThread->queue().post([this]() {
245 std::lock_guard _lock{mVkLock};
246 if (!mVulkanManager.hasVkContext()) {
247 mVulkanManager.initialize();
248 }
John Recke170fb62018-05-07 08:12:07 -0700249 });
John Recke170fb62018-05-07 08:12:07 -0700250 }
Greg Danielc0732522019-02-20 08:31:03 -0500251 void onDestroy() override {
252 mGrContext.reset();
253 mVulkanManager.destroy();
254 }
255 void onIdle() override {
256 mGrContext.reset();
257 }
John Recke170fb62018-05-07 08:12:07 -0700258
Greg Danielc0732522019-02-20 08:31:03 -0500259 void onBeginUpload() override {
260 {
261 std::lock_guard _lock{mVkLock};
262 if (!mVulkanManager.hasVkContext()) {
263 LOG_ALWAYS_FATAL_IF(mGrContext,
264 "GrContext exists with no VulkanManager for vulkan uploads");
265 mUploadThread->queue().runSync([this]() {
266 mVulkanManager.initialize();
267 });
268 }
269 }
270 if (!mGrContext) {
271 GrContextOptions options;
272 mGrContext = mVulkanManager.createContext(options);
273 LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads");
274 this->postIdleTimeoutCheck();
275 }
276 }
John Recke170fb62018-05-07 08:12:07 -0700277
Greg Danielc0732522019-02-20 08:31:03 -0500278 bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
Alec Mouri45238012020-01-29 11:04:40 -0800279 AHardwareBuffer* ahb) override {
Greg Danielc0732522019-02-20 08:31:03 -0500280 ATRACE_CALL();
281
282 std::lock_guard _lock{mLock};
283
Alec Mouri45238012020-01-29 11:04:40 -0800284 sk_sp<SkImage> image =
285 SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(), ahb);
Greg Danielc0732522019-02-20 08:31:03 -0500286 return (image.get() != nullptr);
287 }
288
289 sk_sp<GrContext> mGrContext;
290 renderthread::VulkanManager mVulkanManager;
291 std::mutex mVkLock;
292};
John Recke170fb62018-05-07 08:12:07 -0700293
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500294bool HardwareBitmapUploader::hasFP16Support() {
John Recke170fb62018-05-07 08:12:07 -0700295 static std::once_flag sOnce;
296 static bool hasFP16Support = false;
297
298 // Gralloc shouldn't let us create a USAGE_HW_TEXTURE if GLES is unable to consume it, so
299 // we don't need to double-check the GLES version/extension.
300 std::call_once(sOnce, []() {
Alec Mouri45238012020-01-29 11:04:40 -0800301 AHardwareBuffer_Desc desc = {
302 .width = 1,
303 .height = 1,
304 .layers = 1,
305 .format = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT,
306 .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER |
307 AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
308 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
309 };
310 UniqueAHardwareBuffer buffer = allocateAHardwareBuffer(desc);
311 hasFP16Support = buffer != nullptr;
John Recke170fb62018-05-07 08:12:07 -0700312 });
313
314 return hasFP16Support;
315}
316
Greg Danielc0732522019-02-20 08:31:03 -0500317static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
John Recke170fb62018-05-07 08:12:07 -0700318 FormatInfo formatInfo;
John Recke170fb62018-05-07 08:12:07 -0700319 switch (skBitmap.info().colorType()) {
320 case kRGBA_8888_SkColorType:
321 formatInfo.isSupported = true;
Colin Crossf4e74b82019-10-31 13:47:42 -0700322 [[fallthrough]];
John Recke170fb62018-05-07 08:12:07 -0700323 // ARGB_4444 is upconverted to RGBA_8888
324 case kARGB_4444_SkColorType:
Alec Mouri45238012020-01-29 11:04:40 -0800325 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700326 formatInfo.format = GL_RGBA;
327 formatInfo.type = GL_UNSIGNED_BYTE;
Greg Danielc0732522019-02-20 08:31:03 -0500328 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700329 break;
330 case kRGBA_F16_SkColorType:
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500331 formatInfo.isSupported = HardwareBitmapUploader::hasFP16Support();
John Recke170fb62018-05-07 08:12:07 -0700332 if (formatInfo.isSupported) {
333 formatInfo.type = GL_HALF_FLOAT;
Alec Mouri45238012020-01-29 11:04:40 -0800334 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
Greg Danielc0732522019-02-20 08:31:03 -0500335 formatInfo.vkFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
John Recke170fb62018-05-07 08:12:07 -0700336 } else {
337 formatInfo.type = GL_UNSIGNED_BYTE;
Alec Mouri45238012020-01-29 11:04:40 -0800338 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
Greg Danielc0732522019-02-20 08:31:03 -0500339 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700340 }
341 formatInfo.format = GL_RGBA;
342 break;
343 case kRGB_565_SkColorType:
344 formatInfo.isSupported = true;
Alec Mouri45238012020-01-29 11:04:40 -0800345 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700346 formatInfo.format = GL_RGB;
347 formatInfo.type = GL_UNSIGNED_SHORT_5_6_5;
Greg Danielc0732522019-02-20 08:31:03 -0500348 formatInfo.vkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;
John Recke170fb62018-05-07 08:12:07 -0700349 break;
350 case kGray_8_SkColorType:
Greg Danielc0732522019-02-20 08:31:03 -0500351 formatInfo.isSupported = usingGL;
Alec Mouri45238012020-01-29 11:04:40 -0800352 formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700353 formatInfo.format = GL_LUMINANCE;
354 formatInfo.type = GL_UNSIGNED_BYTE;
Greg Danielc0732522019-02-20 08:31:03 -0500355 formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
John Recke170fb62018-05-07 08:12:07 -0700356 break;
357 default:
358 ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
359 formatInfo.valid = false;
360 }
361 return formatInfo;
362}
363
364static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& source) {
365 if (format.isSupported) {
366 return source;
367 } else {
368 SkBitmap bitmap;
369 const SkImageInfo& info = source.info();
Greg Daniel78b7ddc2019-03-27 12:52:43 -0400370 bitmap.allocPixels(info.makeColorType(kN32_SkColorType));
Derek Sollenberger6e35e632019-01-22 13:56:25 -0500371
372 SkCanvas canvas(bitmap);
373 canvas.drawColor(0);
374 canvas.drawBitmap(source, 0.0f, 0.0f, nullptr);
375
John Recke170fb62018-05-07 08:12:07 -0700376 return bitmap;
377 }
378}
379
Greg Danielc0732522019-02-20 08:31:03 -0500380
381static void createUploader(bool usingGL) {
382 static std::mutex lock;
383 std::lock_guard _lock{lock};
384 if (!sUploader.get()) {
385 if (usingGL) {
386 sUploader = new EGLUploader();
387 } else {
388 sUploader = new VkUploader();
389 }
390 }
391}
John Recke170fb62018-05-07 08:12:07 -0700392
393sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sourceBitmap) {
394 ATRACE_CALL();
395
Greg Danielc0732522019-02-20 08:31:03 -0500396 bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
397 uirenderer::RenderPipelineType::SkiaGL;
398
399 FormatInfo format = determineFormat(sourceBitmap, usingGL);
John Recke170fb62018-05-07 08:12:07 -0700400 if (!format.valid) {
401 return nullptr;
402 }
403
John Recke170fb62018-05-07 08:12:07 -0700404 SkBitmap bitmap = makeHwCompatible(format, sourceBitmap);
Alec Mouri45238012020-01-29 11:04:40 -0800405 AHardwareBuffer_Desc desc = {
406 .width = static_cast<uint32_t>(bitmap.width()),
407 .height = static_cast<uint32_t>(bitmap.height()),
408 .layers = 1,
409 .format = format.bufferFormat,
410 .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
411 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
412 };
413 UniqueAHardwareBuffer ahb = allocateAHardwareBuffer(desc);
414 if (!ahb) {
415 ALOGW("allocateHardwareBitmap() failed in AHardwareBuffer_allocate()");
John Recke170fb62018-05-07 08:12:07 -0700416 return nullptr;
Alec Mouri45238012020-01-29 11:04:40 -0800417 };
John Recke170fb62018-05-07 08:12:07 -0700418
Greg Danielc0732522019-02-20 08:31:03 -0500419 createUploader(usingGL);
John Recke170fb62018-05-07 08:12:07 -0700420
Alec Mouri45238012020-01-29 11:04:40 -0800421 if (!sUploader->uploadHardwareBitmap(bitmap, format, ahb.get())) {
John Recke170fb62018-05-07 08:12:07 -0700422 return nullptr;
423 }
Alec Mouri45238012020-01-29 11:04:40 -0800424 return Bitmap::createFrom(ahb.get(), bitmap.colorType(), bitmap.refColorSpace(),
425 bitmap.alphaType(), Bitmap::computePalette(bitmap));
John Recke170fb62018-05-07 08:12:07 -0700426}
427
Greg Danielc0732522019-02-20 08:31:03 -0500428void HardwareBitmapUploader::initialize() {
429 bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
430 uirenderer::RenderPipelineType::SkiaGL;
431 createUploader(usingGL);
432 sUploader->initialize();
433}
434
John Reck6104cea2019-01-10 14:37:17 -0800435void HardwareBitmapUploader::terminate() {
Greg Daniel78b7ddc2019-03-27 12:52:43 -0400436 if (sUploader) {
437 sUploader->destroy();
438 }
John Reck6104cea2019-01-10 14:37:17 -0800439}
440
Chris Blume7b8a8082018-11-30 15:51:58 -0800441} // namespace android::uirenderer