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