diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index c3357a2cf4e4a..5b2adbf9c2c31 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -222,24 +222,6 @@ void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* func #define FENCE_TIMEOUT 2000000000 -class AutoEglFence { -public: - AutoEglFence(EGLDisplay display) : mDisplay(display) { - fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL); - } - - ~AutoEglFence() { - if (fence != EGL_NO_SYNC_KHR) { - eglDestroySyncKHR(mDisplay, fence); - } - } - - EGLSyncKHR fence = EGL_NO_SYNC_KHR; - -private: - EGLDisplay mDisplay = EGL_NO_DISPLAY; -}; - class AutoEglImage { public: AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) { @@ -273,73 +255,102 @@ private: GLuint mTexture = 0; }; -sk_sp SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread, - SkBitmap& skBitmap) { - renderThread.requireGlContext(); +struct FormatInfo { - sk_sp grContext = sk_ref_sp(renderThread.getGrContext()); - const SkImageInfo& info = skBitmap.info(); 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 = sk_ref_sp(renderThread.getGrContext()); + return grContext->colorTypeSupportedAsImage(kRGBA_F16_SkColorType); + }); + 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 (info.colorType()) { + switch (skBitmap.info().colorType()) { case kRGBA_8888_SkColorType: - isSupported = true; + formatInfo.isSupported = true; // ARGB_4444 is upconverted to RGBA_8888 case kARGB_4444_SkColorType: - pixelFormat = PIXEL_FORMAT_RGBA_8888; - format = GL_RGBA; - type = GL_UNSIGNED_BYTE; + formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; + formatInfo.format = GL_RGBA; + formatInfo.type = GL_UNSIGNED_BYTE; break; case kRGBA_F16_SkColorType: - isSupported = grContext->colorTypeSupportedAsImage(kRGBA_F16_SkColorType); - if (isSupported) { - type = GL_HALF_FLOAT; - pixelFormat = PIXEL_FORMAT_RGBA_FP16; + formatInfo.isSupported = gpuSupportsHalfFloatTextures(renderThread); + if (formatInfo.isSupported) { + formatInfo.type = GL_HALF_FLOAT; + formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16; } else { - type = GL_UNSIGNED_BYTE; - pixelFormat = PIXEL_FORMAT_RGBA_8888; + formatInfo.type = GL_UNSIGNED_BYTE; + formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888; } - format = GL_RGBA; + formatInfo.format = GL_RGBA; break; case kRGB_565_SkColorType: - isSupported = true; - pixelFormat = PIXEL_FORMAT_RGB_565; - format = GL_RGB; - type = GL_UNSIGNED_SHORT_5_6_5; + 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: - isSupported = true; - pixelFormat = PIXEL_FORMAT_RGBA_8888; - format = GL_LUMINANCE; - type = GL_UNSIGNED_BYTE; + 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", info.colorType()); - return nullptr; + ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType()); + formatInfo.valid = false; } + return formatInfo; +} - SkBitmap bitmap; - if (isSupported) { - bitmap = skBitmap; +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 - skBitmap.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()), - bitmap.getPixels(), bitmap.rowBytes(), 0, 0); + source.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()), + bitmap.getPixels(), bitmap.rowBytes(), 0, 0); } else { SkCanvas canvas(bitmap); - canvas.drawBitmap(skBitmap, 0.0f, 0.0f, nullptr); + canvas.drawBitmap(source, 0.0f, 0.0f, nullptr); } + return bitmap; + } +} + +sk_sp 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 buffer = new GraphicBuffer( - info.width(), info.height(), pixelFormat, + static_cast(bitmap.width()), static_cast(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()) + @@ -351,8 +362,11 @@ sk_sp SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr return nullptr; } - // upload the bitmap into a texture - EGLDisplay display = eglGetCurrentDisplay(); + 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 @@ -364,35 +378,40 @@ sk_sp SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr uirenderer::renderthread::EglManager::eglErrorString()); return nullptr; } - 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, info.width(), info.height(), format, type, - bitmap.getPixels()); - GL_CHECKPOINT(MODERATE); + { + ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height()); + EGLSyncKHR fence = thread.queue().runSync([&]() -> EGLSyncKHR { + thread.requireGlContext(); + sk_sp grContext = sk_ref_sp(thread.getGrContext()); + AutoSkiaGlTexture glTexture; + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image); + GL_CHECKPOINT(MODERATE); - // The fence is used to wait for the texture upload to finish - // properly. We cannot rely on glFlush() and glFinish() as - // some drivers completely ignore these API calls - AutoEglFence autoFence(display); - if (autoFence.fence == EGL_NO_SYNC_KHR) { - LOG_ALWAYS_FATAL("Could not create sync fence %#x", eglGetError()); - return nullptr; + // 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); } - // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a - // pipeline flush (similar to what a glFlush() would do.) - EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence, - EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT); - if (waitStatus != EGL_CONDITION_SATISFIED_KHR) { - LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError()); - return nullptr; - } - - grContext->resetContext(kTextureBinding_GrGLBackendState); return sk_sp(new Bitmap(buffer.get(), bitmap.info())); } diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index 5e013b6697a7a..ef5d9347a3ea2 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -49,8 +49,10 @@ public: bool isContextReady() override; static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor); + + // May be called by any thread except RenderThread. static sk_sp allocateHardwareBitmap(renderthread::RenderThread& thread, - SkBitmap& skBitmap); + const SkBitmap& skBitmap); private: renderthread::EglManager& mEglManager; diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 4b948f8c6b362..0caf59b422026 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -21,6 +21,7 @@ #include "Properties.h" #include "Readback.h" #include "Rect.h" +#include "pipeline/skia/SkiaOpenGLPipeline.h" #include "pipeline/skia/VectorDrawableAtlas.h" #include "renderstate/RenderState.h" #include "renderthread/CanvasContext.h" @@ -323,7 +324,13 @@ void RenderProxy::prepareToDraw(Bitmap& bitmap) { sk_sp RenderProxy::allocateHardwareBitmap(SkBitmap& bitmap) { auto& thread = RenderThread::getInstance(); - return thread.queue().runSync([&]() -> auto { return thread.allocateHardwareBitmap(bitmap); }); + if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { + return skiapipeline::SkiaOpenGLPipeline::allocateHardwareBitmap(thread, bitmap); + } else { + return thread.queue().runSync([&]() -> auto { + return thread.allocateHardwareBitmap(bitmap); + }); + } } int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) { diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 711ece46cf319..5dcfc3f579df8 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -24,8 +24,8 @@ #include "hwui/Bitmap.h" #include "pipeline/skia/SkiaOpenGLPipeline.h" #include "pipeline/skia/SkiaOpenGLReadback.h" -#include "pipeline/skia/SkiaVulkanReadback.h" #include "pipeline/skia/SkiaVulkanPipeline.h" +#include "pipeline/skia/SkiaVulkanReadback.h" #include "renderstate/RenderState.h" #include "utils/FatVector.h" #include "utils/TimeUtils.h" @@ -98,14 +98,11 @@ public: DummyVsyncSource(RenderThread* renderThread) : mRenderThread(renderThread) {} virtual void requestNextVsync() override { - mRenderThread->queue().postDelayed(16_ms, [this]() { - mRenderThread->drainDisplayEventQueue(); - }); + mRenderThread->queue().postDelayed(16_ms, + [this]() { mRenderThread->drainDisplayEventQueue(); }); } - virtual nsecs_t latestVsyncEvent() override { - return systemTime(CLOCK_MONOTONIC); - } + virtual nsecs_t latestVsyncEvent() override { return systemTime(CLOCK_MONOTONIC); } private: RenderThread* mRenderThread; @@ -152,13 +149,13 @@ void RenderThread::initializeDisplayEventReceiver() { auto receiver = std::make_unique(); status_t status = receiver->initCheck(); LOG_ALWAYS_FATAL_IF(status != NO_ERROR, - "Initialization of DisplayEventReceiver " - "failed with status: %d", - status); + "Initialization of DisplayEventReceiver " + "failed with status: %d", + status); // Register the FD mLooper->addFd(receiver->getFd(), 0, Looper::EVENT_INPUT, - RenderThread::displayEventReceiverCallback, this); + RenderThread::displayEventReceiverCallback, this); mVsyncSource = new DisplayEventReceiverWrapper(std::move(receiver)); } else { mVsyncSource = new DummyVsyncSource(this); @@ -372,8 +369,6 @@ void RenderThread::pushBackFrameCallback(IFrameCallback* callback) { sk_sp RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) { auto renderType = Properties::getRenderPipelineType(); switch (renderType) { - case RenderPipelineType::SkiaGL: - return skiapipeline::SkiaOpenGLPipeline::allocateHardwareBitmap(*this, skBitmap); case RenderPipelineType::SkiaVulkan: return skiapipeline::SkiaVulkanPipeline::allocateHardwareBitmap(*this, skBitmap); default: