Bitmap.cpp revision 89ddb1f1644e0b47de060d2c9aaf6d5387c38f2f
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 <gui/IGraphicBufferAlloc.h>
34#include <gui/ISurfaceComposer.h>
35#include <private/gui/ComposerService.h>
36#include <binder/IServiceManager.h>
37#include <ui/PixelFormat.h>
38
39#include <SkCanvas.h>
40
41namespace android {
42
43static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) {
44    int32_t rowBytes32 = SkToS32(rowBytes);
45    int64_t bigSize = (int64_t) height * rowBytes32;
46    if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) {
47        return false; // allocation will be too large
48    }
49
50    *size = sk_64_asS32(bigSize);
51    return true;
52}
53
54typedef sk_sp<Bitmap> (*AllocPixeRef)(size_t allocSize, const SkImageInfo& info, size_t rowBytes,
55        SkColorTable* ctable);
56
57static sk_sp<Bitmap> allocateBitmap(SkBitmap* bitmap, SkColorTable* ctable, AllocPixeRef alloc) {
58    const SkImageInfo& info = bitmap->info();
59    if (info.colorType() == kUnknown_SkColorType) {
60        LOG_ALWAYS_FATAL("unknown bitmap configuration");
61        return nullptr;
62    }
63
64    size_t size;
65
66    // we must respect the rowBytes value already set on the bitmap instead of
67    // attempting to compute our own.
68    const size_t rowBytes = bitmap->rowBytes();
69    if (!computeAllocationSize(rowBytes, bitmap->height(), &size)) {
70        return nullptr;
71    }
72
73    auto wrapper = alloc(size, info, rowBytes, ctable);
74    if (wrapper) {
75        wrapper->getSkBitmap(bitmap);
76        // since we're already allocated, we lockPixels right away
77        // HeapAllocator behaves this way too
78        bitmap->lockPixels();
79    }
80    return wrapper;
81}
82
83sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap, SkColorTable* ctable) {
84   return allocateBitmap(bitmap, ctable, &Bitmap::allocateAshmemBitmap);
85}
86
87static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes,
88        SkColorTable* ctable) {
89    void* addr = calloc(size, 1);
90    if (!addr) {
91        return nullptr;
92    }
93    return sk_sp<Bitmap>(new Bitmap(addr, size, info, rowBytes, ctable));
94}
95
96#define FENCE_TIMEOUT 2000000000
97
98// TODO: handle SRGB sanely
99static PixelFormat internalFormatToPixelFormat(GLint internalFormat) {
100    switch (internalFormat) {
101    case GL_LUMINANCE:
102        return PIXEL_FORMAT_RGBA_8888;
103    case GL_SRGB8_ALPHA8:
104        return PIXEL_FORMAT_RGBA_8888;
105    case GL_RGBA:
106        return PIXEL_FORMAT_RGBA_8888;
107    case GL_RGB:
108        return PIXEL_FORMAT_RGB_565;
109    case GL_RGBA16F:
110        return PIXEL_FORMAT_RGBA_FP16;
111    default:
112        LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", internalFormat);
113        return PIXEL_FORMAT_UNKNOWN;
114    }
115}
116
117class AutoEglFence {
118public:
119    AutoEglFence(EGLDisplay display)
120            : mDisplay(display) {
121        fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
122    }
123
124    ~AutoEglFence() {
125        if (fence != EGL_NO_SYNC_KHR) {
126            eglDestroySyncKHR(mDisplay, fence);
127        }
128    }
129
130    EGLSyncKHR fence = EGL_NO_SYNC_KHR;
131private:
132    EGLDisplay mDisplay = EGL_NO_DISPLAY;
133};
134
135class AutoEglImage {
136public:
137    AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer)
138            : mDisplay(display) {
139        EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
140        image = eglCreateImageKHR(display, EGL_NO_CONTEXT,
141                EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
142    }
143
144    ~AutoEglImage() {
145        if (image != EGL_NO_IMAGE_KHR) {
146            eglDestroyImageKHR(mDisplay, image);
147        }
148    }
149
150    EGLImageKHR image = EGL_NO_IMAGE_KHR;
151private:
152    EGLDisplay mDisplay = EGL_NO_DISPLAY;
153};
154
155class AutoGlTexture {
156public:
157    AutoGlTexture(uirenderer::Caches& caches)
158            : mCaches(caches) {
159        glGenTextures(1, &mTexture);
160        caches.textureState().bindTexture(mTexture);
161    }
162
163    ~AutoGlTexture() {
164        mCaches.textureState().deleteTexture(mTexture);
165    }
166
167private:
168    uirenderer::Caches& mCaches;
169    GLuint mTexture = 0;
170};
171
172static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bitmap,
173        GraphicBuffer& buffer, GLint format, GLint type) {
174    SkAutoLockPixels alp(bitmap);
175    EGLDisplay display = eglGetCurrentDisplay();
176    LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY,
177                "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
178                uirenderer::renderthread::EglManager::eglErrorString());
179    // We use an EGLImage to access the content of the GraphicBuffer
180    // The EGL image is later bound to a 2D texture
181    EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer.getNativeBuffer();
182    AutoEglImage autoImage(display, clientBuffer);
183    if (autoImage.image == EGL_NO_IMAGE_KHR) {
184        ALOGW("Could not create EGL image, err =%s",
185                uirenderer::renderthread::EglManager::eglErrorString());
186        return false;
187    }
188    AutoGlTexture glTexture(caches);
189    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
190
191    GL_CHECKPOINT(MODERATE);
192
193    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
194            format, type, bitmap.getPixels());
195
196    GL_CHECKPOINT(MODERATE);
197
198    // The fence is used to wait for the texture upload to finish
199    // properly. We cannot rely on glFlush() and glFinish() as
200    // some drivers completely ignore these API calls
201    AutoEglFence autoFence(display);
202    if (autoFence.fence == EGL_NO_SYNC_KHR) {
203        LOG_ALWAYS_FATAL("Could not create sync fence %#x", eglGetError());
204        return false;
205    }
206    // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
207    // pipeline flush (similar to what a glFlush() would do.)
208    EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence,
209            EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
210    if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
211        LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError());
212        return false;
213    }
214    return true;
215}
216
217sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(uirenderer::renderthread::RenderThread& renderThread,
218        SkBitmap& skBitmap) {
219    renderThread.eglManager().initialize();
220    uirenderer::Caches& caches = uirenderer::Caches::getInstance();
221
222    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
223    sp<IGraphicBufferAlloc> alloc(composer->createGraphicBufferAlloc());
224    if (alloc == NULL) {
225        ALOGW("createGraphicBufferAlloc() failed in GraphicBuffer.create()");
226        return nullptr;
227    }
228
229    const SkImageInfo& info = skBitmap.info();
230    if (info.colorType() == kUnknown_SkColorType || info.colorType() == kAlpha_8_SkColorType) {
231        ALOGW("unable to create hardware bitmap of colortype: %d", info.colorType());
232        return nullptr;
233    }
234
235    sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeSRGB();
236    bool needSRGB = skBitmap.info().colorSpace() == sRGB.get();
237    bool hasSRGB = caches.extensions().hasSRGB();
238    GLint format, type, internalFormat;
239    uirenderer::Texture::colorTypeToGlFormatAndType(caches, skBitmap.colorType(),
240            needSRGB, &internalFormat, &format, &type);
241
242    PixelFormat pixelFormat = internalFormatToPixelFormat(internalFormat);
243    status_t error;
244    sp<GraphicBuffer> buffer = alloc->createGraphicBuffer(info.width(), info.height(), pixelFormat,
245            1, GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER
246            | GraphicBuffer::USAGE_SW_READ_NEVER , &error);
247
248    if (!buffer.get()) {
249        ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()");
250        return nullptr;
251    }
252
253    SkBitmap bitmap;
254    if (CC_UNLIKELY(uirenderer::Texture::hasUnsupportedColorType(skBitmap.info(),
255            hasSRGB, sRGB.get()))) {
256        bitmap = uirenderer::Texture::uploadToN32(skBitmap, hasSRGB, std::move(sRGB));
257    } else {
258        bitmap = skBitmap;
259    }
260
261    if (!uploadBitmapToGraphicBuffer(caches, bitmap, *buffer, format, type)) {
262        return nullptr;
263    }
264    return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info()));
265}
266
267sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(SkBitmap& bitmap) {
268    return uirenderer::renderthread::RenderProxy::allocateHardwareBitmap(bitmap);
269}
270
271sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap, SkColorTable* ctable) {
272   return allocateBitmap(bitmap, ctable, &android::allocateHeapBitmap);
273}
274
275sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) {
276    size_t size;
277    if (!computeAllocationSize(info.minRowBytes(), info.height(), &size)) {
278        LOG_ALWAYS_FATAL("trying to allocate too large bitmap");
279        return nullptr;
280    }
281    return android::allocateHeapBitmap(size, info, info.minRowBytes(), nullptr);
282}
283
284sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info,
285        size_t rowBytes, SkColorTable* ctable) {
286    // Create new ashmem region with read/write priv
287    int fd = ashmem_create_region("bitmap", size);
288    if (fd < 0) {
289        return nullptr;
290    }
291
292    void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
293    if (addr == MAP_FAILED) {
294        close(fd);
295        return nullptr;
296    }
297
298    if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
299        munmap(addr, size);
300        close(fd);
301        return nullptr;
302    }
303    return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes, ctable));
304}
305
306void FreePixelRef(void* addr, void* context) {
307    auto pixelRef = (SkPixelRef*) context;
308    pixelRef->unlockPixels();
309    pixelRef->unref();
310}
311
312sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) {
313    pixelRef.ref();
314    pixelRef.lockPixels();
315    return sk_sp<Bitmap>(new Bitmap((void*) pixelRef.pixels(), (void*) &pixelRef, FreePixelRef,
316            info, pixelRef.rowBytes(), pixelRef.colorTable()));
317}
318
319sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) {
320    PixelFormat format = graphicBuffer->getPixelFormat();
321    if (!graphicBuffer.get() ||
322            (format != PIXEL_FORMAT_RGBA_8888 && format != PIXEL_FORMAT_RGBA_FP16)) {
323        return nullptr;
324    }
325    SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
326            kRGBA_8888_SkColorType, kPremul_SkAlphaType,
327            SkColorSpace::MakeSRGB());
328    return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
329}
330
331void 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
362Bitmap::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
370Bitmap::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
380Bitmap::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
390Bitmap::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
398Bitmap::~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    if (android::uirenderer::Caches::hasInstance()) {
420        android::uirenderer::Caches::getInstance().textureCache.releaseTexture(getStableID());
421    }
422}
423
424bool Bitmap::hasHardwareMipMap() const {
425    return mHasHardwareMipMap;
426}
427
428void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
429    mHasHardwareMipMap = hasMipMap;
430}
431
432void* Bitmap::getStorage() const {
433    switch (mPixelStorageType) {
434    case PixelStorageType::External:
435        return mPixelStorage.external.address;
436    case PixelStorageType::Ashmem:
437        return mPixelStorage.ashmem.address;
438    case PixelStorageType::Heap:
439        return mPixelStorage.heap.address;
440    case PixelStorageType::Hardware:
441        return nullptr;
442    }
443}
444
445bool Bitmap::onNewLockPixels(LockRec* rec) {
446    rec->fPixels = getStorage();
447    rec->fRowBytes = mRowBytes;
448    rec->fColorTable = mColorTable.get();
449    return true;
450}
451
452size_t Bitmap::getAllocatedSizeInBytes() const {
453    return info().getSafeSize(mRowBytes);
454}
455
456int Bitmap::getAshmemFd() const {
457    switch (mPixelStorageType) {
458    case PixelStorageType::Ashmem:
459        return mPixelStorage.ashmem.fd;
460    default:
461        return -1;
462    }
463}
464
465size_t Bitmap::getAllocationByteCount() const {
466    switch (mPixelStorageType) {
467    case PixelStorageType::Heap:
468        return mPixelStorage.heap.size;
469    default:
470        return rowBytes() * height();
471    }
472}
473
474void Bitmap::reconfigure(const SkImageInfo& info) {
475    reconfigure(info, info.minRowBytes(), nullptr);
476}
477
478void Bitmap::setAlphaType(SkAlphaType alphaType) {
479    if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
480        return;
481    }
482
483    changeAlphaType(alphaType);
484}
485
486void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
487    outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
488    if (isHardware()) {
489        ALOGW("Warning: attempt to read pixels from hardware bitmap, which is very slow operation");
490        outBitmap->allocPixels(info());
491        uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
492        return;
493    }
494    outBitmap->setInfo(info(), rowBytes());
495    outBitmap->setPixelRef(this);
496}
497
498void Bitmap::getSkBitmapForShaders(SkBitmap* outBitmap) {
499    outBitmap->setInfo(info(), rowBytes());
500    outBitmap->setPixelRef(this);
501    outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
502}
503
504void Bitmap::getBounds(SkRect* bounds) const {
505    SkASSERT(bounds);
506    bounds->set(0, 0, SkIntToScalar(info().width()), SkIntToScalar(info().height()));
507}
508
509GraphicBuffer* Bitmap::graphicBuffer() {
510    if (isHardware()) {
511        return mPixelStorage.hardware.buffer;
512    }
513    return nullptr;
514}
515
516} // namespace android
517