blob: 5f8ee180bd099cff0babe915f8102ec5271bef75 [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
Stan Iliev7bc3bc62017-05-24 13:28:36 -040019#include "hwui/Bitmap.h"
Stan Iliev500a0c32016-10-26 10:30:09 -040020#include "DeferredLayerUpdater.h"
Greg Daniel8cd3edf2017-01-09 14:15:41 -050021#include "GlLayer.h"
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050022#include "LayerDrawable.h"
Stan Iliev500a0c32016-10-26 10:30:09 -040023#include "renderthread/EglManager.h"
Greg Danielcd558522016-11-17 13:31:40 -050024#include "renderthread/Frame.h"
Stan Iliev500a0c32016-10-26 10:30:09 -040025#include "renderstate/RenderState.h"
Matt Sarettcf2c05c2016-10-26 11:03:23 -040026#include "SkiaPipeline.h"
27#include "SkiaProfileRenderer.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)
42 : SkiaPipeline(thread)
43 , mEglManager(thread.eglManager()) {
44}
45
46MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() {
47 // TODO: Figure out why this workaround is needed, see b/13913604
48 // In the meantime this matches the behavior of GLRenderer, so it is not a regression
49 EGLint error = 0;
50 if (!mEglManager.makeCurrent(mEglSurface, &error)) {
51 return MakeCurrentResult::AlreadyCurrent;
52 }
53 return error ? MakeCurrentResult::Failed : MakeCurrentResult::Succeeded;
54}
55
56Frame SkiaOpenGLPipeline::getFrame() {
57 LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
58 "drawRenderNode called on a context with no surface!");
59 return mEglManager.beginFrame(mEglSurface);
60}
61
62bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty,
63 const SkRect& dirty,
64 const FrameBuilder::LightGeometry& lightGeometry,
65 LayerUpdateQueue* layerUpdateQueue,
Romain Guy07ae5052017-06-13 18:25:32 -070066 const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
Stan Iliev500a0c32016-10-26 10:30:09 -040067 const BakedOpRenderer::LightInfo& lightInfo,
68 const std::vector<sp<RenderNode>>& renderNodes,
69 FrameInfoVisualizer* profiler) {
70
71 mEglManager.damageFrame(frame, dirty);
72
73 // setup surface for fbo0
Greg Danielac2d2322017-07-12 11:30:15 -040074 GrGLFramebufferInfo fboInfo;
75 fboInfo.fFBOID = 0;
Stan Iliev08fc19a2017-07-24 10:20:33 -040076 GrPixelConfig pixelConfig =
77 wideColorGamut ? kRGBA_half_GrPixelConfig : kRGBA_8888_GrPixelConfig;
Greg Danielac2d2322017-07-12 11:30:15 -040078
79 GrBackendRenderTarget backendRT(frame.width(), frame.height(), 0, STENCIL_BUFFER_SIZE,
Stan Iliev08fc19a2017-07-24 10:20:33 -040080 pixelConfig, fboInfo);
Stan Iliev500a0c32016-10-26 10:30:09 -040081
82 SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
83
84 SkASSERT(mRenderThread.getGrContext() != nullptr);
85 sk_sp<SkSurface> surface(SkSurface::MakeFromBackendRenderTarget(
Greg Danielac2d2322017-07-12 11:30:15 -040086 mRenderThread.getGrContext(), backendRT, kBottomLeft_GrSurfaceOrigin, nullptr, &props));
Stan Iliev500a0c32016-10-26 10:30:09 -040087
88 SkiaPipeline::updateLighting(lightGeometry, lightInfo);
Romain Guy07ae5052017-06-13 18:25:32 -070089 renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut,
90 contentDrawBounds, surface);
Stan Iliev500a0c32016-10-26 10:30:09 -040091 layerUpdateQueue->clear();
Matt Sarettcf2c05c2016-10-26 11:03:23 -040092
93 // Draw visual debugging features
94 if (CC_UNLIKELY(Properties::showDirtyRegions
Matt Sarett4c9bbf42016-11-07 14:23:12 -050095 || ProfileType::None != Properties::getProfileType())) {
Matt Sarettcf2c05c2016-10-26 11:03:23 -040096 SkCanvas* profileCanvas = surface->getCanvas();
97 SkiaProfileRenderer profileRenderer(profileCanvas);
98 profiler->draw(profileRenderer);
99 profileCanvas->flush();
100 }
101
Matt Sarett4bda6bf2016-11-07 15:43:41 -0500102 // Log memory statistics
103 if (CC_UNLIKELY(Properties::debugLevel != kDebugDisabled)) {
104 dumpResourceCacheUsage();
105 }
106
Stan Iliev500a0c32016-10-26 10:30:09 -0400107 return true;
108}
109
110bool SkiaOpenGLPipeline::swapBuffers(const Frame& frame, bool drew,
111 const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) {
112
113 GL_CHECKPOINT(LOW);
114
115 // Even if we decided to cancel the frame, from the perspective of jank
116 // metrics the frame was swapped at this point
117 currentFrameInfo->markSwapBuffers();
118
119 *requireSwap = drew || mEglManager.damageRequiresSwap();
120
121 if (*requireSwap && (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty)))) {
122 return false;
123 }
124
125 return *requireSwap;
126}
127
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -0500128bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) {
129 if (!mRenderThread.getGrContext()) {
130 return false;
131 }
132
Chris Craik2f1aaf72017-02-14 13:01:42 -0800133 // acquire most recent buffer for drawing
134 deferredLayer->updateTexImage();
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -0500135 deferredLayer->apply();
136
137 SkCanvas canvas(*bitmap);
138 Layer* layer = deferredLayer->backingLayer();
139 return LayerDrawable::DrawLayer(mRenderThread.getGrContext(), &canvas, layer);
Stan Iliev500a0c32016-10-26 10:30:09 -0400140}
141
sergeyv3e9999b2017-01-19 15:37:02 -0800142static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
143 SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
144 GlLayer* layer = new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha,
145 mode, blend);
146 layer->generateTexture();
147 return layer;
148}
149
Stan Iliev500a0c32016-10-26 10:30:09 -0400150DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() {
151 mEglManager.initialize();
sergeyv3e9999b2017-01-19 15:37:02 -0800152 return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::OpenGL);
Stan Iliev500a0c32016-10-26 10:30:09 -0400153}
154
155void SkiaOpenGLPipeline::onStop() {
156 if (mEglManager.isCurrent(mEglSurface)) {
157 mEglManager.makeCurrent(EGL_NO_SURFACE);
158 }
159}
160
Romain Guy26a2b972017-04-17 09:39:51 -0700161bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
162 ColorMode colorMode) {
Stan Iliev500a0c32016-10-26 10:30:09 -0400163
164 if (mEglSurface != EGL_NO_SURFACE) {
165 mEglManager.destroySurface(mEglSurface);
166 mEglSurface = EGL_NO_SURFACE;
167 }
168
169 if (surface) {
Romain Guy26a2b972017-04-17 09:39:51 -0700170 const bool wideColorGamut = colorMode == ColorMode::WideColorGamut;
171 mEglSurface = mEglManager.createSurface(surface, wideColorGamut);
Stan Iliev500a0c32016-10-26 10:30:09 -0400172 }
173
174 if (mEglSurface != EGL_NO_SURFACE) {
175 const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
176 mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
177 return true;
178 }
179
180 return false;
181}
182
183bool SkiaOpenGLPipeline::isSurfaceReady() {
184 return CC_UNLIKELY(mEglSurface != EGL_NO_SURFACE);
185}
186
187bool SkiaOpenGLPipeline::isContextReady() {
188 return CC_LIKELY(mEglManager.hasEglContext());
189}
190
191void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
192 DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
193 if (thread.eglManager().hasEglContext()) {
194 mode = DrawGlInfo::kModeProcess;
195 }
196
197 (*functor)(mode, nullptr);
198
199 // If there's no context we don't need to reset as there's no gl state to save/restore
200 if (mode != DrawGlInfo::kModeProcessNoContext) {
201 thread.getGrContext()->resetContext();
202 }
203}
204
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400205#define FENCE_TIMEOUT 2000000000
206
207class AutoEglFence {
208public:
209 AutoEglFence(EGLDisplay display)
210 : mDisplay(display) {
211 fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
212 }
213
214 ~AutoEglFence() {
215 if (fence != EGL_NO_SYNC_KHR) {
216 eglDestroySyncKHR(mDisplay, fence);
217 }
218 }
219
220 EGLSyncKHR fence = EGL_NO_SYNC_KHR;
221private:
222 EGLDisplay mDisplay = EGL_NO_DISPLAY;
223};
224
225class AutoEglImage {
226public:
227 AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer)
228 : mDisplay(display) {
229 EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
230 image = eglCreateImageKHR(display, EGL_NO_CONTEXT,
231 EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
232 }
233
234 ~AutoEglImage() {
235 if (image != EGL_NO_IMAGE_KHR) {
236 eglDestroyImageKHR(mDisplay, image);
237 }
238 }
239
240 EGLImageKHR image = EGL_NO_IMAGE_KHR;
241private:
242 EGLDisplay mDisplay = EGL_NO_DISPLAY;
243};
244
245class AutoSkiaGlTexture {
246public:
247 AutoSkiaGlTexture() {
248 glGenTextures(1, &mTexture);
249 glBindTexture(GL_TEXTURE_2D, mTexture);
250 }
251
252 ~AutoSkiaGlTexture() {
253 glDeleteTextures(1, &mTexture);
254 }
255
256private:
257 GLuint mTexture = 0;
258};
259
260sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
261 SkBitmap& skBitmap) {
262 renderThread.eglManager().initialize();
263
264 sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext());
265 const SkImageInfo& info = skBitmap.info();
266 PixelFormat pixelFormat;
267 GLint format, type;
268 bool isSupported = false;
269
270 //TODO: add support for linear blending (when ANDROID_ENABLE_LINEAR_BLENDING is defined)
271 switch (info.colorType()) {
272 case kRGBA_8888_SkColorType:
273 isSupported = true;
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400274 // ARGB_4444 is upconverted to RGBA_8888
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400275 case kARGB_4444_SkColorType:
276 pixelFormat = PIXEL_FORMAT_RGBA_8888;
277 format = GL_RGBA;
278 type = GL_UNSIGNED_BYTE;
279 break;
280 case kRGBA_F16_SkColorType:
281 isSupported = grContext->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig);
282 if (isSupported) {
283 type = GL_HALF_FLOAT;
284 pixelFormat = PIXEL_FORMAT_RGBA_FP16;
285 } else {
286 type = GL_UNSIGNED_BYTE;
287 pixelFormat = PIXEL_FORMAT_RGBA_8888;
288 }
289 format = GL_RGBA;
290 break;
291 case kRGB_565_SkColorType:
292 isSupported = true;
293 pixelFormat = PIXEL_FORMAT_RGB_565;
294 format = GL_RGB;
295 type = GL_UNSIGNED_SHORT_5_6_5;
296 break;
297 case kGray_8_SkColorType:
298 isSupported = true;
299 pixelFormat = PIXEL_FORMAT_RGBA_8888;
300 format = GL_LUMINANCE;
301 type = GL_UNSIGNED_BYTE;
302 break;
303 default:
304 ALOGW("unable to create hardware bitmap of colortype: %d", info.colorType());
305 return nullptr;
306 }
307
Stan Iliev0a3ff952017-07-10 17:04:03 -0400308
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400309 SkBitmap bitmap;
310 if (isSupported) {
311 bitmap = skBitmap;
312 } else {
313 bitmap.allocPixels(SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(),
314 nullptr));
315 bitmap.eraseColor(0);
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400316 if (info.colorType() == kRGBA_F16_SkColorType) {
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400317 // Drawing RGBA_F16 onto ARGB_8888 is not supported
318 skBitmap.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
319 bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
320 } else {
321 SkCanvas canvas(bitmap);
322 canvas.drawBitmap(skBitmap, 0.0f, 0.0f, nullptr);
323 }
324 }
325
326 sp<GraphicBuffer> buffer = new GraphicBuffer(info.width(), info.height(), pixelFormat,
327 GraphicBuffer::USAGE_HW_TEXTURE |
328 GraphicBuffer::USAGE_SW_WRITE_NEVER |
329 GraphicBuffer::USAGE_SW_READ_NEVER,
330 std::string("Bitmap::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) + "]");
331
332 status_t error = buffer->initCheck();
333 if (error < 0) {
334 ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()");
335 return nullptr;
336 }
337
338 //upload the bitmap into a texture
339 EGLDisplay display = eglGetCurrentDisplay();
340 LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY,
341 "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
342 uirenderer::renderthread::EglManager::eglErrorString());
343 // We use an EGLImage to access the content of the GraphicBuffer
344 // The EGL image is later bound to a 2D texture
345 EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer->getNativeBuffer();
346 AutoEglImage autoImage(display, clientBuffer);
347 if (autoImage.image == EGL_NO_IMAGE_KHR) {
348 ALOGW("Could not create EGL image, err =%s",
349 uirenderer::renderthread::EglManager::eglErrorString());
350 return nullptr;
351 }
352 AutoSkiaGlTexture glTexture;
353 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
354 GL_CHECKPOINT(MODERATE);
355
356 // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we provide.
357 // But asynchronous in sense that driver may upload texture onto hardware buffer when we first
358 // use it in drawing
359 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, info.width(), info.height(), format, type,
360 bitmap.getPixels());
361 GL_CHECKPOINT(MODERATE);
362
363 // The fence is used to wait for the texture upload to finish
364 // properly. We cannot rely on glFlush() and glFinish() as
365 // some drivers completely ignore these API calls
366 AutoEglFence autoFence(display);
367 if (autoFence.fence == EGL_NO_SYNC_KHR) {
368 LOG_ALWAYS_FATAL("Could not create sync fence %#x", eglGetError());
369 return nullptr;
370 }
371 // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
372 // pipeline flush (similar to what a glFlush() would do.)
373 EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence,
374 EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
375 if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
376 LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError());
377 return nullptr;
378 }
379
380 grContext->resetContext(kTextureBinding_GrGLBackendState);
381
382 return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info()));
383}
384
Stan Iliev500a0c32016-10-26 10:30:09 -0400385} /* namespace skiapipeline */
386} /* namespace uirenderer */
387} /* namespace android */