Bitmap.cpp revision 91d6354cde90b6625d4af6a5d909d886bf602a49
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    case GL_RGB:
110        return PIXEL_FORMAT_RGB_565;
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) {
219        ALOGW("unable to create hardware bitmap of configuration");
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(), 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() || format != PIXEL_FORMAT_RGBA_8888) {
310        return nullptr;
311    }
312    SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
313            kRGBA_8888_SkColorType, kPremul_SkAlphaType);
314    return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
315}
316
317void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) {
318    if (kIndex_8_SkColorType != newInfo.colorType()) {
319        ctable = nullptr;
320    }
321    mRowBytes = rowBytes;
322    if (mColorTable.get() != ctable) {
323        mColorTable.reset(SkSafeRef(ctable));
324    }
325
326    // Need to validate the alpha type to filter against the color type
327    // to prevent things like a non-opaque RGB565 bitmap
328    SkAlphaType alphaType;
329    LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType(
330            newInfo.colorType(), newInfo.alphaType(), &alphaType),
331            "Failed to validate alpha type!");
332
333    // Dirty hack is dirty
334    // TODO: Figure something out here, Skia's current design makes this
335    // really hard to work with. Skia really, really wants immutable objects,
336    // but with the nested-ref-count hackery going on that's just not
337    // feasible without going insane trying to figure it out
338    SkImageInfo* myInfo = const_cast<SkImageInfo*>(&this->info());
339    *myInfo = newInfo;
340    changeAlphaType(alphaType);
341
342    // Docs say to only call this in the ctor, but we're going to call
343    // it anyway even if this isn't always the ctor.
344    // TODO: Fix this too as part of the above TODO
345    setPreLocked(getStorage(), mRowBytes, mColorTable.get());
346}
347
348Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
349            : SkPixelRef(info)
350            , mPixelStorageType(PixelStorageType::Heap) {
351    mPixelStorage.heap.address = address;
352    mPixelStorage.heap.size = size;
353    reconfigure(info, rowBytes, ctable);
354}
355
356Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc,
357                const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
358            : SkPixelRef(info)
359            , mPixelStorageType(PixelStorageType::External) {
360    mPixelStorage.external.address = address;
361    mPixelStorage.external.context = context;
362    mPixelStorage.external.freeFunc = freeFunc;
363    reconfigure(info, rowBytes, ctable);
364}
365
366Bitmap::Bitmap(void* address, int fd, size_t mappedSize,
367                const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
368            : SkPixelRef(info)
369            , mPixelStorageType(PixelStorageType::Ashmem) {
370    mPixelStorage.ashmem.address = address;
371    mPixelStorage.ashmem.fd = fd;
372    mPixelStorage.ashmem.size = mappedSize;
373    reconfigure(info, rowBytes, ctable);
374}
375
376Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info)
377        : SkPixelRef(info)
378        , mPixelStorageType(PixelStorageType::Hardware) {
379    mPixelStorage.hardware.buffer = buffer;
380    buffer->incStrong(buffer);
381    mRowBytes = bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride();
382}
383
384Bitmap::~Bitmap() {
385    switch (mPixelStorageType) {
386    case PixelStorageType::External:
387        mPixelStorage.external.freeFunc(mPixelStorage.external.address,
388                mPixelStorage.external.context);
389        break;
390    case PixelStorageType::Ashmem:
391        munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
392        close(mPixelStorage.ashmem.fd);
393        break;
394    case PixelStorageType::Heap:
395        free(mPixelStorage.heap.address);
396        break;
397    case PixelStorageType::Hardware:
398        auto buffer = mPixelStorage.hardware.buffer;
399        buffer->decStrong(buffer);
400        mPixelStorage.hardware.buffer = nullptr;
401        break;
402
403    }
404
405    if (android::uirenderer::Caches::hasInstance()) {
406        android::uirenderer::Caches::getInstance().textureCache.releaseTexture(getStableID());
407    }
408}
409
410bool Bitmap::hasHardwareMipMap() const {
411    return mHasHardwareMipMap;
412}
413
414void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
415    mHasHardwareMipMap = hasMipMap;
416}
417
418void* Bitmap::getStorage() const {
419    switch (mPixelStorageType) {
420    case PixelStorageType::External:
421        return mPixelStorage.external.address;
422    case PixelStorageType::Ashmem:
423        return mPixelStorage.ashmem.address;
424    case PixelStorageType::Heap:
425        return mPixelStorage.heap.address;
426    case PixelStorageType::Hardware:
427        return nullptr;
428    }
429}
430
431bool Bitmap::onNewLockPixels(LockRec* rec) {
432    rec->fPixels = getStorage();
433    rec->fRowBytes = mRowBytes;
434    rec->fColorTable = mColorTable.get();
435    return true;
436}
437
438size_t Bitmap::getAllocatedSizeInBytes() const {
439    return info().getSafeSize(mRowBytes);
440}
441
442int Bitmap::getAshmemFd() const {
443    switch (mPixelStorageType) {
444    case PixelStorageType::Ashmem:
445        return mPixelStorage.ashmem.fd;
446    default:
447        return -1;
448    }
449}
450
451size_t Bitmap::getAllocationByteCount() const {
452    switch (mPixelStorageType) {
453    case PixelStorageType::Heap:
454        return mPixelStorage.heap.size;
455    default:
456        return rowBytes() * height();
457    }
458}
459
460void Bitmap::reconfigure(const SkImageInfo& info) {
461    reconfigure(info, info.minRowBytes(), nullptr);
462}
463
464void Bitmap::setAlphaType(SkAlphaType alphaType) {
465    if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
466        return;
467    }
468
469    changeAlphaType(alphaType);
470}
471
472void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
473    outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
474    if (isHardware()) {
475        ALOGW("Warning: attempt to read pixels from hardware bitmap, which is very slow operation");
476        outBitmap->allocPixels(info());
477        uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
478        return;
479    }
480    outBitmap->setInfo(info(), rowBytes());
481    outBitmap->setPixelRef(this);
482}
483
484void Bitmap::getSkBitmapForShaders(SkBitmap* outBitmap) {
485    outBitmap->setInfo(info(), rowBytes());
486    outBitmap->setPixelRef(this);
487    outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
488}
489
490void Bitmap::getBounds(SkRect* bounds) const {
491    SkASSERT(bounds);
492    bounds->set(0, 0, SkIntToScalar(info().width()), SkIntToScalar(info().height()));
493}
494
495GraphicBuffer* Bitmap::graphicBuffer() {
496    if (isHardware()) {
497        return mPixelStorage.hardware.buffer;
498    }
499    return nullptr;
500}
501
502} // namespace android
503