diff options
-rw-r--r-- | libs/hwui/Android.bp | 1 | ||||
-rw-r--r-- | libs/hwui/HardwareBitmapUploader.cpp | 33 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/DumpOpsCanvas.h | 8 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/FunctorDrawable.h | 53 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/GLFunctorDrawable.cpp | 6 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/GLFunctorDrawable.h | 18 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaDisplayList.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaDisplayList.h | 6 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp | 15 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp | 5 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/VkFunctorDrawable.cpp | 223 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/VkFunctorDrawable.h | 55 | ||||
-rw-r--r-- | libs/hwui/tests/unit/SkiaDisplayListTests.cpp | 7 | ||||
-rw-r--r-- | libs/hwui/utils/Color.cpp | 20 | ||||
-rw-r--r-- | libs/hwui/utils/Color.h | 3 | ||||
-rw-r--r-- | libs/hwui/utils/GLUtils.cpp | 17 | ||||
-rw-r--r-- | libs/hwui/utils/GLUtils.h | 51 |
17 files changed, 454 insertions, 69 deletions
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index b01136361101..11dad2e0d731 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -175,6 +175,7 @@ cc_defaults { "pipeline/skia/SkiaRecordingCanvas.cpp", "pipeline/skia/SkiaVulkanPipeline.cpp", "pipeline/skia/VectorDrawableAtlas.cpp", + "pipeline/skia/VkFunctorDrawable.cpp", "renderstate/RenderState.cpp", "renderthread/CacheManager.cpp", "renderthread/CanvasContext.cpp", diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp index ab80d3d98448..7dbef65f10cb 100644 --- a/libs/hwui/HardwareBitmapUploader.cpp +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -107,39 +107,6 @@ static bool hasFP16Support() { #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; diff --git a/libs/hwui/pipeline/skia/DumpOpsCanvas.h b/libs/hwui/pipeline/skia/DumpOpsCanvas.h index dcfe6b371171..e4ba13da709c 100644 --- a/libs/hwui/pipeline/skia/DumpOpsCanvas.h +++ b/libs/hwui/pipeline/skia/DumpOpsCanvas.h @@ -138,7 +138,7 @@ protected: renderNodeDrawable->getRenderNode()->output(mOutput, mLevel + 1); return; } - auto glFunctorDrawable = getGLFunctorDrawable(drawable); + auto glFunctorDrawable = getFunctorDrawable(drawable); if (nullptr != glFunctorDrawable) { mOutput << std::string(mLevel * 2, ' ') << "drawGLFunctorDrawable" << std::endl; return; @@ -157,10 +157,10 @@ private: return nullptr; } - GLFunctorDrawable* getGLFunctorDrawable(SkDrawable* drawable) { + FunctorDrawable* getFunctorDrawable(SkDrawable* drawable) { for (auto& child : mDisplayList.mChildFunctors) { - if (drawable == &child) { - return &child; + if (drawable == child) { + return child; } } return nullptr; diff --git a/libs/hwui/pipeline/skia/FunctorDrawable.h b/libs/hwui/pipeline/skia/FunctorDrawable.h new file mode 100644 index 000000000000..162d13762e1a --- /dev/null +++ b/libs/hwui/pipeline/skia/FunctorDrawable.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "GlFunctorLifecycleListener.h" + +#include <SkCanvas.h> +#include <SkDrawable.h> + +#include <utils/Functor.h> + +namespace android { +namespace uirenderer { + +namespace skiapipeline { + +/** + * This drawable wraps a functor enabling it to be recorded into a list + * of Skia drawing commands. + */ +class FunctorDrawable : public SkDrawable { +public: + FunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas) + : mFunctor(functor), mListener(listener), mBounds(canvas->getLocalClipBounds()) {} + virtual ~FunctorDrawable() {} + + virtual void syncFunctor() const = 0; + +protected: + virtual SkRect onGetBounds() override { return mBounds; } + + Functor* mFunctor; + sp<GlFunctorLifecycleListener> mListener; + const SkRect mBounds; +}; + +}; // namespace skiapipeline +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp index b0fec7a70699..90d5e715f8cd 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp @@ -18,7 +18,6 @@ #include <GrContext.h> #include <private/hwui/DrawGlInfo.h> #include "GlFunctorLifecycleListener.h" -#include "Properties.h" #include "RenderNode.h" #include "SkAndroidFrameworkUtils.h" #include "SkClipStack.h" @@ -80,11 +79,6 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { return; } - if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { - canvas->clear(SK_ColorRED); - return; - } - GLuint fboID = 0; SkISize fboSize; if (!GetFboDetails(canvas, &fboID, &fboSize)) { diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.h b/libs/hwui/pipeline/skia/GLFunctorDrawable.h index d9e65c95444e..dd6ef25f30c5 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.h +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.h @@ -16,12 +16,8 @@ #pragma once -#include "GlFunctorLifecycleListener.h" +#include "FunctorDrawable.h" -#include <SkCanvas.h> -#include <SkDrawable.h> - -#include <utils/Functor.h> #include <utils/RefBase.h> namespace android { @@ -33,22 +29,16 @@ namespace skiapipeline { * This drawable wraps a OpenGL functor enabling it to be recorded into a list * of Skia drawing commands. */ -class GLFunctorDrawable : public SkDrawable { +class GLFunctorDrawable : public FunctorDrawable { public: GLFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas) - : mFunctor(functor), mListener(listener), mBounds(canvas->getLocalClipBounds()) {} + : FunctorDrawable(functor, listener, canvas) {} virtual ~GLFunctorDrawable(); - void syncFunctor() const; + void syncFunctor() const override; protected: - virtual SkRect onGetBounds() override { return mBounds; } virtual void onDraw(SkCanvas* canvas) override; - -private: - Functor* mFunctor; - sp<GlFunctorLifecycleListener> mListener; - const SkRect mBounds; }; }; // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index 82179a37f5be..78b64b2f01eb 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -29,7 +29,7 @@ namespace skiapipeline { void SkiaDisplayList::syncContents() { for (auto& functor : mChildFunctors) { - functor.syncFunctor(); + functor->syncFunctor(); } for (auto& animatedImage : mAnimatedImages) { animatedImage->syncProperties(); diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index 4f30f98e147d..4c7853931029 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -17,7 +17,7 @@ #pragma once #include "hwui/AnimatedImageDrawable.h" -#include "GLFunctorDrawable.h" +#include "FunctorDrawable.h" #include "RecordingCanvas.h" #include "RenderNodeDrawable.h" #include "TreeInfo.h" @@ -77,7 +77,7 @@ public: * that creates them. Allocator dtor invokes all SkDrawable dtors. */ template <class T, typename... Params> - SkDrawable* allocateDrawable(Params&&... params) { + T* allocateDrawable(Params&&... params) { return allocator.create<T>(std::forward<Params>(params)...); } @@ -155,7 +155,7 @@ public: * cannot relocate. */ std::deque<RenderNodeDrawable> mChildNodes; - std::deque<GLFunctorDrawable> mChildFunctors; + std::deque<FunctorDrawable*> mChildFunctors; std::vector<SkImage*> mMutableImages; std::vector<VectorDrawableRoot*> mVectorDrawables; std::vector<AnimatedImageDrawable*> mAnimatedImages; diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index 83d7e6a361bc..3c281e78ddd5 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -23,6 +23,8 @@ #include "NinePatchUtils.h" #include "RenderNode.h" #include "pipeline/skia/AnimatedDrawables.h" +#include "pipeline/skia/GLFunctorDrawable.h" +#include "pipeline/skia/VkFunctorDrawable.h" namespace android { namespace uirenderer { @@ -118,9 +120,16 @@ void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) { void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor, uirenderer::GlFunctorLifecycleListener* listener) { - // Drawable dtor will be invoked when mChildFunctors deque is cleared. - mDisplayList->mChildFunctors.emplace_back(functor, listener, asSkCanvas()); - drawDrawable(&mDisplayList->mChildFunctors.back()); + FunctorDrawable* functorDrawable; + if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { + functorDrawable = mDisplayList->allocateDrawable<VkFunctorDrawable>(functor, listener, + asSkCanvas()); + } else { + functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, listener, + asSkCanvas()); + } + mDisplayList->mChildFunctors.push_back(functorDrawable); + drawDrawable(functorDrawable); } class VectorDrawable : public SkDrawable { diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index 5cbe33debbce..e34f160467af 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -22,6 +22,7 @@ #include "SkiaProfileRenderer.h" #include "renderstate/RenderState.h" #include "renderthread/Frame.h" +#include "VkFunctorDrawable.h" #include <SkSurface.h> #include <SkTypes.h> @@ -146,9 +147,7 @@ sk_sp<SkColorSpace> SkiaVulkanPipeline::getSurfaceColorSpace() { } void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) { - // TODO: we currently don't support OpenGL WebView's - DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext; - (*functor)(mode, nullptr); + VkFunctorDrawable::vkInvokeFunctor(functor); } sk_sp<Bitmap> SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread, diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp new file mode 100644 index 000000000000..6486ddb05aac --- /dev/null +++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "VkFunctorDrawable.h" +#include <private/hwui/DrawGlInfo.h> + +#include "renderthread/EglManager.h" +#include "thread/ThreadBase.h" +#include "utils/TimeUtils.h" +#include <thread> +#include <utils/Color.h> +#include <utils/Trace.h> +#include <utils/TraceUtils.h> + +#include <EGL/eglext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <GLES3/gl3.h> + +#include <utils/GLUtils.h> + +namespace android { +namespace uirenderer { +namespace skiapipeline { + +static std::mutex sLock{}; +static ThreadBase* sGLDrawThread = nullptr; +static renderthread::EglManager sEglManager; + +// ScopedDrawRequest makes sure a GL thread is started and EGL context is initialized on it. +class ScopedDrawRequest { +public: + ScopedDrawRequest() { beginDraw(); } +private: + void beginDraw() { + std::lock_guard{sLock}; + + if (!sGLDrawThread) { + sGLDrawThread = new ThreadBase{}; + } + + if (!sGLDrawThread->isRunning()) { + sGLDrawThread->start("GLFunctorThread"); + } + + if (!sEglManager.hasEglContext()) { + sGLDrawThread->queue().runSync([]() { + sEglManager.initialize(); + }); + } + } +}; + +void VkFunctorDrawable::vkInvokeFunctor(Functor* functor) { + ScopedDrawRequest _drawRequest{}; + sGLDrawThread->queue().runSync([&]() { + EGLDisplay display = sEglManager.eglDisplay(); + DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext; + if (display != EGL_NO_DISPLAY) { + mode = DrawGlInfo::kModeProcess; + } + (*functor)(mode, nullptr); + }); +} + +#define FENCE_TIMEOUT 2000000000 + +void VkFunctorDrawable::onDraw(SkCanvas* canvas) { + ATRACE_CALL(); + + if (canvas->getGrContext() == nullptr) { + SkDEBUGF(("Attempting to draw VkFunctor into an unsupported surface")); + return; + } + + ScopedDrawRequest _drawRequest{}; + + SkImageInfo surfaceInfo = canvas->imageInfo(); + + if (!mFrameBuffer.get() || mFBInfo != surfaceInfo) { + // Buffer will be used as an OpenGL ES render target. + mFrameBuffer = new GraphicBuffer( + //TODO: try to reduce the size of the buffer: possibly by using clip bounds. + static_cast<uint32_t>(surfaceInfo.width()), + static_cast<uint32_t>(surfaceInfo.height()), + ColorTypeToPixelFormat(surfaceInfo.colorType()), + GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER | + GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_HW_RENDER, + std::string("VkFunctorDrawable::onDraw pid [") + std::to_string(getpid()) + "]"); + status_t error = mFrameBuffer->initCheck(); + if (error < 0) { + ALOGW("VkFunctorDrawable::onDraw() failed in GraphicBuffer.create()"); + return; + } + + mFBInfo = surfaceInfo; + } + + //TODO: Synchronization is needed on mFrameBuffer to guarantee that the previous Vulkan + //TODO: draw command has completed. + //TODO: A simple but inefficient way is to flush and issue a QueueWaitIdle call. See + //TODO: GrVkGpu::destroyResources() for example. + bool success = sGLDrawThread->queue().runSync([&]() -> bool { + ATRACE_FORMAT("WebViewDraw_%dx%d", mFBInfo.width(), mFBInfo.height()); + EGLDisplay display = sEglManager.eglDisplay(); + 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)mFrameBuffer->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 false; + } + + AutoSkiaGlTexture glTexture; + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image); + GL_CHECKPOINT(MODERATE); + + glBindTexture(GL_TEXTURE_2D, 0); + + DrawGlInfo info; + SkMatrix44 mat4(canvas->getTotalMatrix()); + SkIRect clipBounds = canvas->getDeviceClipBounds(); + + info.clipLeft = clipBounds.fLeft; + info.clipTop = clipBounds.fTop; + info.clipRight = clipBounds.fRight; + info.clipBottom = clipBounds.fBottom; + info.isLayer = true; + info.width = mFBInfo.width(); + info.height = mFBInfo.height(); + mat4.asColMajorf(&info.transform[0]); + + glViewport(0, 0, info.width, info.height); + + AutoGLFramebuffer glFb; + // Bind texture to the frame buffer. + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + glTexture.mTexture, 0); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + ALOGE("Failed framebuffer check for created target buffer: %s", + GLUtils::getGLFramebufferError()); + return false; + } + + glDisable(GL_STENCIL_TEST); + glDisable(GL_SCISSOR_TEST); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); + + (*mFunctor)(DrawGlInfo::kModeDraw, &info); + + EGLSyncKHR glDrawFinishedFence = + eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL); + LOG_ALWAYS_FATAL_IF(glDrawFinishedFence == EGL_NO_SYNC_KHR, + "Could not create sync fence %#x", eglGetError()); + glFlush(); + // TODO: export EGLSyncKHR in file descr + // TODO: import file desc in Vulkan Semaphore + // TODO: instead block the GPU: probably by using external Vulkan semaphore. + // Block the CPU until the glFlush finish. + EGLint waitStatus = eglClientWaitSyncKHR(display, glDrawFinishedFence, 0, + FENCE_TIMEOUT); + LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR, + "Failed to wait for the fence %#x", eglGetError()); + eglDestroySyncKHR(display, glDrawFinishedFence); + return true; + }); + + if (!success) { + return; + } + + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrcOver); + canvas->save(); + // The size of the image matches the size of the canvas. We've used the matrix already, while + // drawing into the offscreen surface, so we need to reset it here. + canvas->resetMatrix(); + + auto functorImage = SkImage::MakeFromAHardwareBuffer( + reinterpret_cast<AHardwareBuffer*>(mFrameBuffer.get()), kPremul_SkAlphaType, + nullptr, kBottomLeft_GrSurfaceOrigin); + canvas->drawImage(functorImage, 0, 0, &paint); + canvas->restore(); +} + +VkFunctorDrawable::~VkFunctorDrawable() { + if (mListener.get() != nullptr) { + ScopedDrawRequest _drawRequest{}; + sGLDrawThread->queue().runSync([&]() { + mListener->onGlFunctorReleased(mFunctor); + }); + } +} + +void VkFunctorDrawable::syncFunctor() const { + ScopedDrawRequest _drawRequest{}; + sGLDrawThread->queue().runSync([&]() { + (*mFunctor)(DrawGlInfo::kModeSync, nullptr); + }); +} + +}; // namespace skiapipeline +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkFunctorDrawable.h new file mode 100644 index 000000000000..e37f6fb85090 --- /dev/null +++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "FunctorDrawable.h" + +#include <utils/RefBase.h> +#include <ui/GraphicBuffer.h> + +namespace android { +namespace uirenderer { + +namespace skiapipeline { + +/** + * This drawable wraps a Vulkan functor enabling it to be recorded into a list + * of Skia drawing commands. + */ +class VkFunctorDrawable : public FunctorDrawable { +public: + VkFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas) + : FunctorDrawable(functor, listener, canvas) {} + virtual ~VkFunctorDrawable(); + + void syncFunctor() const override; + + static void vkInvokeFunctor(Functor* functor); + +protected: + virtual void onDraw(SkCanvas* canvas) override; + +private: + + // Variables below describe/store temporary offscreen buffer used for Vulkan pipeline. + sp<GraphicBuffer> mFrameBuffer; + SkImageInfo mFBInfo; +}; + +}; // namespace skiapipeline +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp index 6c398eea895f..415f9e8517ff 100644 --- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp +++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp @@ -20,6 +20,7 @@ #include "AnimationContext.h" #include "DamageAccumulator.h" #include "IContextFactory.h" +#include "pipeline/skia/GLFunctorDrawable.h" #include "pipeline/skia/SkiaDisplayList.h" #include "renderthread/CanvasContext.h" #include "tests/common/TestUtils.h" @@ -46,7 +47,8 @@ TEST(SkiaDisplayList, reset) { SkCanvas dummyCanvas; RenderNodeDrawable drawable(nullptr, &dummyCanvas); skiaDL->mChildNodes.emplace_back(nullptr, &dummyCanvas); - skiaDL->mChildFunctors.emplace_back(nullptr, nullptr, &dummyCanvas); + GLFunctorDrawable functorDrawable(nullptr, nullptr, &dummyCanvas); + skiaDL->mChildFunctors.push_back(&functorDrawable); skiaDL->mMutableImages.push_back(nullptr); skiaDL->mVectorDrawables.push_back(nullptr); skiaDL->mProjectionReceiver = &drawable; @@ -95,7 +97,8 @@ TEST(SkiaDisplayList, syncContexts) { SkCanvas dummyCanvas; TestUtils::MockFunctor functor; - skiaDL.mChildFunctors.emplace_back(&functor, nullptr, &dummyCanvas); + GLFunctorDrawable functorDrawable(&functor, nullptr, &dummyCanvas); + skiaDL.mChildFunctors.push_back(&functorDrawable); SkRect bounds = SkRect::MakeWH(200, 200); VectorDrawableRoot vectorDrawable(new VectorDrawable::Group()); diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp index d35fe4f01aa0..9f71e91629fb 100644 --- a/libs/hwui/utils/Color.cpp +++ b/libs/hwui/utils/Color.cpp @@ -72,6 +72,26 @@ SkColorType PixelFormatToColorType(android_pixel_format pixelFormat) { } } +android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) { + switch (colorType) { + case kRGBA_8888_SkColorType: + return PIXEL_FORMAT_RGBA_8888; + case kRGBA_F16_SkColorType: + return PIXEL_FORMAT_RGBA_FP16; + case kRGB_565_SkColorType: + return PIXEL_FORMAT_RGB_565; + case kRGB_888x_SkColorType: + return PIXEL_FORMAT_RGBX_8888; + case kRGBA_1010102_SkColorType: + return PIXEL_FORMAT_RGBA_1010102; + case kARGB_4444_SkColorType: + return PIXEL_FORMAT_RGBA_4444; + default: + ALOGW("Unsupported colorType: %d, return RGBA_8888 by default", (int)colorType); + return PIXEL_FORMAT_RGBA_8888; + } +} + SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace) { switch (dataSpace & HAL_DATASPACE_STANDARD_MASK) { case HAL_DATASPACE_STANDARD_BT709: diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h index ff0e755934f2..e935a0d5ec8b 100644 --- a/libs/hwui/utils/Color.h +++ b/libs/hwui/utils/Color.h @@ -18,6 +18,7 @@ #include <math.h> #include <system/graphics.h> +#include <ui/PixelFormat.h> #include <SkColor.h> #include <SkColorSpace.h> @@ -116,6 +117,8 @@ bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace); SkColorType PixelFormatToColorType(android_pixel_format pixelFormat); +android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType); + SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace); sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace); diff --git a/libs/hwui/utils/GLUtils.cpp b/libs/hwui/utils/GLUtils.cpp index bf27300029c6..fcd036c451e9 100644 --- a/libs/hwui/utils/GLUtils.cpp +++ b/libs/hwui/utils/GLUtils.cpp @@ -59,5 +59,22 @@ bool GLUtils::dumpGLErrors() { #endif } +const char* GLUtils::getGLFramebufferError() { + switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) { + case GL_FRAMEBUFFER_COMPLETE: + return "GL_FRAMEBUFFER_COMPLETE"; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; + case GL_FRAMEBUFFER_UNSUPPORTED: + return "GL_FRAMEBUFFER_UNSUPPORTED"; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS"; + default: + return "Unknown error"; + } +} + }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/utils/GLUtils.h b/libs/hwui/utils/GLUtils.h index debfb5d06944..ca8810bde070 100644 --- a/libs/hwui/utils/GLUtils.h +++ b/libs/hwui/utils/GLUtils.h @@ -20,6 +20,12 @@ #include <log/log.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <GLES3/gl3.h> + namespace android { namespace uirenderer { @@ -43,8 +49,53 @@ public: */ static bool dumpGLErrors(); + static const char* getGLFramebufferError(); }; // class GLUtils +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); } + + GLuint mTexture = 0; +}; + +class AutoGLFramebuffer { +public: + AutoGLFramebuffer() { + glGenFramebuffers(1, &mFb); + glBindFramebuffer(GL_FRAMEBUFFER, mFb); + } + + ~AutoGLFramebuffer() { glDeleteFramebuffers(1, &mFb); } + + GLuint mFb; +}; + } /* namespace uirenderer */ } /* namespace android */ |