1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "OpenGLPipeline.h" 18 19 #include "DeferredLayerUpdater.h" 20 #include "EglManager.h" 21 #include "Frame.h" 22 #include "GlLayer.h" 23 #include "ProfileRenderer.h" 24 #include "renderstate/RenderState.h" 25 #include "OpenGLReadback.h" 26 27 #include <cutils/properties.h> 28 #include <strings.h> 29 30 namespace android { 31 namespace uirenderer { 32 namespace renderthread { 33 34 OpenGLPipeline::OpenGLPipeline(RenderThread& thread) 35 : mEglManager(thread.eglManager()) 36 , mRenderThread(thread) { 37 } 38 39 MakeCurrentResult OpenGLPipeline::makeCurrent() { 40 // TODO: Figure out why this workaround is needed, see b/13913604 41 // In the meantime this matches the behavior of GLRenderer, so it is not a regression 42 EGLint error = 0; 43 bool haveNewSurface = mEglManager.makeCurrent(mEglSurface, &error); 44 45 Caches::getInstance().textureCache.resetMarkInUse(this); 46 if (!haveNewSurface) { 47 return MakeCurrentResult::AlreadyCurrent; 48 } 49 return error ? MakeCurrentResult::Failed : MakeCurrentResult::Succeeded; 50 } 51 52 Frame OpenGLPipeline::getFrame() { 53 LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE, 54 "drawRenderNode called on a context with no surface!"); 55 return mEglManager.beginFrame(mEglSurface); 56 } 57 58 bool OpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, 59 const FrameBuilder::LightGeometry& lightGeometry, 60 LayerUpdateQueue* layerUpdateQueue, 61 const Rect& contentDrawBounds, bool opaque, bool wideColorGamut, 62 const BakedOpRenderer::LightInfo& lightInfo, 63 const std::vector< sp<RenderNode> >& renderNodes, 64 FrameInfoVisualizer* profiler) { 65 66 mEglManager.damageFrame(frame, dirty); 67 68 bool drew = false; 69 70 71 auto& caches = Caches::getInstance(); 72 FrameBuilder frameBuilder(dirty, frame.width(), frame.height(), lightGeometry, caches); 73 74 frameBuilder.deferLayers(*layerUpdateQueue); 75 layerUpdateQueue->clear(); 76 77 frameBuilder.deferRenderNodeScene(renderNodes, contentDrawBounds); 78 79 BakedOpRenderer renderer(caches, mRenderThread.renderState(), 80 opaque, wideColorGamut, lightInfo); 81 frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); 82 ProfileRenderer profileRenderer(renderer); 83 profiler->draw(profileRenderer); 84 drew = renderer.didDraw(); 85 86 // post frame cleanup 87 caches.clearGarbage(); 88 caches.pathCache.trim(); 89 caches.tessellationCache.trim(); 90 91 #if DEBUG_MEMORY_USAGE 92 caches.dumpMemoryUsage(); 93 #else 94 if (CC_UNLIKELY(Properties::debugLevel & kDebugMemory)) { 95 caches.dumpMemoryUsage(); 96 } 97 #endif 98 99 return drew; 100 } 101 102 bool OpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, 103 FrameInfo* currentFrameInfo, bool* requireSwap) { 104 105 GL_CHECKPOINT(LOW); 106 107 // Even if we decided to cancel the frame, from the perspective of jank 108 // metrics the frame was swapped at this point 109 currentFrameInfo->markSwapBuffers(); 110 111 *requireSwap = drew || mEglManager.damageRequiresSwap(); 112 113 if (*requireSwap && (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty)))) { 114 return false; 115 } 116 117 return *requireSwap; 118 } 119 120 bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) { 121 ATRACE_CALL(); 122 // acquire most recent buffer for drawing 123 layer->updateTexImage(); 124 layer->apply(); 125 return OpenGLReadbackImpl::copyLayerInto(mRenderThread, 126 static_cast<GlLayer&>(*layer->backingLayer()), bitmap); 127 } 128 129 static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight, 130 SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) { 131 GlLayer* layer = new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, 132 mode, blend); 133 Caches::getInstance().textureState().activateTexture(0); 134 layer->generateTexture(); 135 return layer; 136 } 137 138 DeferredLayerUpdater* OpenGLPipeline::createTextureLayer() { 139 mEglManager.initialize(); 140 return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::OpenGL); 141 } 142 143 void OpenGLPipeline::onStop() { 144 if (mEglManager.isCurrent(mEglSurface)) { 145 mEglManager.makeCurrent(EGL_NO_SURFACE); 146 } 147 } 148 149 bool OpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, ColorMode colorMode) { 150 151 if (mEglSurface != EGL_NO_SURFACE) { 152 mEglManager.destroySurface(mEglSurface); 153 mEglSurface = EGL_NO_SURFACE; 154 } 155 156 if (surface) { 157 const bool wideColorGamut = colorMode == ColorMode::WideColorGamut; 158 mEglSurface = mEglManager.createSurface(surface, wideColorGamut); 159 } 160 161 if (mEglSurface != EGL_NO_SURFACE) { 162 const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer); 163 mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer); 164 return true; 165 } 166 167 return false; 168 } 169 170 bool OpenGLPipeline::isSurfaceReady() { 171 return CC_UNLIKELY(mEglSurface != EGL_NO_SURFACE); 172 } 173 174 bool OpenGLPipeline::isContextReady() { 175 return CC_LIKELY(mEglManager.hasEglContext()); 176 } 177 178 void OpenGLPipeline::onDestroyHardwareResources() { 179 Caches& caches = Caches::getInstance(); 180 // Make sure to release all the textures we were owning as there won't 181 // be another draw 182 caches.textureCache.resetMarkInUse(this); 183 mRenderThread.renderState().flush(Caches::FlushMode::Layers); 184 } 185 186 void OpenGLPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry, 187 LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut, 188 const BakedOpRenderer::LightInfo& lightInfo) { 189 static const std::vector< sp<RenderNode> > emptyNodeList; 190 auto& caches = Caches::getInstance(); 191 FrameBuilder frameBuilder(*layerUpdateQueue, lightGeometry, caches); 192 layerUpdateQueue->clear(); 193 // TODO: Handle wide color gamut contexts 194 BakedOpRenderer renderer(caches, mRenderThread.renderState(), opaque, wideColorGamut, lightInfo); 195 LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case"); 196 frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); 197 } 198 199 TaskManager* OpenGLPipeline::getTaskManager() { 200 return &Caches::getInstance().tasks; 201 } 202 203 static bool layerMatchesWH(OffscreenBuffer* layer, int width, int height) { 204 return layer->viewportWidth == (uint32_t)width && layer->viewportHeight == (uint32_t)height; 205 } 206 207 bool OpenGLPipeline::createOrUpdateLayer(RenderNode* node, 208 const DamageAccumulator& damageAccumulator, bool wideColorGamut) { 209 RenderState& renderState = mRenderThread.renderState(); 210 OffscreenBufferPool& layerPool = renderState.layerPool(); 211 bool transformUpdateNeeded = false; 212 if (node->getLayer() == nullptr) { 213 node->setLayer(layerPool.get(renderState, 214 node->getWidth(), node->getHeight(), wideColorGamut)); 215 transformUpdateNeeded = true; 216 } else if (!layerMatchesWH(node->getLayer(), node->getWidth(), node->getHeight())) { 217 // TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering) 218 // Or, ideally, maintain damage between frames on node/layer so ordering is always correct 219 if (node->properties().fitsOnLayer()) { 220 node->setLayer(layerPool.resize(node->getLayer(), node->getWidth(), node->getHeight())); 221 } else { 222 destroyLayer(node); 223 } 224 transformUpdateNeeded = true; 225 } 226 227 if (transformUpdateNeeded && node->getLayer()) { 228 // update the transform in window of the layer to reset its origin wrt light source position 229 Matrix4 windowTransform; 230 damageAccumulator.computeCurrentTransform(&windowTransform); 231 node->getLayer()->setWindowTransform(windowTransform); 232 } 233 234 return transformUpdateNeeded; 235 } 236 237 bool OpenGLPipeline::pinImages(LsaVector<sk_sp<Bitmap>>& images) { 238 TextureCache& cache = Caches::getInstance().textureCache; 239 bool prefetchSucceeded = true; 240 for (auto& bitmapResource : images) { 241 prefetchSucceeded &= cache.prefetchAndMarkInUse(this, bitmapResource.get()); 242 } 243 return prefetchSucceeded; 244 } 245 246 void OpenGLPipeline::unpinImages() { 247 Caches::getInstance().textureCache.resetMarkInUse(this); 248 } 249 250 void OpenGLPipeline::destroyLayer(RenderNode* node) { 251 if (OffscreenBuffer* layer = node->getLayer()) { 252 layer->renderState.layerPool().putOrDelete(layer); 253 node->setLayer(nullptr); 254 } 255 } 256 257 void OpenGLPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { 258 if (Caches::hasInstance() && thread.eglManager().hasEglContext()) { 259 ATRACE_NAME("Bitmap#prepareToDraw task"); 260 Caches::getInstance().textureCache.prefetch(bitmap); 261 } 262 } 263 264 void OpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) { 265 DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext; 266 if (thread.eglManager().hasEglContext()) { 267 mode = DrawGlInfo::kModeProcess; 268 } 269 thread.renderState().invokeFunctor(functor, mode, nullptr); 270 } 271 272 #define FENCE_TIMEOUT 2000000000 273 274 class AutoEglFence { 275 public: 276 AutoEglFence(EGLDisplay display) 277 : mDisplay(display) { 278 fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL); 279 } 280 281 ~AutoEglFence() { 282 if (fence != EGL_NO_SYNC_KHR) { 283 eglDestroySyncKHR(mDisplay, fence); 284 } 285 } 286 287 EGLSyncKHR fence = EGL_NO_SYNC_KHR; 288 private: 289 EGLDisplay mDisplay = EGL_NO_DISPLAY; 290 }; 291 292 class AutoEglImage { 293 public: 294 AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) 295 : mDisplay(display) { 296 EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; 297 image = eglCreateImageKHR(display, EGL_NO_CONTEXT, 298 EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs); 299 } 300 301 ~AutoEglImage() { 302 if (image != EGL_NO_IMAGE_KHR) { 303 eglDestroyImageKHR(mDisplay, image); 304 } 305 } 306 307 EGLImageKHR image = EGL_NO_IMAGE_KHR; 308 private: 309 EGLDisplay mDisplay = EGL_NO_DISPLAY; 310 }; 311 312 class AutoGlTexture { 313 public: 314 AutoGlTexture(uirenderer::Caches& caches) 315 : mCaches(caches) { 316 glGenTextures(1, &mTexture); 317 caches.textureState().bindTexture(mTexture); 318 } 319 320 ~AutoGlTexture() { 321 mCaches.textureState().deleteTexture(mTexture); 322 } 323 324 private: 325 uirenderer::Caches& mCaches; 326 GLuint mTexture = 0; 327 }; 328 329 static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bitmap, 330 GraphicBuffer& buffer, GLint format, GLint type) { 331 EGLDisplay display = eglGetCurrentDisplay(); 332 LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, 333 "Failed to get EGL_DEFAULT_DISPLAY! err=%s", 334 uirenderer::renderthread::EglManager::eglErrorString()); 335 // We use an EGLImage to access the content of the GraphicBuffer 336 // The EGL image is later bound to a 2D texture 337 EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer.getNativeBuffer(); 338 AutoEglImage autoImage(display, clientBuffer); 339 if (autoImage.image == EGL_NO_IMAGE_KHR) { 340 ALOGW("Could not create EGL image, err =%s", 341 uirenderer::renderthread::EglManager::eglErrorString()); 342 return false; 343 } 344 AutoGlTexture glTexture(caches); 345 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image); 346 347 GL_CHECKPOINT(MODERATE); 348 349 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), 350 format, type, bitmap.getPixels()); 351 352 GL_CHECKPOINT(MODERATE); 353 354 // The fence is used to wait for the texture upload to finish 355 // properly. We cannot rely on glFlush() and glFinish() as 356 // some drivers completely ignore these API calls 357 AutoEglFence autoFence(display); 358 if (autoFence.fence == EGL_NO_SYNC_KHR) { 359 LOG_ALWAYS_FATAL("Could not create sync fence %#x", eglGetError()); 360 return false; 361 } 362 // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a 363 // pipeline flush (similar to what a glFlush() would do.) 364 EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence, 365 EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT); 366 if (waitStatus != EGL_CONDITION_SATISFIED_KHR) { 367 LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError()); 368 return false; 369 } 370 return true; 371 } 372 373 // TODO: handle SRGB sanely 374 static PixelFormat internalFormatToPixelFormat(GLint internalFormat) { 375 switch (internalFormat) { 376 case GL_LUMINANCE: 377 return PIXEL_FORMAT_RGBA_8888; 378 case GL_SRGB8_ALPHA8: 379 return PIXEL_FORMAT_RGBA_8888; 380 case GL_RGBA: 381 return PIXEL_FORMAT_RGBA_8888; 382 case GL_RGB: 383 return PIXEL_FORMAT_RGB_565; 384 case GL_RGBA16F: 385 return PIXEL_FORMAT_RGBA_FP16; 386 default: 387 LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", internalFormat); 388 return PIXEL_FORMAT_UNKNOWN; 389 } 390 } 391 392 sk_sp<Bitmap> OpenGLPipeline::allocateHardwareBitmap(RenderThread& renderThread, 393 SkBitmap& skBitmap) { 394 renderThread.eglManager().initialize(); 395 uirenderer::Caches& caches = uirenderer::Caches::getInstance(); 396 397 const SkImageInfo& info = skBitmap.info(); 398 if (info.colorType() == kUnknown_SkColorType || info.colorType() == kAlpha_8_SkColorType) { 399 ALOGW("unable to create hardware bitmap of colortype: %d", info.colorType()); 400 return nullptr; 401 } 402 403 bool needSRGB = uirenderer::transferFunctionCloseToSRGB(skBitmap.info().colorSpace()); 404 bool hasLinearBlending = caches.extensions().hasLinearBlending(); 405 GLint format, type, internalFormat; 406 uirenderer::Texture::colorTypeToGlFormatAndType(caches, skBitmap.colorType(), 407 needSRGB && hasLinearBlending, &internalFormat, &format, &type); 408 409 PixelFormat pixelFormat = internalFormatToPixelFormat(internalFormat); 410 sp<GraphicBuffer> buffer = new GraphicBuffer(info.width(), info.height(), pixelFormat, 411 GraphicBuffer::USAGE_HW_TEXTURE | 412 GraphicBuffer::USAGE_SW_WRITE_NEVER | 413 GraphicBuffer::USAGE_SW_READ_NEVER, 414 std::string("Bitmap::allocateHardwareBitmap pid [") + std::to_string(getpid()) + "]"); 415 416 status_t error = buffer->initCheck(); 417 if (error < 0) { 418 ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()"); 419 return nullptr; 420 } 421 422 SkBitmap bitmap; 423 if (CC_UNLIKELY(uirenderer::Texture::hasUnsupportedColorType(skBitmap.info(), 424 hasLinearBlending))) { 425 sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeSRGB(); 426 bitmap = uirenderer::Texture::uploadToN32(skBitmap, hasLinearBlending, std::move(sRGB)); 427 } else { 428 bitmap = skBitmap; 429 } 430 431 if (!uploadBitmapToGraphicBuffer(caches, bitmap, *buffer, format, type)) { 432 return nullptr; 433 } 434 return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info())); 435 } 436 437 } /* namespace renderthread */ 438 } /* namespace uirenderer */ 439 } /* namespace android */ 440