1 /*
2 * Copyright (C) 2015 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 #include "Bitmap.h"
17
18 #include "Caches.h"
19 #include "renderthread/EglManager.h"
20 #include "renderthread/RenderThread.h"
21 #include "renderthread/RenderProxy.h"
22 #include "utils/Color.h"
23
24 #include <sys/mman.h>
25
26 #include <log/log.h>
27 #include <cutils/ashmem.h>
28
29 #include <GLES2/gl2.h>
30 #include <GLES2/gl2ext.h>
31 #include <EGL/egl.h>
32 #include <EGL/eglext.h>
33
34 #include <private/gui/ComposerService.h>
35 #include <binder/IServiceManager.h>
36 #include <ui/PixelFormat.h>
37
38 #include <SkCanvas.h>
39
40 namespace android {
41
computeAllocationSize(size_t rowBytes,int height,size_t * size)42 static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) {
43 int32_t rowBytes32 = SkToS32(rowBytes);
44 int64_t bigSize = (int64_t) height * rowBytes32;
45 if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) {
46 return false; // allocation will be too large
47 }
48
49 *size = sk_64_asS32(bigSize);
50 return true;
51 }
52
53 typedef sk_sp<Bitmap> (*AllocPixeRef)(size_t allocSize, const SkImageInfo& info, size_t rowBytes,
54 SkColorTable* ctable);
55
allocateBitmap(SkBitmap * bitmap,SkColorTable * ctable,AllocPixeRef alloc)56 static sk_sp<Bitmap> allocateBitmap(SkBitmap* bitmap, SkColorTable* ctable, AllocPixeRef alloc) {
57 const SkImageInfo& info = bitmap->info();
58 if (info.colorType() == kUnknown_SkColorType) {
59 LOG_ALWAYS_FATAL("unknown bitmap configuration");
60 return nullptr;
61 }
62
63 size_t size;
64
65 // we must respect the rowBytes value already set on the bitmap instead of
66 // attempting to compute our own.
67 const size_t rowBytes = bitmap->rowBytes();
68 if (!computeAllocationSize(rowBytes, bitmap->height(), &size)) {
69 return nullptr;
70 }
71
72 auto wrapper = alloc(size, info, rowBytes, ctable);
73 if (wrapper) {
74 wrapper->getSkBitmap(bitmap);
75 // since we're already allocated, we lockPixels right away
76 // HeapAllocator behaves this way too
77 bitmap->lockPixels();
78 }
79 return wrapper;
80 }
81
allocateAshmemBitmap(SkBitmap * bitmap,SkColorTable * ctable)82 sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap, SkColorTable* ctable) {
83 return allocateBitmap(bitmap, ctable, &Bitmap::allocateAshmemBitmap);
84 }
85
allocateHeapBitmap(size_t size,const SkImageInfo & info,size_t rowBytes,SkColorTable * ctable)86 static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes,
87 SkColorTable* ctable) {
88 void* addr = calloc(size, 1);
89 if (!addr) {
90 return nullptr;
91 }
92 return sk_sp<Bitmap>(new Bitmap(addr, size, info, rowBytes, ctable));
93 }
94
95 #define FENCE_TIMEOUT 2000000000
96
97 // TODO: handle SRGB sanely
internalFormatToPixelFormat(GLint internalFormat)98 static PixelFormat internalFormatToPixelFormat(GLint internalFormat) {
99 switch (internalFormat) {
100 case GL_LUMINANCE:
101 return PIXEL_FORMAT_RGBA_8888;
102 case GL_SRGB8_ALPHA8:
103 return PIXEL_FORMAT_RGBA_8888;
104 case GL_RGBA:
105 return PIXEL_FORMAT_RGBA_8888;
106 case GL_RGB:
107 return PIXEL_FORMAT_RGB_565;
108 case GL_RGBA16F:
109 return PIXEL_FORMAT_RGBA_FP16;
110 default:
111 LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", internalFormat);
112 return PIXEL_FORMAT_UNKNOWN;
113 }
114 }
115
116 class AutoEglFence {
117 public:
AutoEglFence(EGLDisplay display)118 AutoEglFence(EGLDisplay display)
119 : mDisplay(display) {
120 fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
121 }
122
~AutoEglFence()123 ~AutoEglFence() {
124 if (fence != EGL_NO_SYNC_KHR) {
125 eglDestroySyncKHR(mDisplay, fence);
126 }
127 }
128
129 EGLSyncKHR fence = EGL_NO_SYNC_KHR;
130 private:
131 EGLDisplay mDisplay = EGL_NO_DISPLAY;
132 };
133
134 class AutoEglImage {
135 public:
AutoEglImage(EGLDisplay display,EGLClientBuffer clientBuffer)136 AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer)
137 : mDisplay(display) {
138 EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
139 image = eglCreateImageKHR(display, EGL_NO_CONTEXT,
140 EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
141 }
142
~AutoEglImage()143 ~AutoEglImage() {
144 if (image != EGL_NO_IMAGE_KHR) {
145 eglDestroyImageKHR(mDisplay, image);
146 }
147 }
148
149 EGLImageKHR image = EGL_NO_IMAGE_KHR;
150 private:
151 EGLDisplay mDisplay = EGL_NO_DISPLAY;
152 };
153
154 class AutoGlTexture {
155 public:
AutoGlTexture(uirenderer::Caches & caches)156 AutoGlTexture(uirenderer::Caches& caches)
157 : mCaches(caches) {
158 glGenTextures(1, &mTexture);
159 caches.textureState().bindTexture(mTexture);
160 }
161
~AutoGlTexture()162 ~AutoGlTexture() {
163 mCaches.textureState().deleteTexture(mTexture);
164 }
165
166 private:
167 uirenderer::Caches& mCaches;
168 GLuint mTexture = 0;
169 };
170
uploadBitmapToGraphicBuffer(uirenderer::Caches & caches,SkBitmap & bitmap,GraphicBuffer & buffer,GLint format,GLint type)171 static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bitmap,
172 GraphicBuffer& buffer, GLint format, GLint type) {
173 SkAutoLockPixels alp(bitmap);
174 EGLDisplay display = eglGetCurrentDisplay();
175 LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY,
176 "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
177 uirenderer::renderthread::EglManager::eglErrorString());
178 // We use an EGLImage to access the content of the GraphicBuffer
179 // The EGL image is later bound to a 2D texture
180 EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer.getNativeBuffer();
181 AutoEglImage autoImage(display, clientBuffer);
182 if (autoImage.image == EGL_NO_IMAGE_KHR) {
183 ALOGW("Could not create EGL image, err =%s",
184 uirenderer::renderthread::EglManager::eglErrorString());
185 return false;
186 }
187 AutoGlTexture glTexture(caches);
188 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
189
190 GL_CHECKPOINT(MODERATE);
191
192 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
193 format, type, bitmap.getPixels());
194
195 GL_CHECKPOINT(MODERATE);
196
197 // The fence is used to wait for the texture upload to finish
198 // properly. We cannot rely on glFlush() and glFinish() as
199 // some drivers completely ignore these API calls
200 AutoEglFence autoFence(display);
201 if (autoFence.fence == EGL_NO_SYNC_KHR) {
202 LOG_ALWAYS_FATAL("Could not create sync fence %#x", eglGetError());
203 return false;
204 }
205 // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
206 // pipeline flush (similar to what a glFlush() would do.)
207 EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence,
208 EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
209 if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
210 LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError());
211 return false;
212 }
213 return true;
214 }
215
allocateHardwareBitmap(uirenderer::renderthread::RenderThread & renderThread,SkBitmap & skBitmap)216 sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(uirenderer::renderthread::RenderThread& renderThread,
217 SkBitmap& skBitmap) {
218 renderThread.eglManager().initialize();
219 uirenderer::Caches& caches = uirenderer::Caches::getInstance();
220
221 const SkImageInfo& info = skBitmap.info();
222 if (info.colorType() == kUnknown_SkColorType || info.colorType() == kAlpha_8_SkColorType) {
223 ALOGW("unable to create hardware bitmap of colortype: %d", info.colorType());
224 return nullptr;
225 }
226
227 bool needSRGB = uirenderer::transferFunctionCloseToSRGB(skBitmap.info().colorSpace());
228 bool hasLinearBlending = caches.extensions().hasLinearBlending();
229 GLint format, type, internalFormat;
230 uirenderer::Texture::colorTypeToGlFormatAndType(caches, skBitmap.colorType(),
231 needSRGB && hasLinearBlending, &internalFormat, &format, &type);
232
233 PixelFormat pixelFormat = internalFormatToPixelFormat(internalFormat);
234 sp<GraphicBuffer> buffer = new GraphicBuffer(info.width(), info.height(), pixelFormat,
235 GraphicBuffer::USAGE_HW_TEXTURE |
236 GraphicBuffer::USAGE_SW_WRITE_NEVER |
237 GraphicBuffer::USAGE_SW_READ_NEVER,
238 std::string("Bitmap::allocateHardwareBitmap pid [") + std::to_string(getpid()) + "]");
239
240 status_t error = buffer->initCheck();
241 if (error < 0) {
242 ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()");
243 return nullptr;
244 }
245
246 SkBitmap bitmap;
247 if (CC_UNLIKELY(uirenderer::Texture::hasUnsupportedColorType(skBitmap.info(),
248 hasLinearBlending))) {
249 sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeSRGB();
250 bitmap = uirenderer::Texture::uploadToN32(skBitmap, hasLinearBlending, std::move(sRGB));
251 } else {
252 bitmap = skBitmap;
253 }
254
255 if (!uploadBitmapToGraphicBuffer(caches, bitmap, *buffer, format, type)) {
256 return nullptr;
257 }
258 return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info()));
259 }
260
allocateHardwareBitmap(SkBitmap & bitmap)261 sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(SkBitmap& bitmap) {
262 return uirenderer::renderthread::RenderProxy::allocateHardwareBitmap(bitmap);
263 }
264
allocateHeapBitmap(SkBitmap * bitmap,SkColorTable * ctable)265 sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap, SkColorTable* ctable) {
266 return allocateBitmap(bitmap, ctable, &android::allocateHeapBitmap);
267 }
268
allocateHeapBitmap(const SkImageInfo & info)269 sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) {
270 size_t size;
271 if (!computeAllocationSize(info.minRowBytes(), info.height(), &size)) {
272 LOG_ALWAYS_FATAL("trying to allocate too large bitmap");
273 return nullptr;
274 }
275 return android::allocateHeapBitmap(size, info, info.minRowBytes(), nullptr);
276 }
277
allocateAshmemBitmap(size_t size,const SkImageInfo & info,size_t rowBytes,SkColorTable * ctable)278 sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info,
279 size_t rowBytes, SkColorTable* ctable) {
280 // Create new ashmem region with read/write priv
281 int fd = ashmem_create_region("bitmap", size);
282 if (fd < 0) {
283 return nullptr;
284 }
285
286 void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
287 if (addr == MAP_FAILED) {
288 close(fd);
289 return nullptr;
290 }
291
292 if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
293 munmap(addr, size);
294 close(fd);
295 return nullptr;
296 }
297 return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes, ctable));
298 }
299
FreePixelRef(void * addr,void * context)300 void FreePixelRef(void* addr, void* context) {
301 auto pixelRef = (SkPixelRef*) context;
302 pixelRef->unlockPixels();
303 pixelRef->unref();
304 }
305
createFrom(const SkImageInfo & info,SkPixelRef & pixelRef)306 sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) {
307 pixelRef.ref();
308 pixelRef.lockPixels();
309 return sk_sp<Bitmap>(new Bitmap((void*) pixelRef.pixels(), (void*) &pixelRef, FreePixelRef,
310 info, pixelRef.rowBytes(), pixelRef.colorTable()));
311 }
312
createFrom(sp<GraphicBuffer> graphicBuffer)313 sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) {
314 PixelFormat format = graphicBuffer->getPixelFormat();
315 if (!graphicBuffer.get() ||
316 (format != PIXEL_FORMAT_RGBA_8888 && format != PIXEL_FORMAT_RGBA_FP16)) {
317 return nullptr;
318 }
319 SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
320 kRGBA_8888_SkColorType, kPremul_SkAlphaType,
321 SkColorSpace::MakeSRGB());
322 return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
323 }
324
setColorSpace(sk_sp<SkColorSpace> colorSpace)325 void Bitmap::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
326 // TODO: See todo in reconfigure() below
327 SkImageInfo* myInfo = const_cast<SkImageInfo*>(&this->info());
328 *myInfo = info().makeColorSpace(std::move(colorSpace));
329 }
330
reconfigure(const SkImageInfo & newInfo,size_t rowBytes,SkColorTable * ctable)331 void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) {
332 if (kIndex_8_SkColorType != newInfo.colorType()) {
333 ctable = nullptr;
334 }
335 mRowBytes = rowBytes;
336 if (mColorTable.get() != ctable) {
337 mColorTable.reset(SkSafeRef(ctable));
338 }
339
340 // Need to validate the alpha type to filter against the color type
341 // to prevent things like a non-opaque RGB565 bitmap
342 SkAlphaType alphaType;
343 LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType(
344 newInfo.colorType(), newInfo.alphaType(), &alphaType),
345 "Failed to validate alpha type!");
346
347 // Dirty hack is dirty
348 // TODO: Figure something out here, Skia's current design makes this
349 // really hard to work with. Skia really, really wants immutable objects,
350 // but with the nested-ref-count hackery going on that's just not
351 // feasible without going insane trying to figure it out
352 SkImageInfo* myInfo = const_cast<SkImageInfo*>(&this->info());
353 *myInfo = newInfo;
354 changeAlphaType(alphaType);
355
356 // Docs say to only call this in the ctor, but we're going to call
357 // it anyway even if this isn't always the ctor.
358 // TODO: Fix this too as part of the above TODO
359 setPreLocked(getStorage(), mRowBytes, mColorTable.get());
360 }
361
Bitmap(void * address,size_t size,const SkImageInfo & info,size_t rowBytes,SkColorTable * ctable)362 Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
363 : SkPixelRef(info)
364 , mPixelStorageType(PixelStorageType::Heap) {
365 mPixelStorage.heap.address = address;
366 mPixelStorage.heap.size = size;
367 reconfigure(info, rowBytes, ctable);
368 }
369
Bitmap(void * address,void * context,FreeFunc freeFunc,const SkImageInfo & info,size_t rowBytes,SkColorTable * ctable)370 Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc,
371 const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
372 : SkPixelRef(info)
373 , mPixelStorageType(PixelStorageType::External) {
374 mPixelStorage.external.address = address;
375 mPixelStorage.external.context = context;
376 mPixelStorage.external.freeFunc = freeFunc;
377 reconfigure(info, rowBytes, ctable);
378 }
379
Bitmap(void * address,int fd,size_t mappedSize,const SkImageInfo & info,size_t rowBytes,SkColorTable * ctable)380 Bitmap::Bitmap(void* address, int fd, size_t mappedSize,
381 const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
382 : SkPixelRef(info)
383 , mPixelStorageType(PixelStorageType::Ashmem) {
384 mPixelStorage.ashmem.address = address;
385 mPixelStorage.ashmem.fd = fd;
386 mPixelStorage.ashmem.size = mappedSize;
387 reconfigure(info, rowBytes, ctable);
388 }
389
Bitmap(GraphicBuffer * buffer,const SkImageInfo & info)390 Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info)
391 : SkPixelRef(info)
392 , mPixelStorageType(PixelStorageType::Hardware) {
393 mPixelStorage.hardware.buffer = buffer;
394 buffer->incStrong(buffer);
395 mRowBytes = bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride();
396 }
397
~Bitmap()398 Bitmap::~Bitmap() {
399 switch (mPixelStorageType) {
400 case PixelStorageType::External:
401 mPixelStorage.external.freeFunc(mPixelStorage.external.address,
402 mPixelStorage.external.context);
403 break;
404 case PixelStorageType::Ashmem:
405 munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
406 close(mPixelStorage.ashmem.fd);
407 break;
408 case PixelStorageType::Heap:
409 free(mPixelStorage.heap.address);
410 break;
411 case PixelStorageType::Hardware:
412 auto buffer = mPixelStorage.hardware.buffer;
413 buffer->decStrong(buffer);
414 mPixelStorage.hardware.buffer = nullptr;
415 break;
416
417 }
418
419 android::uirenderer::renderthread::RenderProxy::onBitmapDestroyed(getStableID());
420 }
421
hasHardwareMipMap() const422 bool Bitmap::hasHardwareMipMap() const {
423 return mHasHardwareMipMap;
424 }
425
setHasHardwareMipMap(bool hasMipMap)426 void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
427 mHasHardwareMipMap = hasMipMap;
428 }
429
getStorage() const430 void* Bitmap::getStorage() const {
431 switch (mPixelStorageType) {
432 case PixelStorageType::External:
433 return mPixelStorage.external.address;
434 case PixelStorageType::Ashmem:
435 return mPixelStorage.ashmem.address;
436 case PixelStorageType::Heap:
437 return mPixelStorage.heap.address;
438 case PixelStorageType::Hardware:
439 return nullptr;
440 }
441 }
442
onNewLockPixels(LockRec * rec)443 bool Bitmap::onNewLockPixels(LockRec* rec) {
444 rec->fPixels = getStorage();
445 rec->fRowBytes = mRowBytes;
446 rec->fColorTable = mColorTable.get();
447 return true;
448 }
449
getAllocatedSizeInBytes() const450 size_t Bitmap::getAllocatedSizeInBytes() const {
451 return info().getSafeSize(mRowBytes);
452 }
453
getAshmemFd() const454 int Bitmap::getAshmemFd() const {
455 switch (mPixelStorageType) {
456 case PixelStorageType::Ashmem:
457 return mPixelStorage.ashmem.fd;
458 default:
459 return -1;
460 }
461 }
462
getAllocationByteCount() const463 size_t Bitmap::getAllocationByteCount() const {
464 switch (mPixelStorageType) {
465 case PixelStorageType::Heap:
466 return mPixelStorage.heap.size;
467 default:
468 return rowBytes() * height();
469 }
470 }
471
reconfigure(const SkImageInfo & info)472 void Bitmap::reconfigure(const SkImageInfo& info) {
473 reconfigure(info, info.minRowBytes(), nullptr);
474 }
475
setAlphaType(SkAlphaType alphaType)476 void Bitmap::setAlphaType(SkAlphaType alphaType) {
477 if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
478 return;
479 }
480
481 changeAlphaType(alphaType);
482 }
483
getSkBitmap(SkBitmap * outBitmap)484 void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
485 outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
486 if (isHardware()) {
487 if (uirenderer::Properties::isSkiaEnabled()) {
488 // TODO: add color correctness for Skia pipeline - pass null color space for now
489 outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(),
490 info().colorType(), info().alphaType(), nullptr));
491 } else {
492 outBitmap->allocPixels(info());
493 }
494 uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
495 return;
496 }
497 outBitmap->setInfo(info(), rowBytes());
498 outBitmap->setPixelRef(this);
499 }
500
getSkBitmapForShaders(SkBitmap * outBitmap)501 void Bitmap::getSkBitmapForShaders(SkBitmap* outBitmap) {
502 if (isHardware() && uirenderer::Properties::isSkiaEnabled()) {
503 getSkBitmap(outBitmap);
504 } else {
505 outBitmap->setInfo(info(), rowBytes());
506 outBitmap->setPixelRef(this);
507 outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
508 }
509 }
510
getBounds(SkRect * bounds) const511 void Bitmap::getBounds(SkRect* bounds) const {
512 SkASSERT(bounds);
513 bounds->set(0, 0, SkIntToScalar(info().width()), SkIntToScalar(info().height()));
514 }
515
graphicBuffer()516 GraphicBuffer* Bitmap::graphicBuffer() {
517 if (isHardware()) {
518 return mPixelStorage.hardware.buffer;
519 }
520 return nullptr;
521 }
522
523 } // namespace android
524