diff options
Diffstat (limited to 'libs/renderengine/gl/GLESRenderEngine.cpp')
-rw-r--r-- | libs/renderengine/gl/GLESRenderEngine.cpp | 348 |
1 files changed, 247 insertions, 101 deletions
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 92e7e715ea..467f848237 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -15,6 +15,7 @@ */ //#define LOG_NDEBUG 0 +#include "EGL/egl.h" #undef LOG_TAG #define LOG_TAG "RenderEngine" #define ATRACE_TAG ATRACE_TAG_GRAPHICS @@ -51,8 +52,6 @@ #include "ProgramCache.h" #include "filters/BlurFilter.h" -extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); - bool checkGlError(const char* op, int lineNumber) { bool errorFound = false; GLint error = glGetError(); @@ -116,6 +115,28 @@ namespace android { namespace renderengine { namespace gl { +class BindNativeBufferAsFramebuffer { +public: + BindNativeBufferAsFramebuffer(GLESRenderEngine& engine, ANativeWindowBuffer* buffer, + const bool useFramebufferCache) + : mEngine(engine), mFramebuffer(mEngine.getFramebufferForDrawing()), mStatus(NO_ERROR) { + mStatus = mFramebuffer->setNativeWindowBuffer(buffer, mEngine.isProtected(), + useFramebufferCache) + ? mEngine.bindFrameBuffer(mFramebuffer) + : NO_MEMORY; + } + ~BindNativeBufferAsFramebuffer() { + mFramebuffer->setNativeWindowBuffer(nullptr, false, /*arbitrary*/ true); + mEngine.unbindFrameBuffer(mFramebuffer); + } + status_t getStatus() const { return mStatus; } + +private: + GLESRenderEngine& mEngine; + Framebuffer* mFramebuffer; + status_t mStatus; +}; + using base::StringAppendF; using ui::Dataspace; @@ -201,23 +222,47 @@ static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint render return err; } +std::optional<RenderEngine::ContextPriority> GLESRenderEngine::createContextPriority( + const RenderEngineCreationArgs& args) { + if (!GLExtensions::getInstance().hasContextPriority()) { + return std::nullopt; + } + + switch (args.contextPriority) { + case RenderEngine::ContextPriority::REALTIME: + if (gl::GLExtensions::getInstance().hasRealtimePriority()) { + return RenderEngine::ContextPriority::REALTIME; + } else { + ALOGI("Realtime priority unsupported, degrading gracefully to high priority"); + return RenderEngine::ContextPriority::HIGH; + } + case RenderEngine::ContextPriority::HIGH: + case RenderEngine::ContextPriority::MEDIUM: + case RenderEngine::ContextPriority::LOW: + return args.contextPriority; + default: + return std::nullopt; + } +} + std::unique_ptr<GLESRenderEngine> GLESRenderEngine::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"); + LOG_ALWAYS_FATAL("failed to initialize EGL. EGL error=0x%x", eglGetError()); } - const auto eglVersion = eglQueryStringImplementationANDROID(display, EGL_VERSION); + const auto eglVersion = eglQueryString(display, EGL_VERSION); if (!eglVersion) { checkGlError(__FUNCTION__, __LINE__); - LOG_ALWAYS_FATAL("eglQueryStringImplementationANDROID(EGL_VERSION) failed"); + LOG_ALWAYS_FATAL("eglQueryString(EGL_VERSION) failed"); } - const auto eglExtensions = eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS); + // Use the Android impl to grab EGL_NV_context_priority_realtime + const auto eglExtensions = eglQueryString(display, EGL_EXTENSIONS); if (!eglExtensions) { checkGlError(__FUNCTION__, __LINE__); - LOG_ALWAYS_FATAL("eglQueryStringImplementationANDROID(EGL_EXTENSIONS) failed"); + LOG_ALWAYS_FATAL("eglQueryString(EGL_EXTENSIONS) failed"); } GLExtensions& extensions = GLExtensions::getInstance(); @@ -230,37 +275,36 @@ std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(const RenderEngineCre config = chooseEglConfig(display, args.pixelFormat, /*logConfig*/ true); } - bool useContextPriority = - extensions.hasContextPriority() && args.contextPriority == ContextPriority::HIGH; + const std::optional<RenderEngine::ContextPriority> priority = createContextPriority(args); EGLContext protectedContext = EGL_NO_CONTEXT; if (args.enableProtectedContext && extensions.hasProtectedContent()) { - protectedContext = createEglContext(display, config, nullptr, useContextPriority, - Protection::PROTECTED); + protectedContext = + createEglContext(display, config, nullptr, priority, Protection::PROTECTED); ALOGE_IF(protectedContext == EGL_NO_CONTEXT, "Can't create protected context"); } - EGLContext ctxt = createEglContext(display, config, protectedContext, useContextPriority, - Protection::UNPROTECTED); + EGLContext ctxt = + createEglContext(display, config, protectedContext, priority, 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 dummy = EGL_NO_SURFACE; + EGLSurface stub = EGL_NO_SURFACE; if (!extensions.hasSurfacelessContext()) { - dummy = createDummyEglPbufferSurface(display, config, args.pixelFormat, - Protection::UNPROTECTED); - LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer"); + stub = createStubEglPbufferSurface(display, config, args.pixelFormat, + Protection::UNPROTECTED); + LOG_ALWAYS_FATAL_IF(stub == EGL_NO_SURFACE, "can't create stub pbuffer"); } - EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt); - LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current"); + EGLBoolean success = eglMakeCurrent(display, stub, stub, ctxt); + LOG_ALWAYS_FATAL_IF(!success, "can't make stub pbuffer current"); extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER), glGetString(GL_VERSION), glGetString(GL_EXTENSIONS)); - EGLSurface protectedDummy = EGL_NO_SURFACE; + EGLSurface protectedStub = EGL_NO_SURFACE; if (protectedContext != EGL_NO_CONTEXT && !extensions.hasSurfacelessContext()) { - protectedDummy = createDummyEglPbufferSurface(display, config, args.pixelFormat, - Protection::PROTECTED); - ALOGE_IF(protectedDummy == EGL_NO_SURFACE, "can't create protected dummy pbuffer"); + protectedStub = createStubEglPbufferSurface(display, config, args.pixelFormat, + Protection::PROTECTED); + ALOGE_IF(protectedStub == EGL_NO_SURFACE, "can't create protected stub pbuffer"); } // now figure out what version of GL did we actually get @@ -278,8 +322,8 @@ std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(const RenderEngineCre break; case GLES_VERSION_2_0: case GLES_VERSION_3_0: - engine = std::make_unique<GLESRenderEngine>(args, display, config, ctxt, dummy, - protectedContext, protectedDummy); + engine = std::make_unique<GLESRenderEngine>(args, display, config, ctxt, stub, + protectedContext, protectedStub); break; } @@ -290,7 +334,6 @@ std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(const RenderEngineCre ALOGI("extensions: %s", extensions.getExtensions()); ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize()); ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims()); - return engine; } @@ -334,19 +377,20 @@ EGLConfig GLESRenderEngine::chooseEglConfig(EGLDisplay display, int format, bool } GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, - EGLConfig config, EGLContext ctxt, EGLSurface dummy, - EGLContext protectedContext, EGLSurface protectedDummy) - : renderengine::impl::RenderEngine(args), + EGLConfig config, EGLContext ctxt, EGLSurface stub, + EGLContext protectedContext, EGLSurface protectedStub) + : RenderEngine(args.renderEngineType), mEGLDisplay(display), mEGLConfig(config), mEGLContext(ctxt), - mDummySurface(dummy), + mStubSurface(stub), mProtectedEGLContext(protectedContext), - mProtectedDummySurface(protectedDummy), + mProtectedStubSurface(protectedStub), mVpWidth(0), mVpHeight(0), mFramebufferImageCacheSize(args.imageCacheSize), - mUseColorManagement(args.useColorManagement) { + mUseColorManagement(args.useColorManagement), + mPrecacheToneMapperShaderOnly(args.precacheToneMapperShaderOnly) { glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); @@ -355,12 +399,12 @@ GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisp // Initialize protected EGL Context. if (mProtectedEGLContext != EGL_NO_CONTEXT) { - EGLBoolean success = eglMakeCurrent(display, mProtectedDummySurface, mProtectedDummySurface, + EGLBoolean success = eglMakeCurrent(display, mProtectedStubSurface, mProtectedStubSurface, mProtectedEGLContext); ALOGE_IF(!success, "can't make protected context current"); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glPixelStorei(GL_PACK_ALIGNMENT, 4); - success = eglMakeCurrent(display, mDummySurface, mDummySurface, mEGLContext); + success = eglMakeCurrent(display, mStubSurface, mStubSurface, mEGLContext); LOG_ALWAYS_FATAL_IF(!success, "can't make default context current"); } @@ -409,23 +453,54 @@ GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisp mImageManager = std::make_unique<ImageManager>(this); mImageManager->initThread(); mDrawingBuffer = createFramebuffer(); + sp<GraphicBuffer> buf = + new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE, "placeholder"); + + const status_t err = buf->initCheck(); + if (err != OK) { + ALOGE("Error allocating placeholder buffer: %d", err); + return; + } + mPlaceholderBuffer = buf.get(); + EGLint attributes[] = { + EGL_NONE, + }; + mPlaceholderImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, + mPlaceholderBuffer, attributes); + ALOGE_IF(mPlaceholderImage == EGL_NO_IMAGE_KHR, "Failed to create placeholder image: %#x", + eglGetError()); + + mShadowTexture = std::make_unique<GLShadowTexture>(); } GLESRenderEngine::~GLESRenderEngine() { // Destroy the image manager first. mImageManager = nullptr; + mShadowTexture = nullptr; + cleanFramebufferCache(); + ProgramCache::getInstance().purgeCaches(); std::lock_guard<std::mutex> lock(mRenderingMutex); + glDisableVertexAttribArray(Program::position); unbindFrameBuffer(mDrawingBuffer.get()); mDrawingBuffer = nullptr; - while (!mFramebufferImageCache.empty()) { - EGLImageKHR expired = mFramebufferImageCache.front().second; - mFramebufferImageCache.pop_front(); - eglDestroyImageKHR(mEGLDisplay, expired); - DEBUG_EGL_IMAGE_TRACKER_DESTROY(); - } + eglDestroyImageKHR(mEGLDisplay, mPlaceholderImage); mImageCache.clear(); + if (mStubSurface != EGL_NO_SURFACE) { + eglDestroySurface(mEGLDisplay, mStubSurface); + } + if (mProtectedStubSurface != EGL_NO_SURFACE) { + eglDestroySurface(mEGLDisplay, mProtectedStubSurface); + } + if (mEGLContext != EGL_NO_CONTEXT) { + eglDestroyContext(mEGLDisplay, mEGLContext); + } + if (mProtectedEGLContext != EGL_NO_CONTEXT) { + eglDestroyContext(mEGLDisplay, mProtectedEGLContext); + } eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglTerminate(mEGLDisplay); + eglReleaseThread(); } std::unique_ptr<Framebuffer> GLESRenderEngine::createFramebuffer() { @@ -440,10 +515,10 @@ Framebuffer* GLESRenderEngine::getFramebufferForDrawing() { return mDrawingBuffer.get(); } -void GLESRenderEngine::primeCache() const { +std::future<void> GLESRenderEngine::primeCache() { ProgramCache::getInstance().primeCache(mInProtectedContext ? mProtectedEGLContext : mEGLContext, - mArgs.useColorManagement, - mArgs.precacheToneMapperShaderOnly); + mUseColorManagement, mPrecacheToneMapperShaderOnly); + return {}; } base::unique_fd GLESRenderEngine::flush() { @@ -589,6 +664,9 @@ void GLESRenderEngine::genTextures(size_t count, uint32_t* names) { } void GLESRenderEngine::deleteTextures(size_t count, uint32_t const* names) { + for (int i = 0; i < count; ++i) { + mTextureView.erase(names[i]); + } glDeleteTextures(count, names); } @@ -603,13 +681,8 @@ void GLESRenderEngine::bindExternalTextureImage(uint32_t texName, const Image& i } } -status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, - const sp<GraphicBuffer>& buffer, - const sp<Fence>& bufferFence) { - if (buffer == nullptr) { - return BAD_VALUE; - } - +void GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer, + const sp<Fence>& bufferFence) { ATRACE_CALL(); bool found = false; @@ -625,7 +698,8 @@ status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, if (!found) { status_t cacheResult = mImageManager->cache(buffer); if (cacheResult != NO_ERROR) { - return cacheResult; + ALOGE("Error with caching buffer: %d", cacheResult); + return; } } @@ -642,10 +716,11 @@ status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, // We failed creating the image if we got here, so bail out. ALOGE("Failed to create an EGLImage when rendering"); bindExternalTextureImage(texName, *createImage()); - return NO_INIT; + return; } bindExternalTextureImage(texName, *cachedImage->second); + mTextureView.insert_or_assign(texName, buffer->getId()); } // Wait for the new buffer to be ready. @@ -654,25 +729,27 @@ status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, base::unique_fd fenceFd(bufferFence->dup()); if (fenceFd == -1) { ALOGE("error dup'ing fence fd: %d", errno); - return -errno; + return; } if (!waitFence(std::move(fenceFd))) { ALOGE("failed to wait on fence fd"); - return UNKNOWN_ERROR; + return; } } else { status_t err = bufferFence->waitForever("RenderEngine::bindExternalTextureBuffer"); if (err != NO_ERROR) { ALOGE("error waiting for fence: %d", err); - return err; + return; } } } - return NO_ERROR; + return; } -void GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) { +void GLESRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, + bool /*isRenderable*/) { + ATRACE_CALL(); mImageManager->cacheAsync(buffer, nullptr); } @@ -703,9 +780,9 @@ status_t GLESRenderEngine::cacheExternalTextureBufferInternal(const sp<GraphicBu bool created = newImage->setNativeWindowBuffer(buffer->getNativeBuffer(), buffer->getUsage() & GRALLOC_USAGE_PROTECTED); if (!created) { - ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d", - buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(), - buffer->getPixelFormat()); + ALOGE("Failed to create image. id=%" PRIx64 " size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d", + buffer->getId(), buffer->getWidth(), buffer->getHeight(), buffer->getStride(), + buffer->getUsage(), buffer->getPixelFormat()); return NO_INIT; } @@ -722,8 +799,8 @@ status_t GLESRenderEngine::cacheExternalTextureBufferInternal(const sp<GraphicBu return NO_ERROR; } -void GLESRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) { - mImageManager->releaseAsync(bufferId, nullptr); +void GLESRenderEngine::unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) { + mImageManager->releaseAsync(buffer->getId(), nullptr); } std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::unbindExternalTextureBufferForTesting( @@ -751,6 +828,12 @@ void GLESRenderEngine::unbindExternalTextureBufferInternal(uint64_t bufferId) { ALOGV("Failed to find image for buffer: %" PRIu64, bufferId); } +int GLESRenderEngine::getContextPriority() { + int value; + eglQueryContext(mEGLDisplay, mEGLContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &value); + return value; +} + FloatRect GLESRenderEngine::setupLayerCropping(const LayerSettings& layer, Mesh& mesh) { // Translate win by the rounded corners rect coordinates, to have all values in // layer coordinate space. @@ -887,23 +970,41 @@ void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /*framebuffer*/) { glBindFramebuffer(GL_FRAMEBUFFER, 0); } -bool GLESRenderEngine::cleanupPostRender() { +bool GLESRenderEngine::canSkipPostRenderCleanup() const { + return mPriorResourcesCleaned || + (mLastDrawFence != nullptr && mLastDrawFence->getStatus() != Fence::Status::Signaled); +} + +void GLESRenderEngine::cleanupPostRender() { ATRACE_CALL(); - if (mPriorResourcesCleaned || - (mLastDrawFence != nullptr && mLastDrawFence->getStatus() != Fence::Status::Signaled)) { + if (canSkipPostRenderCleanup()) { // If we don't have a prior frame needing cleanup, then don't do anything. - return false; + return; } - // Bind the texture to dummy data so that backing image data can be freed. + // Bind the texture to placeholder so that backing image data can be freed. GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(getFramebufferForDrawing()); glFramebuffer->allocateBuffers(1, 1, mPlaceholderDrawBuffer); + // Release the cached fence here, so that we don't churn reallocations when // we could no-op repeated calls of this method instead. mLastDrawFence = nullptr; mPriorResourcesCleaned = true; - return true; +} + +void GLESRenderEngine::cleanFramebufferCache() { + std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex); + // Bind the texture to placeholder so that backing image data can be freed. + GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(getFramebufferForDrawing()); + glFramebuffer->allocateBuffers(1, 1, mPlaceholderDrawBuffer); + + while (!mFramebufferImageCache.empty()) { + EGLImageKHR expired = mFramebufferImageCache.front().second; + mFramebufferImageCache.pop_front(); + eglDestroyImageKHR(mEGLDisplay, expired); + DEBUG_EGL_IMAGE_TRACKER_DESTROY(); + } } void GLESRenderEngine::checkErrors() const { @@ -927,20 +1028,17 @@ bool GLESRenderEngine::supportsProtectedContent() const { return mProtectedEGLContext != EGL_NO_CONTEXT; } -bool GLESRenderEngine::useProtectedContext(bool useProtectedContext) { - if (useProtectedContext == mInProtectedContext) { - return true; - } - if (useProtectedContext && mProtectedEGLContext == EGL_NO_CONTEXT) { - return false; +void GLESRenderEngine::useProtectedContext(bool useProtectedContext) { + if (useProtectedContext == mInProtectedContext || + (useProtectedContext && !supportsProtectedContent())) { + return; } - const EGLSurface surface = useProtectedContext ? mProtectedDummySurface : mDummySurface; + + const EGLSurface surface = useProtectedContext ? mProtectedStubSurface : mStubSurface; const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext; - const bool success = eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE; - if (success) { + if (eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE) { mInProtectedContext = useProtectedContext; } - return success; } EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected, @@ -982,7 +1080,7 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, const std::vector<const LayerSettings*>& layers, - ANativeWindowBuffer* const buffer, + const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence, base::unique_fd* drawFence) { ATRACE_CALL(); @@ -1005,6 +1103,8 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, return BAD_VALUE; } + validateOutputBufferUsage(buffer->getBuffer()); + std::unique_ptr<BindNativeBufferAsFramebuffer> fbo; // Gathering layers that requested blur, we'll need them to decide when to render to an // offscreen buffer, and when to render to the native buffer. @@ -1019,10 +1119,14 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, const auto blurLayersSize = blurLayers.size(); if (blurLayersSize == 0) { - fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, buffer, useFramebufferCache); + fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, + buffer->getBuffer() + .get() + ->getNativeBuffer(), + useFramebufferCache); if (fbo->getStatus() != NO_ERROR) { ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors(); return fbo->getStatus(); } @@ -1033,7 +1137,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, mBlurFilter->setAsDrawTarget(display, blurLayers.front()->backgroundBlurRadius); if (status != NO_ERROR) { ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors(); return status; } @@ -1048,6 +1152,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, setOutputDataSpace(display.outputDataspace); setDisplayMaxLuminance(display.maxLuminance); + setDisplayColorTransform(display.colorTransform); const mat4 projectionMatrix = ui::Transform(display.orientation).asMatrix4() * mState.projectionMatrix; @@ -1069,14 +1174,17 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, auto status = mBlurFilter->prepare(); if (status != NO_ERROR) { ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors("Can't render first blur pass"); return status; } if (blurLayers.size() == 0) { // Done blurring, time to bind the native FBO and render our blur onto it. - fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, buffer, + fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, + buffer.get() + ->getBuffer() + ->getNativeBuffer(), useFramebufferCache); status = fbo->getStatus(); setViewportAndProjection(display.physicalDisplay, display.clip); @@ -1088,7 +1196,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, } if (status != NO_ERROR) { ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors("Can't bind native framebuffer"); return status; } @@ -1096,14 +1204,16 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, status = mBlurFilter->render(blurLayersSize > 1); if (status != NO_ERROR) { ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors("Can't render blur filter"); return status; } } - mState.maxMasteringLuminance = layer->source.buffer.maxMasteringLuminance; - mState.maxContentLuminance = layer->source.buffer.maxContentLuminance; + // Ensure luminance is at least 100 nits to avoid div-by-zero + const float maxLuminance = std::max(100.f, layer->source.buffer.maxLuminanceNits); + mState.maxMasteringLuminance = maxLuminance; + mState.maxContentLuminance = maxLuminance; mState.projectionMatrix = projectionMatrix * layer->geometry.positionTransform; const FloatRect bounds = layer->geometry.boundaries; @@ -1114,7 +1224,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, position[3] = vec2(bounds.right, bounds.top); setupLayerCropping(*layer, mesh); - setColorTransform(display.colorTransform * layer->colorTransform); + setColorTransform(layer->colorTransform); bool usePremultipliedAlpha = true; bool disableTexture = true; @@ -1123,7 +1233,8 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, disableTexture = false; isOpaque = layer->source.buffer.isOpaque; - sp<GraphicBuffer> gBuf = layer->source.buffer.buffer; + sp<GraphicBuffer> gBuf = layer->source.buffer.buffer->getBuffer(); + validateInputBufferUsage(gBuf); bindExternalTextureBuffer(layer->source.buffer.textureName, gBuf, layer->source.buffer.fence); @@ -1143,6 +1254,11 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, texCoords[2] = vec2(1.0, 1.0); texCoords[3] = vec2(1.0, 0.0); setupLayerTexturing(texture); + + // Do not cache protected EGLImage, protected memory is limited. + if (gBuf->getUsage() & GRALLOC_USAGE_PROTECTED) { + unmapExternalTextureBuffer(gBuf); + } } const half3 solidColor = layer->source.solidColor; @@ -1228,7 +1344,8 @@ void GLESRenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque, if (color.a < 1.0f || !opaque || cornerRadius > 0.0f) { glEnable(GL_BLEND); - glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, + GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else { glDisable(GL_BLEND); } @@ -1270,6 +1387,10 @@ void GLESRenderEngine::setColorTransform(const mat4& colorTransform) { mState.colorMatrix = colorTransform; } +void GLESRenderEngine::setDisplayColorTransform(const mat4& colorTransform) { + mState.displayColorMatrix = colorTransform; +} + void GLESRenderEngine::disableTexturing() { mState.textureEnabled = false; } @@ -1512,7 +1633,8 @@ GLESRenderEngine::GlesVersion GLESRenderEngine::parseGlesVersion(const char* str } EGLContext GLESRenderEngine::createEglContext(EGLDisplay display, EGLConfig config, - EGLContext shareContext, bool useContextPriority, + EGLContext shareContext, + std::optional<ContextPriority> contextPriority, Protection protection) { EGLint renderableType = 0; if (config == EGL_NO_CONFIG) { @@ -1535,9 +1657,23 @@ EGLContext GLESRenderEngine::createEglContext(EGLDisplay display, EGLConfig conf contextAttributes.reserve(7); contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION); contextAttributes.push_back(contextClientVersion); - if (useContextPriority) { + if (contextPriority) { contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG); - contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG); + switch (*contextPriority) { + case ContextPriority::REALTIME: + contextAttributes.push_back(EGL_CONTEXT_PRIORITY_REALTIME_NV); + break; + case ContextPriority::MEDIUM: + contextAttributes.push_back(EGL_CONTEXT_PRIORITY_MEDIUM_IMG); + break; + case ContextPriority::LOW: + contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LOW_IMG); + break; + case ContextPriority::HIGH: + default: + contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG); + break; + } } if (protection == Protection::PROTECTED) { contextAttributes.push_back(EGL_PROTECTED_CONTENT_EXT); @@ -1562,11 +1698,11 @@ EGLContext GLESRenderEngine::createEglContext(EGLDisplay display, EGLConfig conf return context; } -EGLSurface GLESRenderEngine::createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config, - int hwcFormat, Protection protection) { - EGLConfig dummyConfig = config; - if (dummyConfig == EGL_NO_CONFIG) { - dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true); +EGLSurface GLESRenderEngine::createStubEglPbufferSurface(EGLDisplay display, EGLConfig config, + int hwcFormat, Protection protection) { + EGLConfig stubConfig = config; + if (stubConfig == EGL_NO_CONFIG) { + stubConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true); } std::vector<EGLint> attributes; attributes.reserve(7); @@ -1580,7 +1716,7 @@ EGLSurface GLESRenderEngine::createDummyEglPbufferSurface(EGLDisplay display, EG } attributes.push_back(EGL_NONE); - return eglCreatePbufferSurface(display, dummyConfig, attributes.data()); + return eglCreatePbufferSurface(display, stubConfig, attributes.data()); } bool GLESRenderEngine::isHdrDataSpace(const Dataspace dataSpace) const { @@ -1616,6 +1752,16 @@ bool GLESRenderEngine::isImageCachedForTesting(uint64_t bufferId) { return cachedImage != mImageCache.end(); } +bool GLESRenderEngine::isTextureNameKnownForTesting(uint32_t texName) { + const auto& entry = mTextureView.find(texName); + return entry != mTextureView.end(); +} + +std::optional<uint64_t> GLESRenderEngine::getBufferIdForTextureNameForTesting(uint32_t texName) { + const auto& entry = mTextureView.find(texName); + return entry != mTextureView.end() ? entry->second : std::nullopt; +} + bool GLESRenderEngine::isFramebufferImageCachedForTesting(uint64_t bufferId) { std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex); return std::any_of(mFramebufferImageCache.cbegin(), mFramebufferImageCache.cend(), @@ -1704,7 +1850,7 @@ void GLESRenderEngine::handleShadow(const FloatRect& casterRect, float casterCor mState.cornerRadius = 0.0f; mState.drawShadows = true; - setupLayerTexturing(mShadowTexture.getTexture()); + setupLayerTexturing(mShadowTexture->getTexture()); drawMesh(mesh); mState.drawShadows = false; } |