diff options
-rw-r--r-- | libs/renderengine/Android.bp | 10 | ||||
-rw-r--r-- | libs/renderengine/RenderEngine.cpp | 7 | ||||
-rw-r--r-- | libs/renderengine/include/renderengine/RenderEngine.h | 1 | ||||
-rw-r--r-- | libs/renderengine/skia/SkiaGLRenderEngine.cpp | 539 | ||||
-rw-r--r-- | libs/renderengine/skia/SkiaGLRenderEngine.h | 93 | ||||
-rw-r--r-- | libs/renderengine/skia/SkiaRenderEngine.cpp | 26 | ||||
-rw-r--r-- | libs/renderengine/skia/SkiaRenderEngine.h | 71 | ||||
-rw-r--r-- | services/surfaceflinger/Android.bp | 5 | ||||
-rw-r--r-- | services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp | 10 | ||||
-rw-r--r-- | services/surfaceflinger/RegionSamplingThread.cpp | 3 |
10 files changed, 763 insertions, 2 deletions
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 9264bb6b0e..1ccbff16f7 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -31,6 +31,7 @@ cc_defaults { "libui", "libutils", ], + whole_static_libs: ["libskia"], local_include_dirs: ["include"], export_include_dirs: ["include"], } @@ -71,6 +72,14 @@ filegroup { ], } +filegroup { + name: "librenderengine_skia_sources", + srcs: [ + "skia/SkiaRenderEngine.cpp", + "skia/SkiaGLRenderEngine.cpp", + ], +} + cc_library_static { name: "librenderengine", defaults: ["librenderengine_defaults"], @@ -84,6 +93,7 @@ cc_library_static { ":librenderengine_sources", ":librenderengine_gl_sources", ":librenderengine_threaded_sources", + ":librenderengine_skia_sources", ], lto: { thin: true, diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp index eb0074bc40..c6436cdbec 100644 --- a/libs/renderengine/RenderEngine.cpp +++ b/libs/renderengine/RenderEngine.cpp @@ -22,6 +22,8 @@ #include "gl/GLESRenderEngine.h" #include "threaded/RenderEngineThreaded.h" +#include "skia/SkiaGLRenderEngine.h" + namespace android { namespace renderengine { @@ -37,12 +39,17 @@ std::unique_ptr<RenderEngine> RenderEngine::create(const RenderEngineCreationArg if (strcmp(prop, "threaded") == 0) { renderEngineType = RenderEngineType::THREADED; } + if (strcmp(prop, "skiagl") == 0) { + renderEngineType = RenderEngineType::SKIA_GL; + } switch (renderEngineType) { case RenderEngineType::THREADED: ALOGD("Threaded RenderEngine with GLES Backend"); return renderengine::threaded::RenderEngineThreaded::create( [args]() { return android::renderengine::gl::GLESRenderEngine::create(args); }); + case RenderEngineType::SKIA_GL: + return renderengine::skia::SkiaGLRenderEngine::create(args); case RenderEngineType::GLES: default: ALOGD("RenderEngine with GLES Backend"); diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index a0e7ab7a43..3c90a3aeaf 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -73,6 +73,7 @@ public: enum class RenderEngineType { GLES = 1, THREADED = 2, + SKIA_GL = 3, }; static std::unique_ptr<RenderEngine> create(const RenderEngineCreationArgs& args); diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp new file mode 100644 index 0000000000..94ba15392f --- /dev/null +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -0,0 +1,539 @@ +/* + * Copyright 2020 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. + */ + +//#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "RenderEngine" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include <cmath> + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES2/gl2.h> +#include <sync/sync.h> +#include <ui/GraphicBuffer.h> +#include <utils/Trace.h> +#include "../gl/GLExtensions.h" +#include "SkiaGLRenderEngine.h" + +#include <GrContextOptions.h> +#include <gl/GrGLInterface.h> + +#include <SkCanvas.h> +#include <SkImage.h> +#include <SkSurface.h> + +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); + +bool checkGlError(const char* op, int lineNumber); + +namespace android { +namespace renderengine { +namespace skia { + +static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute, + EGLint wanted, EGLConfig* outConfig) { + EGLint numConfigs = -1, n = 0; + eglGetConfigs(dpy, nullptr, 0, &numConfigs); + std::vector<EGLConfig> configs(numConfigs, EGL_NO_CONFIG_KHR); + eglChooseConfig(dpy, attrs, configs.data(), configs.size(), &n); + configs.resize(n); + + if (!configs.empty()) { + if (attribute != EGL_NONE) { + for (EGLConfig config : configs) { + EGLint value = 0; + eglGetConfigAttrib(dpy, config, attribute, &value); + if (wanted == value) { + *outConfig = config; + return NO_ERROR; + } + } + } else { + // just pick the first one + *outConfig = configs[0]; + return NO_ERROR; + } + } + + return NAME_NOT_FOUND; +} + +static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType, + EGLConfig* config) { + // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if + // it is to be used with WIFI displays + status_t err; + EGLint wantedAttribute; + EGLint wantedAttributeValue; + + std::vector<EGLint> attribs; + if (renderableType) { + const ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(format); + const bool is1010102 = pixelFormat == ui::PixelFormat::RGBA_1010102; + + // Default to 8 bits per channel. + const EGLint tmpAttribs[] = { + EGL_RENDERABLE_TYPE, + renderableType, + EGL_RECORDABLE_ANDROID, + EGL_TRUE, + EGL_SURFACE_TYPE, + EGL_WINDOW_BIT | EGL_PBUFFER_BIT, + EGL_FRAMEBUFFER_TARGET_ANDROID, + EGL_TRUE, + EGL_RED_SIZE, + is1010102 ? 10 : 8, + EGL_GREEN_SIZE, + is1010102 ? 10 : 8, + EGL_BLUE_SIZE, + is1010102 ? 10 : 8, + EGL_ALPHA_SIZE, + is1010102 ? 2 : 8, + EGL_NONE, + }; + std::copy(tmpAttribs, tmpAttribs + (sizeof(tmpAttribs) / sizeof(EGLint)), + std::back_inserter(attribs)); + wantedAttribute = EGL_NONE; + wantedAttributeValue = EGL_NONE; + } else { + // if no renderable type specified, fallback to a simplified query + wantedAttribute = EGL_NATIVE_VISUAL_ID; + wantedAttributeValue = format; + } + + err = selectConfigForAttribute(display, attribs.data(), wantedAttribute, wantedAttributeValue, + config); + if (err == NO_ERROR) { + EGLint caveat; + if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat)) + ALOGW_IF(caveat == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!"); + } + + return err; +} + +std::unique_ptr<SkiaGLRenderEngine> SkiaGLRenderEngine::create( + const RenderEngineCreationArgs& args) { + // initialize EGL for the default display + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (!eglInitialize(display, nullptr, nullptr)) { + LOG_ALWAYS_FATAL("failed to initialize EGL"); + } + + const auto eglVersion = eglQueryStringImplementationANDROID(display, EGL_VERSION); + if (!eglVersion) { + checkGlError(__FUNCTION__, __LINE__); + LOG_ALWAYS_FATAL("eglQueryStringImplementationANDROID(EGL_VERSION) failed"); + } + + const auto eglExtensions = eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS); + if (!eglExtensions) { + checkGlError(__FUNCTION__, __LINE__); + LOG_ALWAYS_FATAL("eglQueryStringImplementationANDROID(EGL_EXTENSIONS) failed"); + } + + auto& extensions = gl::GLExtensions::getInstance(); + extensions.initWithEGLStrings(eglVersion, eglExtensions); + + // The code assumes that ES2 or later is available if this extension is + // supported. + EGLConfig config = EGL_NO_CONFIG_KHR; + if (!extensions.hasNoConfigContext()) { + config = chooseEglConfig(display, args.pixelFormat, /*logConfig*/ true); + } + + bool useContextPriority = + extensions.hasContextPriority() && args.contextPriority == ContextPriority::HIGH; + EGLContext protectedContext = EGL_NO_CONTEXT; + if (args.enableProtectedContext && extensions.hasProtectedContent()) { + protectedContext = createEglContext(display, config, nullptr, useContextPriority, + Protection::PROTECTED); + ALOGE_IF(protectedContext == EGL_NO_CONTEXT, "Can't create protected context"); + } + + EGLContext ctxt = createEglContext(display, config, protectedContext, useContextPriority, + Protection::UNPROTECTED); + + // if can't create a GL context, we can only abort. + LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed"); + + EGLSurface placeholder = EGL_NO_SURFACE; + if (!extensions.hasSurfacelessContext()) { + placeholder = createPlaceholderEglPbufferSurface(display, config, args.pixelFormat, + Protection::UNPROTECTED); + LOG_ALWAYS_FATAL_IF(placeholder == EGL_NO_SURFACE, "can't create placeholder pbuffer"); + } + EGLBoolean success = eglMakeCurrent(display, placeholder, placeholder, ctxt); + LOG_ALWAYS_FATAL_IF(!success, "can't make placeholder pbuffer current"); + extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER), + glGetString(GL_VERSION), glGetString(GL_EXTENSIONS)); + + EGLSurface protectedPlaceholder = EGL_NO_SURFACE; + if (protectedContext != EGL_NO_CONTEXT && !extensions.hasSurfacelessContext()) { + protectedPlaceholder = createPlaceholderEglPbufferSurface(display, config, args.pixelFormat, + Protection::PROTECTED); + ALOGE_IF(protectedPlaceholder == EGL_NO_SURFACE, + "can't create protected placeholder pbuffer"); + } + + // initialize the renderer while GL is current + std::unique_ptr<SkiaGLRenderEngine> engine = + std::make_unique<SkiaGLRenderEngine>(args, display, config, ctxt, placeholder, + protectedContext, protectedPlaceholder); + + ALOGI("OpenGL ES informations:"); + ALOGI("vendor : %s", extensions.getVendor()); + ALOGI("renderer : %s", extensions.getRenderer()); + ALOGI("version : %s", extensions.getVersion()); + ALOGI("extensions: %s", extensions.getExtensions()); + ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize()); + ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims()); + + return engine; +} + +EGLConfig SkiaGLRenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) { + status_t err; + EGLConfig config; + + // First try to get an ES3 config + err = selectEGLConfig(display, format, EGL_OPENGL_ES3_BIT, &config); + if (err != NO_ERROR) { + // If ES3 fails, try to get an ES2 config + err = selectEGLConfig(display, format, EGL_OPENGL_ES2_BIT, &config); + if (err != NO_ERROR) { + // If ES2 still doesn't work, probably because we're on the emulator. + // try a simplified query + ALOGW("no suitable EGLConfig found, trying a simpler query"); + err = selectEGLConfig(display, format, 0, &config); + if (err != NO_ERROR) { + // this EGL is too lame for android + LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up"); + } + } + } + + if (logConfig) { + // print some debugging info + EGLint r, g, b, a; + eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); + eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); + eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); + eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); + ALOGI("EGL information:"); + ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR)); + ALOGI("version : %s", eglQueryString(display, EGL_VERSION)); + ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS)); + ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS) ?: "Not Supported"); + ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); + } + + return config; +} + +SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, + EGLConfig config, EGLContext ctxt, EGLSurface placeholder, + EGLContext protectedContext, EGLSurface protectedPlaceholder) + : renderengine::skia::SkiaRenderEngine(args), + mEGLDisplay(display), + mEGLConfig(config), + mEGLContext(ctxt), + mPlaceholderSurface(placeholder), + mProtectedEGLContext(protectedContext), + mProtectedPlaceholderSurface(protectedPlaceholder) { + // Suppress unused field warnings for things we definitely will need/use + // These EGL fields will all be needed for toggling between protected & unprotected contexts + // Or we need different RE instances for that + (void)mEGLDisplay; + (void)mEGLConfig; + (void)mEGLContext; + (void)mPlaceholderSurface; + (void)mProtectedEGLContext; + (void)mProtectedPlaceholderSurface; + + sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface()); + LOG_ALWAYS_FATAL_IF(!glInterface.get()); + + GrContextOptions options; + options.fPreferExternalImagesOverES3 = true; + options.fDisableDistanceFieldPaths = true; + mGrContext = GrDirectContext::MakeGL(std::move(glInterface), options); +} + +base::unique_fd SkiaGLRenderEngine::flush() { + ATRACE_CALL(); + if (!gl::GLExtensions::getInstance().hasNativeFenceSync()) { + return base::unique_fd(); + } + + EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); + if (sync == EGL_NO_SYNC_KHR) { + ALOGW("failed to create EGL native fence sync: %#x", eglGetError()); + return base::unique_fd(); + } + + // native fence fd will not be populated until flush() is done. + glFlush(); + + // get the fence fd + base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync)); + eglDestroySyncKHR(mEGLDisplay, sync); + if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { + ALOGW("failed to dup EGL native fence sync: %#x", eglGetError()); + } + + return fenceFd; +} + +bool SkiaGLRenderEngine::waitFence(base::unique_fd fenceFd) { + if (!gl::GLExtensions::getInstance().hasNativeFenceSync() || + !gl::GLExtensions::getInstance().hasWaitSync()) { + return false; + } + + // release the fd and transfer the ownership to EGLSync + EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd.release(), EGL_NONE}; + EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); + if (sync == EGL_NO_SYNC_KHR) { + ALOGE("failed to create EGL native fence sync: %#x", eglGetError()); + return false; + } + + // XXX: The spec draft is inconsistent as to whether this should return an + // EGLint or void. Ignore the return value for now, as it's not strictly + // needed. + eglWaitSyncKHR(mEGLDisplay, sync, 0); + EGLint error = eglGetError(); + eglDestroySyncKHR(mEGLDisplay, sync); + if (error != EGL_SUCCESS) { + ALOGE("failed to wait for EGL native fence sync: %#x", error); + return false; + } + + return true; +} + +static bool hasUsage(const AHardwareBuffer_Desc& desc, uint64_t usage) { + return !!(desc.usage & usage); +} + +void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) { + std::lock_guard<std::mutex> lock(mRenderingMutex); + mImageCache.erase(bufferId); +} + +status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, + const std::vector<const LayerSettings*>& layers, + const sp<GraphicBuffer>& buffer, + const bool useFramebufferCache, + base::unique_fd&& bufferFence, base::unique_fd* drawFence) { + ATRACE_NAME("SkiaGL::drawLayers"); + std::lock_guard<std::mutex> lock(mRenderingMutex); + if (layers.empty()) { + ALOGV("Drawing empty layer stack"); + return NO_ERROR; + } + + if (bufferFence.get() >= 0) { + // Duplicate the fence for passing to waitFence. + base::unique_fd bufferFenceDup(dup(bufferFence.get())); + if (bufferFenceDup < 0 || !waitFence(std::move(bufferFenceDup))) { + ATRACE_NAME("Waiting before draw"); + sync_wait(bufferFence.get(), -1); + } + } + if (buffer == nullptr) { + ALOGE("No output buffer provided. Aborting GPU composition."); + return BAD_VALUE; + } + + AHardwareBuffer_Desc bufferDesc; + AHardwareBuffer_describe(buffer->toAHardwareBuffer(), &bufferDesc); + + LOG_ALWAYS_FATAL_IF(!hasUsage(bufferDesc, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE), + "missing usage"); + + sk_sp<SkSurface> surface; + if (useFramebufferCache) { + auto iter = mSurfaceCache.find(buffer->getId()); + if (iter != mSurfaceCache.end()) { + ALOGV("Cache hit!"); + surface = iter->second; + } + } + if (!surface) { + surface = SkSurface::MakeFromAHardwareBuffer(mGrContext.get(), buffer->toAHardwareBuffer(), + GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin, + SkColorSpace::MakeSRGB(), nullptr); + if (useFramebufferCache && surface) { + ALOGD("Adding to cache"); + mSurfaceCache.insert({buffer->getId(), surface}); + } + } + if (!surface) { + ALOGE("Failed to make surface"); + return BAD_VALUE; + } + auto canvas = surface->getCanvas(); + + canvas->clipRect(SkRect::MakeLTRB(display.clip.left, display.clip.top, display.clip.right, + display.clip.bottom)); + canvas->drawColor(0, SkBlendMode::kSrc); + for (const auto& layer : layers) { + if (layer->source.buffer.buffer) { + ATRACE_NAME("DrawImage"); + const auto& item = layer->source.buffer; + sk_sp<SkImage> image; + auto iter = mImageCache.find(item.buffer->getId()); + if (iter != mImageCache.end()) { + image = iter->second; + } else { + image = SkImage::MakeFromAHardwareBuffer(item.buffer->toAHardwareBuffer(), + item.usePremultipliedAlpha + ? kPremul_SkAlphaType + : kUnpremul_SkAlphaType); + mImageCache.insert({item.buffer->getId(), image}); + } + const auto& bounds = layer->geometry.boundaries; + SkRect dest = SkRect::MakeLTRB(bounds.left, bounds.top, bounds.right, bounds.bottom); + canvas->drawImageRect(image, dest, nullptr); + } else { + ATRACE_NAME("DrawColor"); + SkPaint paint; + const auto color = layer->source.solidColor; + paint.setColor(SkColor4f{.fR = color.r, .fG = color.g, .fB = color.b, layer->alpha}); + } + } + { + ATRACE_NAME("flush surface"); + surface->flush(); + } + + if (drawFence != nullptr) { + *drawFence = flush(); + } + + // If flush failed or we don't support native fences, we need to force the + // gl command stream to be executed. + bool requireSync = drawFence == nullptr || drawFence->get() < 0; + if (requireSync) { + ATRACE_BEGIN("Submit(sync=true)"); + } else { + ATRACE_BEGIN("Submit(sync=false)"); + } + bool success = mGrContext->submit(requireSync); + ATRACE_END(); + if (!success) { + ALOGE("Failed to flush RenderEngine commands"); + // Chances are, something illegal happened (either the caller passed + // us bad parameters, or we messed up our shader generation). + return INVALID_OPERATION; + } + + // checkErrors(); + return NO_ERROR; +} + +size_t SkiaGLRenderEngine::getMaxTextureSize() const { + return mGrContext->maxTextureSize(); +} + +size_t SkiaGLRenderEngine::getMaxViewportDims() const { + return mGrContext->maxRenderTargetSize(); +} + +EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config, + EGLContext shareContext, bool useContextPriority, + Protection protection) { + EGLint renderableType = 0; + if (config == EGL_NO_CONFIG_KHR) { + renderableType = EGL_OPENGL_ES3_BIT; + } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) { + LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE"); + } + EGLint contextClientVersion = 0; + if (renderableType & EGL_OPENGL_ES3_BIT) { + contextClientVersion = 3; + } else if (renderableType & EGL_OPENGL_ES2_BIT) { + contextClientVersion = 2; + } else if (renderableType & EGL_OPENGL_ES_BIT) { + contextClientVersion = 1; + } else { + LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs"); + } + + std::vector<EGLint> contextAttributes; + contextAttributes.reserve(7); + contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION); + contextAttributes.push_back(contextClientVersion); + if (useContextPriority) { + contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG); + contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG); + } + if (protection == Protection::PROTECTED) { + contextAttributes.push_back(EGL_PROTECTED_CONTENT_EXT); + contextAttributes.push_back(EGL_TRUE); + } + contextAttributes.push_back(EGL_NONE); + + EGLContext context = eglCreateContext(display, config, shareContext, contextAttributes.data()); + + if (contextClientVersion == 3 && context == EGL_NO_CONTEXT) { + // eglGetConfigAttrib indicated we can create GLES 3 context, but we failed, thus + // EGL_NO_CONTEXT so that we can abort. + if (config != EGL_NO_CONFIG_KHR) { + return context; + } + // If |config| is EGL_NO_CONFIG_KHR, we speculatively try to create GLES 3 context, so we + // should try to fall back to GLES 2. + contextAttributes[1] = 2; + context = eglCreateContext(display, config, shareContext, contextAttributes.data()); + } + + return context; +} + +EGLSurface SkiaGLRenderEngine::createPlaceholderEglPbufferSurface(EGLDisplay display, + EGLConfig config, int hwcFormat, + Protection protection) { + EGLConfig placeholderConfig = config; + if (placeholderConfig == EGL_NO_CONFIG_KHR) { + placeholderConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true); + } + std::vector<EGLint> attributes; + attributes.reserve(7); + attributes.push_back(EGL_WIDTH); + attributes.push_back(1); + attributes.push_back(EGL_HEIGHT); + attributes.push_back(1); + if (protection == Protection::PROTECTED) { + attributes.push_back(EGL_PROTECTED_CONTENT_EXT); + attributes.push_back(EGL_TRUE); + } + attributes.push_back(EGL_NONE); + + return eglCreatePbufferSurface(display, placeholderConfig, attributes.data()); +} + +void SkiaGLRenderEngine::cleanFramebufferCache() { + mSurfaceCache.clear(); +} + +} // namespace skia +} // namespace renderengine +} // namespace android
\ No newline at end of file diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h new file mode 100644 index 0000000000..eb098cb0ac --- /dev/null +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -0,0 +1,93 @@ +/* + * Copyright 2020 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. + */ + +#ifndef SF_SKIAGLRENDERENGINE_H_ +#define SF_SKIAGLRENDERENGINE_H_ + +#include <sys/types.h> +#include <mutex> +#include <unordered_map> + +#include <android-base/thread_annotations.h> +#include <renderengine/RenderEngine.h> + +#include <GrDirectContext.h> +#include <SkSurface.h> + +#include "SkiaRenderEngine.h" + +namespace android { +namespace renderengine { +namespace skia { + +class SkiaGLRenderEngine : public skia::SkiaRenderEngine { +public: + static std::unique_ptr<SkiaGLRenderEngine> create(const RenderEngineCreationArgs& args); + SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLConfig config, + EGLContext ctxt, EGLSurface placeholder, EGLContext protectedContext, + EGLSurface protectedPlaceholder); + ~SkiaGLRenderEngine() override{}; + + void unbindExternalTextureBuffer(uint64_t bufferId) override; + status_t drawLayers(const DisplaySettings& display, + const std::vector<const LayerSettings*>& layers, + const sp<GraphicBuffer>& buffer, const bool useFramebufferCache, + base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; + void cleanFramebufferCache() override; + +protected: + void dump(std::string& /*result*/) override{}; + size_t getMaxTextureSize() const override; + size_t getMaxViewportDims() const override; + +private: + static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); + static EGLContext createEglContext(EGLDisplay display, EGLConfig config, + EGLContext shareContext, bool useContextPriority, + Protection protection); + static EGLSurface createPlaceholderEglPbufferSurface(EGLDisplay display, EGLConfig config, + int hwcFormat, Protection protection); + + base::unique_fd flush(); + bool waitFence(base::unique_fd fenceFd); + + EGLDisplay mEGLDisplay; + EGLConfig mEGLConfig; + EGLContext mEGLContext; + EGLSurface mPlaceholderSurface; + EGLContext mProtectedEGLContext; + EGLSurface mProtectedPlaceholderSurface; + + // Cache of GL images that we'll store per GraphicBuffer ID + std::unordered_map<uint64_t, sk_sp<SkImage>> mImageCache GUARDED_BY(mRenderingMutex); + // Mutex guarding rendering operations, so that: + // 1. GL operations aren't interleaved, and + // 2. Internal state related to rendering that is potentially modified by + // multiple threads is guaranteed thread-safe. + std::mutex mRenderingMutex; + + sp<Fence> mLastDrawFence; + + sk_sp<GrDirectContext> mGrContext; + + std::unordered_map<uint64_t, sk_sp<SkSurface>> mSurfaceCache; +}; + +} // namespace skia +} // namespace renderengine +} // namespace android + +#endif /* SF_GLESRENDERENGINE_H_ */
\ No newline at end of file diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp new file mode 100644 index 0000000000..81f0b6f970 --- /dev/null +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -0,0 +1,26 @@ +/* + * Copyright 2020 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. + */ + +//#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "RenderEngine" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +namespace android { +namespace renderengine { +namespace skia {} // namespace skia +} // namespace renderengine +} // namespace android
\ No newline at end of file diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h new file mode 100644 index 0000000000..3c5d0cf24d --- /dev/null +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -0,0 +1,71 @@ +/* + * Copyright 2020 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. + */ + +#ifndef SF_SKIARENDERENGINE_H_ +#define SF_SKIARENDERENGINE_H_ + +#include <renderengine/RenderEngine.h> +#include <sys/types.h> + +namespace android { + +namespace renderengine { + +class Mesh; +class Texture; + +namespace skia { + +class BlurFilter; + +// TODO: Put common skia stuff here that can be shared between the GL & Vulkan backends +// Currently mostly just handles all the no-op / missing APIs +class SkiaRenderEngine : public impl::RenderEngine { +public: + static std::unique_ptr<SkiaRenderEngine> create(const RenderEngineCreationArgs& args); + SkiaRenderEngine(const RenderEngineCreationArgs& args) : RenderEngine(args){}; + ~SkiaRenderEngine() override {} + + virtual void primeCache() const override{}; + virtual void genTextures(size_t /*count*/, uint32_t* /*names*/) override{}; + virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{}; + virtual status_t bindExternalTextureBuffer(uint32_t /*texName*/, + const sp<GraphicBuffer>& /*buffer*/, + const sp<Fence>& /*fence*/) { + return 0; + }; // EXCLUDES(mRenderingMutex); + virtual void cacheExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/){}; + virtual void unbindExternalTextureBuffer(uint64_t /*bufferId*/){}; + + virtual bool isProtected() const override { return false; } // mInProtectedContext; } + virtual bool supportsProtectedContent() const override { return false; }; + virtual bool useProtectedContext(bool /*useProtectedContext*/) override { return false; }; + virtual status_t drawLayers(const DisplaySettings& /*display*/, + const std::vector<const LayerSettings*>& /*layers*/, + const sp<GraphicBuffer>& /*buffer*/, + const bool /*useFramebufferCache*/, + base::unique_fd&& /*bufferFence*/, + base::unique_fd* /*drawFence*/) override { + return 0; + }; + virtual bool cleanupPostRender(CleanupMode) override { return true; }; +}; + +} // namespace skia +} // namespace renderengine +} // namespace android + +#endif /* SF_GLESRENDERENGINE_H_ */
\ No newline at end of file diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index b017ad7e78..db808e0663 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -13,7 +13,10 @@ cc_defaults { cc_defaults { name: "libsurfaceflinger_defaults", - defaults: ["surfaceflinger_defaults"], + defaults: [ + "surfaceflinger_defaults", + "skia_deps", + ], cflags: [ "-DLOG_TAG=\"SurfaceFlinger\"", "-DGL_GLEXT_PROTOTYPES", diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index 2773fd3a16..8d1ffe326d 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -42,6 +42,9 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion" +// Uncomment to enable RE-SK workarounds; b/b/168499446 +//#define USE_SKIA_WORKAROUNDS + namespace android::compositionengine { RenderSurface::~RenderSurface() = default; @@ -81,7 +84,11 @@ void RenderSurface::initialize() { ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status); status = native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); ALOGE_IF(status != NO_ERROR, "Unable to set BQ format to RGBA888: %d", status); +#ifdef USE_SKIA_WORKAROUNDS + status = native_window_set_usage(window, GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE); +#else status = native_window_set_usage(window, GRALLOC_USAGE_HW_RENDER); +#endif ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for GPU rendering: %d", status); } @@ -113,6 +120,9 @@ void RenderSurface::setProtected(bool useProtected) { if (useProtected) { usageFlags |= GRALLOC_USAGE_PROTECTED; } +#ifdef USE_SKIA_WORKAROUNDS + usageFlags |= GRALLOC_USAGE_HW_TEXTURE; +#endif const int status = native_window_set_usage(mNativeWindow.get(), usageFlags); ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for protected content: %d", status); if (status == NO_ERROR) { diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index a2fc6925b8..890945f6f3 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -441,7 +441,8 @@ void RegionSamplingThread::captureSample() { mCachedBuffer->getHeight() == sampledBounds.getHeight()) { buffer = mCachedBuffer; } else { - const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER; + const uint32_t usage = + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; buffer = new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(), PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); } |