Bitmap.cpp revision 6f773a0d8717162f81ff21d943baaa539a2d6c7e
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
155static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bitmap,
156        GraphicBuffer& buffer, GLint format, GLint type) {
157    SkAutoLockPixels alp(bitmap);
158    EGLDisplay display = eglGetCurrentDisplay();
159    LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY,
160                "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
161                uirenderer::renderthread::EglManager::eglErrorString());
162    // These objects are initialized below but the default "null"
163    // values are used to cleanup properly at any point in the
164    // initialization sequenc
165    GLuint texture = 0;
166    // We use an EGLImage to access the content of the GraphicBuffer
167    // The EGL image is later bound to a 2D texture
168    EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer.getNativeBuffer();
169    AutoEglImage autoImage(display, clientBuffer);
170    if (autoImage.image == EGL_NO_IMAGE_KHR) {
171        ALOGW("Could not create EGL image, err =%s",
172                uirenderer::renderthread::EglManager::eglErrorString());
173        return false;
174    }
175    glGenTextures(1, &texture);
176    caches.textureState().bindTexture(texture);
177    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
178
179    GL_CHECKPOINT(MODERATE);
180
181    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
182            format, type, bitmap.getPixels());
183
184    GL_CHECKPOINT(MODERATE);
185
186    // The fence is used to wait for the texture upload to finish
187    // properly. We cannot rely on glFlush() and glFinish() as
188    // some drivers completely ignore these API calls
189    AutoEglFence autoFence(display);
190    if (autoFence.fence == EGL_NO_SYNC_KHR) {
191        LOG_ALWAYS_FATAL("Could not create sync fence %#x", eglGetError());
192        return false;
193    }
194    // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
195    // pipeline flush (similar to what a glFlush() would do.)
196    EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence,
197            EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
198    if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
199        LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError());
200        return false;
201    }
202    return true;
203}
204
205sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(uirenderer::renderthread::RenderThread& renderThread,
206        SkBitmap& skBitmap) {
207    renderThread.eglManager().initialize();
208    uirenderer::Caches& caches = uirenderer::Caches::getInstance();
209
210    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
211    sp<IGraphicBufferAlloc> alloc(composer->createGraphicBufferAlloc());
212    if (alloc == NULL) {
213        ALOGW("createGraphicBufferAlloc() failed in GraphicBuffer.create()");
214        return nullptr;
215    }
216
217    const SkImageInfo& info = skBitmap.info();
218    if (info.colorType() == kUnknown_SkColorType || info.colorType() == kAlpha_8_SkColorType) {
219        ALOGW("unable to create hardware bitmap of colortype: %d", info.colorType());
220        return nullptr;
221    }
222
223    sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
224    bool needSRGB = skBitmap.info().colorSpace() == sRGB.get();
225    bool hasSRGB = caches.extensions().hasSRGB();
226    GLint format, type, internalFormat;
227    uirenderer::Texture::colorTypeToGlFormatAndType(caches, skBitmap.colorType(),
228            needSRGB, &internalFormat, &format, &type);
229
230    PixelFormat pixelFormat = internalFormatToPixelFormat(internalFormat);
231    status_t error;
232    sp<GraphicBuffer> buffer = alloc->createGraphicBuffer(info.width(), info.height(), pixelFormat,
233            1, GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER
234            | GraphicBuffer::USAGE_SW_READ_NEVER , &error);
235
236    if (!buffer.get()) {
237        ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()");
238        return nullptr;
239    }
240
241    SkBitmap bitmap;
242    if (CC_UNLIKELY(uirenderer::Texture::hasUnsupportedColorType(skBitmap.info(),
243            hasSRGB, sRGB.get()))) {
244        bitmap = uirenderer::Texture::uploadToN32(skBitmap, hasSRGB, std::move(sRGB));
245    } else {
246        bitmap = skBitmap;
247    }
248
249    if (!uploadBitmapToGraphicBuffer(caches, bitmap, *buffer, format, type)) {
250        return nullptr;
251    }
252    return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info()));
253}
254
255sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(SkBitmap& bitmap) {
256    return uirenderer::renderthread::RenderProxy::allocateHardwareBitmap(bitmap);
257}
258
259sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap, SkColorTable* ctable) {
260   return allocateBitmap(bitmap, ctable, &android::allocateHeapBitmap);
261}
262
263sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) {
264    size_t size;
265    if (!computeAllocationSize(info.minRowBytes(), info.height(), &size)) {
266        LOG_ALWAYS_FATAL("trying to allocate too large bitmap");
267        return nullptr;
268    }
269    return android::allocateHeapBitmap(size, info, info.minRowBytes(), nullptr);
270}
271
272sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info,
273        size_t rowBytes, SkColorTable* ctable) {
274    // Create new ashmem region with read/write priv
275    int fd = ashmem_create_region("bitmap", size);
276    if (fd < 0) {
277        return nullptr;
278    }
279
280    void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
281    if (addr == MAP_FAILED) {
282        close(fd);
283        return nullptr;
284    }
285
286    if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
287        munmap(addr, size);
288        close(fd);
289        return nullptr;
290    }
291    return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes, ctable));
292}
293
294void FreePixelRef(void* addr, void* context) {
295    auto pixelRef = (SkPixelRef*) context;
296    pixelRef->unlockPixels();
297    pixelRef->unref();
298}
299
300sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) {
301    pixelRef.ref();
302    pixelRef.lockPixels();
303    return sk_sp<Bitmap>(new Bitmap((void*) pixelRef.pixels(), (void*) &pixelRef, FreePixelRef,
304            info, pixelRef.rowBytes(), pixelRef.colorTable()));
305}
306
307sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) {
308    PixelFormat format = graphicBuffer->getPixelFormat();
309    if (!graphicBuffer.get() ||
310            (format != PIXEL_FORMAT_RGBA_8888 && format != PIXEL_FORMAT_RGBA_FP16)) {
311        return nullptr;
312    }
313    SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
314            kRGBA_8888_SkColorType, kPremul_SkAlphaType,
315            SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named));
316    return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
317}
318
319void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) {
320    if (kIndex_8_SkColorType != newInfo.colorType()) {
321        ctable = nullptr;
322    }
323    mRowBytes = rowBytes;
324    if (mColorTable.get() != ctable) {
325        mColorTable.reset(SkSafeRef(ctable));
326    }
327
328    // Need to validate the alpha type to filter against the color type
329    // to prevent things like a non-opaque RGB565 bitmap
330    SkAlphaType alphaType;
331    LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType(
332            newInfo.colorType(), newInfo.alphaType(), &alphaType),
333            "Failed to validate alpha type!");
334
335    // Dirty hack is dirty
336    // TODO: Figure something out here, Skia's current design makes this
337    // really hard to work with. Skia really, really wants immutable objects,
338    // but with the nested-ref-count hackery going on that's just not
339    // feasible without going insane trying to figure it out
340    SkImageInfo* myInfo = const_cast<SkImageInfo*>(&this->info());
341    *myInfo = newInfo;
342    changeAlphaType(alphaType);
343
344    // Docs say to only call this in the ctor, but we're going to call
345    // it anyway even if this isn't always the ctor.
346    // TODO: Fix this too as part of the above TODO
347    setPreLocked(getStorage(), mRowBytes, mColorTable.get());
348}
349
350Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
351            : SkPixelRef(info)
352            , mPixelStorageType(PixelStorageType::Heap) {
353    mPixelStorage.heap.address = address;
354    mPixelStorage.heap.size = size;
355    reconfigure(info, rowBytes, ctable);
356}
357
358Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc,
359                const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
360            : SkPixelRef(info)
361            , mPixelStorageType(PixelStorageType::External) {
362    mPixelStorage.external.address = address;
363    mPixelStorage.external.context = context;
364    mPixelStorage.external.freeFunc = freeFunc;
365    reconfigure(info, rowBytes, ctable);
366}
367
368Bitmap::Bitmap(void* address, int fd, size_t mappedSize,
369                const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
370            : SkPixelRef(info)
371            , mPixelStorageType(PixelStorageType::Ashmem) {
372    mPixelStorage.ashmem.address = address;
373    mPixelStorage.ashmem.fd = fd;
374    mPixelStorage.ashmem.size = mappedSize;
375    reconfigure(info, rowBytes, ctable);
376}
377
378Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info)
379        : SkPixelRef(info)
380        , mPixelStorageType(PixelStorageType::Hardware) {
381    mPixelStorage.hardware.buffer = buffer;
382    buffer->incStrong(buffer);
383    mRowBytes = bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride();
384}
385
386Bitmap::~Bitmap() {
387    switch (mPixelStorageType) {
388    case PixelStorageType::External:
389        mPixelStorage.external.freeFunc(mPixelStorage.external.address,
390                mPixelStorage.external.context);
391        break;
392    case PixelStorageType::Ashmem:
393        munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
394        close(mPixelStorage.ashmem.fd);
395        break;
396    case PixelStorageType::Heap:
397        free(mPixelStorage.heap.address);
398        break;
399    case PixelStorageType::Hardware:
400        auto buffer = mPixelStorage.hardware.buffer;
401        buffer->decStrong(buffer);
402        mPixelStorage.hardware.buffer = nullptr;
403        break;
404
405    }
406
407    if (android::uirenderer::Caches::hasInstance()) {
408        android::uirenderer::Caches::getInstance().textureCache.releaseTexture(getStableID());
409    }
410}
411
412bool Bitmap::hasHardwareMipMap() const {
413    return mHasHardwareMipMap;
414}
415
416void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
417    mHasHardwareMipMap = hasMipMap;
418}
419
420void* Bitmap::getStorage() const {
421    switch (mPixelStorageType) {
422    case PixelStorageType::External:
423        return mPixelStorage.external.address;
424    case PixelStorageType::Ashmem:
425        return mPixelStorage.ashmem.address;
426    case PixelStorageType::Heap:
427        return mPixelStorage.heap.address;
428    case PixelStorageType::Hardware:
429        return nullptr;
430    }
431}
432
433bool Bitmap::onNewLockPixels(LockRec* rec) {
434    rec->fPixels = getStorage();
435    rec->fRowBytes = mRowBytes;
436    rec->fColorTable = mColorTable.get();
437    return true;
438}
439
440size_t Bitmap::getAllocatedSizeInBytes() const {
441    return info().getSafeSize(mRowBytes);
442}
443
444int Bitmap::getAshmemFd() const {
445    switch (mPixelStorageType) {
446    case PixelStorageType::Ashmem:
447        return mPixelStorage.ashmem.fd;
448    default:
449        return -1;
450    }
451}
452
453size_t Bitmap::getAllocationByteCount() const {
454    switch (mPixelStorageType) {
455    case PixelStorageType::Heap:
456        return mPixelStorage.heap.size;
457    default:
458        return rowBytes() * height();
459    }
460}
461
462void Bitmap::reconfigure(const SkImageInfo& info) {
463    reconfigure(info, info.minRowBytes(), nullptr);
464}
465
466void Bitmap::setAlphaType(SkAlphaType alphaType) {
467    if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
468        return;
469    }
470
471    changeAlphaType(alphaType);
472}
473
474void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
475    outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
476    if (isHardware()) {
477        ALOGW("Warning: attempt to read pixels from hardware bitmap, which is very slow operation");
478        outBitmap->allocPixels(info());
479        uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
480        return;
481    }
482    outBitmap->setInfo(info(), rowBytes());
483    outBitmap->setPixelRef(this);
484}
485
486void Bitmap::getSkBitmapForShaders(SkBitmap* outBitmap) {
487    outBitmap->setInfo(info(), rowBytes());
488    outBitmap->setPixelRef(this);
489    outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
490}
491
492void Bitmap::getBounds(SkRect* bounds) const {
493    SkASSERT(bounds);
494    bounds->set(0, 0, SkIntToScalar(info().width()), SkIntToScalar(info().height()));
495}
496
497GraphicBuffer* Bitmap::graphicBuffer() {
498    if (isHardware()) {
499        return mPixelStorage.hardware.buffer;
500    }
501    return nullptr;
502}
503
504} // namespace android
505