diff options
author | John Reck <jreck@google.com> | 2018-05-07 08:12:07 -0700 |
---|---|---|
committer | John Reck <jreck@google.com> | 2018-05-09 11:39:37 -0700 |
commit | e170fb6686c3e88cee6e32f4e3eb12fcf9bfe931 (patch) | |
tree | bf0ccbbcd2f89ccb468b216e14670451fedc3221 /libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp | |
parent | 33f4f1cb1645635f8b5c369e1dddda84e0396c34 (diff) |
A better HW Bitmap uploader
Move all HW bitmap upload operations off of RenderThread.
Ensure EGL context outlives all upload requests
Bug: 79250950
Test: builds, boots, systrace is good, CTS bitmap tests pass
Change-Id: I5ace6c516d33b1afdf1a407cd8b183f6b60c22c1
Diffstat (limited to 'libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp')
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp | 204 |
1 files changed, 0 insertions, 204 deletions
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index 766fab61f3db..78f5a71dee3b 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -251,210 +251,6 @@ void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* func } } -#define FENCE_TIMEOUT 2000000000 - -class AutoEglImage { -public: - AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) { - EGLint imageAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; - image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, - imageAttrs); - } - - ~AutoEglImage() { - if (image != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(mDisplay, image); - } - } - - EGLImageKHR image = EGL_NO_IMAGE_KHR; - -private: - EGLDisplay mDisplay = EGL_NO_DISPLAY; -}; - -class AutoSkiaGlTexture { -public: - AutoSkiaGlTexture() { - glGenTextures(1, &mTexture); - glBindTexture(GL_TEXTURE_2D, mTexture); - } - - ~AutoSkiaGlTexture() { glDeleteTextures(1, &mTexture); } - -private: - GLuint mTexture = 0; -}; - -struct FormatInfo { - PixelFormat pixelFormat; - GLint format, type; - bool isSupported = false; - bool valid = true; -}; - -static bool gpuSupportsHalfFloatTextures(renderthread::RenderThread& renderThread) { - static bool isSupported = renderThread.queue().runSync([&renderThread]() -> bool { - renderThread.requireGlContext(); - sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext()); - if (!grContext->colorTypeSupportedAsImage(kRGBA_F16_SkColorType)) { - return false; - } - sp<GraphicBuffer> buffer = new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_FP16, - GraphicBuffer::USAGE_HW_TEXTURE | - GraphicBuffer::USAGE_SW_WRITE_NEVER | - GraphicBuffer::USAGE_SW_READ_NEVER, - "tempFp16Buffer"); - status_t error = buffer->initCheck(); - return error != OK; - }); - return isSupported; -} - -static FormatInfo determineFormat(renderthread::RenderThread& renderThread, - const SkBitmap& skBitmap) { - FormatInfo formatInfo; - // TODO: add support for linear blending (when ANDROID_ENABLE_LINEAR_BLENDING is defined) - switch (skBitmap.info().colorType()) { - case kRGBA_8888_SkColorType: - formatInfo.isSupported = true; - // ARGB_4444 is upconverted to RGBA_8888 - case kARGB_4444_SkColorType: - formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; - formatInfo.format = GL_RGBA; - formatInfo.type = GL_UNSIGNED_BYTE; - break; - case kRGBA_F16_SkColorType: - formatInfo.isSupported = gpuSupportsHalfFloatTextures(renderThread); - if (formatInfo.isSupported) { - formatInfo.type = GL_HALF_FLOAT; - formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16; - } else { - formatInfo.type = GL_UNSIGNED_BYTE; - formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; - } - formatInfo.format = GL_RGBA; - break; - case kRGB_565_SkColorType: - formatInfo.isSupported = true; - formatInfo.pixelFormat = PIXEL_FORMAT_RGB_565; - formatInfo.format = GL_RGB; - formatInfo.type = GL_UNSIGNED_SHORT_5_6_5; - break; - case kGray_8_SkColorType: - formatInfo.isSupported = true; - formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; - formatInfo.format = GL_LUMINANCE; - formatInfo.type = GL_UNSIGNED_BYTE; - break; - default: - ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType()); - formatInfo.valid = false; - } - return formatInfo; -} - -static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& source) { - if (format.isSupported) { - return source; - } else { - SkBitmap bitmap; - const SkImageInfo& info = source.info(); - bitmap.allocPixels( - SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(), nullptr)); - bitmap.eraseColor(0); - if (info.colorType() == kRGBA_F16_SkColorType) { - // Drawing RGBA_F16 onto ARGB_8888 is not supported - source.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()), - bitmap.getPixels(), bitmap.rowBytes(), 0, 0); - } else { - SkCanvas canvas(bitmap); - canvas.drawBitmap(source, 0.0f, 0.0f, nullptr); - } - return bitmap; - } -} - -sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThread& thread, - const SkBitmap& sourceBitmap) { - ATRACE_CALL(); - - LOG_ALWAYS_FATAL_IF(thread.isCurrent(), "Must not be called on RenderThread"); - - FormatInfo format = determineFormat(thread, sourceBitmap); - if (!format.valid) { - return nullptr; - } - - SkBitmap bitmap = makeHwCompatible(format, sourceBitmap); - sp<GraphicBuffer> buffer = new GraphicBuffer( - static_cast<uint32_t>(bitmap.width()), static_cast<uint32_t>(bitmap.height()), - format.pixelFormat, - GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER | - GraphicBuffer::USAGE_SW_READ_NEVER, - std::string("Bitmap::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) + - "]"); - - status_t error = buffer->initCheck(); - if (error < 0) { - ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()"); - return nullptr; - } - - EGLDisplay display = thread.queue().runSync([&]() -> EGLDisplay { - thread.requireGlContext(); - return eglGetCurrentDisplay(); - }); - - LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s", - uirenderer::renderthread::EglManager::eglErrorString()); - // We use an EGLImage to access the content of the GraphicBuffer - // The EGL image is later bound to a 2D texture - EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer->getNativeBuffer(); - AutoEglImage autoImage(display, clientBuffer); - if (autoImage.image == EGL_NO_IMAGE_KHR) { - ALOGW("Could not create EGL image, err =%s", - uirenderer::renderthread::EglManager::eglErrorString()); - return nullptr; - } - - { - ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height()); - EGLSyncKHR fence = thread.queue().runSync([&]() -> EGLSyncKHR { - thread.requireGlContext(); - sk_sp<GrContext> grContext = sk_ref_sp(thread.getGrContext()); - AutoSkiaGlTexture glTexture; - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image); - GL_CHECKPOINT(MODERATE); - - // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we - // provide. - // But asynchronous in sense that driver may upload texture onto hardware buffer when we - // first - // use it in drawing - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), format.format, - format.type, bitmap.getPixels()); - GL_CHECKPOINT(MODERATE); - - EGLSyncKHR uploadFence = - eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL); - LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR, "Could not create sync fence %#x", - eglGetError()); - glFlush(); - grContext->resetContext(kTextureBinding_GrGLBackendState); - return uploadFence; - }); - - EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT); - LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR, - "Failed to wait for the fence %#x", eglGetError()); - - eglDestroySyncKHR(display, fence); - } - - return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info())); -} - } /* namespace skiapipeline */ } /* namespace uirenderer */ } /* namespace android */ |