diff options
52 files changed, 32 insertions, 6668 deletions
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 8d19c45527..ba2eb7d224 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -56,30 +56,8 @@ cc_defaults { filegroup { name: "librenderengine_sources", srcs: [ - "Description.cpp", "ExternalTexture.cpp", - "Mesh.cpp", "RenderEngine.cpp", - "Texture.cpp", - ], -} - -filegroup { - name: "librenderengine_gl_sources", - srcs: [ - "gl/GLESRenderEngine.cpp", - "gl/GLExtensions.cpp", - "gl/GLFramebuffer.cpp", - "gl/GLImage.cpp", - "gl/GLShadowTexture.cpp", - "gl/GLShadowVertexGenerator.cpp", - "gl/GLSkiaShadowPort.cpp", - "gl/GLVertexBuffer.cpp", - "gl/ImageManager.cpp", - "gl/Program.cpp", - "gl/ProgramCache.cpp", - "gl/filters/BlurFilter.cpp", - "gl/filters/GenericProgram.cpp", ], } @@ -96,6 +74,7 @@ filegroup { "skia/AutoBackendTexture.cpp", "skia/Cache.cpp", "skia/ColorSpaces.cpp", + "skia/GLExtensions.cpp", "skia/SkiaRenderEngine.cpp", "skia/SkiaGLRenderEngine.cpp", "skia/SkiaVkRenderEngine.cpp", @@ -136,7 +115,6 @@ cc_library_static { ], srcs: [ ":librenderengine_sources", - ":librenderengine_gl_sources", ":librenderengine_threaded_sources", ":librenderengine_skia_sources", ], @@ -155,8 +133,6 @@ cc_library_static { name: "librenderengine_mocks", defaults: ["librenderengine_defaults"], srcs: [ - "mock/Framebuffer.cpp", - "mock/Image.cpp", "mock/RenderEngine.cpp", ], static_libs: [ diff --git a/libs/renderengine/Description.cpp b/libs/renderengine/Description.cpp deleted file mode 100644 index 245c9e1e30..0000000000 --- a/libs/renderengine/Description.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013 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 <renderengine/private/Description.h> - -#include <stdint.h> - -#include <utils/TypeHelpers.h> - -namespace android { -namespace renderengine { - -Description::TransferFunction Description::dataSpaceToTransferFunction(ui::Dataspace dataSpace) { - ui::Dataspace transfer = static_cast<ui::Dataspace>(dataSpace & ui::Dataspace::TRANSFER_MASK); - switch (transfer) { - case ui::Dataspace::TRANSFER_ST2084: - return Description::TransferFunction::ST2084; - case ui::Dataspace::TRANSFER_HLG: - return Description::TransferFunction::HLG; - case ui::Dataspace::TRANSFER_LINEAR: - return Description::TransferFunction::LINEAR; - default: - return Description::TransferFunction::SRGB; - } -} - -bool Description::hasInputTransformMatrix() const { - const mat4 identity; - return inputTransformMatrix != identity; -} - -bool Description::hasOutputTransformMatrix() const { - const mat4 identity; - return outputTransformMatrix != identity; -} - -bool Description::hasColorMatrix() const { - const mat4 identity; - return colorMatrix != identity; -} - -bool Description::hasDisplayColorMatrix() const { - const mat4 identity; - return displayColorMatrix != identity; -} - -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/ExternalTexture.cpp b/libs/renderengine/ExternalTexture.cpp index 9eb42cd8e1..6f2a96a87b 100644 --- a/libs/renderengine/ExternalTexture.cpp +++ b/libs/renderengine/ExternalTexture.cpp @@ -27,14 +27,6 @@ ExternalTexture::ExternalTexture(const sp<GraphicBuffer>& buffer, : mBuffer(buffer), mRenderEngine(renderEngine), mWritable(usage & WRITEABLE) { LOG_ALWAYS_FATAL_IF(buffer == nullptr, "Attempted to bind a null buffer to an external texture!"); - // GLESRenderEngine has a separate texture cache for output buffers, - if (usage == WRITEABLE && - (mRenderEngine.getRenderEngineType() == - renderengine::RenderEngine::RenderEngineType::GLES || - mRenderEngine.getRenderEngineType() == - renderengine::RenderEngine::RenderEngineType::THREADED)) { - return; - } mRenderEngine.mapExternalTextureBuffer(mBuffer, mWritable); } diff --git a/libs/renderengine/Mesh.cpp b/libs/renderengine/Mesh.cpp deleted file mode 100644 index ed2f45fdf5..0000000000 --- a/libs/renderengine/Mesh.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2013 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 <renderengine/Mesh.h> - -#include <utils/Log.h> - -namespace android { -namespace renderengine { - -Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize, - size_t cropCoordsSize, size_t shadowColorSize, size_t shadowParamsSize, - size_t indexCount) - : mVertexCount(vertexCount), - mVertexSize(vertexSize), - mTexCoordsSize(texCoordSize), - mCropCoordsSize(cropCoordsSize), - mShadowColorSize(shadowColorSize), - mShadowParamsSize(shadowParamsSize), - mPrimitive(primitive), - mIndexCount(indexCount) { - if (vertexCount == 0) { - mVertices.resize(1); - mVertices[0] = 0.0f; - mStride = 0; - return; - } - size_t stride = vertexSize + texCoordSize + cropCoordsSize + shadowColorSize + shadowParamsSize; - size_t remainder = (stride * vertexCount) / vertexCount; - // Since all of the input parameters are unsigned, if stride is less than - // either vertexSize or texCoordSize, it must have overflowed. remainder - // will be equal to stride as long as stride * vertexCount doesn't overflow. - if ((stride < vertexSize) || (remainder != stride)) { - ALOGE("Overflow in Mesh(..., %zu, %zu, %zu, %zu, %zu, %zu)", vertexCount, vertexSize, - texCoordSize, cropCoordsSize, shadowColorSize, shadowParamsSize); - mVertices.resize(1); - mVertices[0] = 0.0f; - mVertexCount = 0; - mVertexSize = 0; - mTexCoordsSize = 0; - mCropCoordsSize = 0; - mShadowColorSize = 0; - mShadowParamsSize = 0; - mStride = 0; - return; - } - - mVertices.resize(stride * vertexCount); - mStride = stride; - mIndices.resize(indexCount); -} - -Mesh::Primitive Mesh::getPrimitive() const { - return mPrimitive; -} - -float const* Mesh::getPositions() const { - return mVertices.data(); -} -float* Mesh::getPositions() { - return mVertices.data(); -} - -float const* Mesh::getTexCoords() const { - return mVertices.data() + mVertexSize; -} -float* Mesh::getTexCoords() { - return mVertices.data() + mVertexSize; -} - -float const* Mesh::getCropCoords() const { - return mVertices.data() + mVertexSize + mTexCoordsSize; -} -float* Mesh::getCropCoords() { - return mVertices.data() + mVertexSize + mTexCoordsSize; -} - -float const* Mesh::getShadowColor() const { - return mVertices.data() + mVertexSize + mTexCoordsSize + mCropCoordsSize; -} -float* Mesh::getShadowColor() { - return mVertices.data() + mVertexSize + mTexCoordsSize + mCropCoordsSize; -} - -float const* Mesh::getShadowParams() const { - return mVertices.data() + mVertexSize + mTexCoordsSize + mCropCoordsSize + mShadowColorSize; -} -float* Mesh::getShadowParams() { - return mVertices.data() + mVertexSize + mTexCoordsSize + mCropCoordsSize + mShadowColorSize; -} - -uint16_t const* Mesh::getIndices() const { - return mIndices.data(); -} - -uint16_t* Mesh::getIndices() { - return mIndices.data(); -} - -size_t Mesh::getVertexCount() const { - return mVertexCount; -} - -size_t Mesh::getVertexSize() const { - return mVertexSize; -} - -size_t Mesh::getTexCoordsSize() const { - return mTexCoordsSize; -} - -size_t Mesh::getShadowColorSize() const { - return mShadowColorSize; -} - -size_t Mesh::getShadowParamsSize() const { - return mShadowParamsSize; -} - -size_t Mesh::getByteStride() const { - return mStride * sizeof(float); -} - -size_t Mesh::getStride() const { - return mStride; -} - -size_t Mesh::getIndexCount() const { - return mIndexCount; -} - -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp index d08c2213ad..a8e92c6807 100644 --- a/libs/renderengine/RenderEngine.cpp +++ b/libs/renderengine/RenderEngine.cpp @@ -18,7 +18,6 @@ #include <cutils/properties.h> #include <log/log.h> -#include "gl/GLESRenderEngine.h" #include "renderengine/ExternalTexture.h" #include "threaded/RenderEngineThreaded.h" @@ -30,11 +29,6 @@ namespace renderengine { std::unique_ptr<RenderEngine> RenderEngine::create(const RenderEngineCreationArgs& args) { switch (args.renderEngineType) { - case RenderEngineType::THREADED: - ALOGD("Threaded RenderEngine with GLES Backend"); - return renderengine::threaded::RenderEngineThreaded::create( - [args]() { return android::renderengine::gl::GLESRenderEngine::create(args); }, - args.renderEngineType); case RenderEngineType::SKIA_GL: ALOGD("RenderEngine with SkiaGL Backend"); return renderengine::skia::SkiaGLRenderEngine::create(args); @@ -56,10 +50,6 @@ std::unique_ptr<RenderEngine> RenderEngine::create(const RenderEngineCreationArg return android::renderengine::skia::SkiaVkRenderEngine::create(args); }, args.renderEngineType); - case RenderEngineType::GLES: - default: - ALOGD("RenderEngine with GLES Backend"); - return renderengine::gl::GLESRenderEngine::create(args); } } diff --git a/libs/renderengine/Texture.cpp b/libs/renderengine/Texture.cpp deleted file mode 100644 index 154cde80b9..0000000000 --- a/libs/renderengine/Texture.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2013 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 <renderengine/Texture.h> - -namespace android { -namespace renderengine { - -Texture::Texture() - : mTextureName(0), mTextureTarget(TEXTURE_2D), mWidth(0), mHeight(0), mFiltering(false) {} - -Texture::Texture(Target textureTarget, uint32_t textureName) - : mTextureName(textureName), - mTextureTarget(textureTarget), - mWidth(0), - mHeight(0), - mFiltering(false) {} - -void Texture::init(Target textureTarget, uint32_t textureName) { - mTextureName = textureName; - mTextureTarget = textureTarget; -} - -Texture::~Texture() {} - -void Texture::setMatrix(float const* matrix) { - mTextureMatrix = mat4(matrix); -} - -void Texture::setFiltering(bool enabled) { - mFiltering = enabled; -} - -void Texture::setDimensions(size_t width, size_t height) { - mWidth = width; - mHeight = height; -} - -uint32_t Texture::getTextureName() const { - return mTextureName; -} - -uint32_t Texture::getTextureTarget() const { - return mTextureTarget; -} - -const mat4& Texture::getMatrix() const { - return mTextureMatrix; -} - -bool Texture::getFiltering() const { - return mFiltering; -} - -size_t Texture::getWidth() const { - return mWidth; -} - -size_t Texture::getHeight() const { - return mHeight; -} - -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp index 791d4c94b4..ce2c7d7b6b 100644 --- a/libs/renderengine/benchmark/RenderEngineBench.cpp +++ b/libs/renderengine/benchmark/RenderEngineBench.cpp @@ -43,10 +43,6 @@ std::string RenderEngineTypeName(RenderEngine::RenderEngineType type) { return "skiavk"; case RenderEngine::RenderEngineType::SKIA_VK_THREADED: return "skiavkthreaded"; - case RenderEngine::RenderEngineType::GLES: - case RenderEngine::RenderEngineType::THREADED: - LOG_ALWAYS_FATAL("GLESRenderEngine is deprecated - why time it?"); - return "unused"; } } diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp deleted file mode 100644 index a512b9aca1..0000000000 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ /dev/null @@ -1,1853 +0,0 @@ -/* - * Copyright 2013 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 -#include "EGL/egl.h" -#undef LOG_TAG -#define LOG_TAG "RenderEngine" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include <sched.h> -#include <cmath> -#include <fstream> -#include <sstream> -#include <unordered_set> - -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#include <android-base/stringprintf.h> -#include <cutils/compiler.h> -#include <cutils/properties.h> -#include <gui/DebugEGLImageTracker.h> -#include <renderengine/Mesh.h> -#include <renderengine/Texture.h> -#include <renderengine/private/Description.h> -#include <sync/sync.h> -#include <ui/ColorSpace.h> -#include <ui/DebugUtils.h> -#include <ui/GraphicBuffer.h> -#include <ui/Rect.h> -#include <ui/Region.h> -#include <utils/KeyedVector.h> -#include <utils/Trace.h> -#include "GLESRenderEngine.h" -#include "GLExtensions.h" -#include "GLFramebuffer.h" -#include "GLImage.h" -#include "GLShadowVertexGenerator.h" -#include "Program.h" -#include "ProgramCache.h" -#include "filters/BlurFilter.h" - -bool checkGlError(const char* op, int lineNumber) { - bool errorFound = false; - GLint error = glGetError(); - while (error != GL_NO_ERROR) { - errorFound = true; - error = glGetError(); - ALOGV("after %s() (line # %d) glError (0x%x)\n", op, lineNumber, error); - } - return errorFound; -} - -static constexpr bool outputDebugPPMs = false; - -void writePPM(const char* basename, GLuint width, GLuint height) { - ALOGV("writePPM #%s: %d x %d", basename, width, height); - - std::vector<GLubyte> pixels(width * height * 4); - std::vector<GLubyte> outBuffer(width * height * 3); - - // TODO(courtneygo): We can now have float formats, need - // to remove this code or update to support. - // Make returned pixels fit in uint32_t, one byte per component - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); - if (checkGlError(__FUNCTION__, __LINE__)) { - return; - } - - std::string filename(basename); - filename.append(".ppm"); - std::ofstream file(filename.c_str(), std::ios::binary); - if (!file.is_open()) { - ALOGE("Unable to open file: %s", filename.c_str()); - ALOGE("You may need to do: \"adb shell setenforce 0\" to enable " - "surfaceflinger to write debug images"); - return; - } - - file << "P6\n"; - file << width << "\n"; - file << height << "\n"; - file << 255 << "\n"; - - auto ptr = reinterpret_cast<char*>(pixels.data()); - auto outPtr = reinterpret_cast<char*>(outBuffer.data()); - for (int y = height - 1; y >= 0; y--) { - char* data = ptr + y * width * sizeof(uint32_t); - - for (GLuint x = 0; x < width; x++) { - // Only copy R, G and B components - outPtr[0] = data[0]; - outPtr[1] = data[1]; - outPtr[2] = data[2]; - data += sizeof(uint32_t); - outPtr += 3; - } - } - file.write(reinterpret_cast<char*>(outBuffer.data()), outBuffer.size()); -} - -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; - -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::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. EGL error=0x%x", eglGetError()); - } - - const auto eglVersion = eglQueryString(display, EGL_VERSION); - if (!eglVersion) { - checkGlError(__FUNCTION__, __LINE__); - LOG_ALWAYS_FATAL("eglQueryString(EGL_VERSION) failed"); - } - - // 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("eglQueryString(EGL_EXTENSIONS) failed"); - } - - GLExtensions& extensions = 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; - if (!extensions.hasNoConfigContext()) { - config = chooseEglConfig(display, args.pixelFormat, /*logConfig*/ true); - } - - const std::optional<RenderEngine::ContextPriority> priority = createContextPriority(args); - EGLContext protectedContext = EGL_NO_CONTEXT; - if (args.enableProtectedContext && extensions.hasProtectedContent()) { - 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, 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 stub = EGL_NO_SURFACE; - if (!extensions.hasSurfacelessContext()) { - 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, 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 protectedStub = EGL_NO_SURFACE; - if (protectedContext != EGL_NO_CONTEXT && !extensions.hasSurfacelessContext()) { - 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 - GlesVersion version = parseGlesVersion(extensions.getVersion()); - - LOG_ALWAYS_FATAL_IF(args.supportsBackgroundBlur && version < GLES_VERSION_3_0, - "Blurs require OpenGL ES 3.0. Please unset ro.surface_flinger.supports_background_blur"); - - // initialize the renderer while GL is current - std::unique_ptr<GLESRenderEngine> engine; - switch (version) { - case GLES_VERSION_1_0: - case GLES_VERSION_1_1: - LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run."); - break; - case GLES_VERSION_2_0: - case GLES_VERSION_3_0: - engine = std::make_unique<GLESRenderEngine>(args, display, config, ctxt, stub, - protectedContext, protectedStub); - break; - } - - 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 GLESRenderEngine::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; -} - -GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, - EGLConfig config, EGLContext ctxt, EGLSurface stub, - EGLContext protectedContext, EGLSurface protectedStub) - : RenderEngine(args.renderEngineType), - mEGLDisplay(display), - mEGLConfig(config), - mEGLContext(ctxt), - mStubSurface(stub), - mProtectedEGLContext(protectedContext), - mProtectedStubSurface(protectedStub), - mVpWidth(0), - mVpHeight(0), - mFramebufferImageCacheSize(args.imageCacheSize), - mPrecacheToneMapperShaderOnly(args.precacheToneMapperShaderOnly) { - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); - glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); - - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glPixelStorei(GL_PACK_ALIGNMENT, 4); - - // Initialize protected EGL Context. - if (mProtectedEGLContext != EGL_NO_CONTEXT) { - 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, mStubSurface, mStubSurface, mEGLContext); - LOG_ALWAYS_FATAL_IF(!success, "can't make default context current"); - } - - // mColorBlindnessCorrection = M; - - const ColorSpace srgb(ColorSpace::sRGB()); - const ColorSpace displayP3(ColorSpace::DisplayP3()); - const ColorSpace bt2020(ColorSpace::BT2020()); - - // no chromatic adaptation needed since all color spaces use D65 for their white points. - mSrgbToXyz = mat4(srgb.getRGBtoXYZ()); - mDisplayP3ToXyz = mat4(displayP3.getRGBtoXYZ()); - mBt2020ToXyz = mat4(bt2020.getRGBtoXYZ()); - mXyzToSrgb = mat4(srgb.getXYZtoRGB()); - mXyzToDisplayP3 = mat4(displayP3.getXYZtoRGB()); - mXyzToBt2020 = mat4(bt2020.getXYZtoRGB()); - - // Compute sRGB to Display P3 and BT2020 transform matrix. - // NOTE: For now, we are limiting output wide color space support to - // Display-P3 and BT2020 only. - mSrgbToDisplayP3 = mXyzToDisplayP3 * mSrgbToXyz; - mSrgbToBt2020 = mXyzToBt2020 * mSrgbToXyz; - - // Compute Display P3 to sRGB and BT2020 transform matrix. - mDisplayP3ToSrgb = mXyzToSrgb * mDisplayP3ToXyz; - mDisplayP3ToBt2020 = mXyzToBt2020 * mDisplayP3ToXyz; - - // Compute BT2020 to sRGB and Display P3 transform matrix - mBt2020ToSrgb = mXyzToSrgb * mBt2020ToXyz; - mBt2020ToDisplayP3 = mXyzToDisplayP3 * mBt2020ToXyz; - - char value[PROPERTY_VALUE_MAX]; - property_get("debug.egl.traceGpuCompletion", value, "0"); - if (atoi(value)) { - mTraceGpuCompletion = true; - mFlushTracer = std::make_unique<FlushTracer>(this); - } - - if (args.supportsBackgroundBlur) { - mBlurFilter = new BlurFilter(*this); - checkErrors("BlurFilter creation"); - } - - mImageManager = std::make_unique<ImageManager>(this); - mImageManager->initThread(); - mDrawingBuffer = createFramebuffer(); - sp<GraphicBuffer> buf = - sp<GraphicBuffer>::make(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; - 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() { - return std::make_unique<GLFramebuffer>(*this); -} - -std::unique_ptr<Image> GLESRenderEngine::createImage() { - return std::make_unique<GLImage>(*this); -} - -Framebuffer* GLESRenderEngine::getFramebufferForDrawing() { - return mDrawingBuffer.get(); -} - -std::future<void> GLESRenderEngine::primeCache() { - ProgramCache::getInstance().primeCache(mInProtectedContext ? mProtectedEGLContext : mEGLContext, - mPrecacheToneMapperShaderOnly); - return {}; -} - -base::unique_fd GLESRenderEngine::flush() { - ATRACE_CALL(); - if (!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()); - } - - // Only trace if we have a valid fence, as current usage falls back to - // calling finish() if the fence fd is invalid. - if (CC_UNLIKELY(mTraceGpuCompletion && mFlushTracer) && fenceFd.get() >= 0) { - mFlushTracer->queueSync(eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr)); - } - - return fenceFd; -} - -bool GLESRenderEngine::finish() { - ATRACE_CALL(); - if (!GLExtensions::getInstance().hasFenceSync()) { - ALOGW("no synchronization support"); - return false; - } - - EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr); - if (sync == EGL_NO_SYNC_KHR) { - ALOGW("failed to create EGL fence sync: %#x", eglGetError()); - return false; - } - - if (CC_UNLIKELY(mTraceGpuCompletion && mFlushTracer)) { - mFlushTracer->queueSync(eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr)); - } - - return waitSync(sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR); -} - -bool GLESRenderEngine::waitSync(EGLSyncKHR sync, EGLint flags) { - EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, flags, 2000000000 /*2 sec*/); - EGLint error = eglGetError(); - eglDestroySyncKHR(mEGLDisplay, sync); - if (result != EGL_CONDITION_SATISFIED_KHR) { - if (result == EGL_TIMEOUT_EXPIRED_KHR) { - ALOGW("fence wait timed out"); - } else { - ALOGW("error waiting on EGL fence: %#x", error); - } - return false; - } - - return true; -} - -bool GLESRenderEngine::waitFence(base::unique_fd fenceFd) { - if (!GLExtensions::getInstance().hasNativeFenceSync() || - !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; -} - -void GLESRenderEngine::clearWithColor(float red, float green, float blue, float alpha) { - ATRACE_CALL(); - glDisable(GL_BLEND); - glClearColor(red, green, blue, alpha); - glClear(GL_COLOR_BUFFER_BIT); -} - -void GLESRenderEngine::fillRegionWithColor(const Region& region, float red, float green, float blue, - float alpha) { - size_t c; - Rect const* r = region.getArray(&c); - Mesh mesh = Mesh::Builder() - .setPrimitive(Mesh::TRIANGLES) - .setVertices(c * 6 /* count */, 2 /* size */) - .build(); - Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); - for (size_t i = 0; i < c; i++, r++) { - position[i * 6 + 0].x = r->left; - position[i * 6 + 0].y = r->top; - position[i * 6 + 1].x = r->left; - position[i * 6 + 1].y = r->bottom; - position[i * 6 + 2].x = r->right; - position[i * 6 + 2].y = r->bottom; - position[i * 6 + 3].x = r->left; - position[i * 6 + 3].y = r->top; - position[i * 6 + 4].x = r->right; - position[i * 6 + 4].y = r->bottom; - position[i * 6 + 5].x = r->right; - position[i * 6 + 5].y = r->top; - } - setupFillWithColor(red, green, blue, alpha); - drawMesh(mesh); -} - -void GLESRenderEngine::setScissor(const Rect& region) { - glScissor(region.left, region.top, region.getWidth(), region.getHeight()); - glEnable(GL_SCISSOR_TEST); -} - -void GLESRenderEngine::disableScissor() { - glDisable(GL_SCISSOR_TEST); -} - -void GLESRenderEngine::genTextures(size_t count, uint32_t* names) { - glGenTextures(count, 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); -} - -void GLESRenderEngine::bindExternalTextureImage(uint32_t texName, const Image& image) { - ATRACE_CALL(); - const GLImage& glImage = static_cast<const GLImage&>(image); - const GLenum target = GL_TEXTURE_EXTERNAL_OES; - - glBindTexture(target, texName); - if (glImage.getEGLImage() != EGL_NO_IMAGE_KHR) { - glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(glImage.getEGLImage())); - } -} - -void GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer, - const sp<Fence>& bufferFence) { - ATRACE_CALL(); - - bool found = false; - { - std::lock_guard<std::mutex> lock(mRenderingMutex); - auto cachedImage = mImageCache.find(buffer->getId()); - found = (cachedImage != mImageCache.end()); - } - - // If we couldn't find the image in the cache at this time, then either - // SurfaceFlinger messed up registering the buffer ahead of time or we got - // backed up creating other EGLImages. - if (!found) { - status_t cacheResult = mImageManager->cache(buffer); - if (cacheResult != NO_ERROR) { - ALOGE("Error with caching buffer: %d", cacheResult); - return; - } - } - - // Whether or not we needed to cache, re-check mImageCache to make sure that - // there's an EGLImage. The current threading model guarantees that we don't - // destroy a cached image until it's really not needed anymore (i.e. this - // function should not be called), so the only possibility is that something - // terrible went wrong and we should just bind something and move on. - { - std::lock_guard<std::mutex> lock(mRenderingMutex); - auto cachedImage = mImageCache.find(buffer->getId()); - - if (cachedImage == mImageCache.end()) { - // We failed creating the image if we got here, so bail out. - ALOGE("Failed to create an EGLImage when rendering"); - bindExternalTextureImage(texName, *createImage()); - return; - } - - bindExternalTextureImage(texName, *cachedImage->second); - mTextureView.insert_or_assign(texName, buffer->getId()); - } - - // Wait for the new buffer to be ready. - if (bufferFence != nullptr && bufferFence->isValid()) { - if (GLExtensions::getInstance().hasWaitSync()) { - base::unique_fd fenceFd(bufferFence->dup()); - if (fenceFd == -1) { - ALOGE("error dup'ing fence fd: %d", errno); - return; - } - if (!waitFence(std::move(fenceFd))) { - ALOGE("failed to wait on fence fd"); - return; - } - } else { - status_t err = bufferFence->waitForever("RenderEngine::bindExternalTextureBuffer"); - if (err != NO_ERROR) { - ALOGE("error waiting for fence: %d", err); - return; - } - } - } - - return; -} - -void GLESRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, - bool /*isRenderable*/) { - ATRACE_CALL(); - mImageManager->cacheAsync(buffer, nullptr); -} - -std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::cacheExternalTextureBufferForTesting( - const sp<GraphicBuffer>& buffer) { - auto barrier = std::make_shared<ImageManager::Barrier>(); - mImageManager->cacheAsync(buffer, barrier); - return barrier; -} - -status_t GLESRenderEngine::cacheExternalTextureBufferInternal(const sp<GraphicBuffer>& buffer) { - if (buffer == nullptr) { - return BAD_VALUE; - } - - { - std::lock_guard<std::mutex> lock(mRenderingMutex); - if (mImageCache.count(buffer->getId()) > 0) { - // If there's already an image then fail fast here. - return NO_ERROR; - } - } - ATRACE_CALL(); - - // Create the image without holding a lock so that we don't block anything. - std::unique_ptr<Image> newImage = createImage(); - - bool created = newImage->setNativeWindowBuffer(buffer->getNativeBuffer(), - buffer->getUsage() & GRALLOC_USAGE_PROTECTED); - if (!created) { - 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; - } - - { - std::lock_guard<std::mutex> lock(mRenderingMutex); - if (mImageCache.count(buffer->getId()) > 0) { - // In theory it's possible for another thread to recache the image, - // so bail out if another thread won. - return NO_ERROR; - } - mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage))); - } - - return NO_ERROR; -} - -void GLESRenderEngine::unmapExternalTextureBuffer(sp<GraphicBuffer>&& buffer) { - mImageManager->releaseAsync(buffer->getId(), nullptr); -} - -std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::unbindExternalTextureBufferForTesting( - uint64_t bufferId) { - auto barrier = std::make_shared<ImageManager::Barrier>(); - mImageManager->releaseAsync(bufferId, barrier); - return barrier; -} - -void GLESRenderEngine::unbindExternalTextureBufferInternal(uint64_t bufferId) { - std::unique_ptr<Image> image; - { - std::lock_guard<std::mutex> lock(mRenderingMutex); - const auto& cachedImage = mImageCache.find(bufferId); - - if (cachedImage != mImageCache.end()) { - ALOGV("Destroying image for buffer: %" PRIu64, bufferId); - // Move the buffer out of cache first, so that we can destroy - // without holding the cache's lock. - image = std::move(cachedImage->second); - mImageCache.erase(bufferId); - return; - } - } - 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. - FloatRect cropWin = layer.geometry.boundaries; - const FloatRect& roundedCornersCrop = layer.geometry.roundedCornersCrop; - cropWin.left -= roundedCornersCrop.left; - cropWin.right -= roundedCornersCrop.left; - cropWin.top -= roundedCornersCrop.top; - cropWin.bottom -= roundedCornersCrop.top; - Mesh::VertexArray<vec2> cropCoords(mesh.getCropCoordArray<vec2>()); - cropCoords[0] = vec2(cropWin.left, cropWin.top); - cropCoords[1] = vec2(cropWin.left, cropWin.top + cropWin.getHeight()); - cropCoords[2] = vec2(cropWin.right, cropWin.top + cropWin.getHeight()); - cropCoords[3] = vec2(cropWin.right, cropWin.top); - - setupCornerRadiusCropSize(roundedCornersCrop.getWidth(), roundedCornersCrop.getHeight()); - return cropWin; -} - -void GLESRenderEngine::handleRoundedCorners(const DisplaySettings& display, - const LayerSettings& layer, const Mesh& mesh) { - // We separate the layer into 3 parts essentially, such that we only turn on blending for the - // top rectangle and the bottom rectangle, and turn off blending for the middle rectangle. - FloatRect bounds = layer.geometry.roundedCornersCrop; - - // Explicitly compute the transform from the clip rectangle to the physical - // display. Normally, this is done in glViewport but we explicitly compute - // it here so that we can get the scissor bounds correct. - const Rect& source = display.clip; - const Rect& destination = display.physicalDisplay; - // Here we compute the following transform: - // 1. Translate the top left corner of the source clip to (0, 0) - // 2. Rotate the clip rectangle about the origin in accordance with the - // orientation flag - // 3. Translate the top left corner back to the origin. - // 4. Scale the clip rectangle to the destination rectangle dimensions - // 5. Translate the top left corner to the destination rectangle's top left - // corner. - const mat4 translateSource = mat4::translate(vec4(-source.left, -source.top, 0, 1)); - mat4 rotation; - int displacementX = 0; - int displacementY = 0; - float destinationWidth = static_cast<float>(destination.getWidth()); - float destinationHeight = static_cast<float>(destination.getHeight()); - float sourceWidth = static_cast<float>(source.getWidth()); - float sourceHeight = static_cast<float>(source.getHeight()); - const float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f; - switch (display.orientation) { - case ui::Transform::ROT_90: - rotation = mat4::rotate(rot90InRadians, vec3(0, 0, 1)); - displacementX = source.getHeight(); - std::swap(sourceHeight, sourceWidth); - break; - case ui::Transform::ROT_180: - rotation = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)); - displacementY = source.getHeight(); - displacementX = source.getWidth(); - break; - case ui::Transform::ROT_270: - rotation = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)); - displacementY = source.getWidth(); - std::swap(sourceHeight, sourceWidth); - break; - default: - break; - } - - const mat4 intermediateTranslation = mat4::translate(vec4(displacementX, displacementY, 0, 1)); - const mat4 scale = mat4::scale( - vec4(destinationWidth / sourceWidth, destinationHeight / sourceHeight, 1, 1)); - const mat4 translateDestination = - mat4::translate(vec4(destination.left, destination.top, 0, 1)); - const mat4 globalTransform = - translateDestination * scale * intermediateTranslation * rotation * translateSource; - - const mat4 transformMatrix = globalTransform * layer.geometry.positionTransform; - const vec4 leftTopCoordinate(bounds.left, bounds.top, 1.0, 1.0); - const vec4 rightBottomCoordinate(bounds.right, bounds.bottom, 1.0, 1.0); - const vec4 leftTopCoordinateInBuffer = transformMatrix * leftTopCoordinate; - const vec4 rightBottomCoordinateInBuffer = transformMatrix * rightBottomCoordinate; - bounds = FloatRect(std::min(leftTopCoordinateInBuffer[0], rightBottomCoordinateInBuffer[0]), - std::min(leftTopCoordinateInBuffer[1], rightBottomCoordinateInBuffer[1]), - std::max(leftTopCoordinateInBuffer[0], rightBottomCoordinateInBuffer[0]), - std::max(leftTopCoordinateInBuffer[1], rightBottomCoordinateInBuffer[1])); - - // Finally, we cut the layer into 3 parts, with top and bottom parts having rounded corners - // and the middle part without rounded corners. - const int32_t radius = ceil( - (layer.geometry.roundedCornersRadius.x + layer.geometry.roundedCornersRadius.y) / 2.0); - const Rect topRect(bounds.left, bounds.top, bounds.right, bounds.top + radius); - setScissor(topRect); - drawMesh(mesh); - const Rect bottomRect(bounds.left, bounds.bottom - radius, bounds.right, bounds.bottom); - setScissor(bottomRect); - drawMesh(mesh); - - // The middle part of the layer can turn off blending. - if (topRect.bottom < bottomRect.top) { - const Rect middleRect(bounds.left, bounds.top + radius, bounds.right, - bounds.bottom - radius); - setScissor(middleRect); - mState.cornerRadius = 0.0; - disableBlending(); - drawMesh(mesh); - } - disableScissor(); -} - -status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) { - ATRACE_CALL(); - GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(framebuffer); - EGLImageKHR eglImage = glFramebuffer->getEGLImage(); - uint32_t textureName = glFramebuffer->getTextureName(); - uint32_t framebufferName = glFramebuffer->getFramebufferName(); - - // Bind the texture and turn our EGLImage into a texture - glBindTexture(GL_TEXTURE_2D, textureName); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)eglImage); - - // Bind the Framebuffer to render into - glBindFramebuffer(GL_FRAMEBUFFER, framebufferName); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0); - - uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d", - glStatus); - - return glStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE; -} - -void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /*framebuffer*/) { - ATRACE_CALL(); - - // back to main framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -bool GLESRenderEngine::canSkipPostRenderCleanup() const { - return mPriorResourcesCleaned || - (mLastDrawFence != nullptr && mLastDrawFence->getStatus() != Fence::Status::Signaled); -} - -void GLESRenderEngine::cleanupPostRender() { - ATRACE_CALL(); - - if (canSkipPostRenderCleanup()) { - // If we don't have a prior frame needing cleanup, then don't do anything. - return; - } - - // 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; -} - -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 { - checkErrors(nullptr); -} - -void GLESRenderEngine::checkErrors(const char* tag) const { - do { - // there could be more than one error flag - GLenum error = glGetError(); - if (error == GL_NO_ERROR) break; - if (tag == nullptr) { - ALOGE("GL error 0x%04x", int(error)); - } else { - ALOGE("GL error: %s -> 0x%04x", tag, int(error)); - } - } while (true); -} - -bool GLESRenderEngine::supportsProtectedContent() const { - return mProtectedEGLContext != EGL_NO_CONTEXT; -} - -void GLESRenderEngine::useProtectedContext(bool useProtectedContext) { - if (useProtectedContext == mInProtectedContext || - (useProtectedContext && !supportsProtectedContent())) { - return; - } - - const EGLSurface surface = useProtectedContext ? mProtectedStubSurface : mStubSurface; - const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext; - if (eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE) { - mInProtectedContext = useProtectedContext; - } -} -EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, - bool isProtected, - bool useFramebufferCache) { - sp<GraphicBuffer> graphicBuffer = GraphicBuffer::from(nativeBuffer); - if (useFramebufferCache) { - std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex); - for (const auto& image : mFramebufferImageCache) { - if (image.first == graphicBuffer->getId()) { - return image.second; - } - } - } - EGLint attributes[] = { - isProtected ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE, - isProtected ? EGL_TRUE : EGL_NONE, - EGL_NONE, - }; - EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, - nativeBuffer, attributes); - if (useFramebufferCache) { - if (image != EGL_NO_IMAGE_KHR) { - std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex); - if (mFramebufferImageCache.size() >= mFramebufferImageCacheSize) { - EGLImageKHR expired = mFramebufferImageCache.front().second; - mFramebufferImageCache.pop_front(); - eglDestroyImageKHR(mEGLDisplay, expired); - DEBUG_EGL_IMAGE_TRACKER_DESTROY(); - } - mFramebufferImageCache.push_back({graphicBuffer->getId(), image}); - } - } - - if (image != EGL_NO_IMAGE_KHR) { - DEBUG_EGL_IMAGE_TRACKER_CREATE(); - } - return image; -} - -void GLESRenderEngine::drawLayersInternal( - const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, - const DisplaySettings& display, const std::vector<LayerSettings>& layers, - const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence) { - ATRACE_CALL(); - if (layers.empty()) { - ALOGV("Drawing empty layer stack"); - resultPromise->set_value(Fence::NO_FENCE); - return; - } - - 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."); - resultPromise->set_value(base::unexpected(BAD_VALUE)); - return; - } - - 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. - std::deque<const LayerSettings> blurLayers; - if (CC_LIKELY(mBlurFilter != nullptr)) { - for (const auto& layer : layers) { - if (layer.backgroundBlurRadius > 0) { - blurLayers.push_back(layer); - } - } - } - const auto blurLayersSize = blurLayers.size(); - - if (blurLayersSize == 0) { - 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->getBuffer()->handle); - checkErrors(); - resultPromise->set_value(base::unexpected(fbo->getStatus())); - return; - } - setViewportAndProjection(display.physicalDisplay, display.clip); - } else { - setViewportAndProjection(display.physicalDisplay, display.clip); - auto status = - mBlurFilter->setAsDrawTarget(display, blurLayers.front().backgroundBlurRadius); - if (status != NO_ERROR) { - ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).", - buffer->getBuffer()->handle); - checkErrors(); - resultPromise->set_value(base::unexpected(status)); - return; - } - } - - // clear the entire buffer, sometimes when we reuse buffers we'd persist - // ghost images otherwise. - // we also require a full transparent framebuffer for overlays. This is - // probably not quite efficient on all GPUs, since we could filter out - // opaque layers. - clearWithColor(0.0, 0.0, 0.0, 0.0); - - setOutputDataSpace(display.outputDataspace); - setDisplayMaxLuminance(display.maxLuminance); - setDisplayColorTransform(display.colorTransform); - - const mat4 projectionMatrix = - ui::Transform(display.orientation).asMatrix4() * mState.projectionMatrix; - - Mesh mesh = Mesh::Builder() - .setPrimitive(Mesh::TRIANGLE_FAN) - .setVertices(4 /* count */, 2 /* size */) - .setTexCoords(2 /* size */) - .setCropCoords(2 /* size */) - .build(); - for (const auto& layer : layers) { - if (blurLayers.size() > 0 && blurLayers.front() == layer) { - blurLayers.pop_front(); - - auto status = mBlurFilter->prepare(); - if (status != NO_ERROR) { - ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", - buffer->getBuffer()->handle); - checkErrors("Can't render first blur pass"); - resultPromise->set_value(base::unexpected(status)); - return; - } - - 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.get() - ->getBuffer() - ->getNativeBuffer(), - useFramebufferCache); - status = fbo->getStatus(); - setViewportAndProjection(display.physicalDisplay, display.clip); - } else { - // There's still something else to blur, so let's keep rendering to our FBO - // instead of to the display. - status = mBlurFilter->setAsDrawTarget(display, - blurLayers.front().backgroundBlurRadius); - } - if (status != NO_ERROR) { - ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", - buffer->getBuffer()->handle); - checkErrors("Can't bind native framebuffer"); - resultPromise->set_value(base::unexpected(status)); - return; - } - - status = mBlurFilter->render(blurLayersSize > 1); - if (status != NO_ERROR) { - ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", - buffer->getBuffer()->handle); - checkErrors("Can't render blur filter"); - resultPromise->set_value(base::unexpected(status)); - return; - } - } - - // 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; - Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); - position[0] = vec2(bounds.left, bounds.top); - position[1] = vec2(bounds.left, bounds.bottom); - position[2] = vec2(bounds.right, bounds.bottom); - position[3] = vec2(bounds.right, bounds.top); - - setupLayerCropping(layer, mesh); - setColorTransform(layer.colorTransform); - - bool usePremultipliedAlpha = true; - bool disableTexture = true; - bool isOpaque = false; - if (layer.source.buffer.buffer != nullptr) { - disableTexture = false; - isOpaque = layer.source.buffer.isOpaque; - - sp<GraphicBuffer> gBuf = layer.source.buffer.buffer->getBuffer(); - validateInputBufferUsage(gBuf); - bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf, - layer.source.buffer.fence); - - usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha; - Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName); - mat4 texMatrix = layer.source.buffer.textureTransform; - - texture.setMatrix(texMatrix.asArray()); - texture.setFiltering(layer.source.buffer.useTextureFiltering); - - texture.setDimensions(gBuf->getWidth(), gBuf->getHeight()); - - renderengine::Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>()); - texCoords[0] = vec2(0.0, 0.0); - texCoords[1] = vec2(0.0, 1.0); - 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(std::move(gBuf)); - } - } - - const half3 solidColor = layer.source.solidColor; - const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha); - const float radius = - (layer.geometry.roundedCornersRadius.x + layer.geometry.roundedCornersRadius.y) / - 2.0f; - // Buffer sources will have a black solid color ignored in the shader, - // so in that scenario the solid color passed here is arbitrary. - setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color, radius); - if (layer.disableBlending) { - glDisable(GL_BLEND); - } - setSourceDataSpace(layer.sourceDataspace); - - if (layer.shadow.length > 0.0f) { - handleShadow(layer.geometry.boundaries, radius, layer.shadow); - } - // We only want to do a special handling for rounded corners when having rounded corners - // is the only reason it needs to turn on blending, otherwise, we handle it like the - // usual way since it needs to turn on blending anyway. - else if (radius > 0.0 && color.a >= 1.0f && isOpaque) { - handleRoundedCorners(display, layer, mesh); - } else { - drawMesh(mesh); - } - - // Cleanup if there's a buffer source - if (layer.source.buffer.buffer != nullptr) { - disableBlending(); - disableTexturing(); - } - } - - base::unique_fd drawFence = flush(); - - // If flush failed or we don't support native fences, we need to force the - // gl command stream to be executed. - if (drawFence.get() < 0) { - bool success = finish(); - if (!success) { - ALOGE("Failed to flush RenderEngine commands"); - checkErrors(); - // Chances are, something illegal happened (either the caller passed - // us bad parameters, or we messed up our shader generation). - resultPromise->set_value(base::unexpected(INVALID_OPERATION)); - return; - } - mLastDrawFence = nullptr; - } else { - // The caller takes ownership of drawFence, so we need to duplicate the - // fd here. - mLastDrawFence = new Fence(dup(drawFence.get())); - } - mPriorResourcesCleaned = false; - - checkErrors(); - resultPromise->set_value(sp<Fence>::make(std::move(drawFence))); -} - -void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) { - ATRACE_CALL(); - mVpWidth = viewport.getWidth(); - mVpHeight = viewport.getHeight(); - - // We pass the the top left corner instead of the bottom left corner, - // because since we're rendering off-screen first. - glViewport(viewport.left, viewport.top, mVpWidth, mVpHeight); - - mState.projectionMatrix = mat4::ortho(clip.left, clip.right, clip.top, clip.bottom, 0, 1); -} - -void GLESRenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, - const half4& color, float cornerRadius) { - mState.isPremultipliedAlpha = premultipliedAlpha; - mState.isOpaque = opaque; - mState.color = color; - mState.cornerRadius = cornerRadius; - - if (disableTexture) { - mState.textureEnabled = false; - } - - if (color.a < 1.0f || !opaque || cornerRadius > 0.0f) { - glEnable(GL_BLEND); - glBlendFuncSeparate(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, - GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glDisable(GL_BLEND); - } -} - -void GLESRenderEngine::setSourceDataSpace(Dataspace source) { - mDataSpace = source; -} - -void GLESRenderEngine::setOutputDataSpace(Dataspace dataspace) { - mOutputDataSpace = dataspace; -} - -void GLESRenderEngine::setDisplayMaxLuminance(const float maxLuminance) { - mState.displayMaxLuminance = maxLuminance; -} - -void GLESRenderEngine::setupLayerTexturing(const Texture& texture) { - GLuint target = texture.getTextureTarget(); - glBindTexture(target, texture.getTextureName()); - GLenum filter = GL_NEAREST; - if (texture.getFiltering()) { - filter = GL_LINEAR; - } - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter); - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter); - - mState.texture = texture; - mState.textureEnabled = true; -} - -void GLESRenderEngine::setColorTransform(const mat4& colorTransform) { - mState.colorMatrix = colorTransform; -} - -void GLESRenderEngine::setDisplayColorTransform(const mat4& colorTransform) { - mState.displayColorMatrix = colorTransform; -} - -void GLESRenderEngine::disableTexturing() { - mState.textureEnabled = false; -} - -void GLESRenderEngine::disableBlending() { - glDisable(GL_BLEND); -} - -void GLESRenderEngine::setupFillWithColor(float r, float g, float b, float a) { - mState.isPremultipliedAlpha = true; - mState.isOpaque = false; - mState.color = half4(r, g, b, a); - mState.textureEnabled = false; - glDisable(GL_BLEND); -} - -void GLESRenderEngine::setupCornerRadiusCropSize(float width, float height) { - mState.cropSize = half2(width, height); -} - -void GLESRenderEngine::drawMesh(const Mesh& mesh) { - ATRACE_CALL(); - if (mesh.getTexCoordsSize()) { - glEnableVertexAttribArray(Program::texCoords); - glVertexAttribPointer(Program::texCoords, mesh.getTexCoordsSize(), GL_FLOAT, GL_FALSE, - mesh.getByteStride(), mesh.getTexCoords()); - } - - glVertexAttribPointer(Program::position, mesh.getVertexSize(), GL_FLOAT, GL_FALSE, - mesh.getByteStride(), mesh.getPositions()); - - if (mState.cornerRadius > 0.0f) { - glEnableVertexAttribArray(Program::cropCoords); - glVertexAttribPointer(Program::cropCoords, mesh.getVertexSize(), GL_FLOAT, GL_FALSE, - mesh.getByteStride(), mesh.getCropCoords()); - } - - if (mState.drawShadows) { - glEnableVertexAttribArray(Program::shadowColor); - glVertexAttribPointer(Program::shadowColor, mesh.getShadowColorSize(), GL_FLOAT, GL_FALSE, - mesh.getByteStride(), mesh.getShadowColor()); - - glEnableVertexAttribArray(Program::shadowParams); - glVertexAttribPointer(Program::shadowParams, mesh.getShadowParamsSize(), GL_FLOAT, GL_FALSE, - mesh.getByteStride(), mesh.getShadowParams()); - } - - Description managedState = mState; - // By default, DISPLAY_P3 is the only supported wide color output. However, - // when HDR content is present, hardware composer may be able to handle - // BT2020 data space, in that case, the output data space is set to be - // BT2020_HLG or BT2020_PQ respectively. In GPU fall back we need - // to respect this and convert non-HDR content to HDR format. - Dataspace inputStandard = static_cast<Dataspace>(mDataSpace & Dataspace::STANDARD_MASK); - Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK); - Dataspace outputStandard = static_cast<Dataspace>(mOutputDataSpace & Dataspace::STANDARD_MASK); - Dataspace outputTransfer = static_cast<Dataspace>(mOutputDataSpace & Dataspace::TRANSFER_MASK); - bool needsXYZConversion = needsXYZTransformMatrix(); - - // NOTE: if the input standard of the input dataspace is not STANDARD_DCI_P3 or - // STANDARD_BT2020, it will be treated as STANDARD_BT709 - if (inputStandard != Dataspace::STANDARD_DCI_P3 && - inputStandard != Dataspace::STANDARD_BT2020) { - inputStandard = Dataspace::STANDARD_BT709; - } - - if (needsXYZConversion) { - // The supported input color spaces are standard RGB, Display P3 and BT2020. - switch (inputStandard) { - case Dataspace::STANDARD_DCI_P3: - managedState.inputTransformMatrix = mDisplayP3ToXyz; - break; - case Dataspace::STANDARD_BT2020: - managedState.inputTransformMatrix = mBt2020ToXyz; - break; - default: - managedState.inputTransformMatrix = mSrgbToXyz; - break; - } - - // The supported output color spaces are BT2020, Display P3 and standard RGB. - switch (outputStandard) { - case Dataspace::STANDARD_BT2020: - managedState.outputTransformMatrix = mXyzToBt2020; - break; - case Dataspace::STANDARD_DCI_P3: - managedState.outputTransformMatrix = mXyzToDisplayP3; - break; - default: - managedState.outputTransformMatrix = mXyzToSrgb; - break; - } - } else if (inputStandard != outputStandard) { - // At this point, the input data space and output data space could be both - // HDR data spaces, but they match each other, we do nothing in this case. - // In addition to the case above, the input data space could be - // - scRGB linear - // - scRGB non-linear - // - sRGB - // - Display P3 - // - BT2020 - // The output data spaces could be - // - sRGB - // - Display P3 - // - BT2020 - switch (outputStandard) { - case Dataspace::STANDARD_BT2020: - if (inputStandard == Dataspace::STANDARD_BT709) { - managedState.outputTransformMatrix = mSrgbToBt2020; - } else if (inputStandard == Dataspace::STANDARD_DCI_P3) { - managedState.outputTransformMatrix = mDisplayP3ToBt2020; - } - break; - case Dataspace::STANDARD_DCI_P3: - if (inputStandard == Dataspace::STANDARD_BT709) { - managedState.outputTransformMatrix = mSrgbToDisplayP3; - } else if (inputStandard == Dataspace::STANDARD_BT2020) { - managedState.outputTransformMatrix = mBt2020ToDisplayP3; - } - break; - default: - if (inputStandard == Dataspace::STANDARD_DCI_P3) { - managedState.outputTransformMatrix = mDisplayP3ToSrgb; - } else if (inputStandard == Dataspace::STANDARD_BT2020) { - managedState.outputTransformMatrix = mBt2020ToSrgb; - } - break; - } - } - - // we need to convert the RGB value to linear space and convert it back when: - // - there is a color matrix that is not an identity matrix, or - // - there is an output transform matrix that is not an identity matrix, or - // - the input transfer function doesn't match the output transfer function. - if (managedState.hasColorMatrix() || managedState.hasOutputTransformMatrix() || - inputTransfer != outputTransfer) { - managedState.inputTransferFunction = - Description::dataSpaceToTransferFunction(inputTransfer); - managedState.outputTransferFunction = - Description::dataSpaceToTransferFunction(outputTransfer); - } - - ProgramCache::getInstance().useProgram(mInProtectedContext ? mProtectedEGLContext : mEGLContext, - managedState); - - if (mState.drawShadows) { - glDrawElements(mesh.getPrimitive(), mesh.getIndexCount(), GL_UNSIGNED_SHORT, - mesh.getIndices()); - } else { - glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount()); - } - - if (outputDebugPPMs) { - static uint64_t managedColorFrameCount = 0; - std::ostringstream out; - out << "/data/texture_out" << managedColorFrameCount++; - writePPM(out.str().c_str(), mVpWidth, mVpHeight); - } - - if (mesh.getTexCoordsSize()) { - glDisableVertexAttribArray(Program::texCoords); - } - - if (mState.cornerRadius > 0.0f) { - glDisableVertexAttribArray(Program::cropCoords); - } - - if (mState.drawShadows) { - glDisableVertexAttribArray(Program::shadowColor); - glDisableVertexAttribArray(Program::shadowParams); - } -} - -size_t GLESRenderEngine::getMaxTextureSize() const { - return mMaxTextureSize; -} - -size_t GLESRenderEngine::getMaxViewportDims() const { - return mMaxViewportDims[0] < mMaxViewportDims[1] ? mMaxViewportDims[0] : mMaxViewportDims[1]; -} - -void GLESRenderEngine::dump(std::string& result) { - const GLExtensions& extensions = GLExtensions::getInstance(); - ProgramCache& cache = ProgramCache::getInstance(); - - StringAppendF(&result, "EGL implementation : %s\n", extensions.getEGLVersion()); - StringAppendF(&result, "%s\n", extensions.getEGLExtensions()); - StringAppendF(&result, "GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(), - extensions.getVersion()); - StringAppendF(&result, "%s\n", extensions.getExtensions()); - StringAppendF(&result, "RenderEngine supports protected context: %d\n", - supportsProtectedContent()); - StringAppendF(&result, "RenderEngine is in protected context: %d\n", mInProtectedContext); - StringAppendF(&result, "RenderEngine program cache size for unprotected context: %zu\n", - cache.getSize(mEGLContext)); - StringAppendF(&result, "RenderEngine program cache size for protected context: %zu\n", - cache.getSize(mProtectedEGLContext)); - StringAppendF(&result, "RenderEngine last dataspace conversion: (%s) to (%s)\n", - dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(), - dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str()); - { - std::lock_guard<std::mutex> lock(mRenderingMutex); - StringAppendF(&result, "RenderEngine image cache size: %zu\n", mImageCache.size()); - StringAppendF(&result, "Dumping buffer ids...\n"); - for (const auto& [id, unused] : mImageCache) { - StringAppendF(&result, "0x%" PRIx64 "\n", id); - } - } - { - std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex); - StringAppendF(&result, "RenderEngine framebuffer image cache size: %zu\n", - mFramebufferImageCache.size()); - StringAppendF(&result, "Dumping buffer ids...\n"); - for (const auto& [id, unused] : mFramebufferImageCache) { - StringAppendF(&result, "0x%" PRIx64 "\n", id); - } - } -} - -GLESRenderEngine::GlesVersion GLESRenderEngine::parseGlesVersion(const char* str) { - int major, minor; - if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) { - if (sscanf(str, "OpenGL ES %d.%d", &major, &minor) != 2) { - ALOGW("Unable to parse GL_VERSION string: \"%s\"", str); - return GLES_VERSION_1_0; - } - } - - if (major == 1 && minor == 0) return GLES_VERSION_1_0; - if (major == 1 && minor >= 1) return GLES_VERSION_1_1; - if (major == 2 && minor >= 0) return GLES_VERSION_2_0; - if (major == 3 && minor >= 0) return GLES_VERSION_3_0; - - ALOGW("Unrecognized OpenGL ES version: %d.%d", major, minor); - return GLES_VERSION_1_0; -} - -EGLContext GLESRenderEngine::createEglContext(EGLDisplay display, EGLConfig config, - EGLContext shareContext, - std::optional<ContextPriority> contextPriority, - Protection protection) { - EGLint renderableType = 0; - if (config == EGL_NO_CONFIG) { - 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 (contextPriority) { - contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_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); - 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) { - return context; - } - // If |config| is EGL_NO_CONFIG, 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 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); - 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, stubConfig, attributes.data()); -} - -bool GLESRenderEngine::isHdrDataSpace(const Dataspace dataSpace) const { - const Dataspace standard = static_cast<Dataspace>(dataSpace & Dataspace::STANDARD_MASK); - const Dataspace transfer = static_cast<Dataspace>(dataSpace & Dataspace::TRANSFER_MASK); - return standard == Dataspace::STANDARD_BT2020 && - (transfer == Dataspace::TRANSFER_ST2084 || transfer == Dataspace::TRANSFER_HLG); -} - -// For convenience, we want to convert the input color space to XYZ color space first, -// and then convert from XYZ color space to output color space when -// - SDR and HDR contents are mixed, either SDR content will be converted to HDR or -// HDR content will be tone-mapped to SDR; Or, -// - there are HDR PQ and HLG contents presented at the same time, where we want to convert -// HLG content to PQ content. -// In either case above, we need to operate the Y value in XYZ color space. Thus, when either -// input data space or output data space is HDR data space, and the input transfer function -// doesn't match the output transfer function, we would enable an intermediate transfrom to -// XYZ color space. -bool GLESRenderEngine::needsXYZTransformMatrix() const { - const bool isInputHdrDataSpace = isHdrDataSpace(mDataSpace); - const bool isOutputHdrDataSpace = isHdrDataSpace(mOutputDataSpace); - const Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK); - const Dataspace outputTransfer = - static_cast<Dataspace>(mOutputDataSpace & Dataspace::TRANSFER_MASK); - - return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer; -} - -bool GLESRenderEngine::isImageCachedForTesting(uint64_t bufferId) { - std::lock_guard<std::mutex> lock(mRenderingMutex); - const auto& cachedImage = mImageCache.find(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(), - [=](std::pair<uint64_t, EGLImageKHR> image) { - return image.first == bufferId; - }); -} - -// FlushTracer implementation -GLESRenderEngine::FlushTracer::FlushTracer(GLESRenderEngine* engine) : mEngine(engine) { - mThread = std::thread(&GLESRenderEngine::FlushTracer::loop, this); -} - -GLESRenderEngine::FlushTracer::~FlushTracer() { - { - std::lock_guard<std::mutex> lock(mMutex); - mRunning = false; - } - mCondition.notify_all(); - if (mThread.joinable()) { - mThread.join(); - } -} - -void GLESRenderEngine::FlushTracer::queueSync(EGLSyncKHR sync) { - std::lock_guard<std::mutex> lock(mMutex); - char name[64]; - const uint64_t frameNum = mFramesQueued++; - snprintf(name, sizeof(name), "Queueing sync for frame: %lu", - static_cast<unsigned long>(frameNum)); - ATRACE_NAME(name); - mQueue.push({sync, frameNum}); - ATRACE_INT("GPU Frames Outstanding", mQueue.size()); - mCondition.notify_one(); -} - -void GLESRenderEngine::FlushTracer::loop() { - while (mRunning) { - QueueEntry entry; - { - std::lock_guard<std::mutex> lock(mMutex); - - mCondition.wait(mMutex, - [&]() REQUIRES(mMutex) { return !mQueue.empty() || !mRunning; }); - - if (!mRunning) { - // if mRunning is false, then FlushTracer is being destroyed, so - // bail out now. - break; - } - entry = mQueue.front(); - mQueue.pop(); - } - { - char name[64]; - snprintf(name, sizeof(name), "waiting for frame %lu", - static_cast<unsigned long>(entry.mFrameNum)); - ATRACE_NAME(name); - mEngine->waitSync(entry.mSync, 0); - } - } -} - -void GLESRenderEngine::handleShadow(const FloatRect& casterRect, float casterCornerRadius, - const ShadowSettings& settings) { - ATRACE_CALL(); - const float casterZ = settings.length / 2.0f; - const GLShadowVertexGenerator shadows(casterRect, casterCornerRadius, casterZ, - settings.casterIsTranslucent, settings.ambientColor, - settings.spotColor, settings.lightPos, - settings.lightRadius); - - // setup mesh for both shadows - Mesh mesh = Mesh::Builder() - .setPrimitive(Mesh::TRIANGLES) - .setVertices(shadows.getVertexCount(), 2 /* size */) - .setShadowAttrs() - .setIndices(shadows.getIndexCount()) - .build(); - - Mesh::VertexArray<vec2> position = mesh.getPositionArray<vec2>(); - Mesh::VertexArray<vec4> shadowColor = mesh.getShadowColorArray<vec4>(); - Mesh::VertexArray<vec3> shadowParams = mesh.getShadowParamsArray<vec3>(); - shadows.fillVertices(position, shadowColor, shadowParams); - shadows.fillIndices(mesh.getIndicesArray()); - - mState.cornerRadius = 0.0f; - mState.drawShadows = true; - setupLayerTexturing(mShadowTexture->getTexture()); - drawMesh(mesh); - mState.drawShadows = false; -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h deleted file mode 100644 index f5368d4e9f..0000000000 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright 2013 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_GLESRENDERENGINE_H_ -#define SF_GLESRENDERENGINE_H_ - -#include <condition_variable> -#include <deque> -#include <mutex> -#include <queue> -#include <thread> -#include <unordered_map> - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES2/gl2.h> -#include <android-base/thread_annotations.h> -#include <renderengine/RenderEngine.h> -#include <renderengine/private/Description.h> -#include <sys/types.h> -#include <ui/FenceResult.h> -#include "GLShadowTexture.h" -#include "ImageManager.h" - -#define EGL_NO_CONFIG ((EGLConfig)0) - -namespace android { - -namespace renderengine { - -class Mesh; -class Texture; - -namespace gl { - -class GLImage; -class BlurFilter; - -class GLESRenderEngine : public RenderEngine { -public: - static std::unique_ptr<GLESRenderEngine> create(const RenderEngineCreationArgs& args); - - GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLConfig config, - EGLContext ctxt, EGLSurface stub, EGLContext protectedContext, - EGLSurface protectedStub); - ~GLESRenderEngine() override EXCLUDES(mRenderingMutex); - - std::future<void> primeCache() override; - void genTextures(size_t count, uint32_t* names) override; - void deleteTextures(size_t count, uint32_t const* names) override; - bool isProtected() const { return mInProtectedContext; } - bool supportsProtectedContent() const override; - void useProtectedContext(bool useProtectedContext) override; - void cleanupPostRender() override; - int getContextPriority() override; - bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; } - void onActiveDisplaySizeChanged(ui::Size size) override {} - - EGLDisplay getEGLDisplay() const { return mEGLDisplay; } - // Creates an output image for rendering to - EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected, - bool useFramebufferCache) - EXCLUDES(mFramebufferImageCacheMutex); - - // Test-only methods - // Returns true iff mImageCache contains an image keyed by bufferId - bool isImageCachedForTesting(uint64_t bufferId) EXCLUDES(mRenderingMutex); - // Returns true iff texName was previously generated by RenderEngine and was - // not destroyed. - bool isTextureNameKnownForTesting(uint32_t texName); - // Returns the buffer ID of the content bound to texName, or nullopt if no - // such mapping exists. - std::optional<uint64_t> getBufferIdForTextureNameForTesting(uint32_t texName); - // Returns true iff mFramebufferImageCache contains an image keyed by bufferId - bool isFramebufferImageCachedForTesting(uint64_t bufferId) - EXCLUDES(mFramebufferImageCacheMutex); - // These are wrappers around public methods above, but exposing Barrier - // objects so that tests can block. - std::shared_ptr<ImageManager::Barrier> cacheExternalTextureBufferForTesting( - const sp<GraphicBuffer>& buffer); - std::shared_ptr<ImageManager::Barrier> unbindExternalTextureBufferForTesting(uint64_t bufferId); - -protected: - Framebuffer* getFramebufferForDrawing(); - void dump(std::string& result) override EXCLUDES(mRenderingMutex) - EXCLUDES(mFramebufferImageCacheMutex); - size_t getMaxTextureSize() const override; - size_t getMaxViewportDims() const override; - void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) - EXCLUDES(mRenderingMutex); - void unmapExternalTextureBuffer(sp<GraphicBuffer>&& buffer) EXCLUDES(mRenderingMutex); - bool canSkipPostRenderCleanup() const override; - void drawLayersInternal(const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, - const DisplaySettings& display, - const std::vector<LayerSettings>& layers, - const std::shared_ptr<ExternalTexture>& buffer, - const bool useFramebufferCache, base::unique_fd&& bufferFence) override; - -private: - friend class BindNativeBufferAsFramebuffer; - - enum GlesVersion { - GLES_VERSION_1_0 = 0x10000, - GLES_VERSION_1_1 = 0x10001, - GLES_VERSION_2_0 = 0x20000, - GLES_VERSION_3_0 = 0x30000, - }; - - static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); - static GlesVersion parseGlesVersion(const char* str); - static EGLContext createEglContext(EGLDisplay display, EGLConfig config, - EGLContext shareContext, - std::optional<ContextPriority> contextPriority, - Protection protection); - static std::optional<RenderEngine::ContextPriority> createContextPriority( - const RenderEngineCreationArgs& args); - static EGLSurface createStubEglPbufferSurface(EGLDisplay display, EGLConfig config, - int hwcFormat, Protection protection); - std::unique_ptr<Framebuffer> createFramebuffer(); - std::unique_ptr<Image> createImage(); - void checkErrors() const; - void checkErrors(const char* tag) const; - void setScissor(const Rect& region); - void disableScissor(); - bool waitSync(EGLSyncKHR sync, EGLint flags); - status_t cacheExternalTextureBufferInternal(const sp<GraphicBuffer>& buffer) - EXCLUDES(mRenderingMutex); - void unbindExternalTextureBufferInternal(uint64_t bufferId) EXCLUDES(mRenderingMutex); - status_t bindFrameBuffer(Framebuffer* framebuffer); - void unbindFrameBuffer(Framebuffer* framebuffer); - void bindExternalTextureImage(uint32_t texName, const Image& image); - void bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer, - const sp<Fence>& fence) EXCLUDES(mRenderingMutex); - void cleanFramebufferCache() EXCLUDES(mFramebufferImageCacheMutex) override; - - // A data space is considered HDR data space if it has BT2020 color space - // with PQ or HLG transfer function. - bool isHdrDataSpace(const ui::Dataspace dataSpace) const; - bool needsXYZTransformMatrix() const; - // Defines the viewport, and sets the projection matrix to the projection - // defined by the clip. - void setViewportAndProjection(Rect viewport, Rect clip); - // Evicts stale images from the buffer cache. - void evictImages(const std::vector<LayerSettings>& layers); - // Computes the cropping window for the layer and sets up cropping - // coordinates for the mesh. - FloatRect setupLayerCropping(const LayerSettings& layer, Mesh& mesh); - - // We do a special handling for rounded corners when it's possible to turn off blending - // for the majority of the layer. The rounded corners needs to turn on blending such that - // we can set the alpha value correctly, however, only the corners need this, and since - // blending is an expensive operation, we want to turn off blending when it's not necessary. - void handleRoundedCorners(const DisplaySettings& display, const LayerSettings& layer, - const Mesh& mesh); - base::unique_fd flush(); - bool finish(); - bool waitFence(base::unique_fd fenceFd); - void clearWithColor(float red, float green, float blue, float alpha); - void fillRegionWithColor(const Region& region, float red, float green, float blue, float alpha); - void handleShadow(const FloatRect& casterRect, float casterCornerRadius, - const ShadowSettings& shadowSettings); - void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, - const half4& color, float cornerRadius); - void setupLayerTexturing(const Texture& texture); - void setupFillWithColor(float r, float g, float b, float a); - void setColorTransform(const mat4& colorTransform); - void setDisplayColorTransform(const mat4& colorTransform); - void disableTexturing(); - void disableBlending(); - void setupCornerRadiusCropSize(float width, float height); - - // HDR and color management related functions and state - void setSourceDataSpace(ui::Dataspace source); - void setOutputDataSpace(ui::Dataspace dataspace); - void setDisplayMaxLuminance(const float maxLuminance); - - // drawing - void drawMesh(const Mesh& mesh); - - EGLDisplay mEGLDisplay; - EGLConfig mEGLConfig; - EGLContext mEGLContext; - EGLSurface mStubSurface; - EGLContext mProtectedEGLContext; - EGLSurface mProtectedStubSurface; - GLint mMaxViewportDims[2]; - GLint mMaxTextureSize; - GLuint mVpWidth; - GLuint mVpHeight; - Description mState; - std::unique_ptr<GLShadowTexture> mShadowTexture = nullptr; - - mat4 mSrgbToXyz; - mat4 mDisplayP3ToXyz; - mat4 mBt2020ToXyz; - mat4 mXyzToSrgb; - mat4 mXyzToDisplayP3; - mat4 mXyzToBt2020; - mat4 mSrgbToDisplayP3; - mat4 mSrgbToBt2020; - mat4 mDisplayP3ToSrgb; - mat4 mDisplayP3ToBt2020; - mat4 mBt2020ToSrgb; - mat4 mBt2020ToDisplayP3; - - bool mInProtectedContext = false; - // If set to true, then enables tracing flush() and finish() to systrace. - bool mTraceGpuCompletion = false; - // Maximum size of mFramebufferImageCache. If more images would be cached, then (approximately) - // the last recently used buffer should be kicked out. - uint32_t mFramebufferImageCacheSize = 0; - - // Cache of output images, keyed by corresponding GraphicBuffer ID. - std::deque<std::pair<uint64_t, EGLImageKHR>> mFramebufferImageCache - GUARDED_BY(mFramebufferImageCacheMutex); - // The only reason why we have this mutex is so that we don't segfault when - // dumping info. - std::mutex mFramebufferImageCacheMutex; - - // Current dataspace of layer being rendered - ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN; - - // Current output dataspace of the render engine - ui::Dataspace mOutputDataSpace = ui::Dataspace::UNKNOWN; - - // Whether only shaders performing tone mapping from HDR to SDR will be generated on - // primeCache(). - const bool mPrecacheToneMapperShaderOnly = false; - - // Cache of GL images that we'll store per GraphicBuffer ID - std::unordered_map<uint64_t, std::unique_ptr<Image>> mImageCache GUARDED_BY(mRenderingMutex); - std::unordered_map<uint32_t, std::optional<uint64_t>> mTextureView; - - // 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; - - std::unique_ptr<Framebuffer> mDrawingBuffer; - // this is a 1x1 RGB buffer, but over-allocate in case a driver wants more - // memory or if it needs to satisfy alignment requirements. In this case: - // assume that each channel requires 4 bytes, and add 3 additional bytes to - // ensure that we align on a word. Allocating 16 bytes will provide a - // guarantee that we don't clobber memory. - uint32_t mPlaceholderDrawBuffer[4]; - // Placeholder buffer and image, similar to mPlaceholderDrawBuffer, but - // instead these are intended for cleaning up texture memory with the - // GL_TEXTURE_EXTERNAL_OES target. - ANativeWindowBuffer* mPlaceholderBuffer = nullptr; - EGLImage mPlaceholderImage = EGL_NO_IMAGE_KHR; - sp<Fence> mLastDrawFence; - // Store a separate boolean checking if prior resources were cleaned up, as - // devices that don't support native sync fences can't rely on a last draw - // fence that doesn't exist. - bool mPriorResourcesCleaned = true; - - // Blur effect processor, only instantiated when a layer requests it. - BlurFilter* mBlurFilter = nullptr; - - class FlushTracer { - public: - FlushTracer(GLESRenderEngine* engine); - ~FlushTracer(); - void queueSync(EGLSyncKHR sync) EXCLUDES(mMutex); - - struct QueueEntry { - EGLSyncKHR mSync = nullptr; - uint64_t mFrameNum = 0; - }; - - private: - void loop(); - GLESRenderEngine* const mEngine; - std::thread mThread; - std::condition_variable_any mCondition; - std::mutex mMutex; - std::queue<QueueEntry> mQueue GUARDED_BY(mMutex); - uint64_t mFramesQueued GUARDED_BY(mMutex) = 0; - bool mRunning = true; - }; - friend class FlushTracer; - friend class ImageManager; - friend class GLFramebuffer; - friend class BlurFilter; - friend class GenericProgram; - std::unique_ptr<FlushTracer> mFlushTracer; - std::unique_ptr<ImageManager> mImageManager; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android - -#endif /* SF_GLESRENDERENGINE_H_ */ diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp deleted file mode 100644 index 58d6caa48a..0000000000 --- a/libs/renderengine/gl/GLFramebuffer.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 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. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "GLFramebuffer.h" - -#include <GLES/gl.h> -#include <GLES/glext.h> -#include <GLES2/gl2ext.h> -#include <GLES3/gl3.h> -#include <gui/DebugEGLImageTracker.h> -#include <nativebase/nativebase.h> -#include <utils/Trace.h> -#include "GLESRenderEngine.h" - -namespace android { -namespace renderengine { -namespace gl { - -GLFramebuffer::GLFramebuffer(GLESRenderEngine& engine) - : mEngine(engine), mEGLDisplay(engine.getEGLDisplay()), mEGLImage(EGL_NO_IMAGE_KHR) { - glGenTextures(1, &mTextureName); - glGenFramebuffers(1, &mFramebufferName); -} - -GLFramebuffer::~GLFramebuffer() { - setNativeWindowBuffer(nullptr, false, false); - glDeleteFramebuffers(1, &mFramebufferName); - glDeleteTextures(1, &mTextureName); -} - -bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected, - const bool useFramebufferCache) { - ATRACE_CALL(); - if (mEGLImage != EGL_NO_IMAGE_KHR) { - if (!usingFramebufferCache) { - eglDestroyImageKHR(mEGLDisplay, mEGLImage); - DEBUG_EGL_IMAGE_TRACKER_DESTROY(); - } - mEGLImage = EGL_NO_IMAGE_KHR; - mBufferWidth = 0; - mBufferHeight = 0; - } - - if (nativeBuffer) { - mEGLImage = mEngine.createFramebufferImageIfNeeded(nativeBuffer, isProtected, - useFramebufferCache); - if (mEGLImage == EGL_NO_IMAGE_KHR) { - return false; - } - usingFramebufferCache = useFramebufferCache; - mBufferWidth = nativeBuffer->width; - mBufferHeight = nativeBuffer->height; - } - return true; -} - -void GLFramebuffer::allocateBuffers(uint32_t width, uint32_t height, void* data) { - ATRACE_CALL(); - - glBindTexture(GL_TEXTURE_2D, mTextureName); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); - - mBufferHeight = height; - mBufferWidth = width; - mEngine.checkErrors("Allocating Fbo texture"); - - bind(); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextureName, 0); - mStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); - unbind(); - glBindTexture(GL_TEXTURE_2D, 0); - - if (mStatus != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Frame buffer is not complete. Error %d", mStatus); - } -} - -void GLFramebuffer::bind() const { - glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferName); -} - -void GLFramebuffer::bindAsReadBuffer() const { - glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebufferName); -} - -void GLFramebuffer::bindAsDrawBuffer() const { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebufferName); -} - -void GLFramebuffer::unbind() const { - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h deleted file mode 100644 index 6757695ddb..0000000000 --- a/libs/renderengine/gl/GLFramebuffer.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 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 <cstdint> - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES2/gl2.h> -#include <renderengine/Framebuffer.h> - -struct ANativeWindowBuffer; - -namespace android { -namespace renderengine { -namespace gl { - -class GLESRenderEngine; - -class GLFramebuffer : public renderengine::Framebuffer { -public: - explicit GLFramebuffer(GLESRenderEngine& engine); - explicit GLFramebuffer(GLESRenderEngine& engine, bool multiTarget); - ~GLFramebuffer() override; - - bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected, - const bool useFramebufferCache) override; - void allocateBuffers(uint32_t width, uint32_t height, void* data = nullptr); - EGLImageKHR getEGLImage() const { return mEGLImage; } - uint32_t getTextureName() const { return mTextureName; } - uint32_t getFramebufferName() const { return mFramebufferName; } - int32_t getBufferHeight() const { return mBufferHeight; } - int32_t getBufferWidth() const { return mBufferWidth; } - GLenum getStatus() const { return mStatus; } - void bind() const; - void bindAsReadBuffer() const; - void bindAsDrawBuffer() const; - void unbind() const; - -private: - GLESRenderEngine& mEngine; - EGLDisplay mEGLDisplay; - EGLImageKHR mEGLImage; - bool usingFramebufferCache = false; - GLenum mStatus = GL_FRAMEBUFFER_UNSUPPORTED; - uint32_t mTextureName, mFramebufferName; - - int32_t mBufferHeight = 0; - int32_t mBufferWidth = 0; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLImage.cpp b/libs/renderengine/gl/GLImage.cpp deleted file mode 100644 index 8497721956..0000000000 --- a/libs/renderengine/gl/GLImage.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 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. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "GLImage.h" - -#include <vector> - -#include <gui/DebugEGLImageTracker.h> -#include <log/log.h> -#include <utils/Trace.h> -#include "GLESRenderEngine.h" -#include "GLExtensions.h" - -namespace android { -namespace renderengine { -namespace gl { - -static std::vector<EGLint> buildAttributeList(bool isProtected) { - std::vector<EGLint> attrs; - attrs.reserve(16); - - attrs.push_back(EGL_IMAGE_PRESERVED_KHR); - attrs.push_back(EGL_TRUE); - - if (isProtected && GLExtensions::getInstance().hasProtectedContent()) { - attrs.push_back(EGL_PROTECTED_CONTENT_EXT); - attrs.push_back(EGL_TRUE); - } - - attrs.push_back(EGL_NONE); - - return attrs; -} - -GLImage::GLImage(const GLESRenderEngine& engine) : mEGLDisplay(engine.getEGLDisplay()) {} - -GLImage::~GLImage() { - setNativeWindowBuffer(nullptr, false); -} - -bool GLImage::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) { - ATRACE_CALL(); - if (mEGLImage != EGL_NO_IMAGE_KHR) { - if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) { - ALOGE("failed to destroy image: %#x", eglGetError()); - } - DEBUG_EGL_IMAGE_TRACKER_DESTROY(); - mEGLImage = EGL_NO_IMAGE_KHR; - } - - if (buffer) { - std::vector<EGLint> attrs = buildAttributeList(isProtected); - mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, - static_cast<EGLClientBuffer>(buffer), attrs.data()); - if (mEGLImage == EGL_NO_IMAGE_KHR) { - ALOGE("failed to create EGLImage: %#x", eglGetError()); - return false; - } - DEBUG_EGL_IMAGE_TRACKER_CREATE(); - mProtected = isProtected; - } - - return true; -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLImage.h b/libs/renderengine/gl/GLImage.h deleted file mode 100644 index 59d6ce3549..0000000000 --- a/libs/renderengine/gl/GLImage.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 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 <cstdint> - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <android-base/macros.h> -#include <renderengine/Image.h> - -struct ANativeWindowBuffer; - -namespace android { -namespace renderengine { -namespace gl { - -class GLESRenderEngine; - -class GLImage : public renderengine::Image { -public: - explicit GLImage(const GLESRenderEngine& engine); - ~GLImage() override; - - bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) override; - - EGLImageKHR getEGLImage() const { return mEGLImage; } - bool isProtected() const { return mProtected; } - -private: - EGLDisplay mEGLDisplay; - EGLImageKHR mEGLImage = EGL_NO_IMAGE_KHR; - bool mProtected = false; - - DISALLOW_COPY_AND_ASSIGN(GLImage); -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLShadowTexture.cpp b/libs/renderengine/gl/GLShadowTexture.cpp deleted file mode 100644 index 2423a3467e..0000000000 --- a/libs/renderengine/gl/GLShadowTexture.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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. - */ - -#include <GLES/gl.h> -#include <GLES/glext.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#include <GLES3/gl3.h> - -#include "GLShadowTexture.h" -#include "GLSkiaShadowPort.h" - -namespace android { -namespace renderengine { -namespace gl { - -GLShadowTexture::GLShadowTexture() { - fillShadowTextureData(mTextureData, SHADOW_TEXTURE_WIDTH); - - glGenTextures(1, &mName); - glBindTexture(GL_TEXTURE_2D, mName); - glTexImage2D(GL_TEXTURE_2D, 0 /* base image level */, GL_ALPHA, SHADOW_TEXTURE_WIDTH, - SHADOW_TEXTURE_HEIGHT, 0 /* border */, GL_ALPHA, GL_UNSIGNED_BYTE, mTextureData); - mTexture.init(Texture::TEXTURE_2D, mName); - mTexture.setFiltering(true); - mTexture.setDimensions(SHADOW_TEXTURE_WIDTH, 1); -} - -GLShadowTexture::~GLShadowTexture() { - glDeleteTextures(1, &mName); -} - -const Texture& GLShadowTexture::getTexture() { - return mTexture; -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLShadowTexture.h b/libs/renderengine/gl/GLShadowTexture.h deleted file mode 100644 index 250a9d77d0..0000000000 --- a/libs/renderengine/gl/GLShadowTexture.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include <renderengine/Texture.h> -#include <cstdint> - -namespace android { -namespace renderengine { -namespace gl { - -class GLShadowTexture { -public: - GLShadowTexture(); - ~GLShadowTexture(); - - const Texture& getTexture(); - -private: - static constexpr int SHADOW_TEXTURE_WIDTH = 128; - static constexpr int SHADOW_TEXTURE_HEIGHT = 1; - - GLuint mName; - Texture mTexture; - uint8_t mTextureData[SHADOW_TEXTURE_WIDTH]; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLShadowVertexGenerator.cpp b/libs/renderengine/gl/GLShadowVertexGenerator.cpp deleted file mode 100644 index 3181f9bebb..0000000000 --- a/libs/renderengine/gl/GLShadowVertexGenerator.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2019 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 <renderengine/Mesh.h> - -#include <math/vec4.h> - -#include <ui/Rect.h> -#include <ui/Transform.h> - -#include "GLShadowVertexGenerator.h" - -namespace android { -namespace renderengine { -namespace gl { - -GLShadowVertexGenerator::GLShadowVertexGenerator(const FloatRect& casterRect, - float casterCornerRadius, float casterZ, - bool casterIsTranslucent, const vec4& ambientColor, - const vec4& spotColor, const vec3& lightPosition, - float lightRadius) { - mDrawAmbientShadow = ambientColor.a > 0.f; - mDrawSpotShadow = spotColor.a > 0.f; - - // Generate geometries and find number of vertices to generate - if (mDrawAmbientShadow) { - mAmbientShadowGeometry = getAmbientShadowGeometry(casterRect, casterCornerRadius, casterZ, - casterIsTranslucent, ambientColor); - mAmbientShadowVertexCount = getVertexCountForGeometry(*mAmbientShadowGeometry.get()); - mAmbientShadowIndexCount = getIndexCountForGeometry(*mAmbientShadowGeometry.get()); - } else { - mAmbientShadowVertexCount = 0; - mAmbientShadowIndexCount = 0; - } - - if (mDrawSpotShadow) { - mSpotShadowGeometry = - getSpotShadowGeometry(casterRect, casterCornerRadius, casterZ, casterIsTranslucent, - spotColor, lightPosition, lightRadius); - mSpotShadowVertexCount = getVertexCountForGeometry(*mSpotShadowGeometry.get()); - mSpotShadowIndexCount = getIndexCountForGeometry(*mSpotShadowGeometry.get()); - } else { - mSpotShadowVertexCount = 0; - mSpotShadowIndexCount = 0; - } -} - -size_t GLShadowVertexGenerator::getVertexCount() const { - return mAmbientShadowVertexCount + mSpotShadowVertexCount; -} - -size_t GLShadowVertexGenerator::getIndexCount() const { - return mAmbientShadowIndexCount + mSpotShadowIndexCount; -} - -void GLShadowVertexGenerator::fillVertices(Mesh::VertexArray<vec2>& position, - Mesh::VertexArray<vec4>& color, - Mesh::VertexArray<vec3>& params) const { - if (mDrawAmbientShadow) { - fillVerticesForGeometry(*mAmbientShadowGeometry.get(), mAmbientShadowVertexCount, position, - color, params); - } - if (mDrawSpotShadow) { - fillVerticesForGeometry(*mSpotShadowGeometry.get(), mSpotShadowVertexCount, - Mesh::VertexArray<vec2>(position, mAmbientShadowVertexCount), - Mesh::VertexArray<vec4>(color, mAmbientShadowVertexCount), - Mesh::VertexArray<vec3>(params, mAmbientShadowVertexCount)); - } -} - -void GLShadowVertexGenerator::fillIndices(uint16_t* indices) const { - if (mDrawAmbientShadow) { - fillIndicesForGeometry(*mAmbientShadowGeometry.get(), mAmbientShadowIndexCount, - 0 /* starting vertex offset */, indices); - } - if (mDrawSpotShadow) { - fillIndicesForGeometry(*mSpotShadowGeometry.get(), mSpotShadowIndexCount, - mAmbientShadowVertexCount /* starting vertex offset */, - &(indices[mAmbientShadowIndexCount])); - } -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLShadowVertexGenerator.h b/libs/renderengine/gl/GLShadowVertexGenerator.h deleted file mode 100644 index 112f97623b..0000000000 --- a/libs/renderengine/gl/GLShadowVertexGenerator.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2019 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 <math/vec4.h> -#include <ui/Rect.h> - -#include "GLSkiaShadowPort.h" - -namespace android { -namespace renderengine { - -class Mesh; - -namespace gl { - -/** - * Generates gl attributes required to draw shadow spot and/or ambient shadows. - * - * Each shadow can support different colors. This class generates three vertex attributes for - * each shadow, its position, color and shadow params(offset and distance). These can be sent - * using a single glDrawElements call. - */ -class GLShadowVertexGenerator { -public: - GLShadowVertexGenerator(const FloatRect& casterRect, float casterCornerRadius, float casterZ, - bool casterIsTranslucent, const vec4& ambientColor, - const vec4& spotColor, const vec3& lightPosition, float lightRadius); - ~GLShadowVertexGenerator() = default; - - size_t getVertexCount() const; - size_t getIndexCount() const; - void fillVertices(Mesh::VertexArray<vec2>& position, Mesh::VertexArray<vec4>& color, - Mesh::VertexArray<vec3>& params) const; - void fillIndices(uint16_t* indices) const; - -private: - bool mDrawAmbientShadow; - std::unique_ptr<Geometry> mAmbientShadowGeometry; - int mAmbientShadowVertexCount = 0; - int mAmbientShadowIndexCount = 0; - - bool mDrawSpotShadow; - std::unique_ptr<Geometry> mSpotShadowGeometry; - int mSpotShadowVertexCount = 0; - int mSpotShadowIndexCount = 0; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLSkiaShadowPort.cpp b/libs/renderengine/gl/GLSkiaShadowPort.cpp deleted file mode 100644 index da8b435854..0000000000 --- a/libs/renderengine/gl/GLSkiaShadowPort.cpp +++ /dev/null @@ -1,656 +0,0 @@ -/* - * Copyright 2019 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 <math/vec4.h> - -#include <renderengine/Mesh.h> - -#include <ui/Rect.h> -#include <ui/Transform.h> - -#include <utils/Log.h> - -#include "GLSkiaShadowPort.h" - -namespace android { -namespace renderengine { -namespace gl { - -/** - * The shadow geometry logic and vertex generation code has been ported from skia shadow - * fast path OpenGL implementation to draw shadows around rects and rounded rects including - * circles. - * - * path: skia/src/gpu/GrRenderTargetContext.cpp GrRenderTargetContext::drawFastShadow - * - * Modifications made: - * - Switched to using std lib math functions - * - Fall off function is implemented in vertex shader rather than a shadow texture - * - Removed transformations applied on the caster rect since the caster will be in local - * coordinate space and will be transformed by the vertex shader. - */ - -static inline float divide_and_pin(float numer, float denom, float min, float max) { - if (denom == 0.0f) return min; - return std::clamp(numer / denom, min, max); -} - -static constexpr auto SK_ScalarSqrt2 = 1.41421356f; -static constexpr auto kAmbientHeightFactor = 1.0f / 128.0f; -static constexpr auto kAmbientGeomFactor = 64.0f; -// Assuming that we have a light height of 600 for the spot shadow, -// the spot values will reach their maximum at a height of approximately 292.3077. -// We'll round up to 300 to keep it simple. -static constexpr auto kMaxAmbientRadius = 300 * kAmbientHeightFactor * kAmbientGeomFactor; - -inline float AmbientBlurRadius(float height) { - return std::min(height * kAmbientHeightFactor * kAmbientGeomFactor, kMaxAmbientRadius); -} -inline float AmbientRecipAlpha(float height) { - return 1.0f + std::max(height * kAmbientHeightFactor, 0.0f); -} - -////////////////////////////////////////////////////////////////////////////// -// Circle Data -// -// We have two possible cases for geometry for a circle: - -// In the case of a normal fill, we draw geometry for the circle as an octagon. -static const uint16_t gFillCircleIndices[] = { - // enter the octagon - // clang-format off - 0, 1, 8, 1, 2, 8, - 2, 3, 8, 3, 4, 8, - 4, 5, 8, 5, 6, 8, - 6, 7, 8, 7, 0, 8, - // clang-format on -}; - -// For stroked circles, we use two nested octagons. -static const uint16_t gStrokeCircleIndices[] = { - // enter the octagon - // clang-format off - 0, 1, 9, 0, 9, 8, - 1, 2, 10, 1, 10, 9, - 2, 3, 11, 2, 11, 10, - 3, 4, 12, 3, 12, 11, - 4, 5, 13, 4, 13, 12, - 5, 6, 14, 5, 14, 13, - 6, 7, 15, 6, 15, 14, - 7, 0, 8, 7, 8, 15, - // clang-format on -}; - -#define SK_ARRAY_COUNT(a) (sizeof(a) / sizeof((a)[0])) -static const int kIndicesPerFillCircle = SK_ARRAY_COUNT(gFillCircleIndices); -static const int kIndicesPerStrokeCircle = SK_ARRAY_COUNT(gStrokeCircleIndices); -static const int kVertsPerStrokeCircle = 16; -static const int kVertsPerFillCircle = 9; - -static int circle_type_to_vert_count(bool stroked) { - return stroked ? kVertsPerStrokeCircle : kVertsPerFillCircle; -} - -static int circle_type_to_index_count(bool stroked) { - return stroked ? kIndicesPerStrokeCircle : kIndicesPerFillCircle; -} - -static const uint16_t* circle_type_to_indices(bool stroked) { - return stroked ? gStrokeCircleIndices : gFillCircleIndices; -} - -/////////////////////////////////////////////////////////////////////////////// -// RoundRect Data -// -// The geometry for a shadow roundrect is similar to a 9-patch: -// ____________ -// |_|________|_| -// | | | | -// | | | | -// | | | | -// |_|________|_| -// |_|________|_| -// -// However, each corner is rendered as a fan rather than a simple quad, as below. (The diagram -// shows the upper part of the upper left corner. The bottom triangle would similarly be split -// into two triangles.) -// ________ -// |\ \ | -// | \ \ | -// | \\ | -// | \| -// -------- -// -// The center of the fan handles the curve of the corner. For roundrects where the stroke width -// is greater than the corner radius, the outer triangles blend from the curve to the straight -// sides. Otherwise these triangles will be degenerate. -// -// In the case where the stroke width is greater than the corner radius and the -// blur radius (overstroke), we add additional geometry to mark out the rectangle in the center. -// This rectangle extends the coverage values of the center edges of the 9-patch. -// ____________ -// |_|________|_| -// | |\ ____ /| | -// | | | | | | -// | | |____| | | -// |_|/______\|_| -// |_|________|_| -// -// For filled rrects we reuse the stroke geometry but add an additional quad to the center. - -static const uint16_t gRRectIndices[] = { - // clang-format off - // overstroke quads - // we place this at the beginning so that we can skip these indices when rendering as filled - 0, 6, 25, 0, 25, 24, - 6, 18, 27, 6, 27, 25, - 18, 12, 26, 18, 26, 27, - 12, 0, 24, 12, 24, 26, - - // corners - 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, - 6, 11, 10, 6, 10, 9, 6, 9, 8, 6, 8, 7, - 12, 17, 16, 12, 16, 15, 12, 15, 14, 12, 14, 13, - 18, 19, 20, 18, 20, 21, 18, 21, 22, 18, 22, 23, - - // edges - 0, 5, 11, 0, 11, 6, - 6, 7, 19, 6, 19, 18, - 18, 23, 17, 18, 17, 12, - 12, 13, 1, 12, 1, 0, - - // fill quad - // we place this at the end so that we can skip these indices when rendering as stroked - 0, 6, 18, 0, 18, 12, - // clang-format on -}; - -// overstroke count -static const int kIndicesPerOverstrokeRRect = SK_ARRAY_COUNT(gRRectIndices) - 6; -// simple stroke count skips overstroke indices -static const int kIndicesPerStrokeRRect = kIndicesPerOverstrokeRRect - 6 * 4; -// fill count adds final quad to stroke count -static const int kIndicesPerFillRRect = kIndicesPerStrokeRRect + 6; -static const int kVertsPerStrokeRRect = 24; -static const int kVertsPerOverstrokeRRect = 28; -static const int kVertsPerFillRRect = 24; - -static int rrect_type_to_vert_count(RRectType type) { - switch (type) { - case kFill_RRectType: - return kVertsPerFillRRect; - case kStroke_RRectType: - return kVertsPerStrokeRRect; - case kOverstroke_RRectType: - return kVertsPerOverstrokeRRect; - } - ALOGE("Invalid rect type: %d", type); - return -1; -} - -static int rrect_type_to_index_count(RRectType type) { - switch (type) { - case kFill_RRectType: - return kIndicesPerFillRRect; - case kStroke_RRectType: - return kIndicesPerStrokeRRect; - case kOverstroke_RRectType: - return kIndicesPerOverstrokeRRect; - } - ALOGE("Invalid rect type: %d", type); - return -1; -} - -static const uint16_t* rrect_type_to_indices(RRectType type) { - switch (type) { - case kFill_RRectType: - case kStroke_RRectType: - return gRRectIndices + 6 * 4; - case kOverstroke_RRectType: - return gRRectIndices; - } - ALOGE("Invalid rect type: %d", type); - return nullptr; -} - -static void fillInCircleVerts(const Geometry& args, bool isStroked, - Mesh::VertexArray<vec2>& position, - Mesh::VertexArray<vec4>& shadowColor, - Mesh::VertexArray<vec3>& shadowParams) { - vec4 color = args.fColor; - float outerRadius = args.fOuterRadius; - float innerRadius = args.fInnerRadius; - float blurRadius = args.fBlurRadius; - float distanceCorrection = outerRadius / blurRadius; - - const FloatRect& bounds = args.fDevBounds; - - // The inner radius in the vertex data must be specified in normalized space. - innerRadius = innerRadius / outerRadius; - - vec2 center = vec2(bounds.getWidth() / 2.0f, bounds.getHeight() / 2.0f); - float halfWidth = 0.5f * bounds.getWidth(); - float octOffset = 0.41421356237f; // sqrt(2) - 1 - int vertexCount = 0; - - position[vertexCount] = center + vec2(-octOffset * halfWidth, -halfWidth); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(-octOffset, -1, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(octOffset * halfWidth, -halfWidth); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(octOffset, -1, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(halfWidth, -octOffset * halfWidth); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(1, -octOffset, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(halfWidth, octOffset * halfWidth); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(1, octOffset, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(octOffset * halfWidth, halfWidth); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(octOffset, 1, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(-octOffset * halfWidth, halfWidth); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(-octOffset, 1, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(-halfWidth, octOffset * halfWidth); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(-1, octOffset, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(-halfWidth, -octOffset * halfWidth); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(-1, -octOffset, distanceCorrection); - vertexCount++; - - if (isStroked) { - // compute the inner ring - - // cosine and sine of pi/8 - float c = 0.923579533f; - float s = 0.382683432f; - float r = args.fInnerRadius; - - position[vertexCount] = center + vec2(-s * r, -c * r); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(-s * innerRadius, -c * innerRadius, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(s * r, -c * r); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(s * innerRadius, -c * innerRadius, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(c * r, -s * r); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(c * innerRadius, -s * innerRadius, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(c * r, s * r); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(c * innerRadius, s * innerRadius, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(s * r, c * r); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(s * innerRadius, c * innerRadius, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(-s * r, c * r); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(-s * innerRadius, c * innerRadius, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(-c * r, s * r); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(-c * innerRadius, s * innerRadius, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(-c * r, -s * r); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(-c * innerRadius, -s * innerRadius, distanceCorrection); - vertexCount++; - } else { - // filled - position[vertexCount] = center; - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(0, 0, distanceCorrection); - vertexCount++; - } -} - -static void fillInRRectVerts(const Geometry& args, Mesh::VertexArray<vec2>& position, - Mesh::VertexArray<vec4>& shadowColor, - Mesh::VertexArray<vec3>& shadowParams) { - vec4 color = args.fColor; - float outerRadius = args.fOuterRadius; - - const FloatRect& bounds = args.fDevBounds; - - float umbraInset = args.fUmbraInset; - float minDim = 0.5f * std::min(bounds.getWidth(), bounds.getHeight()); - if (umbraInset > minDim) { - umbraInset = minDim; - } - - float xInner[4] = {bounds.left + umbraInset, bounds.right - umbraInset, - bounds.left + umbraInset, bounds.right - umbraInset}; - float xMid[4] = {bounds.left + outerRadius, bounds.right - outerRadius, - bounds.left + outerRadius, bounds.right - outerRadius}; - float xOuter[4] = {bounds.left, bounds.right, bounds.left, bounds.right}; - float yInner[4] = {bounds.top + umbraInset, bounds.top + umbraInset, bounds.bottom - umbraInset, - bounds.bottom - umbraInset}; - float yMid[4] = {bounds.top + outerRadius, bounds.top + outerRadius, - bounds.bottom - outerRadius, bounds.bottom - outerRadius}; - float yOuter[4] = {bounds.top, bounds.top, bounds.bottom, bounds.bottom}; - - float blurRadius = args.fBlurRadius; - - // In the case where we have to inset more for the umbra, our two triangles in the - // corner get skewed to a diamond rather than a square. To correct for that, - // we also skew the vectors we send to the shader that help define the circle. - // By doing so, we end up with a quarter circle in the corner rather than the - // elliptical curve. - - // This is a bit magical, but it gives us the correct results at extrema: - // a) umbraInset == outerRadius produces an orthogonal vector - // b) outerRadius == 0 produces a diagonal vector - // And visually the corner looks correct. - vec2 outerVec = vec2(outerRadius - umbraInset, -outerRadius - umbraInset); - outerVec = normalize(outerVec); - // We want the circle edge to fall fractionally along the diagonal at - // (sqrt(2)*(umbraInset - outerRadius) + outerRadius)/sqrt(2)*umbraInset - // - // Setting the components of the diagonal offset to the following value will give us that. - float diagVal = umbraInset / (SK_ScalarSqrt2 * (outerRadius - umbraInset) - outerRadius); - vec2 diagVec = vec2(diagVal, diagVal); - float distanceCorrection = umbraInset / blurRadius; - - int vertexCount = 0; - // build corner by corner - for (int i = 0; i < 4; ++i) { - // inner point - position[vertexCount] = vec2(xInner[i], yInner[i]); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(0, 0, distanceCorrection); - vertexCount++; - - // outer points - position[vertexCount] = vec2(xOuter[i], yInner[i]); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(0, -1, distanceCorrection); - vertexCount++; - - position[vertexCount] = vec2(xOuter[i], yMid[i]); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(outerVec.x, outerVec.y, distanceCorrection); - vertexCount++; - - position[vertexCount] = vec2(xOuter[i], yOuter[i]); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(diagVec.x, diagVec.y, distanceCorrection); - vertexCount++; - - position[vertexCount] = vec2(xMid[i], yOuter[i]); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(outerVec.x, outerVec.y, distanceCorrection); - vertexCount++; - - position[vertexCount] = vec2(xInner[i], yOuter[i]); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(0, -1, distanceCorrection); - vertexCount++; - } - - // Add the additional vertices for overstroked rrects. - // Effectively this is an additional stroked rrect, with its - // parameters equal to those in the center of the 9-patch. This will - // give constant values across this inner ring. - if (kOverstroke_RRectType == args.fType) { - float inset = umbraInset + args.fInnerRadius; - - // TL - position[vertexCount] = vec2(bounds.left + inset, bounds.top + inset); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(0, 0, distanceCorrection); - vertexCount++; - - // TR - position[vertexCount] = vec2(bounds.right - inset, bounds.top + inset); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(0, 0, distanceCorrection); - vertexCount++; - - // BL - position[vertexCount] = vec2(bounds.left + inset, bounds.bottom - inset); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(0, 0, distanceCorrection); - vertexCount++; - - // BR - position[vertexCount] = vec2(bounds.right - inset, bounds.bottom - inset); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(0, 0, distanceCorrection); - vertexCount++; - } -} - -int getVertexCountForGeometry(const Geometry& shadowGeometry) { - if (shadowGeometry.fIsCircle) { - return circle_type_to_vert_count(shadowGeometry.fType); - } - - return rrect_type_to_vert_count(shadowGeometry.fType); -} - -int getIndexCountForGeometry(const Geometry& shadowGeometry) { - if (shadowGeometry.fIsCircle) { - return circle_type_to_index_count(kStroke_RRectType == shadowGeometry.fType); - } - - return rrect_type_to_index_count(shadowGeometry.fType); -} - -void fillVerticesForGeometry(const Geometry& shadowGeometry, int /* vertexCount */, - Mesh::VertexArray<vec2> position, Mesh::VertexArray<vec4> shadowColor, - Mesh::VertexArray<vec3> shadowParams) { - if (shadowGeometry.fIsCircle) { - fillInCircleVerts(shadowGeometry, shadowGeometry.fIsStroked, position, shadowColor, - shadowParams); - } else { - fillInRRectVerts(shadowGeometry, position, shadowColor, shadowParams); - } -} - -void fillIndicesForGeometry(const Geometry& shadowGeometry, int indexCount, - int startingVertexOffset, uint16_t* indices) { - if (shadowGeometry.fIsCircle) { - const uint16_t* primIndices = circle_type_to_indices(shadowGeometry.fIsStroked); - for (int i = 0; i < indexCount; ++i) { - indices[i] = primIndices[i] + startingVertexOffset; - } - } else { - const uint16_t* primIndices = rrect_type_to_indices(shadowGeometry.fType); - for (int i = 0; i < indexCount; ++i) { - indices[i] = primIndices[i] + startingVertexOffset; - } - } -} - -inline void GetSpotParams(float occluderZ, float lightX, float lightY, float lightZ, - float lightRadius, float& blurRadius, float& scale, vec2& translate) { - float zRatio = divide_and_pin(occluderZ, lightZ - occluderZ, 0.0f, 0.95f); - blurRadius = lightRadius * zRatio; - scale = divide_and_pin(lightZ, lightZ - occluderZ, 1.0f, 1.95f); - translate.x = -zRatio * lightX; - translate.y = -zRatio * lightY; -} - -static std::unique_ptr<Geometry> getShadowGeometry(const vec4& color, const FloatRect& devRect, - float devRadius, float blurRadius, - float insetWidth) { - // An insetWidth > 1/2 rect width or height indicates a simple fill. - const bool isCircle = ((devRadius >= devRect.getWidth()) && (devRadius >= devRect.getHeight())); - - FloatRect bounds = devRect; - float innerRadius = 0.0f; - float outerRadius = devRadius; - float umbraInset; - - RRectType type = kFill_RRectType; - if (isCircle) { - umbraInset = 0; - } else { - umbraInset = std::max(outerRadius, blurRadius); - } - - // If stroke is greater than width or height, this is still a fill, - // otherwise we compute stroke params. - if (isCircle) { - innerRadius = devRadius - insetWidth; - type = innerRadius > 0 ? kStroke_RRectType : kFill_RRectType; - } else { - if (insetWidth <= 0.5f * std::min(devRect.getWidth(), devRect.getHeight())) { - // We don't worry about a real inner radius, we just need to know if we - // need to create overstroke vertices. - innerRadius = std::max(insetWidth - umbraInset, 0.0f); - type = innerRadius > 0 ? kOverstroke_RRectType : kStroke_RRectType; - } - } - const bool isStroked = (kStroke_RRectType == type); - return std::make_unique<Geometry>(Geometry{color, outerRadius, umbraInset, innerRadius, - blurRadius, bounds, type, isCircle, isStroked}); -} - -std::unique_ptr<Geometry> getAmbientShadowGeometry(const FloatRect& casterRect, - float casterCornerRadius, float casterZ, - bool casterIsTranslucent, - const vec4& ambientColor) { - float devSpaceInsetWidth = AmbientBlurRadius(casterZ); - const float umbraRecipAlpha = AmbientRecipAlpha(casterZ); - const float devSpaceAmbientBlur = devSpaceInsetWidth * umbraRecipAlpha; - - // Outset the shadow rrect to the border of the penumbra - float ambientPathOutset = devSpaceInsetWidth; - FloatRect outsetRect(casterRect); - outsetRect.left -= ambientPathOutset; - outsetRect.top -= ambientPathOutset; - outsetRect.right += ambientPathOutset; - outsetRect.bottom += ambientPathOutset; - - float outsetRad = casterCornerRadius + ambientPathOutset; - if (casterIsTranslucent) { - // set a large inset to force a fill - devSpaceInsetWidth = outsetRect.getWidth(); - } - - return getShadowGeometry(ambientColor, outsetRect, std::abs(outsetRad), devSpaceAmbientBlur, - std::abs(devSpaceInsetWidth)); -} - -std::unique_ptr<Geometry> getSpotShadowGeometry(const FloatRect& casterRect, - float casterCornerRadius, float casterZ, - bool casterIsTranslucent, const vec4& spotColor, - const vec3& lightPosition, float lightRadius) { - float devSpaceSpotBlur; - float spotScale; - vec2 spotOffset; - GetSpotParams(casterZ, lightPosition.x, lightPosition.y, lightPosition.z, lightRadius, - devSpaceSpotBlur, spotScale, spotOffset); - // handle scale of radius due to CTM - const float srcSpaceSpotBlur = devSpaceSpotBlur; - - // Adjust translate for the effect of the scale. - spotOffset.x += spotScale; - spotOffset.y += spotScale; - - // Compute the transformed shadow rect - ui::Transform shadowTransform; - shadowTransform.set(spotOffset.x, spotOffset.y); - shadowTransform.set(spotScale, 0, 0, spotScale); - FloatRect spotShadowRect = shadowTransform.transform(casterRect); - float spotShadowRadius = casterCornerRadius * spotScale; - - // Compute the insetWidth - float blurOutset = srcSpaceSpotBlur; - float insetWidth = blurOutset; - if (casterIsTranslucent) { - // If transparent, just do a fill - insetWidth += spotShadowRect.getWidth(); - } else { - // For shadows, instead of using a stroke we specify an inset from the penumbra - // border. We want to extend this inset area so that it meets up with the caster - // geometry. The inset geometry will by default already be inset by the blur width. - // - // We compare the min and max corners inset by the radius between the original - // rrect and the shadow rrect. The distance between the two plus the difference - // between the scaled radius and the original radius gives the distance from the - // transformed shadow shape to the original shape in that corner. The max - // of these gives the maximum distance we need to cover. - // - // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to - // that to get the full insetWidth. - float maxOffset; - if (casterCornerRadius <= 0.f) { - // Manhattan distance works better for rects - maxOffset = std::max(std::max(std::abs(spotShadowRect.left - casterRect.left), - std::abs(spotShadowRect.top - casterRect.top)), - std::max(std::abs(spotShadowRect.right - casterRect.right), - std::abs(spotShadowRect.bottom - casterRect.bottom))); - } else { - float dr = spotShadowRadius - casterCornerRadius; - vec2 upperLeftOffset = vec2(spotShadowRect.left - casterRect.left + dr, - spotShadowRect.top - casterRect.top + dr); - vec2 lowerRightOffset = vec2(spotShadowRect.right - casterRect.right - dr, - spotShadowRect.bottom - casterRect.bottom - dr); - maxOffset = sqrt(std::max(dot(upperLeftOffset, lowerRightOffset), - dot(lowerRightOffset, lowerRightOffset))) + - dr; - } - insetWidth += std::max(blurOutset, maxOffset); - } - - // Outset the shadow rrect to the border of the penumbra - spotShadowRadius += blurOutset; - spotShadowRect.left -= blurOutset; - spotShadowRect.top -= blurOutset; - spotShadowRect.right += blurOutset; - spotShadowRect.bottom += blurOutset; - - return getShadowGeometry(spotColor, spotShadowRect, std::abs(spotShadowRadius), - 2.0f * devSpaceSpotBlur, std::abs(insetWidth)); -} - -void fillShadowTextureData(uint8_t* data, size_t shadowTextureWidth) { - for (int i = 0; i < shadowTextureWidth; i++) { - const float d = 1 - i / ((shadowTextureWidth * 1.0f) - 1.0f); - data[i] = static_cast<uint8_t>((exp(-4.0f * d * d) - 0.018f) * 255); - } -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLSkiaShadowPort.h b/libs/renderengine/gl/GLSkiaShadowPort.h deleted file mode 100644 index 912c8bb7b3..0000000000 --- a/libs/renderengine/gl/GLSkiaShadowPort.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2019 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 <math/vec4.h> -#include <renderengine/Mesh.h> -#include <ui/Rect.h> - -namespace android { -namespace renderengine { -namespace gl { - -/** - * The shadow geometry logic and vertex generation code has been ported from skia shadow - * fast path OpenGL implementation to draw shadows around rects and rounded rects including - * circles. - * - * path: skia/src/gpu/GrRenderTargetContext.cpp GrRenderTargetContext::drawFastShadow - * - * Modifications made: - * - Switched to using std lib math functions - * - Fall off function is implemented in vertex shader rather than a shadow texture - * - Removed transformations applied on the caster rect since the caster will be in local - * coordinate space and will be transformed by the vertex shader. - */ - -enum RRectType { - kFill_RRectType, - kStroke_RRectType, - kOverstroke_RRectType, -}; - -struct Geometry { - vec4 fColor; - float fOuterRadius; - float fUmbraInset; - float fInnerRadius; - float fBlurRadius; - FloatRect fDevBounds; - RRectType fType; - bool fIsCircle; - bool fIsStroked; -}; - -std::unique_ptr<Geometry> getSpotShadowGeometry(const FloatRect& casterRect, - float casterCornerRadius, float casterZ, - bool casterIsTranslucent, const vec4& spotColor, - const vec3& lightPosition, float lightRadius); - -std::unique_ptr<Geometry> getAmbientShadowGeometry(const FloatRect& casterRect, - float casterCornerRadius, float casterZ, - bool casterIsTranslucent, - const vec4& ambientColor); - -int getVertexCountForGeometry(const Geometry& shadowGeometry); - -int getIndexCountForGeometry(const Geometry& shadowGeometry); - -void fillVerticesForGeometry(const Geometry& shadowGeometry, int vertexCount, - Mesh::VertexArray<vec2> position, Mesh::VertexArray<vec4> shadowColor, - Mesh::VertexArray<vec3> shadowParams); - -void fillIndicesForGeometry(const Geometry& shadowGeometry, int indexCount, - int startingVertexOffset, uint16_t* indices); - -/** - * Maps shadow geometry 'alpha' varying (1 for darkest, 0 for transparent) to - * darkness at that spot. Values are determined by an exponential falloff - * function provided by UX. - * - * The texture is used for quick lookup in theshadow shader. - * - * textureData - filled with shadow texture data that needs to be at least of - * size textureWidth - * - * textureWidth - width of the texture, height is always 1 - */ -void fillShadowTextureData(uint8_t* textureData, size_t textureWidth); - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLVertexBuffer.cpp b/libs/renderengine/gl/GLVertexBuffer.cpp deleted file mode 100644 index e50c471b6d..0000000000 --- a/libs/renderengine/gl/GLVertexBuffer.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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 ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "GLVertexBuffer.h" - -#include <GLES/gl.h> -#include <GLES2/gl2.h> -#include <nativebase/nativebase.h> -#include <utils/Trace.h> - -namespace android { -namespace renderengine { -namespace gl { - -GLVertexBuffer::GLVertexBuffer() { - glGenBuffers(1, &mBufferName); -} - -GLVertexBuffer::~GLVertexBuffer() { - glDeleteBuffers(1, &mBufferName); -} - -void GLVertexBuffer::allocateBuffers(const GLfloat data[], const GLuint size) { - ATRACE_CALL(); - bind(); - glBufferData(GL_ARRAY_BUFFER, size * sizeof(GLfloat), data, GL_STATIC_DRAW); - unbind(); -} - -void GLVertexBuffer::bind() const { - glBindBuffer(GL_ARRAY_BUFFER, mBufferName); -} - -void GLVertexBuffer::unbind() const { - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLVertexBuffer.h b/libs/renderengine/gl/GLVertexBuffer.h deleted file mode 100644 index c0fd0c1b04..0000000000 --- a/libs/renderengine/gl/GLVertexBuffer.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include <cstdint> - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES2/gl2.h> - -struct ANativeWindowBuffer; - -namespace android { -namespace renderengine { -namespace gl { - -class GLESRenderEngine; - -class GLVertexBuffer { -public: - explicit GLVertexBuffer(); - ~GLVertexBuffer(); - - void allocateBuffers(const GLfloat data[], const GLuint size); - uint32_t getBufferName() const { return mBufferName; } - void bind() const; - void unbind() const; - -private: - uint32_t mBufferName; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/ImageManager.cpp b/libs/renderengine/gl/ImageManager.cpp deleted file mode 100644 index 62566494f0..0000000000 --- a/libs/renderengine/gl/ImageManager.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2019 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 <pthread.h> - -#include <processgroup/sched_policy.h> -#include <utils/Trace.h> -#include "GLESRenderEngine.h" -#include "ImageManager.h" - -namespace android { -namespace renderengine { -namespace gl { - -ImageManager::ImageManager(GLESRenderEngine* engine) : mEngine(engine) {} - -void ImageManager::initThread() { - mThread = std::thread([this]() { threadMain(); }); - pthread_setname_np(mThread.native_handle(), "ImageManager"); - // Use SCHED_FIFO to minimize jitter - struct sched_param param = {0}; - param.sched_priority = 2; - if (pthread_setschedparam(mThread.native_handle(), SCHED_FIFO, ¶m) != 0) { - ALOGE("Couldn't set SCHED_FIFO for ImageManager"); - } -} - -ImageManager::~ImageManager() { - { - std::lock_guard<std::mutex> lock(mMutex); - mRunning = false; - } - mCondition.notify_all(); - if (mThread.joinable()) { - mThread.join(); - } -} - -void ImageManager::cacheAsync(const sp<GraphicBuffer>& buffer, - const std::shared_ptr<Barrier>& barrier) { - if (buffer == nullptr) { - { - std::lock_guard<std::mutex> lock(barrier->mutex); - barrier->isOpen = true; - barrier->result = BAD_VALUE; - } - barrier->condition.notify_one(); - return; - } - ATRACE_CALL(); - QueueEntry entry = {QueueEntry::Operation::Insert, buffer, buffer->getId(), barrier}; - queueOperation(std::move(entry)); -} - -status_t ImageManager::cache(const sp<GraphicBuffer>& buffer) { - ATRACE_CALL(); - auto barrier = std::make_shared<Barrier>(); - cacheAsync(buffer, barrier); - std::lock_guard<std::mutex> lock(barrier->mutex); - barrier->condition.wait(barrier->mutex, - [&]() REQUIRES(barrier->mutex) { return barrier->isOpen; }); - return barrier->result; -} - -void ImageManager::releaseAsync(uint64_t bufferId, const std::shared_ptr<Barrier>& barrier) { - ATRACE_CALL(); - QueueEntry entry = {QueueEntry::Operation::Delete, nullptr, bufferId, barrier}; - queueOperation(std::move(entry)); -} - -void ImageManager::queueOperation(const QueueEntry&& entry) { - { - std::lock_guard<std::mutex> lock(mMutex); - mQueue.emplace(entry); - ATRACE_INT("ImageManagerQueueDepth", mQueue.size()); - } - mCondition.notify_one(); -} - -void ImageManager::threadMain() { - set_sched_policy(0, SP_FOREGROUND); - bool run; - { - std::lock_guard<std::mutex> lock(mMutex); - run = mRunning; - } - while (run) { - QueueEntry entry; - { - std::lock_guard<std::mutex> lock(mMutex); - mCondition.wait(mMutex, - [&]() REQUIRES(mMutex) { return !mQueue.empty() || !mRunning; }); - run = mRunning; - - if (!mRunning) { - // if mRunning is false, then ImageManager is being destroyed, so - // bail out now. - break; - } - - entry = mQueue.front(); - mQueue.pop(); - ATRACE_INT("ImageManagerQueueDepth", mQueue.size()); - } - - status_t result = NO_ERROR; - switch (entry.op) { - case QueueEntry::Operation::Delete: - mEngine->unbindExternalTextureBufferInternal(entry.bufferId); - break; - case QueueEntry::Operation::Insert: - result = mEngine->cacheExternalTextureBufferInternal(entry.buffer); - break; - } - if (entry.barrier != nullptr) { - { - std::lock_guard<std::mutex> entryLock(entry.barrier->mutex); - entry.barrier->result = result; - entry.barrier->isOpen = true; - } - entry.barrier->condition.notify_one(); - } - } - - ALOGD("Reached end of threadMain, terminating ImageManager thread!"); -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/ImageManager.h b/libs/renderengine/gl/ImageManager.h deleted file mode 100644 index be67de8367..0000000000 --- a/libs/renderengine/gl/ImageManager.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2019 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 <condition_variable> -#include <mutex> -#include <queue> -#include <thread> - -#include <ui/GraphicBuffer.h> - -namespace android { -namespace renderengine { -namespace gl { - -class GLESRenderEngine; - -class ImageManager { -public: - struct Barrier { - std::mutex mutex; - std::condition_variable_any condition; - bool isOpen GUARDED_BY(mutex) = false; - status_t result GUARDED_BY(mutex) = NO_ERROR; - }; - ImageManager(GLESRenderEngine* engine); - ~ImageManager(); - // Starts the background thread for the ImageManager - // We need this to guarantee that the class is fully-constructed before the - // thread begins running. - void initThread(); - void cacheAsync(const sp<GraphicBuffer>& buffer, const std::shared_ptr<Barrier>& barrier) - EXCLUDES(mMutex); - status_t cache(const sp<GraphicBuffer>& buffer); - void releaseAsync(uint64_t bufferId, const std::shared_ptr<Barrier>& barrier) EXCLUDES(mMutex); - -private: - struct QueueEntry { - enum class Operation { Delete, Insert }; - - Operation op = Operation::Delete; - sp<GraphicBuffer> buffer = nullptr; - uint64_t bufferId = 0; - std::shared_ptr<Barrier> barrier = nullptr; - }; - - void queueOperation(const QueueEntry&& entry); - void threadMain(); - GLESRenderEngine* const mEngine; - std::thread mThread; - std::condition_variable_any mCondition; - std::mutex mMutex; - std::queue<QueueEntry> mQueue GUARDED_BY(mMutex); - - bool mRunning GUARDED_BY(mMutex) = true; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/Program.cpp b/libs/renderengine/gl/Program.cpp deleted file mode 100644 index 26f6166761..0000000000 --- a/libs/renderengine/gl/Program.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/*Gluint - * Copyright 2013 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 "Program.h" - -#include <stdint.h> - -#include <log/log.h> -#include <math/mat4.h> -#include <utils/String8.h> -#include "ProgramCache.h" - -namespace android { -namespace renderengine { -namespace gl { - -Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const char* fragment) - : mInitialized(false) { - GLuint vertexId = buildShader(vertex, GL_VERTEX_SHADER); - GLuint fragmentId = buildShader(fragment, GL_FRAGMENT_SHADER); - GLuint programId = glCreateProgram(); - glAttachShader(programId, vertexId); - glAttachShader(programId, fragmentId); - glBindAttribLocation(programId, position, "position"); - glBindAttribLocation(programId, texCoords, "texCoords"); - glBindAttribLocation(programId, cropCoords, "cropCoords"); - glBindAttribLocation(programId, shadowColor, "shadowColor"); - glBindAttribLocation(programId, shadowParams, "shadowParams"); - glLinkProgram(programId); - - GLint status; - glGetProgramiv(programId, GL_LINK_STATUS, &status); - if (status != GL_TRUE) { - ALOGE("Error while linking shaders:"); - GLint infoLen = 0; - glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &infoLen); - if (infoLen > 1) { - GLchar log[infoLen]; - glGetProgramInfoLog(programId, infoLen, 0, &log[0]); - ALOGE("%s", log); - } - glDetachShader(programId, vertexId); - glDetachShader(programId, fragmentId); - glDeleteShader(vertexId); - glDeleteShader(fragmentId); - glDeleteProgram(programId); - } else { - mProgram = programId; - mVertexShader = vertexId; - mFragmentShader = fragmentId; - mInitialized = true; - mProjectionMatrixLoc = glGetUniformLocation(programId, "projection"); - mTextureMatrixLoc = glGetUniformLocation(programId, "texture"); - mSamplerLoc = glGetUniformLocation(programId, "sampler"); - mColorLoc = glGetUniformLocation(programId, "color"); - mDisplayColorMatrixLoc = glGetUniformLocation(programId, "displayColorMatrix"); - mDisplayMaxLuminanceLoc = glGetUniformLocation(programId, "displayMaxLuminance"); - mMaxMasteringLuminanceLoc = glGetUniformLocation(programId, "maxMasteringLuminance"); - mMaxContentLuminanceLoc = glGetUniformLocation(programId, "maxContentLuminance"); - mInputTransformMatrixLoc = glGetUniformLocation(programId, "inputTransformMatrix"); - mOutputTransformMatrixLoc = glGetUniformLocation(programId, "outputTransformMatrix"); - mCornerRadiusLoc = glGetUniformLocation(programId, "cornerRadius"); - mCropCenterLoc = glGetUniformLocation(programId, "cropCenter"); - - // set-up the default values for our uniforms - glUseProgram(programId); - glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, mat4().asArray()); - glEnableVertexAttribArray(0); - } -} - -Program::~Program() { - glDetachShader(mProgram, mVertexShader); - glDetachShader(mProgram, mFragmentShader); - glDeleteShader(mVertexShader); - glDeleteShader(mFragmentShader); - glDeleteProgram(mProgram); -} - -bool Program::isValid() const { - return mInitialized; -} - -void Program::use() { - glUseProgram(mProgram); -} - -GLuint Program::getAttrib(const char* name) const { - // TODO: maybe use a local cache - return glGetAttribLocation(mProgram, name); -} - -GLint Program::getUniform(const char* name) const { - // TODO: maybe use a local cache - return glGetUniformLocation(mProgram, name); -} - -GLuint Program::buildShader(const char* source, GLenum type) { - GLuint shader = glCreateShader(type); - glShaderSource(shader, 1, &source, 0); - glCompileShader(shader); - GLint status; - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - if (status != GL_TRUE) { - // Some drivers return wrong values for GL_INFO_LOG_LENGTH - // use a fixed size instead - GLchar log[512]; - glGetShaderInfoLog(shader, sizeof(log), 0, log); - ALOGE("Error while compiling shader: \n%s\n%s", source, log); - glDeleteShader(shader); - return 0; - } - return shader; -} - -void Program::setUniforms(const Description& desc) { - // TODO: we should have a mechanism here to not always reset uniforms that - // didn't change for this program. - - if (mSamplerLoc >= 0) { - glUniform1i(mSamplerLoc, 0); - glUniformMatrix4fv(mTextureMatrixLoc, 1, GL_FALSE, desc.texture.getMatrix().asArray()); - } - if (mColorLoc >= 0) { - const float color[4] = {desc.color.r, desc.color.g, desc.color.b, desc.color.a}; - glUniform4fv(mColorLoc, 1, color); - } - if (mDisplayColorMatrixLoc >= 0) { - glUniformMatrix4fv(mDisplayColorMatrixLoc, 1, GL_FALSE, desc.displayColorMatrix.asArray()); - } - if (mInputTransformMatrixLoc >= 0) { - mat4 inputTransformMatrix = desc.inputTransformMatrix; - glUniformMatrix4fv(mInputTransformMatrixLoc, 1, GL_FALSE, inputTransformMatrix.asArray()); - } - if (mOutputTransformMatrixLoc >= 0) { - // The output transform matrix and color matrix can be combined as one matrix - // that is applied right before applying OETF. - mat4 outputTransformMatrix = desc.colorMatrix * desc.outputTransformMatrix; - glUniformMatrix4fv(mOutputTransformMatrixLoc, 1, GL_FALSE, outputTransformMatrix.asArray()); - } - if (mDisplayMaxLuminanceLoc >= 0) { - glUniform1f(mDisplayMaxLuminanceLoc, desc.displayMaxLuminance); - } - if (mMaxMasteringLuminanceLoc >= 0) { - glUniform1f(mMaxMasteringLuminanceLoc, desc.maxMasteringLuminance); - } - if (mMaxContentLuminanceLoc >= 0) { - glUniform1f(mMaxContentLuminanceLoc, desc.maxContentLuminance); - } - if (mCornerRadiusLoc >= 0) { - glUniform1f(mCornerRadiusLoc, desc.cornerRadius); - } - if (mCropCenterLoc >= 0) { - glUniform2f(mCropCenterLoc, desc.cropSize.x / 2.0f, desc.cropSize.y / 2.0f); - } - // these uniforms are always present - glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.projectionMatrix.asArray()); -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/Program.h b/libs/renderengine/gl/Program.h deleted file mode 100644 index 41f1bf865e..0000000000 --- a/libs/renderengine/gl/Program.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2013 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_RENDER_ENGINE_PROGRAM_H -#define SF_RENDER_ENGINE_PROGRAM_H - -#include <stdint.h> - -#include <GLES2/gl2.h> -#include <renderengine/private/Description.h> -#include "ProgramCache.h" - -namespace android { - -class String8; - -namespace renderengine { -namespace gl { - -/* - * Abstracts a GLSL program comprising a vertex and fragment shader - */ -class Program { -public: - // known locations for position and texture coordinates - enum { - /* position of each vertex for vertex shader */ - position = 0, - - /* UV coordinates for texture mapping */ - texCoords = 1, - - /* Crop coordinates, in pixels */ - cropCoords = 2, - - /* Shadow color */ - shadowColor = 3, - - /* Shadow params */ - shadowParams = 4, - }; - - Program(const ProgramCache::Key& needs, const char* vertex, const char* fragment); - ~Program(); - - /* whether this object is usable */ - bool isValid() const; - - /* Binds this program to the GLES context */ - void use(); - - /* Returns the location of the specified attribute */ - GLuint getAttrib(const char* name) const; - - /* Returns the location of the specified uniform */ - GLint getUniform(const char* name) const; - - /* set-up uniforms from the description */ - void setUniforms(const Description& desc); - -private: - GLuint buildShader(const char* source, GLenum type); - - // whether the initialization succeeded - bool mInitialized; - - // Name of the OpenGL program and shaders - GLuint mProgram; - GLuint mVertexShader; - GLuint mFragmentShader; - - /* location of the projection matrix uniform */ - GLint mProjectionMatrixLoc; - - /* location of the texture matrix uniform */ - GLint mTextureMatrixLoc; - - /* location of the sampler uniform */ - GLint mSamplerLoc; - - /* location of the color uniform */ - GLint mColorLoc; - - /* location of display luminance uniform */ - GLint mDisplayMaxLuminanceLoc; - /* location of max mastering luminance uniform */ - GLint mMaxMasteringLuminanceLoc; - /* location of max content luminance uniform */ - GLint mMaxContentLuminanceLoc; - - /* location of transform matrix */ - GLint mInputTransformMatrixLoc; - GLint mOutputTransformMatrixLoc; - GLint mDisplayColorMatrixLoc; - - /* location of corner radius uniform */ - GLint mCornerRadiusLoc; - - /* location of surface crop origin uniform, for rounded corner clipping */ - GLint mCropCenterLoc; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android - -#endif /* SF_RENDER_ENGINE_PROGRAM_H */ diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp deleted file mode 100644 index 96ccf5c512..0000000000 --- a/libs/renderengine/gl/ProgramCache.cpp +++ /dev/null @@ -1,802 +0,0 @@ -/* - * Copyright 2013 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 ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "ProgramCache.h" - -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#include <log/log.h> -#include <renderengine/private/Description.h> -#include <utils/String8.h> -#include <utils/Trace.h> -#include "Program.h" - -ANDROID_SINGLETON_STATIC_INSTANCE(android::renderengine::gl::ProgramCache) - -namespace android { -namespace renderengine { -namespace gl { - -/* - * A simple formatter class to automatically add the endl and - * manage the indentation. - */ - -class Formatter; -static Formatter& indent(Formatter& f); -static Formatter& dedent(Formatter& f); - -class Formatter { - String8 mString; - int mIndent; - typedef Formatter& (*FormaterManipFunc)(Formatter&); - friend Formatter& indent(Formatter& f); - friend Formatter& dedent(Formatter& f); - -public: - Formatter() : mIndent(0) {} - - String8 getString() const { return mString; } - - friend Formatter& operator<<(Formatter& out, const char* in) { - for (int i = 0; i < out.mIndent; i++) { - out.mString.append(" "); - } - out.mString.append(in); - out.mString.append("\n"); - return out; - } - friend inline Formatter& operator<<(Formatter& out, const String8& in) { - return operator<<(out, in.string()); - } - friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) { - return (*func)(to); - } -}; -Formatter& indent(Formatter& f) { - f.mIndent++; - return f; -} -Formatter& dedent(Formatter& f) { - f.mIndent--; - return f; -} - -void ProgramCache::primeCache(EGLContext context, bool toneMapperShaderOnly) { - auto& cache = mCaches[context]; - uint32_t shaderCount = 0; - - if (toneMapperShaderOnly) { - Key shaderKey; - // base settings used by HDR->SDR tonemap only - shaderKey.set(Key::BLEND_MASK | Key::INPUT_TRANSFORM_MATRIX_MASK | - Key::OUTPUT_TRANSFORM_MATRIX_MASK | Key::OUTPUT_TF_MASK | - Key::OPACITY_MASK | Key::ALPHA_MASK | - Key::ROUNDED_CORNERS_MASK | Key::TEXTURE_MASK, - Key::BLEND_NORMAL | Key::INPUT_TRANSFORM_MATRIX_ON | - Key::OUTPUT_TRANSFORM_MATRIX_ON | Key::OUTPUT_TF_SRGB | - Key::OPACITY_OPAQUE | Key::ALPHA_EQ_ONE | - Key::ROUNDED_CORNERS_OFF | Key::TEXTURE_EXT); - for (int i = 0; i < 4; i++) { - // Cache input transfer for HLG & ST2084 - shaderKey.set(Key::INPUT_TF_MASK, (i & 1) ? - Key::INPUT_TF_HLG : Key::INPUT_TF_ST2084); - - if (cache.count(shaderKey) == 0) { - cache.emplace(shaderKey, generateProgram(shaderKey)); - shaderCount++; - } - } - return; - } - - uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK - | Key::ROUNDED_CORNERS_MASK; - // Prime the cache for all combinations of the above masks, - // leaving off the experimental color matrix mask options. - - nsecs_t timeBefore = systemTime(); - for (uint32_t keyVal = 0; keyVal <= keyMask; keyVal++) { - Key shaderKey; - shaderKey.set(keyMask, keyVal); - uint32_t tex = shaderKey.getTextureTarget(); - if (tex != Key::TEXTURE_OFF && tex != Key::TEXTURE_EXT && tex != Key::TEXTURE_2D) { - continue; - } - if (cache.count(shaderKey) == 0) { - cache.emplace(shaderKey, generateProgram(shaderKey)); - shaderCount++; - } - } - - // Prime for sRGB->P3 conversion - Key shaderKey; - shaderKey.set(Key::BLEND_MASK | Key::OUTPUT_TRANSFORM_MATRIX_MASK | Key::INPUT_TF_MASK | - Key::OUTPUT_TF_MASK, - Key::BLEND_PREMULT | Key::OUTPUT_TRANSFORM_MATRIX_ON | Key::INPUT_TF_SRGB | - Key::OUTPUT_TF_SRGB); - for (int i = 0; i < 16; i++) { - shaderKey.set(Key::OPACITY_MASK, (i & 1) ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT); - shaderKey.set(Key::ALPHA_MASK, (i & 2) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE); - - // Cache rounded corners - shaderKey.set(Key::ROUNDED_CORNERS_MASK, - (i & 4) ? Key::ROUNDED_CORNERS_ON : Key::ROUNDED_CORNERS_OFF); - - // Cache texture off option for window transition - shaderKey.set(Key::TEXTURE_MASK, (i & 8) ? Key::TEXTURE_EXT : Key::TEXTURE_OFF); - if (cache.count(shaderKey) == 0) { - cache.emplace(shaderKey, generateProgram(shaderKey)); - shaderCount++; - } - } - - nsecs_t timeAfter = systemTime(); - float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6; - ALOGD("shader cache generated - %u shaders in %f ms\n", shaderCount, compileTimeMs); -} - -ProgramCache::Key ProgramCache::computeKey(const Description& description) { - Key needs; - needs.set(Key::TEXTURE_MASK, - !description.textureEnabled ? Key::TEXTURE_OFF - : description.texture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES - ? Key::TEXTURE_EXT - : description.texture.getTextureTarget() == GL_TEXTURE_2D ? Key::TEXTURE_2D - : Key::TEXTURE_OFF) - .set(Key::ALPHA_MASK, (description.color.a < 1) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE) - .set(Key::BLEND_MASK, - description.isPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL) - .set(Key::OPACITY_MASK, - description.isOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT) - .set(Key::Key::INPUT_TRANSFORM_MATRIX_MASK, - description.hasInputTransformMatrix() ? Key::INPUT_TRANSFORM_MATRIX_ON - : Key::INPUT_TRANSFORM_MATRIX_OFF) - .set(Key::Key::OUTPUT_TRANSFORM_MATRIX_MASK, - description.hasOutputTransformMatrix() || description.hasColorMatrix() - ? Key::OUTPUT_TRANSFORM_MATRIX_ON - : Key::OUTPUT_TRANSFORM_MATRIX_OFF) - .set(Key::Key::DISPLAY_COLOR_TRANSFORM_MATRIX_MASK, - description.hasDisplayColorMatrix() ? Key::DISPLAY_COLOR_TRANSFORM_MATRIX_ON - : Key::DISPLAY_COLOR_TRANSFORM_MATRIX_OFF) - .set(Key::ROUNDED_CORNERS_MASK, - description.cornerRadius > 0 ? Key::ROUNDED_CORNERS_ON : Key::ROUNDED_CORNERS_OFF) - .set(Key::SHADOW_MASK, description.drawShadows ? Key::SHADOW_ON : Key::SHADOW_OFF); - - if (needs.hasTransformMatrix() || - (description.inputTransferFunction != description.outputTransferFunction)) { - switch (description.inputTransferFunction) { - case Description::TransferFunction::LINEAR: - default: - needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_LINEAR); - break; - case Description::TransferFunction::SRGB: - needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_SRGB); - break; - case Description::TransferFunction::ST2084: - needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_ST2084); - break; - case Description::TransferFunction::HLG: - needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_HLG); - break; - } - - switch (description.outputTransferFunction) { - case Description::TransferFunction::LINEAR: - default: - needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_LINEAR); - break; - case Description::TransferFunction::SRGB: - needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_SRGB); - break; - case Description::TransferFunction::ST2084: - needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_ST2084); - break; - case Description::TransferFunction::HLG: - needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_HLG); - break; - } - } - - return needs; -} - -// Generate EOTF that converts signal values to relative display light, -// both normalized to [0, 1]. -void ProgramCache::generateEOTF(Formatter& fs, const Key& needs) { - switch (needs.getInputTF()) { - case Key::INPUT_TF_SRGB: - fs << R"__SHADER__( - float EOTF_sRGB(float srgb) { - return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4); - } - - vec3 EOTF_sRGB(const vec3 srgb) { - return vec3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b)); - } - - vec3 EOTF(const vec3 srgb) { - return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb)); - } - )__SHADER__"; - break; - case Key::INPUT_TF_ST2084: - fs << R"__SHADER__( - vec3 EOTF(const highp vec3 color) { - const highp float m1 = (2610.0 / 4096.0) / 4.0; - const highp float m2 = (2523.0 / 4096.0) * 128.0; - const highp float c1 = (3424.0 / 4096.0); - const highp float c2 = (2413.0 / 4096.0) * 32.0; - const highp float c3 = (2392.0 / 4096.0) * 32.0; - - highp vec3 tmp = pow(clamp(color, 0.0, 1.0), 1.0 / vec3(m2)); - tmp = max(tmp - c1, 0.0) / (c2 - c3 * tmp); - return pow(tmp, 1.0 / vec3(m1)); - } - )__SHADER__"; - break; - case Key::INPUT_TF_HLG: - fs << R"__SHADER__( - highp float EOTF_channel(const highp float channel) { - const highp float a = 0.17883277; - const highp float b = 0.28466892; - const highp float c = 0.55991073; - return channel <= 0.5 ? channel * channel / 3.0 : - (exp((channel - c) / a) + b) / 12.0; - } - - vec3 EOTF(const highp vec3 color) { - return vec3(EOTF_channel(color.r), EOTF_channel(color.g), - EOTF_channel(color.b)); - } - )__SHADER__"; - break; - default: - fs << R"__SHADER__( - vec3 EOTF(const vec3 linear) { - return linear; - } - )__SHADER__"; - break; - } -} - -void ProgramCache::generateToneMappingProcess(Formatter& fs, const Key& needs) { - // Convert relative light to absolute light. - switch (needs.getInputTF()) { - case Key::INPUT_TF_ST2084: - fs << R"__SHADER__( - highp vec3 ScaleLuminance(highp vec3 color) { - return color * 10000.0; - } - )__SHADER__"; - break; - case Key::INPUT_TF_HLG: - fs << R"__SHADER__( - highp vec3 ScaleLuminance(highp vec3 color) { - // The formula is: - // alpha * pow(Y, gamma - 1.0) * color + beta; - // where alpha is 1000.0, gamma is 1.2, beta is 0.0. - return color * 1000.0 * pow(color.y, 0.2); - } - )__SHADER__"; - break; - default: - fs << R"__SHADER__( - highp vec3 ScaleLuminance(highp vec3 color) { - return color * displayMaxLuminance; - } - )__SHADER__"; - break; - } - - // Tone map absolute light to display luminance range. - switch (needs.getInputTF()) { - case Key::INPUT_TF_ST2084: - case Key::INPUT_TF_HLG: - switch (needs.getOutputTF()) { - case Key::OUTPUT_TF_HLG: - // Right now when mixed PQ and HLG contents are presented, - // HLG content will always be converted to PQ. However, for - // completeness, we simply clamp the value to [0.0, 1000.0]. - fs << R"__SHADER__( - highp vec3 ToneMap(highp vec3 color) { - return clamp(color, 0.0, 1000.0); - } - )__SHADER__"; - break; - case Key::OUTPUT_TF_ST2084: - fs << R"__SHADER__( - highp vec3 ToneMap(highp vec3 color) { - return color; - } - )__SHADER__"; - break; - default: - fs << R"__SHADER__( - highp vec3 ToneMap(highp vec3 color) { - float maxMasteringLumi = maxMasteringLuminance; - float maxContentLumi = maxContentLuminance; - float maxInLumi = min(maxMasteringLumi, maxContentLumi); - float maxOutLumi = displayMaxLuminance; - - float nits = color.y; - - // clamp to max input luminance - nits = clamp(nits, 0.0, maxInLumi); - - // scale [0.0, maxInLumi] to [0.0, maxOutLumi] - if (maxInLumi <= maxOutLumi) { - return color * (maxOutLumi / maxInLumi); - } else { - // three control points - const float x0 = 10.0; - const float y0 = 17.0; - float x1 = maxOutLumi * 0.75; - float y1 = x1; - float x2 = x1 + (maxInLumi - x1) / 2.0; - float y2 = y1 + (maxOutLumi - y1) * 0.75; - - // horizontal distances between the last three control points - float h12 = x2 - x1; - float h23 = maxInLumi - x2; - // tangents at the last three control points - float m1 = (y2 - y1) / h12; - float m3 = (maxOutLumi - y2) / h23; - float m2 = (m1 + m3) / 2.0; - - if (nits < x0) { - // scale [0.0, x0] to [0.0, y0] linearly - float slope = y0 / x0; - return color * slope; - } else if (nits < x1) { - // scale [x0, x1] to [y0, y1] linearly - float slope = (y1 - y0) / (x1 - x0); - nits = y0 + (nits - x0) * slope; - } else if (nits < x2) { - // scale [x1, x2] to [y1, y2] using Hermite interp - float t = (nits - x1) / h12; - nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) + - (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t; - } else { - // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp - float t = (nits - x2) / h23; - nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) + - (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t; - } - } - - // color.y is greater than x0 and is thus non-zero - return color * (nits / color.y); - } - )__SHADER__"; - break; - } - break; - default: - // inverse tone map; the output luminance can be up to maxOutLumi. - fs << R"__SHADER__( - highp vec3 ToneMap(highp vec3 color) { - const float maxOutLumi = 3000.0; - - const float x0 = 5.0; - const float y0 = 2.5; - float x1 = displayMaxLuminance * 0.7; - float y1 = maxOutLumi * 0.15; - float x2 = displayMaxLuminance * 0.9; - float y2 = maxOutLumi * 0.45; - float x3 = displayMaxLuminance; - float y3 = maxOutLumi; - - float c1 = y1 / 3.0; - float c2 = y2 / 2.0; - float c3 = y3 / 1.5; - - float nits = color.y; - - float scale; - if (nits <= x0) { - // scale [0.0, x0] to [0.0, y0] linearly - const float slope = y0 / x0; - return color * slope; - } else if (nits <= x1) { - // scale [x0, x1] to [y0, y1] using a curve - float t = (nits - x0) / (x1 - x0); - nits = (1.0 - t) * (1.0 - t) * y0 + 2.0 * (1.0 - t) * t * c1 + t * t * y1; - } else if (nits <= x2) { - // scale [x1, x2] to [y1, y2] using a curve - float t = (nits - x1) / (x2 - x1); - nits = (1.0 - t) * (1.0 - t) * y1 + 2.0 * (1.0 - t) * t * c2 + t * t * y2; - } else { - // scale [x2, x3] to [y2, y3] using a curve - float t = (nits - x2) / (x3 - x2); - nits = (1.0 - t) * (1.0 - t) * y2 + 2.0 * (1.0 - t) * t * c3 + t * t * y3; - } - - // color.y is greater than x0 and is thus non-zero - return color * (nits / color.y); - } - )__SHADER__"; - break; - } - - // convert absolute light to relative light. - switch (needs.getOutputTF()) { - case Key::OUTPUT_TF_ST2084: - fs << R"__SHADER__( - highp vec3 NormalizeLuminance(highp vec3 color) { - return color / 10000.0; - } - )__SHADER__"; - break; - case Key::OUTPUT_TF_HLG: - fs << R"__SHADER__( - highp vec3 NormalizeLuminance(highp vec3 color) { - return color / 1000.0 * pow(color.y / 1000.0, -0.2 / 1.2); - } - )__SHADER__"; - break; - default: - fs << R"__SHADER__( - highp vec3 NormalizeLuminance(highp vec3 color) { - return color / displayMaxLuminance; - } - )__SHADER__"; - break; - } -} - -// Generate OOTF that modifies the relative scence light to relative display light. -void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) { - if (!needs.needsToneMapping()) { - fs << R"__SHADER__( - highp vec3 OOTF(const highp vec3 color) { - return color; - } - )__SHADER__"; - } else { - generateToneMappingProcess(fs, needs); - fs << R"__SHADER__( - highp vec3 OOTF(const highp vec3 color) { - return NormalizeLuminance(ToneMap(ScaleLuminance(color))); - } - )__SHADER__"; - } -} - -// Generate OETF that converts relative display light to signal values, -// both normalized to [0, 1] -void ProgramCache::generateOETF(Formatter& fs, const Key& needs) { - switch (needs.getOutputTF()) { - case Key::OUTPUT_TF_SRGB: - fs << R"__SHADER__( - float OETF_sRGB(const float linear) { - return linear <= 0.0031308 ? - linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055; - } - - vec3 OETF_sRGB(const vec3 linear) { - return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b)); - } - - vec3 OETF(const vec3 linear) { - return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)); - } - )__SHADER__"; - break; - case Key::OUTPUT_TF_ST2084: - fs << R"__SHADER__( - vec3 OETF(const vec3 linear) { - const highp float m1 = (2610.0 / 4096.0) / 4.0; - const highp float m2 = (2523.0 / 4096.0) * 128.0; - const highp float c1 = (3424.0 / 4096.0); - const highp float c2 = (2413.0 / 4096.0) * 32.0; - const highp float c3 = (2392.0 / 4096.0) * 32.0; - - highp vec3 tmp = pow(linear, vec3(m1)); - tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp); - return pow(tmp, vec3(m2)); - } - )__SHADER__"; - break; - case Key::OUTPUT_TF_HLG: - fs << R"__SHADER__( - highp float OETF_channel(const highp float channel) { - const highp float a = 0.17883277; - const highp float b = 0.28466892; - const highp float c = 0.55991073; - return channel <= 1.0 / 12.0 ? sqrt(3.0 * channel) : - a * log(12.0 * channel - b) + c; - } - - vec3 OETF(const highp vec3 color) { - return vec3(OETF_channel(color.r), OETF_channel(color.g), - OETF_channel(color.b)); - } - )__SHADER__"; - break; - default: - fs << R"__SHADER__( - vec3 OETF(const vec3 linear) { - return linear; - } - )__SHADER__"; - break; - } -} - -String8 ProgramCache::generateVertexShader(const Key& needs) { - Formatter vs; - if (needs.hasTextureCoords()) { - vs << "attribute vec4 texCoords;" - << "varying vec2 outTexCoords;"; - } - if (needs.hasRoundedCorners()) { - vs << "attribute lowp vec4 cropCoords;"; - vs << "varying lowp vec2 outCropCoords;"; - } - if (needs.drawShadows()) { - vs << "attribute lowp vec4 shadowColor;"; - vs << "varying lowp vec4 outShadowColor;"; - vs << "attribute lowp vec4 shadowParams;"; - vs << "varying lowp vec3 outShadowParams;"; - } - vs << "attribute vec4 position;" - << "uniform mat4 projection;" - << "uniform mat4 texture;" - << "void main(void) {" << indent << "gl_Position = projection * position;"; - if (needs.hasTextureCoords()) { - vs << "outTexCoords = (texture * texCoords).st;"; - } - if (needs.hasRoundedCorners()) { - vs << "outCropCoords = cropCoords.st;"; - } - if (needs.drawShadows()) { - vs << "outShadowColor = shadowColor;"; - vs << "outShadowParams = shadowParams.xyz;"; - } - vs << dedent << "}"; - return vs.getString(); -} - -String8 ProgramCache::generateFragmentShader(const Key& needs) { - Formatter fs; - if (needs.getTextureTarget() == Key::TEXTURE_EXT) { - fs << "#extension GL_OES_EGL_image_external : require"; - } - - // default precision is required-ish in fragment shaders - fs << "precision mediump float;"; - - if (needs.getTextureTarget() == Key::TEXTURE_EXT) { - fs << "uniform samplerExternalOES sampler;"; - } else if (needs.getTextureTarget() == Key::TEXTURE_2D) { - fs << "uniform sampler2D sampler;"; - } - - if (needs.hasTextureCoords()) { - fs << "varying highp vec2 outTexCoords;"; - } - - if (needs.hasRoundedCorners()) { - // Rounded corners implementation using a signed distance function. - fs << R"__SHADER__( - uniform float cornerRadius; - uniform vec2 cropCenter; - varying vec2 outCropCoords; - - /** - * This function takes the current crop coordinates and calculates an alpha value based - * on the corner radius and distance from the crop center. - */ - float applyCornerRadius(vec2 cropCoords) - { - vec2 position = cropCoords - cropCenter; - // Scale down the dist vector here, as otherwise large corner - // radii can cause floating point issues when computing the norm - vec2 dist = (abs(position) - cropCenter + vec2(cornerRadius)) / 16.0; - // Once we've found the norm, then scale back up. - float plane = length(max(dist, vec2(0.0))) * 16.0; - return 1.0 - clamp(plane - cornerRadius, 0.0, 1.0); - } - )__SHADER__"; - } - - if (needs.drawShadows()) { - fs << R"__SHADER__( - varying lowp vec4 outShadowColor; - varying lowp vec3 outShadowParams; - - /** - * Returns the shadow color. - */ - vec4 getShadowColor() - { - lowp float d = length(outShadowParams.xy); - vec2 uv = vec2(outShadowParams.z * (1.0 - d), 0.5); - lowp float factor = texture2D(sampler, uv).a; - return outShadowColor * factor; - } - )__SHADER__"; - } - - if (needs.getTextureTarget() == Key::TEXTURE_OFF || needs.hasAlpha()) { - fs << "uniform vec4 color;"; - } - - if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF()) || - needs.hasDisplayColorMatrix()) { - if (needs.needsToneMapping()) { - fs << "uniform float displayMaxLuminance;"; - fs << "uniform float maxMasteringLuminance;"; - fs << "uniform float maxContentLuminance;"; - } - - if (needs.hasInputTransformMatrix()) { - fs << "uniform mat4 inputTransformMatrix;"; - fs << R"__SHADER__( - highp vec3 InputTransform(const highp vec3 color) { - return clamp(vec3(inputTransformMatrix * vec4(color, 1.0)), 0.0, 1.0); - } - )__SHADER__"; - } else { - fs << R"__SHADER__( - highp vec3 InputTransform(const highp vec3 color) { - return color; - } - )__SHADER__"; - } - - // the transformation from a wider colorspace to a narrower one can - // result in >1.0 or <0.0 pixel values - if (needs.hasOutputTransformMatrix()) { - fs << "uniform mat4 outputTransformMatrix;"; - fs << R"__SHADER__( - highp vec3 OutputTransform(const highp vec3 color) { - return clamp(vec3(outputTransformMatrix * vec4(color, 1.0)), 0.0, 1.0); - } - )__SHADER__"; - } else { - fs << R"__SHADER__( - highp vec3 OutputTransform(const highp vec3 color) { - return clamp(color, 0.0, 1.0); - } - )__SHADER__"; - } - - if (needs.hasDisplayColorMatrix()) { - fs << "uniform mat4 displayColorMatrix;"; - fs << R"__SHADER__( - highp vec3 DisplayColorMatrix(const highp vec3 color) { - return clamp(vec3(displayColorMatrix * vec4(color, 1.0)), 0.0, 1.0); - } - )__SHADER__"; - } else { - fs << R"__SHADER__( - highp vec3 DisplayColorMatrix(const highp vec3 color) { - return color; - } - )__SHADER__"; - } - - generateEOTF(fs, needs); - generateOOTF(fs, needs); - generateOETF(fs, needs); - } - - fs << "void main(void) {" << indent; - if (needs.drawShadows()) { - fs << "gl_FragColor = getShadowColor();"; - } else { - if (needs.isTexturing()) { - fs << "gl_FragColor = texture2D(sampler, outTexCoords);"; - } else { - fs << "gl_FragColor.rgb = color.rgb;"; - fs << "gl_FragColor.a = 1.0;"; - } - if (needs.isOpaque()) { - fs << "gl_FragColor.a = 1.0;"; - } - } - - if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF()) || - needs.hasDisplayColorMatrix()) { - if (!needs.isOpaque() && needs.isPremultiplied()) { - // un-premultiply if needed before linearization - // avoid divide by 0 by adding 0.5/256 to the alpha channel - fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);"; - } - fs << "gl_FragColor.rgb = " - "DisplayColorMatrix(OETF(OutputTransform(OOTF(InputTransform(EOTF(gl_FragColor.rgb)))" - ")));"; - - if (!needs.isOpaque() && needs.isPremultiplied()) { - // and re-premultiply if needed after gamma correction - fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);"; - } - } - - /* - * Whether applying layer alpha before or after color transform doesn't matter, - * as long as we can undo premultiplication. But we cannot un-premultiply - * for color transform if the layer alpha = 0, e.g. 0 / (0 + 0.0019) = 0. - */ - if (!needs.drawShadows()) { - if (needs.hasAlpha()) { - // modulate the current alpha value with alpha set - if (needs.isPremultiplied()) { - // ... and the color too if we're premultiplied - fs << "gl_FragColor *= color.a;"; - } else { - fs << "gl_FragColor.a *= color.a;"; - } - } - } - - if (needs.hasRoundedCorners()) { - if (needs.isPremultiplied()) { - fs << "gl_FragColor *= vec4(applyCornerRadius(outCropCoords));"; - } else { - fs << "gl_FragColor.a *= applyCornerRadius(outCropCoords);"; - } - } - - fs << dedent << "}"; - return fs.getString(); -} - -std::unique_ptr<Program> ProgramCache::generateProgram(const Key& needs) { - ATRACE_CALL(); - - // vertex shader - String8 vs = generateVertexShader(needs); - - // fragment shader - String8 fs = generateFragmentShader(needs); - - return std::make_unique<Program>(needs, vs.string(), fs.string()); -} - -void ProgramCache::useProgram(EGLContext context, const Description& description) { - // generate the key for the shader based on the description - Key needs(computeKey(description)); - - // look-up the program in the cache - auto& cache = mCaches[context]; - auto it = cache.find(needs); - if (it == cache.end()) { - // we didn't find our program, so generate one... - nsecs_t time = systemTime(); - it = cache.emplace(needs, generateProgram(needs)).first; - time = systemTime() - time; - - ALOGV(">>> generated new program for context %p: needs=%08X, time=%u ms (%zu programs)", - context, needs.mKey, uint32_t(ns2ms(time)), cache.size()); - } - - // here we have a suitable program for this description - std::unique_ptr<Program>& program = it->second; - if (program->isValid()) { - program->use(); - program->setUniforms(description); - } -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h deleted file mode 100644 index 83fef8e1db..0000000000 --- a/libs/renderengine/gl/ProgramCache.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright 2013 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_RENDER_ENGINE_PROGRAMCACHE_H -#define SF_RENDER_ENGINE_PROGRAMCACHE_H - -#include <memory> -#include <unordered_map> - -#include <EGL/egl.h> -#include <GLES2/gl2.h> -#include <renderengine/private/Description.h> -#include <utils/Singleton.h> -#include <utils/TypeHelpers.h> - -namespace android { - -class String8; - -namespace renderengine { - -struct Description; - -namespace gl { - -class Formatter; -class Program; - -/* - * This class generates GLSL programs suitable to handle a given - * Description. It's responsible for figuring out what to - * generate from a Description. - * It also maintains a cache of these Programs. - */ -class ProgramCache : public Singleton<ProgramCache> { -public: - /* - * Key is used to retrieve a Program in the cache. - * A Key is generated from a Description. - */ - class Key { - friend class ProgramCache; - typedef uint32_t key_t; - key_t mKey; - - public: - enum { - BLEND_SHIFT = 0, - BLEND_MASK = 1 << BLEND_SHIFT, - BLEND_PREMULT = 1 << BLEND_SHIFT, - BLEND_NORMAL = 0 << BLEND_SHIFT, - - OPACITY_SHIFT = 1, - OPACITY_MASK = 1 << OPACITY_SHIFT, - OPACITY_OPAQUE = 1 << OPACITY_SHIFT, - OPACITY_TRANSLUCENT = 0 << OPACITY_SHIFT, - - ALPHA_SHIFT = 2, - ALPHA_MASK = 1 << ALPHA_SHIFT, - ALPHA_LT_ONE = 1 << ALPHA_SHIFT, - ALPHA_EQ_ONE = 0 << ALPHA_SHIFT, - - TEXTURE_SHIFT = 3, - TEXTURE_MASK = 3 << TEXTURE_SHIFT, - TEXTURE_OFF = 0 << TEXTURE_SHIFT, - TEXTURE_EXT = 1 << TEXTURE_SHIFT, - TEXTURE_2D = 2 << TEXTURE_SHIFT, - - ROUNDED_CORNERS_SHIFT = 5, - ROUNDED_CORNERS_MASK = 1 << ROUNDED_CORNERS_SHIFT, - ROUNDED_CORNERS_OFF = 0 << ROUNDED_CORNERS_SHIFT, - ROUNDED_CORNERS_ON = 1 << ROUNDED_CORNERS_SHIFT, - - INPUT_TRANSFORM_MATRIX_SHIFT = 6, - INPUT_TRANSFORM_MATRIX_MASK = 1 << INPUT_TRANSFORM_MATRIX_SHIFT, - INPUT_TRANSFORM_MATRIX_OFF = 0 << INPUT_TRANSFORM_MATRIX_SHIFT, - INPUT_TRANSFORM_MATRIX_ON = 1 << INPUT_TRANSFORM_MATRIX_SHIFT, - - OUTPUT_TRANSFORM_MATRIX_SHIFT = 7, - OUTPUT_TRANSFORM_MATRIX_MASK = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT, - OUTPUT_TRANSFORM_MATRIX_OFF = 0 << OUTPUT_TRANSFORM_MATRIX_SHIFT, - OUTPUT_TRANSFORM_MATRIX_ON = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT, - - INPUT_TF_SHIFT = 8, - INPUT_TF_MASK = 3 << INPUT_TF_SHIFT, - INPUT_TF_LINEAR = 0 << INPUT_TF_SHIFT, - INPUT_TF_SRGB = 1 << INPUT_TF_SHIFT, - INPUT_TF_ST2084 = 2 << INPUT_TF_SHIFT, - INPUT_TF_HLG = 3 << INPUT_TF_SHIFT, - - OUTPUT_TF_SHIFT = 10, - OUTPUT_TF_MASK = 3 << OUTPUT_TF_SHIFT, - OUTPUT_TF_LINEAR = 0 << OUTPUT_TF_SHIFT, - OUTPUT_TF_SRGB = 1 << OUTPUT_TF_SHIFT, - OUTPUT_TF_ST2084 = 2 << OUTPUT_TF_SHIFT, - OUTPUT_TF_HLG = 3 << OUTPUT_TF_SHIFT, - - SHADOW_SHIFT = 13, - SHADOW_MASK = 1 << SHADOW_SHIFT, - SHADOW_OFF = 0 << SHADOW_SHIFT, - SHADOW_ON = 1 << SHADOW_SHIFT, - - DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT = 14, - DISPLAY_COLOR_TRANSFORM_MATRIX_MASK = 1 << DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT, - DISPLAY_COLOR_TRANSFORM_MATRIX_OFF = 0 << DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT, - DISPLAY_COLOR_TRANSFORM_MATRIX_ON = 1 << DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT, - }; - - inline Key() : mKey(0) {} - inline Key(const Key& rhs) : mKey(rhs.mKey) {} - - inline Key& set(key_t mask, key_t value) { - mKey = (mKey & ~mask) | value; - return *this; - } - - inline bool isTexturing() const { return (mKey & TEXTURE_MASK) != TEXTURE_OFF; } - inline bool hasTextureCoords() const { return isTexturing() && !drawShadows(); } - inline int getTextureTarget() const { return (mKey & TEXTURE_MASK); } - inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; } - inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; } - inline bool hasAlpha() const { return (mKey & ALPHA_MASK) == ALPHA_LT_ONE; } - inline bool hasRoundedCorners() const { - return (mKey & ROUNDED_CORNERS_MASK) == ROUNDED_CORNERS_ON; - } - inline bool drawShadows() const { return (mKey & SHADOW_MASK) == SHADOW_ON; } - inline bool hasInputTransformMatrix() const { - return (mKey & INPUT_TRANSFORM_MATRIX_MASK) == INPUT_TRANSFORM_MATRIX_ON; - } - inline bool hasOutputTransformMatrix() const { - return (mKey & OUTPUT_TRANSFORM_MATRIX_MASK) == OUTPUT_TRANSFORM_MATRIX_ON; - } - inline bool hasDisplayColorMatrix() const { - return (mKey & DISPLAY_COLOR_TRANSFORM_MATRIX_MASK) == - DISPLAY_COLOR_TRANSFORM_MATRIX_ON; - } - inline bool hasTransformMatrix() const { - return hasInputTransformMatrix() || hasOutputTransformMatrix(); - } - inline int getInputTF() const { return (mKey & INPUT_TF_MASK); } - inline int getOutputTF() const { return (mKey & OUTPUT_TF_MASK); } - - // When HDR and non-HDR contents are mixed, or different types of HDR contents are - // mixed, we will do a tone mapping process to tone map the input content to output - // content. Currently, the following conversions handled, they are: - // * SDR -> HLG - // * SDR -> PQ - // * HLG -> PQ - inline bool needsToneMapping() const { - int inputTF = getInputTF(); - int outputTF = getOutputTF(); - - // Return false when converting from SDR to SDR. - if (inputTF == Key::INPUT_TF_SRGB && outputTF == Key::OUTPUT_TF_LINEAR) { - return false; - } - if (inputTF == Key::INPUT_TF_LINEAR && outputTF == Key::OUTPUT_TF_SRGB) { - return false; - } - - inputTF >>= Key::INPUT_TF_SHIFT; - outputTF >>= Key::OUTPUT_TF_SHIFT; - return inputTF != outputTF; - } - - // for use by std::unordered_map - - bool operator==(const Key& other) const { return mKey == other.mKey; } - - struct Hash { - size_t operator()(const Key& key) const { return static_cast<size_t>(key.mKey); } - }; - }; - - ProgramCache() = default; - ~ProgramCache() = default; - - // Generate shaders to populate the cache - void primeCache(const EGLContext context, bool toneMapperShaderOnly); - - size_t getSize(const EGLContext context) { return mCaches[context].size(); } - - // useProgram lookup a suitable program in the cache or generates one - // if none can be found. - void useProgram(const EGLContext context, const Description& description); - - void purgeCaches() { mCaches.clear(); } - -private: - // compute a cache Key from a Description - static Key computeKey(const Description& description); - // Generate EOTF based from Key. - static void generateEOTF(Formatter& fs, const Key& needs); - // Generate necessary tone mapping methods for OOTF. - static void generateToneMappingProcess(Formatter& fs, const Key& needs); - // Generate OOTF based from Key. - static void generateOOTF(Formatter& fs, const Key& needs); - // Generate OETF based from Key. - static void generateOETF(Formatter& fs, const Key& needs); - // generates a program from the Key - static std::unique_ptr<Program> generateProgram(const Key& needs); - // generates the vertex shader from the Key - static String8 generateVertexShader(const Key& needs); - // generates the fragment shader from the Key - static String8 generateFragmentShader(const Key& needs); - - // Key/Value map used for caching Programs. Currently the cache - // is never shrunk (and the GL program objects are never deleted). - std::unordered_map<EGLContext, std::unordered_map<Key, std::unique_ptr<Program>, Key::Hash>> - mCaches; -}; - -} // namespace gl -} // namespace renderengine - -ANDROID_BASIC_TYPES_TRAITS(renderengine::gl::ProgramCache::Key) - -} // namespace android - -#endif /* SF_RENDER_ENGINE_PROGRAMCACHE_H */ diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp deleted file mode 100644 index 3455e08cfe..0000000000 --- a/libs/renderengine/gl/filters/BlurFilter.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright 2019 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 ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "BlurFilter.h" -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES3/gl3.h> -#include <GLES3/gl3ext.h> -#include <ui/GraphicTypes.h> -#include <cstdint> - -#include <utils/Trace.h> - -namespace android { -namespace renderengine { -namespace gl { - -BlurFilter::BlurFilter(GLESRenderEngine& engine) - : mEngine(engine), - mCompositionFbo(engine), - mPingFbo(engine), - mPongFbo(engine), - mMixProgram(engine), - mBlurProgram(engine) { - mMixProgram.compile(getVertexShader(), getMixFragShader()); - mMPosLoc = mMixProgram.getAttributeLocation("aPosition"); - mMUvLoc = mMixProgram.getAttributeLocation("aUV"); - mMTextureLoc = mMixProgram.getUniformLocation("uTexture"); - mMCompositionTextureLoc = mMixProgram.getUniformLocation("uCompositionTexture"); - mMMixLoc = mMixProgram.getUniformLocation("uMix"); - - mBlurProgram.compile(getVertexShader(), getFragmentShader()); - mBPosLoc = mBlurProgram.getAttributeLocation("aPosition"); - mBUvLoc = mBlurProgram.getAttributeLocation("aUV"); - mBTextureLoc = mBlurProgram.getUniformLocation("uTexture"); - mBOffsetLoc = mBlurProgram.getUniformLocation("uOffset"); - - static constexpr auto size = 2.0f; - static constexpr auto translation = 1.0f; - const GLfloat vboData[] = { - // Vertex data - translation - size, -translation - size, - translation - size, -translation + size, - translation + size, -translation + size, - // UV data - 0.0f, 0.0f - translation, - 0.0f, size - translation, - size, size - translation - }; - mMeshBuffer.allocateBuffers(vboData, 12 /* size */); -} - -status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t radius) { - ATRACE_NAME("BlurFilter::setAsDrawTarget"); - mRadius = radius; - mDisplayX = display.physicalDisplay.left; - mDisplayY = display.physicalDisplay.top; - - if (mDisplayWidth < display.physicalDisplay.width() || - mDisplayHeight < display.physicalDisplay.height()) { - ATRACE_NAME("BlurFilter::allocatingTextures"); - - mDisplayWidth = display.physicalDisplay.width(); - mDisplayHeight = display.physicalDisplay.height(); - mCompositionFbo.allocateBuffers(mDisplayWidth, mDisplayHeight); - - const uint32_t fboWidth = floorf(mDisplayWidth * kFboScale); - const uint32_t fboHeight = floorf(mDisplayHeight * kFboScale); - mPingFbo.allocateBuffers(fboWidth, fboHeight); - mPongFbo.allocateBuffers(fboWidth, fboHeight); - - if (mPingFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Invalid ping buffer"); - return mPingFbo.getStatus(); - } - if (mPongFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Invalid pong buffer"); - return mPongFbo.getStatus(); - } - if (mCompositionFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Invalid composition buffer"); - return mCompositionFbo.getStatus(); - } - if (!mBlurProgram.isValid()) { - ALOGE("Invalid shader"); - return GL_INVALID_OPERATION; - } - } - - mCompositionFbo.bind(); - glViewport(0, 0, mCompositionFbo.getBufferWidth(), mCompositionFbo.getBufferHeight()); - return NO_ERROR; -} - -void BlurFilter::drawMesh(GLuint uv, GLuint position) { - - glEnableVertexAttribArray(uv); - glEnableVertexAttribArray(position); - mMeshBuffer.bind(); - glVertexAttribPointer(position, 2 /* size */, GL_FLOAT, GL_FALSE, - 2 * sizeof(GLfloat) /* stride */, 0 /* offset */); - glVertexAttribPointer(uv, 2 /* size */, GL_FLOAT, GL_FALSE, 0 /* stride */, - (GLvoid*)(6 * sizeof(GLfloat)) /* offset */); - mMeshBuffer.unbind(); - - // draw mesh - glDrawArrays(GL_TRIANGLES, 0 /* first */, 3 /* count */); -} - -status_t BlurFilter::prepare() { - ATRACE_NAME("BlurFilter::prepare"); - - // Kawase is an approximation of Gaussian, but it behaves differently from it. - // A radius transformation is required for approximating them, and also to introduce - // non-integer steps, necessary to smoothly interpolate large radii. - const auto radius = mRadius / 6.0f; - - // Calculate how many passes we'll do, based on the radius. - // Too many passes will make the operation expensive. - const auto passes = min(kMaxPasses, (uint32_t)ceil(radius)); - - const float radiusByPasses = radius / (float)passes; - const float stepX = radiusByPasses / (float)mCompositionFbo.getBufferWidth(); - const float stepY = radiusByPasses / (float)mCompositionFbo.getBufferHeight(); - - // Let's start by downsampling and blurring the composited frame simultaneously. - mBlurProgram.useProgram(); - glActiveTexture(GL_TEXTURE0); - glUniform1i(mBTextureLoc, 0); - glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName()); - glUniform2f(mBOffsetLoc, stepX, stepY); - glViewport(0, 0, mPingFbo.getBufferWidth(), mPingFbo.getBufferHeight()); - mPingFbo.bind(); - drawMesh(mBUvLoc, mBPosLoc); - - // And now we'll ping pong between our textures, to accumulate the result of various offsets. - GLFramebuffer* read = &mPingFbo; - GLFramebuffer* draw = &mPongFbo; - glViewport(0, 0, draw->getBufferWidth(), draw->getBufferHeight()); - for (auto i = 1; i < passes; i++) { - ATRACE_NAME("BlurFilter::renderPass"); - draw->bind(); - - glBindTexture(GL_TEXTURE_2D, read->getTextureName()); - glUniform2f(mBOffsetLoc, stepX * i, stepY * i); - - drawMesh(mBUvLoc, mBPosLoc); - - // Swap buffers for next iteration - auto tmp = draw; - draw = read; - read = tmp; - } - mLastDrawTarget = read; - - return NO_ERROR; -} - -status_t BlurFilter::render(bool multiPass) { - ATRACE_NAME("BlurFilter::render"); - - // Now let's scale our blur up. It will be interpolated with the larger composited - // texture for the first frames, to hide downscaling artifacts. - GLfloat mix = fmin(1.0, mRadius / kMaxCrossFadeRadius); - - // When doing multiple passes, we cannot try to read mCompositionFbo, given that we'll - // be writing onto it. Let's disable the crossfade, otherwise we'd need 1 extra frame buffer, - // as large as the screen size. - if (mix >= 1 || multiPass) { - mLastDrawTarget->bindAsReadBuffer(); - glBlitFramebuffer(0, 0, mLastDrawTarget->getBufferWidth(), - mLastDrawTarget->getBufferHeight(), mDisplayX, mDisplayY, mDisplayWidth, - mDisplayHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); - return NO_ERROR; - } - - mMixProgram.useProgram(); - glUniform1f(mMMixLoc, mix); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, mLastDrawTarget->getTextureName()); - glUniform1i(mMTextureLoc, 0); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName()); - glUniform1i(mMCompositionTextureLoc, 1); - - drawMesh(mMUvLoc, mMPosLoc); - - glUseProgram(0); - glActiveTexture(GL_TEXTURE0); - mEngine.checkErrors("Drawing blur mesh"); - return NO_ERROR; -} - -string BlurFilter::getVertexShader() const { - return R"SHADER(#version 300 es - precision mediump float; - - in vec2 aPosition; - in highp vec2 aUV; - out highp vec2 vUV; - - void main() { - vUV = aUV; - gl_Position = vec4(aPosition, 0.0, 1.0); - } - )SHADER"; -} - -string BlurFilter::getFragmentShader() const { - return R"SHADER(#version 300 es - precision mediump float; - - uniform sampler2D uTexture; - uniform vec2 uOffset; - - in highp vec2 vUV; - out vec4 fragColor; - - void main() { - fragColor = texture(uTexture, vUV, 0.0); - fragColor += texture(uTexture, vUV + vec2( uOffset.x, uOffset.y), 0.0); - fragColor += texture(uTexture, vUV + vec2( uOffset.x, -uOffset.y), 0.0); - fragColor += texture(uTexture, vUV + vec2(-uOffset.x, uOffset.y), 0.0); - fragColor += texture(uTexture, vUV + vec2(-uOffset.x, -uOffset.y), 0.0); - - fragColor = vec4(fragColor.rgb * 0.2, 1.0); - } - )SHADER"; -} - -string BlurFilter::getMixFragShader() const { - string shader = R"SHADER(#version 300 es - precision mediump float; - - in highp vec2 vUV; - out vec4 fragColor; - - uniform sampler2D uCompositionTexture; - uniform sampler2D uTexture; - uniform float uMix; - - void main() { - vec4 blurred = texture(uTexture, vUV); - vec4 composition = texture(uCompositionTexture, vUV); - fragColor = mix(composition, blurred, uMix); - } - )SHADER"; - return shader; -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h deleted file mode 100644 index 593a8fd54e..0000000000 --- a/libs/renderengine/gl/filters/BlurFilter.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2019 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 <ui/GraphicTypes.h> -#include "../GLESRenderEngine.h" -#include "../GLFramebuffer.h" -#include "../GLVertexBuffer.h" -#include "GenericProgram.h" - -using namespace std; - -namespace android { -namespace renderengine { -namespace gl { - -/** - * This is an implementation of a Kawase blur, as described in here: - * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/ - * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf - */ -class BlurFilter { -public: - // Downsample FBO to improve performance - static constexpr float kFboScale = 0.25f; - // Maximum number of render passes - static constexpr uint32_t kMaxPasses = 4; - // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited - // image, up to this radius. - static constexpr float kMaxCrossFadeRadius = 30.0f; - - explicit BlurFilter(GLESRenderEngine& engine); - virtual ~BlurFilter(){}; - - // Set up render targets, redirecting output to offscreen texture. - status_t setAsDrawTarget(const DisplaySettings&, uint32_t radius); - // Execute blur passes, rendering to offscreen texture. - status_t prepare(); - // Render blur to the bound framebuffer (screen). - status_t render(bool multiPass); - -private: - uint32_t mRadius; - void drawMesh(GLuint uv, GLuint position); - string getVertexShader() const; - string getFragmentShader() const; - string getMixFragShader() const; - - GLESRenderEngine& mEngine; - // Frame buffer holding the composited background. - GLFramebuffer mCompositionFbo; - // Frame buffers holding the blur passes. - GLFramebuffer mPingFbo; - GLFramebuffer mPongFbo; - uint32_t mDisplayWidth = 0; - uint32_t mDisplayHeight = 0; - uint32_t mDisplayX = 0; - uint32_t mDisplayY = 0; - // Buffer holding the final blur pass. - GLFramebuffer* mLastDrawTarget; - - // VBO containing vertex and uv data of a fullscreen triangle. - GLVertexBuffer mMeshBuffer; - - GenericProgram mMixProgram; - GLuint mMPosLoc; - GLuint mMUvLoc; - GLuint mMMixLoc; - GLuint mMTextureLoc; - GLuint mMCompositionTextureLoc; - - GenericProgram mBlurProgram; - GLuint mBPosLoc; - GLuint mBUvLoc; - GLuint mBTextureLoc; - GLuint mBOffsetLoc; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/filters/GenericProgram.cpp b/libs/renderengine/gl/filters/GenericProgram.cpp deleted file mode 100644 index bb35889665..0000000000 --- a/libs/renderengine/gl/filters/GenericProgram.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2019 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 "GenericProgram.h" - -#include <GLES/gl.h> -#include <GLES/glext.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> - -namespace android { -namespace renderengine { -namespace gl { - -GenericProgram::GenericProgram(GLESRenderEngine& engine) : mEngine(engine) {} - -GenericProgram::~GenericProgram() { - if (mVertexShaderHandle != 0) { - if (mProgramHandle != 0) { - glDetachShader(mProgramHandle, mVertexShaderHandle); - } - glDeleteShader(mVertexShaderHandle); - } - - if (mFragmentShaderHandle != 0) { - if (mProgramHandle != 0) { - glDetachShader(mProgramHandle, mFragmentShaderHandle); - } - glDeleteShader(mFragmentShaderHandle); - } - - if (mProgramHandle != 0) { - glDeleteProgram(mProgramHandle); - } -} - -void GenericProgram::compile(string vertexShader, string fragmentShader) { - mVertexShaderHandle = compileShader(GL_VERTEX_SHADER, vertexShader); - mFragmentShaderHandle = compileShader(GL_FRAGMENT_SHADER, fragmentShader); - if (mVertexShaderHandle == 0 || mFragmentShaderHandle == 0) { - ALOGE("Aborting program creation."); - return; - } - mProgramHandle = createAndLink(mVertexShaderHandle, mFragmentShaderHandle); - mEngine.checkErrors("Linking program"); -} - -void GenericProgram::useProgram() const { - glUseProgram(mProgramHandle); -} - -GLuint GenericProgram::compileShader(GLuint type, string src) const { - const GLuint shader = glCreateShader(type); - if (shader == 0) { - mEngine.checkErrors("Creating shader"); - return 0; - } - const GLchar* charSrc = (const GLchar*)src.c_str(); - glShaderSource(shader, 1, &charSrc, nullptr); - glCompileShader(shader); - - GLint isCompiled = 0; - glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled); - if (isCompiled == GL_FALSE) { - GLint maxLength = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); - string errorLog; - errorLog.reserve(maxLength); - glGetShaderInfoLog(shader, maxLength, &maxLength, errorLog.data()); - glDeleteShader(shader); - ALOGE("Error compiling shader: %s", errorLog.c_str()); - return 0; - } - return shader; -} -GLuint GenericProgram::createAndLink(GLuint vertexShader, GLuint fragmentShader) const { - const GLuint program = glCreateProgram(); - mEngine.checkErrors("Creating program"); - - glAttachShader(program, vertexShader); - glAttachShader(program, fragmentShader); - glLinkProgram(program); - mEngine.checkErrors("Linking program"); - return program; -} - -GLuint GenericProgram::getUniformLocation(const string name) const { - if (mProgramHandle == 0) { - ALOGE("Can't get location of %s on an invalid program.", name.c_str()); - return -1; - } - return glGetUniformLocation(mProgramHandle, (const GLchar*)name.c_str()); -} - -GLuint GenericProgram::getAttributeLocation(const string name) const { - if (mProgramHandle == 0) { - ALOGE("Can't get location of %s on an invalid program.", name.c_str()); - return -1; - } - return glGetAttribLocation(mProgramHandle, (const GLchar*)name.c_str()); -} - -bool GenericProgram::isValid() const { - return mProgramHandle != 0; -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/filters/GenericProgram.h b/libs/renderengine/gl/filters/GenericProgram.h deleted file mode 100644 index 6da2a5af58..0000000000 --- a/libs/renderengine/gl/filters/GenericProgram.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2019 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 <ui/GraphicTypes.h> -#include "../GLESRenderEngine.h" -#include "../GLFramebuffer.h" - -using namespace std; - -namespace android { -namespace renderengine { -namespace gl { - -class GenericProgram { -public: - explicit GenericProgram(GLESRenderEngine& renderEngine); - ~GenericProgram(); - void compile(string vertexShader, string fragmentShader); - bool isValid() const; - void useProgram() const; - GLuint getAttributeLocation(const string name) const; - GLuint getUniformLocation(const string name) const; - -private: - GLuint compileShader(GLuint type, const string src) const; - GLuint createAndLink(GLuint vertexShader, GLuint fragmentShader) const; - - GLESRenderEngine& mEngine; - GLuint mVertexShaderHandle = 0; - GLuint mFragmentShaderHandle = 0; - GLuint mProgramHandle = 0; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/include/renderengine/Framebuffer.h b/libs/renderengine/include/renderengine/Framebuffer.h deleted file mode 100644 index 65111278e0..0000000000 --- a/libs/renderengine/include/renderengine/Framebuffer.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 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 <cstdint> - -struct ANativeWindowBuffer; - -namespace android { -namespace renderengine { - -class Framebuffer { -public: - virtual ~Framebuffer() = default; - - virtual bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected, - const bool useFramebufferCache) = 0; -}; - -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/include/renderengine/Image.h b/libs/renderengine/include/renderengine/Image.h deleted file mode 100644 index 3bb47318ef..0000000000 --- a/libs/renderengine/include/renderengine/Image.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2017 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 - -struct ANativeWindowBuffer; - -namespace android { -namespace renderengine { - -class Image { -public: - virtual ~Image() = default; - virtual bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) = 0; -}; - -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/include/renderengine/Mesh.h b/libs/renderengine/include/renderengine/Mesh.h deleted file mode 100644 index 167f13f1bc..0000000000 --- a/libs/renderengine/include/renderengine/Mesh.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2013 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_RENDER_ENGINE_MESH_H -#define SF_RENDER_ENGINE_MESH_H - -#include <vector> - -#include <stdint.h> - -namespace android { -namespace renderengine { - -class Mesh { -public: - class Builder; - - enum Primitive { - TRIANGLES = 0x0004, // GL_TRIANGLES - TRIANGLE_STRIP = 0x0005, // GL_TRIANGLE_STRIP - TRIANGLE_FAN = 0x0006 // GL_TRIANGLE_FAN - }; - - ~Mesh() = default; - - /* - * VertexArray handles the stride automatically. - */ - template <typename TYPE> - class VertexArray { - friend class Mesh; - float* mData; - size_t mStride; - size_t mOffset = 0; - VertexArray(float* data, size_t stride) : mData(data), mStride(stride) {} - - public: - // Returns a vertex array at an offset so its easier to append attributes from - // multiple sources. - VertexArray(VertexArray<TYPE>& other, size_t offset) - : mData(other.mData), mStride(other.mStride), mOffset(offset) {} - - TYPE& operator[](size_t index) { - return *reinterpret_cast<TYPE*>(&mData[(index + mOffset) * mStride]); - } - TYPE const& operator[](size_t index) const { - return *reinterpret_cast<TYPE const*>(&mData[(index + mOffset) * mStride]); - } - }; - - template <typename TYPE> - VertexArray<TYPE> getPositionArray() { - return VertexArray<TYPE>(getPositions(), mStride); - } - - template <typename TYPE> - VertexArray<TYPE> getTexCoordArray() { - return VertexArray<TYPE>(getTexCoords(), mStride); - } - - template <typename TYPE> - VertexArray<TYPE> getCropCoordArray() { - return VertexArray<TYPE>(getCropCoords(), mStride); - } - - template <typename TYPE> - VertexArray<TYPE> getShadowColorArray() { - return VertexArray<TYPE>(getShadowColor(), mStride); - } - - template <typename TYPE> - VertexArray<TYPE> getShadowParamsArray() { - return VertexArray<TYPE>(getShadowParams(), mStride); - } - - uint16_t* getIndicesArray() { return getIndices(); } - - Primitive getPrimitive() const; - - // returns a pointer to the vertices positions - float const* getPositions() const; - - // returns a pointer to the vertices texture coordinates - float const* getTexCoords() const; - - // returns a pointer to the vertices crop coordinates - float const* getCropCoords() const; - - // returns a pointer to colors - float const* getShadowColor() const; - - // returns a pointer to the shadow params - float const* getShadowParams() const; - - // returns a pointer to indices - uint16_t const* getIndices() const; - - // number of vertices in this mesh - size_t getVertexCount() const; - - // dimension of vertices - size_t getVertexSize() const; - - // dimension of texture coordinates - size_t getTexCoordsSize() const; - - size_t getShadowParamsSize() const; - - size_t getShadowColorSize() const; - - size_t getIndexCount() const; - - // return stride in bytes - size_t getByteStride() const; - - // return stride in floats - size_t getStride() const; - -private: - Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize, - size_t cropCoordsSize, size_t shadowColorSize, size_t shadowParamsSize, size_t indexCount); - Mesh(const Mesh&); - Mesh& operator=(const Mesh&); - Mesh const& operator=(const Mesh&) const; - - float* getPositions(); - float* getTexCoords(); - float* getCropCoords(); - float* getShadowColor(); - float* getShadowParams(); - uint16_t* getIndices(); - - std::vector<float> mVertices; - size_t mVertexCount; - size_t mVertexSize; - size_t mTexCoordsSize; - size_t mCropCoordsSize; - size_t mShadowColorSize; - size_t mShadowParamsSize; - size_t mStride; - Primitive mPrimitive; - std::vector<uint16_t> mIndices; - size_t mIndexCount; -}; - -class Mesh::Builder { -public: - Builder& setPrimitive(Primitive primitive) { - mPrimitive = primitive; - return *this; - }; - Builder& setVertices(size_t vertexCount, size_t vertexSize) { - mVertexCount = vertexCount; - mVertexSize = vertexSize; - return *this; - }; - Builder& setTexCoords(size_t texCoordsSize) { - mTexCoordsSize = texCoordsSize; - return *this; - }; - Builder& setCropCoords(size_t cropCoordsSize) { - mCropCoordsSize = cropCoordsSize; - return *this; - }; - Builder& setShadowAttrs() { - mShadowParamsSize = 3; - mShadowColorSize = 4; - return *this; - }; - Builder& setIndices(size_t indexCount) { - mIndexCount = indexCount; - return *this; - }; - Mesh build() const { - return Mesh{mPrimitive, mVertexCount, mVertexSize, mTexCoordsSize, - mCropCoordsSize, mShadowColorSize, mShadowParamsSize, mIndexCount}; - } - -private: - size_t mVertexCount = 0; - size_t mVertexSize = 0; - size_t mTexCoordsSize = 0; - size_t mCropCoordsSize = 0; - size_t mShadowColorSize = 0; - size_t mShadowParamsSize = 0; - size_t mIndexCount = 0; - Primitive mPrimitive; -}; - -} // namespace renderengine -} // namespace android -#endif /* SF_RENDER_ENGINE_MESH_H */ diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 83af252740..72a6075ff1 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -22,8 +22,6 @@ #include <math/mat4.h> #include <renderengine/DisplaySettings.h> #include <renderengine/ExternalTexture.h> -#include <renderengine/Framebuffer.h> -#include <renderengine/Image.h> #include <renderengine/LayerSettings.h> #include <stdint.h> #include <sys/types.h> @@ -95,8 +93,6 @@ public: }; enum class RenderEngineType { - GLES = 1, - THREADED = 2, SKIA_GL = 3, SKIA_GL_THREADED = 4, SKIA_VK = 5, @@ -171,8 +167,6 @@ public: // being drawn, then the implementation is free to silently ignore this call. virtual void cleanupPostRender() = 0; - virtual void cleanFramebufferCache() = 0; - // Returns the priority this context was actually created with. Note: this // may not be the same as specified at context creation time, due to // implementation limits on the number of contexts that can be created at a @@ -204,7 +198,7 @@ public: virtual void setEnableTracing(bool /*tracingEnabled*/) {} protected: - RenderEngine() : RenderEngine(RenderEngineType::GLES) {} + RenderEngine() : RenderEngine(RenderEngineType::SKIA_GL) {} RenderEngine(RenderEngineType type) : mRenderEngineType(type) {} diff --git a/libs/renderengine/include/renderengine/Texture.h b/libs/renderengine/include/renderengine/Texture.h deleted file mode 100644 index c69ace0603..0000000000 --- a/libs/renderengine/include/renderengine/Texture.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2013 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_RENDER_ENGINE_TEXTURE_H -#define SF_RENDER_ENGINE_TEXTURE_H - -#include <stdint.h> - -#include <math/mat4.h> - -namespace android { -namespace renderengine { - -class Texture { -public: - enum Target { TEXTURE_2D = 0x0DE1, TEXTURE_EXTERNAL = 0x8D65 }; - - Texture(); - Texture(Target textureTarget, uint32_t textureName); - ~Texture(); - - void init(Target textureTarget, uint32_t textureName); - - void setMatrix(float const* matrix); - void setFiltering(bool enabled); - void setDimensions(size_t width, size_t height); - - uint32_t getTextureName() const; - uint32_t getTextureTarget() const; - - const mat4& getMatrix() const; - bool getFiltering() const; - size_t getWidth() const; - size_t getHeight() const; - -private: - uint32_t mTextureName; - uint32_t mTextureTarget; - size_t mWidth; - size_t mHeight; - bool mFiltering; - mat4 mTextureMatrix; -}; - -} // namespace renderengine -} // namespace android -#endif /* SF_RENDER_ENGINE_TEXTURE_H */ diff --git a/libs/renderengine/include/renderengine/mock/Framebuffer.h b/libs/renderengine/include/renderengine/mock/Framebuffer.h deleted file mode 100644 index dfb6a4e41e..0000000000 --- a/libs/renderengine/include/renderengine/mock/Framebuffer.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 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 <gmock/gmock.h> -#include <renderengine/Framebuffer.h> - -namespace android { -namespace renderengine { -namespace mock { - -class Framebuffer : public renderengine::Framebuffer { -public: - Framebuffer(); - ~Framebuffer() override; - - MOCK_METHOD3(setNativeWindowBuffer, bool(ANativeWindowBuffer*, bool, const bool)); -}; - -} // namespace mock -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/include/renderengine/mock/Image.h b/libs/renderengine/include/renderengine/mock/Image.h deleted file mode 100644 index 2b0eed1173..0000000000 --- a/libs/renderengine/include/renderengine/mock/Image.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 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 <gmock/gmock.h> -#include <renderengine/Image.h> - -namespace android { -namespace renderengine { -namespace mock { - -class Image : public renderengine::Image { -public: - Image(); - ~Image() override; - - MOCK_METHOD2(setNativeWindowBuffer, bool(ANativeWindowBuffer* buffer, bool isProtected)); -}; - -} // namespace mock -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index d3035e24a5..571b52b787 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -19,9 +19,7 @@ #include <gmock/gmock.h> #include <renderengine/DisplaySettings.h> #include <renderengine/LayerSettings.h> -#include <renderengine/Mesh.h> #include <renderengine/RenderEngine.h> -#include <renderengine/Texture.h> #include <ui/Fence.h> #include <ui/GraphicBuffer.h> #include <ui/Region.h> diff --git a/libs/renderengine/include/renderengine/private/Description.h b/libs/renderengine/include/renderengine/private/Description.h deleted file mode 100644 index 2873ad7148..0000000000 --- a/libs/renderengine/include/renderengine/private/Description.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2013 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_RENDER_ENGINE_DESCRIPTION_H_ -#define SF_RENDER_ENGINE_DESCRIPTION_H_ - -#include <renderengine/Texture.h> -#include <ui/GraphicTypes.h> - -namespace android { -namespace renderengine { - -/* - * This is the structure that holds the state of the rendering engine. - * This class is used to generate a corresponding GLSL program and set the - * appropriate uniform. - */ -struct Description { - enum class TransferFunction : int { - LINEAR, - SRGB, - ST2084, - HLG, // Hybrid Log-Gamma for HDR. - }; - - static TransferFunction dataSpaceToTransferFunction(ui::Dataspace dataSpace); - - Description() = default; - ~Description() = default; - - bool hasInputTransformMatrix() const; - bool hasOutputTransformMatrix() const; - bool hasColorMatrix() const; - bool hasDisplayColorMatrix() const; - - // whether textures are premultiplied - bool isPremultipliedAlpha = false; - // whether this layer is marked as opaque - bool isOpaque = true; - - // corner radius of the layer - float cornerRadius = 0; - - // Size of the rounded rectangle we are cropping to - half2 cropSize; - - // Texture this layer uses - Texture texture; - bool textureEnabled = false; - - // color used when texturing is disabled or when setting alpha. - half4 color; - - // transfer functions for the input/output - TransferFunction inputTransferFunction = TransferFunction::LINEAR; - TransferFunction outputTransferFunction = TransferFunction::LINEAR; - - float displayMaxLuminance; - float maxMasteringLuminance; - float maxContentLuminance; - - // projection matrix - mat4 projectionMatrix; - - // The color matrix will be applied in linear space right before OETF. - mat4 colorMatrix; - // The display color matrix will be applied in gamma space after OETF - mat4 displayColorMatrix; - mat4 inputTransformMatrix; - mat4 outputTransformMatrix; - - // True if this layer will draw a shadow. - bool drawShadows = false; -}; - -} // namespace renderengine -} // namespace android - -#endif /* SF_RENDER_ENGINE_DESCRIPTION_H_ */ diff --git a/libs/renderengine/mock/Framebuffer.cpp b/libs/renderengine/mock/Framebuffer.cpp deleted file mode 100644 index fbdcaab697..0000000000 --- a/libs/renderengine/mock/Framebuffer.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 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 <renderengine/mock/Framebuffer.h> - -namespace android { -namespace renderengine { -namespace mock { - -// The Google Mock documentation recommends explicit non-header instantiations -// for better compile time performance. -Framebuffer::Framebuffer() = default; -Framebuffer::~Framebuffer() = default; - -} // namespace mock -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/mock/Image.cpp b/libs/renderengine/mock/Image.cpp deleted file mode 100644 index 57f4346f8f..0000000000 --- a/libs/renderengine/mock/Image.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 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 <renderengine/mock/Image.h> - -namespace android { -namespace renderengine { -namespace mock { - -// The Google Mock documentation recommends explicit non-header instantiations -// for better compile time performance. -Image::Image() = default; -Image::~Image() = default; - -} // namespace mock -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLExtensions.cpp b/libs/renderengine/skia/GLExtensions.cpp index 3dd534e602..32da303a92 100644 --- a/libs/renderengine/gl/GLExtensions.cpp +++ b/libs/renderengine/skia/GLExtensions.cpp @@ -23,11 +23,11 @@ #include <stdio.h> #include <stdlib.h> -ANDROID_SINGLETON_STATIC_INSTANCE(android::renderengine::gl::GLExtensions) +ANDROID_SINGLETON_STATIC_INSTANCE(android::renderengine::skia::GLExtensions) namespace android { namespace renderengine { -namespace gl { +namespace skia { namespace { @@ -134,6 +134,6 @@ char const* GLExtensions::getEGLExtensions() const { return mEGLExtensions.string(); } -} // namespace gl +} // namespace skia } // namespace renderengine } // namespace android diff --git a/libs/renderengine/gl/GLExtensions.h b/libs/renderengine/skia/GLExtensions.h index e415ff304a..0cb1bda0df 100644 --- a/libs/renderengine/gl/GLExtensions.h +++ b/libs/renderengine/skia/GLExtensions.h @@ -29,7 +29,7 @@ namespace android { namespace renderengine { -namespace gl { +namespace skia { class GLExtensions : public Singleton<GLExtensions> { public: @@ -81,7 +81,7 @@ private: GLExtensions& operator=(const GLExtensions&); }; -} // namespace gl +} // namespace skia } // namespace renderengine } // namespace android diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 92181d87c8..e253ad596e 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -36,17 +36,26 @@ #include <memory> #include <numeric> -#include "../gl/GLExtensions.h" +#include "GLExtensions.h" #include "log/log_main.h" -bool checkGlError(const char* op, int lineNumber); - namespace android { namespace renderengine { namespace skia { using base::StringAppendF; +static bool checkGlError(const char* op, int lineNumber) { + bool errorFound = false; + GLint error = glGetError(); + while (error != GL_NO_ERROR) { + errorFound = true; + error = glGetError(); + ALOGV("after %s() (line # %d) glError (0x%x)\n", op, lineNumber, error); + } + return errorFound; +} + static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute, EGLint wanted, EGLConfig* outConfig) { EGLint numConfigs = -1, n = 0; @@ -149,7 +158,7 @@ std::unique_ptr<SkiaGLRenderEngine> SkiaGLRenderEngine::create( LOG_ALWAYS_FATAL("eglQueryString(EGL_EXTENSIONS) failed"); } - auto& extensions = gl::GLExtensions::getInstance(); + auto& extensions = GLExtensions::getInstance(); extensions.initWithEGLStrings(eglVersion, eglExtensions); // The code assumes that ES2 or later is available if this extension is @@ -342,8 +351,8 @@ base::unique_fd SkiaGLRenderEngine::flushAndSubmit(GrDirectContext* grContext) { } bool SkiaGLRenderEngine::waitGpuFence(base::borrowed_fd fenceFd) { - if (!gl::GLExtensions::getInstance().hasNativeFenceSync() || - !gl::GLExtensions::getInstance().hasWaitSync()) { + if (!GLExtensions::getInstance().hasNativeFenceSync() || + !GLExtensions::getInstance().hasWaitSync()) { return false; } @@ -378,7 +387,7 @@ bool SkiaGLRenderEngine::waitGpuFence(base::borrowed_fd fenceFd) { base::unique_fd SkiaGLRenderEngine::flush() { ATRACE_CALL(); - if (!gl::GLExtensions::getInstance().hasNativeFenceSync()) { + if (!GLExtensions::getInstance().hasNativeFenceSync()) { return base::unique_fd(); } @@ -469,13 +478,13 @@ EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig co std::optional<RenderEngine::ContextPriority> SkiaGLRenderEngine::createContextPriority( const RenderEngineCreationArgs& args) { - if (!gl::GLExtensions::getInstance().hasContextPriority()) { + if (!GLExtensions::getInstance().hasContextPriority()) { return std::nullopt; } switch (args.contextPriority) { case RenderEngine::ContextPriority::REALTIME: - if (gl::GLExtensions::getInstance().hasRealtimePriority()) { + if (GLExtensions::getInstance().hasRealtimePriority()) { return RenderEngine::ContextPriority::REALTIME; } else { ALOGI("Realtime priority unsupported, degrading gracefully to high priority"); @@ -519,7 +528,7 @@ int SkiaGLRenderEngine::getContextPriority() { } void SkiaGLRenderEngine::appendBackendSpecificInfoToDump(std::string& result) { - const gl::GLExtensions& extensions = gl::GLExtensions::getInstance(); + const GLExtensions& extensions = GLExtensions::getInstance(); StringAppendF(&result, "\n ------------RE GLES------------\n"); StringAppendF(&result, "EGL implementation : %s\n", extensions.getEGLVersion()); StringAppendF(&result, "%s\n", extensions.getEGLExtensions()); diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 7b4a0a0af2..011052102d 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -64,7 +64,6 @@ public: std::future<void> primeCache() override final; void cleanupPostRender() override final; - void cleanFramebufferCache() override final{ } bool supportsBackgroundBlur() override final { return mBlurFilter != nullptr; } diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index fe3a16d4bf..281a502b06 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -36,7 +36,7 @@ struct RenderEngineThreadedTest : public ::testing::Test { void SetUp() override { mThreadedRE = renderengine::threaded::RenderEngineThreaded::create( [this]() { return std::unique_ptr<renderengine::RenderEngine>(mRenderEngine); }, - renderengine::RenderEngine::RenderEngineType::THREADED); + renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED); } std::unique_ptr<renderengine::threaded::RenderEngineThreaded> mThreadedRE; @@ -57,18 +57,6 @@ TEST_F(RenderEngineThreadedTest, primeCache) { mThreadedRE->getContextPriority(); } -TEST_F(RenderEngineThreadedTest, genTextures) { - uint32_t texName; - EXPECT_CALL(*mRenderEngine, genTextures(1, &texName)); - mThreadedRE->genTextures(1, &texName); -} - -TEST_F(RenderEngineThreadedTest, deleteTextures) { - uint32_t texName; - EXPECT_CALL(*mRenderEngine, deleteTextures(1, &texName)); - mThreadedRE->deleteTextures(1, &texName); -} - TEST_F(RenderEngineThreadedTest, getMaxTextureSize_returns20) { size_t size = 20; EXPECT_CALL(*mRenderEngine, getMaxTextureSize()).WillOnce(Return(size)); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index 6a1561abcd..57055bd9ac 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -27,8 +27,6 @@ #include <processgroup/processgroup.h> #include <utils/Trace.h> -#include "gl/GLESRenderEngine.h" - using namespace std::chrono_literals; namespace android { @@ -178,41 +176,13 @@ void RenderEngineThreaded::dump(std::string& result) { void RenderEngineThreaded::genTextures(size_t count, uint32_t* names) { ATRACE_CALL(); // This is a no-op in SkiaRenderEngine. - if (getRenderEngineType() != RenderEngineType::THREADED) { - return; - } - std::promise<void> resultPromise; - std::future<void> resultFuture = resultPromise.get_future(); - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise, count, names](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::genTextures"); - instance.genTextures(count, names); - resultPromise.set_value(); - }); - } - mCondition.notify_one(); - resultFuture.wait(); + return; } void RenderEngineThreaded::deleteTextures(size_t count, uint32_t const* names) { ATRACE_CALL(); // This is a no-op in SkiaRenderEngine. - if (getRenderEngineType() != RenderEngineType::THREADED) { - return; - } - std::promise<void> resultPromise; - std::future<void> resultFuture = resultPromise.get_future(); - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise, count, &names](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::deleteTextures"); - instance.deleteTextures(count, names); - resultPromise.set_value(); - }); - } - mCondition.notify_one(); - resultFuture.wait(); + return; } void RenderEngineThreaded::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, @@ -313,20 +283,6 @@ ftl::Future<FenceResult> RenderEngineThreaded::drawLayers( return resultFuture; } -void RenderEngineThreaded::cleanFramebufferCache() { - ATRACE_CALL(); - // This function is designed so it can run asynchronously, so we do not need to wait - // for the futures. - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::cleanFramebufferCache"); - instance.cleanFramebufferCache(); - }); - } - mCondition.notify_one(); -} - int RenderEngineThreaded::getContextPriority() { std::promise<int> resultPromise; std::future<int> resultFuture = resultPromise.get_future(); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 6eb108e064..68e50625c8 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -60,7 +60,6 @@ public: const bool useFramebufferCache, base::unique_fd&& bufferFence) override; - void cleanFramebufferCache() override; int getContextPriority() override; bool supportsBackgroundBlur() override; void onActiveDisplaySizeChanged(ui::Size size) override; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index d1912e4c9c..faf0e3c117 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -23,8 +23,6 @@ #include <gui/WindowInfo.h> #include <layerproto/LayerProtoHeader.h> #include <math/vec4.h> -#include <renderengine/Mesh.h> -#include <renderengine/Texture.h> #include <sys/types.h> #include <ui/BlurRegion.h> #include <ui/FloatRect.h> diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 06adfec0d2..5dd1598299 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -769,13 +769,9 @@ void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { static std::optional<renderengine::RenderEngine::RenderEngineType> chooseRenderEngineTypeViaSysProp() { char prop[PROPERTY_VALUE_MAX]; - property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, ""); + property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "skiaglthreaded"); - if (strcmp(prop, "gles") == 0) { - return renderengine::RenderEngine::RenderEngineType::GLES; - } else if (strcmp(prop, "threaded") == 0) { - return renderengine::RenderEngine::RenderEngineType::THREADED; - } else if (strcmp(prop, "skiagl") == 0) { + if (strcmp(prop, "skiagl") == 0) { return renderengine::RenderEngine::RenderEngineType::SKIA_GL; } else if (strcmp(prop, "skiaglthreaded") == 0) { return renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED; @@ -3578,8 +3574,6 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, // Recreate the DisplayDevice if the surface or sequence ID changed. if (currentBinder != drawingBinder || currentState.sequenceId != drawingState.sequenceId) { - getRenderEngine().cleanFramebufferCache(); - if (const auto display = getDisplayDeviceLocked(displayToken)) { display->disconnect(); if (display->isVirtual()) { @@ -7872,7 +7866,7 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( const bool renderEngineIsThreaded = [&]() { using Type = renderengine::RenderEngine::RenderEngineType; const auto type = mRenderEngine->getRenderEngineType(); - return type == Type::THREADED || type == Type::SKIA_GL_THREADED; + return type == Type::SKIA_GL_THREADED; }(); auto presentFuture = renderEngineIsThreaded ? ftl::defer(std::move(present)).share() : ftl::yield(present()).share(); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 14fa492576..14f71f28a2 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -31,8 +31,6 @@ #include <gui/LayerMetadata.h> #include <log/log.h> #include <renderengine/mock/FakeExternalTexture.h> -#include <renderengine/mock/Framebuffer.h> -#include <renderengine/mock/Image.h> #include <renderengine/mock/RenderEngine.h> #include <system/window.h> #include <utils/String8.h> |