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