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