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