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