blob: b7aa78b7afae3d2bba06daf1aee5d44139277659 [file] [log] [blame]
Stan Iliev500a0c32016-10-26 10:30:09 -04001/*
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 "SkiaOpenGLPipeline.h"
18
19#include "DeferredLayerUpdater.h"
Greg Daniel8cd3edf2017-01-09 14:15:41 -050020#include "GlLayer.h"
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050021#include "LayerDrawable.h"
Matt Sarettcf2c05c2016-10-26 11:03:23 -040022#include "SkiaPipeline.h"
23#include "SkiaProfileRenderer.h"
John Reck1bcacfd2017-11-03 10:12:19 -070024#include "hwui/Bitmap.h"
25#include "renderstate/RenderState.h"
26#include "renderthread/EglManager.h"
27#include "renderthread/Frame.h"
Stan Iliev500a0c32016-10-26 10:30:09 -040028#include "utils/TraceUtils.h"
29
Greg Danielac2d2322017-07-12 11:30:15 -040030#include <GrBackendSurface.h>
31
Stan Iliev500a0c32016-10-26 10:30:09 -040032#include <cutils/properties.h>
33#include <strings.h>
34
35using namespace android::uirenderer::renderthread;
36
37namespace android {
38namespace uirenderer {
39namespace skiapipeline {
40
41SkiaOpenGLPipeline::SkiaOpenGLPipeline(RenderThread& thread)
John Reck1bcacfd2017-11-03 10:12:19 -070042 : SkiaPipeline(thread), mEglManager(thread.eglManager()) {}
Stan Iliev500a0c32016-10-26 10:30:09 -040043
44MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() {
45 // TODO: Figure out why this workaround is needed, see b/13913604
46 // In the meantime this matches the behavior of GLRenderer, so it is not a regression
47 EGLint error = 0;
48 if (!mEglManager.makeCurrent(mEglSurface, &error)) {
49 return MakeCurrentResult::AlreadyCurrent;
50 }
51 return error ? MakeCurrentResult::Failed : MakeCurrentResult::Succeeded;
52}
53
54Frame SkiaOpenGLPipeline::getFrame() {
55 LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
John Reck1bcacfd2017-11-03 10:12:19 -070056 "drawRenderNode called on a context with no surface!");
Stan Iliev500a0c32016-10-26 10:30:09 -040057 return mEglManager.beginFrame(mEglSurface);
58}
59
John Reck1bcacfd2017-11-03 10:12:19 -070060bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
61 const FrameBuilder::LightGeometry& lightGeometry,
62 LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
63 bool opaque, bool wideColorGamut,
64 const BakedOpRenderer::LightInfo& lightInfo,
65 const std::vector<sp<RenderNode>>& renderNodes,
66 FrameInfoVisualizer* profiler) {
Stan Iliev500a0c32016-10-26 10:30:09 -040067 mEglManager.damageFrame(frame, dirty);
68
Greg Danielc9da8e82018-03-21 10:50:24 -040069 SkColorType colorType;
Stan Iliev500a0c32016-10-26 10:30:09 -040070 // setup surface for fbo0
Greg Danielac2d2322017-07-12 11:30:15 -040071 GrGLFramebufferInfo fboInfo;
72 fboInfo.fFBOID = 0;
Greg Danielc9da8e82018-03-21 10:50:24 -040073 if (wideColorGamut) {
74 fboInfo.fFormat = GL_RGBA16F;
75 colorType = kRGBA_F16_SkColorType;
76 } else {
77 fboInfo.fFormat = GL_RGBA8;
78 colorType = kN32_SkColorType;
79 }
Greg Danielac2d2322017-07-12 11:30:15 -040080
Greg Danielc9da8e82018-03-21 10:50:24 -040081 GrBackendRenderTarget backendRT(frame.width(), frame.height(), 0, STENCIL_BUFFER_SIZE, fboInfo);
Stan Iliev500a0c32016-10-26 10:30:09 -040082
83 SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
84
85 SkASSERT(mRenderThread.getGrContext() != nullptr);
86 sk_sp<SkSurface> surface(SkSurface::MakeFromBackendRenderTarget(
Greg Danielc9da8e82018-03-21 10:50:24 -040087 mRenderThread.getGrContext(), backendRT, kBottomLeft_GrSurfaceOrigin, colorType,
88 nullptr, &props));
Stan Iliev500a0c32016-10-26 10:30:09 -040089
90 SkiaPipeline::updateLighting(lightGeometry, lightInfo);
John Reck1bcacfd2017-11-03 10:12:19 -070091 renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut, contentDrawBounds,
92 surface);
Stan Iliev500a0c32016-10-26 10:30:09 -040093 layerUpdateQueue->clear();
Matt Sarettcf2c05c2016-10-26 11:03:23 -040094
95 // Draw visual debugging features
John Reck1bcacfd2017-11-03 10:12:19 -070096 if (CC_UNLIKELY(Properties::showDirtyRegions ||
97 ProfileType::None != Properties::getProfileType())) {
Matt Sarettcf2c05c2016-10-26 11:03:23 -040098 SkCanvas* profileCanvas = surface->getCanvas();
99 SkiaProfileRenderer profileRenderer(profileCanvas);
100 profiler->draw(profileRenderer);
101 profileCanvas->flush();
102 }
103
Matt Sarett4bda6bf2016-11-07 15:43:41 -0500104 // Log memory statistics
105 if (CC_UNLIKELY(Properties::debugLevel != kDebugDisabled)) {
106 dumpResourceCacheUsage();
107 }
108
Stan Iliev500a0c32016-10-26 10:30:09 -0400109 return true;
110}
111
John Reck1bcacfd2017-11-03 10:12:19 -0700112bool SkiaOpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
113 FrameInfo* currentFrameInfo, bool* requireSwap) {
Stan Iliev500a0c32016-10-26 10:30:09 -0400114 GL_CHECKPOINT(LOW);
115
116 // Even if we decided to cancel the frame, from the perspective of jank
117 // metrics the frame was swapped at this point
118 currentFrameInfo->markSwapBuffers();
119
120 *requireSwap = drew || mEglManager.damageRequiresSwap();
121
122 if (*requireSwap && (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty)))) {
123 return false;
124 }
125
126 return *requireSwap;
127}
128
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -0500129bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) {
130 if (!mRenderThread.getGrContext()) {
131 return false;
132 }
133
Chris Craik2f1aaf72017-02-14 13:01:42 -0800134 // acquire most recent buffer for drawing
135 deferredLayer->updateTexImage();
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -0500136 deferredLayer->apply();
137
Derek Sollenberger4170db32017-08-09 13:52:36 -0400138 /* This intermediate surface is present to work around a bug in SwiftShader that
139 * prevents us from reading the contents of the layer's texture directly. The
140 * workaround involves first rendering that texture into an intermediate buffer and
141 * then reading from the intermediate buffer into the bitmap.
142 */
143 sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
John Reck1bcacfd2017-11-03 10:12:19 -0700144 SkBudgeted::kYes, bitmap->info());
Derek Sollenberger4170db32017-08-09 13:52:36 -0400145
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -0500146 Layer* layer = deferredLayer->backingLayer();
Leon Scroggins III1a12ab22018-03-26 15:00:49 -0400147 const SkRect dstRect = SkRect::MakeIWH(bitmap->width(), bitmap->height());
148 if (LayerDrawable::DrawLayer(mRenderThread.getGrContext(), tmpSurface->getCanvas(), layer,
149 &dstRect)) {
Derek Sollenberger4170db32017-08-09 13:52:36 -0400150 sk_sp<SkImage> tmpImage = tmpSurface->makeImageSnapshot();
151 if (tmpImage->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
152 bitmap->notifyPixelsChanged();
153 return true;
154 }
155 }
156
157 return false;
Stan Iliev500a0c32016-10-26 10:30:09 -0400158}
159
sergeyv3e9999b2017-01-19 15:37:02 -0800160static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
John Reck1bcacfd2017-11-03 10:12:19 -0700161 SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
162 GlLayer* layer =
163 new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
sergeyv3e9999b2017-01-19 15:37:02 -0800164 layer->generateTexture();
165 return layer;
166}
167
Stan Iliev500a0c32016-10-26 10:30:09 -0400168DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() {
169 mEglManager.initialize();
sergeyv3e9999b2017-01-19 15:37:02 -0800170 return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::OpenGL);
Stan Iliev500a0c32016-10-26 10:30:09 -0400171}
172
173void SkiaOpenGLPipeline::onStop() {
174 if (mEglManager.isCurrent(mEglSurface)) {
175 mEglManager.makeCurrent(EGL_NO_SURFACE);
176 }
177}
178
Romain Guy26a2b972017-04-17 09:39:51 -0700179bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
John Reck1bcacfd2017-11-03 10:12:19 -0700180 ColorMode colorMode) {
Stan Iliev500a0c32016-10-26 10:30:09 -0400181 if (mEglSurface != EGL_NO_SURFACE) {
182 mEglManager.destroySurface(mEglSurface);
183 mEglSurface = EGL_NO_SURFACE;
184 }
185
186 if (surface) {
Romain Guy26a2b972017-04-17 09:39:51 -0700187 const bool wideColorGamut = colorMode == ColorMode::WideColorGamut;
188 mEglSurface = mEglManager.createSurface(surface, wideColorGamut);
Stan Iliev500a0c32016-10-26 10:30:09 -0400189 }
190
191 if (mEglSurface != EGL_NO_SURFACE) {
192 const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
193 mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
194 return true;
195 }
196
197 return false;
198}
199
200bool SkiaOpenGLPipeline::isSurfaceReady() {
201 return CC_UNLIKELY(mEglSurface != EGL_NO_SURFACE);
202}
203
204bool SkiaOpenGLPipeline::isContextReady() {
205 return CC_LIKELY(mEglManager.hasEglContext());
206}
207
208void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
209 DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
210 if (thread.eglManager().hasEglContext()) {
211 mode = DrawGlInfo::kModeProcess;
212 }
213
214 (*functor)(mode, nullptr);
215
216 // If there's no context we don't need to reset as there's no gl state to save/restore
217 if (mode != DrawGlInfo::kModeProcessNoContext) {
218 thread.getGrContext()->resetContext();
219 }
220}
221
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400222#define FENCE_TIMEOUT 2000000000
223
224class AutoEglFence {
225public:
John Reck1bcacfd2017-11-03 10:12:19 -0700226 AutoEglFence(EGLDisplay display) : mDisplay(display) {
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400227 fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
228 }
229
230 ~AutoEglFence() {
231 if (fence != EGL_NO_SYNC_KHR) {
232 eglDestroySyncKHR(mDisplay, fence);
233 }
234 }
235
236 EGLSyncKHR fence = EGL_NO_SYNC_KHR;
John Reck1bcacfd2017-11-03 10:12:19 -0700237
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400238private:
239 EGLDisplay mDisplay = EGL_NO_DISPLAY;
240};
241
242class AutoEglImage {
243public:
John Reck1bcacfd2017-11-03 10:12:19 -0700244 AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) {
245 EGLint imageAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
246 image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer,
247 imageAttrs);
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400248 }
249
250 ~AutoEglImage() {
251 if (image != EGL_NO_IMAGE_KHR) {
252 eglDestroyImageKHR(mDisplay, image);
253 }
254 }
255
256 EGLImageKHR image = EGL_NO_IMAGE_KHR;
John Reck1bcacfd2017-11-03 10:12:19 -0700257
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400258private:
259 EGLDisplay mDisplay = EGL_NO_DISPLAY;
260};
261
262class AutoSkiaGlTexture {
263public:
264 AutoSkiaGlTexture() {
265 glGenTextures(1, &mTexture);
266 glBindTexture(GL_TEXTURE_2D, mTexture);
267 }
268
John Reck1bcacfd2017-11-03 10:12:19 -0700269 ~AutoSkiaGlTexture() { glDeleteTextures(1, &mTexture); }
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400270
271private:
272 GLuint mTexture = 0;
273};
274
275sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
John Reck1bcacfd2017-11-03 10:12:19 -0700276 SkBitmap& skBitmap) {
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400277 renderThread.eglManager().initialize();
278
279 sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext());
280 const SkImageInfo& info = skBitmap.info();
281 PixelFormat pixelFormat;
282 GLint format, type;
283 bool isSupported = false;
284
John Reck1bcacfd2017-11-03 10:12:19 -0700285 // TODO: add support for linear blending (when ANDROID_ENABLE_LINEAR_BLENDING is defined)
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400286 switch (info.colorType()) {
John Reck1bcacfd2017-11-03 10:12:19 -0700287 case kRGBA_8888_SkColorType:
288 isSupported = true;
289 // ARGB_4444 is upconverted to RGBA_8888
290 case kARGB_4444_SkColorType:
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400291 pixelFormat = PIXEL_FORMAT_RGBA_8888;
John Reck1bcacfd2017-11-03 10:12:19 -0700292 format = GL_RGBA;
293 type = GL_UNSIGNED_BYTE;
294 break;
295 case kRGBA_F16_SkColorType:
Greg Danielc9da8e82018-03-21 10:50:24 -0400296 isSupported = grContext->colorTypeSupportedAsImage(kRGBA_F16_SkColorType);
John Reck1bcacfd2017-11-03 10:12:19 -0700297 if (isSupported) {
298 type = GL_HALF_FLOAT;
299 pixelFormat = PIXEL_FORMAT_RGBA_FP16;
300 } else {
301 type = GL_UNSIGNED_BYTE;
302 pixelFormat = PIXEL_FORMAT_RGBA_8888;
303 }
304 format = GL_RGBA;
305 break;
306 case kRGB_565_SkColorType:
307 isSupported = true;
308 pixelFormat = PIXEL_FORMAT_RGB_565;
309 format = GL_RGB;
310 type = GL_UNSIGNED_SHORT_5_6_5;
311 break;
312 case kGray_8_SkColorType:
313 isSupported = true;
314 pixelFormat = PIXEL_FORMAT_RGBA_8888;
315 format = GL_LUMINANCE;
316 type = GL_UNSIGNED_BYTE;
317 break;
318 default:
319 ALOGW("unable to create hardware bitmap of colortype: %d", info.colorType());
320 return nullptr;
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400321 }
322
323 SkBitmap bitmap;
324 if (isSupported) {
325 bitmap = skBitmap;
326 } else {
John Reck1bcacfd2017-11-03 10:12:19 -0700327 bitmap.allocPixels(
328 SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(), nullptr));
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400329 bitmap.eraseColor(0);
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400330 if (info.colorType() == kRGBA_F16_SkColorType) {
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400331 // Drawing RGBA_F16 onto ARGB_8888 is not supported
332 skBitmap.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
John Reck1bcacfd2017-11-03 10:12:19 -0700333 bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400334 } else {
335 SkCanvas canvas(bitmap);
336 canvas.drawBitmap(skBitmap, 0.0f, 0.0f, nullptr);
337 }
338 }
339
John Reck1bcacfd2017-11-03 10:12:19 -0700340 sp<GraphicBuffer> buffer = new GraphicBuffer(
341 info.width(), info.height(), pixelFormat,
342 GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
343 GraphicBuffer::USAGE_SW_READ_NEVER,
344 std::string("Bitmap::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) +
345 "]");
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400346
347 status_t error = buffer->initCheck();
348 if (error < 0) {
349 ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()");
350 return nullptr;
351 }
352
John Reck1bcacfd2017-11-03 10:12:19 -0700353 // upload the bitmap into a texture
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400354 EGLDisplay display = eglGetCurrentDisplay();
John Reck1bcacfd2017-11-03 10:12:19 -0700355 LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
356 uirenderer::renderthread::EglManager::eglErrorString());
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400357 // We use an EGLImage to access the content of the GraphicBuffer
358 // The EGL image is later bound to a 2D texture
John Reck1bcacfd2017-11-03 10:12:19 -0700359 EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer->getNativeBuffer();
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400360 AutoEglImage autoImage(display, clientBuffer);
361 if (autoImage.image == EGL_NO_IMAGE_KHR) {
362 ALOGW("Could not create EGL image, err =%s",
John Reck1bcacfd2017-11-03 10:12:19 -0700363 uirenderer::renderthread::EglManager::eglErrorString());
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400364 return nullptr;
365 }
366 AutoSkiaGlTexture glTexture;
367 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
368 GL_CHECKPOINT(MODERATE);
369
370 // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we provide.
371 // But asynchronous in sense that driver may upload texture onto hardware buffer when we first
372 // use it in drawing
373 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, info.width(), info.height(), format, type,
John Reck1bcacfd2017-11-03 10:12:19 -0700374 bitmap.getPixels());
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400375 GL_CHECKPOINT(MODERATE);
376
377 // The fence is used to wait for the texture upload to finish
378 // properly. We cannot rely on glFlush() and glFinish() as
379 // some drivers completely ignore these API calls
380 AutoEglFence autoFence(display);
381 if (autoFence.fence == EGL_NO_SYNC_KHR) {
382 LOG_ALWAYS_FATAL("Could not create sync fence %#x", eglGetError());
383 return nullptr;
384 }
385 // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
386 // pipeline flush (similar to what a glFlush() would do.)
387 EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence,
John Reck1bcacfd2017-11-03 10:12:19 -0700388 EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400389 if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
390 LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError());
391 return nullptr;
392 }
393
394 grContext->resetContext(kTextureBinding_GrGLBackendState);
395
396 return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info()));
397}
398
Stan Iliev500a0c32016-10-26 10:30:09 -0400399} /* namespace skiapipeline */
400} /* namespace uirenderer */
401} /* namespace android */