Home | History | Annotate | Download | only in hwui
      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/RenderProxy.h"
     21 #include "renderthread/RenderThread.h"
     22 #include "utils/Color.h"
     23 
     24 #include <sys/mman.h>
     25 
     26 #include <cutils/ashmem.h>
     27 #include <log/log.h>
     28 
     29 #include <binder/IServiceManager.h>
     30 #include <private/gui/ComposerService.h>
     31 #include <ui/PixelFormat.h>
     32 
     33 #include <SkCanvas.h>
     34 #include <SkImagePriv.h>
     35 #include <SkToSRGBColorFilter.h>
     36 
     37 namespace android {
     38 
     39 static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) {
     40     int32_t rowBytes32 = SkToS32(rowBytes);
     41     int64_t bigSize = (int64_t)height * rowBytes32;
     42     if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) {
     43         return false;  // allocation will be too large
     44     }
     45 
     46     *size = sk_64_asS32(bigSize);
     47     return true;
     48 }
     49 
     50 typedef sk_sp<Bitmap> (*AllocPixelRef)(size_t allocSize, const SkImageInfo& info, size_t rowBytes);
     51 
     52 static sk_sp<Bitmap> allocateBitmap(SkBitmap* bitmap, AllocPixelRef alloc) {
     53     const SkImageInfo& info = bitmap->info();
     54     if (info.colorType() == kUnknown_SkColorType) {
     55         LOG_ALWAYS_FATAL("unknown bitmap configuration");
     56         return nullptr;
     57     }
     58 
     59     size_t size;
     60 
     61     // we must respect the rowBytes value already set on the bitmap instead of
     62     // attempting to compute our own.
     63     const size_t rowBytes = bitmap->rowBytes();
     64     if (!computeAllocationSize(rowBytes, bitmap->height(), &size)) {
     65         return nullptr;
     66     }
     67 
     68     auto wrapper = alloc(size, info, rowBytes);
     69     if (wrapper) {
     70         wrapper->getSkBitmap(bitmap);
     71     }
     72     return wrapper;
     73 }
     74 
     75 sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap) {
     76     return allocateBitmap(bitmap, &Bitmap::allocateAshmemBitmap);
     77 }
     78 
     79 static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
     80     void* addr = calloc(size, 1);
     81     if (!addr) {
     82         return nullptr;
     83     }
     84     return sk_sp<Bitmap>(new Bitmap(addr, size, info, rowBytes));
     85 }
     86 
     87 sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(SkBitmap& bitmap) {
     88     return uirenderer::renderthread::RenderProxy::allocateHardwareBitmap(bitmap);
     89 }
     90 
     91 sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap) {
     92     return allocateBitmap(bitmap, &android::allocateHeapBitmap);
     93 }
     94 
     95 sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) {
     96     size_t size;
     97     if (!computeAllocationSize(info.minRowBytes(), info.height(), &size)) {
     98         LOG_ALWAYS_FATAL("trying to allocate too large bitmap");
     99         return nullptr;
    100     }
    101     return android::allocateHeapBitmap(size, info, info.minRowBytes());
    102 }
    103 
    104 sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
    105     // Create new ashmem region with read/write priv
    106     int fd = ashmem_create_region("bitmap", size);
    107     if (fd < 0) {
    108         return nullptr;
    109     }
    110 
    111     void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    112     if (addr == MAP_FAILED) {
    113         close(fd);
    114         return nullptr;
    115     }
    116 
    117     if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
    118         munmap(addr, size);
    119         close(fd);
    120         return nullptr;
    121     }
    122     return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes));
    123 }
    124 
    125 void FreePixelRef(void* addr, void* context) {
    126     auto pixelRef = (SkPixelRef*)context;
    127     pixelRef->unref();
    128 }
    129 
    130 sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) {
    131     pixelRef.ref();
    132     return sk_sp<Bitmap>(new Bitmap((void*)pixelRef.pixels(), (void*)&pixelRef, FreePixelRef, info,
    133                                     pixelRef.rowBytes()));
    134 }
    135 
    136 sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) {
    137     PixelFormat format = graphicBuffer->getPixelFormat();
    138     if (!graphicBuffer.get() ||
    139         (format != PIXEL_FORMAT_RGBA_8888 && format != PIXEL_FORMAT_RGBA_FP16)) {
    140         return nullptr;
    141     }
    142     SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
    143                                          kRGBA_8888_SkColorType, kPremul_SkAlphaType,
    144                                          SkColorSpace::MakeSRGB());
    145     return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
    146 }
    147 
    148 void Bitmap::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
    149     mInfo = mInfo.makeColorSpace(std::move(colorSpace));
    150 }
    151 
    152 static SkImageInfo validateAlpha(const SkImageInfo& info) {
    153     // Need to validate the alpha type to filter against the color type
    154     // to prevent things like a non-opaque RGB565 bitmap
    155     SkAlphaType alphaType;
    156     LOG_ALWAYS_FATAL_IF(
    157             !SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &alphaType),
    158             "Failed to validate alpha type!");
    159     return info.makeAlphaType(alphaType);
    160 }
    161 
    162 void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes) {
    163     mInfo = validateAlpha(newInfo);
    164 
    165     // Dirty hack is dirty
    166     // TODO: Figure something out here, Skia's current design makes this
    167     // really hard to work with. Skia really, really wants immutable objects,
    168     // but with the nested-ref-count hackery going on that's just not
    169     // feasible without going insane trying to figure it out
    170     this->android_only_reset(mInfo.width(), mInfo.height(), rowBytes);
    171 }
    172 
    173 Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes)
    174         : SkPixelRef(info.width(), info.height(), address, rowBytes)
    175         , mInfo(validateAlpha(info))
    176         , mPixelStorageType(PixelStorageType::Heap) {
    177     mPixelStorage.heap.address = address;
    178     mPixelStorage.heap.size = size;
    179 }
    180 
    181 Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info,
    182                size_t rowBytes)
    183         : SkPixelRef(info.width(), info.height(), address, rowBytes)
    184         , mInfo(validateAlpha(info))
    185         , mPixelStorageType(PixelStorageType::External) {
    186     mPixelStorage.external.address = address;
    187     mPixelStorage.external.context = context;
    188     mPixelStorage.external.freeFunc = freeFunc;
    189 }
    190 
    191 Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes)
    192         : SkPixelRef(info.width(), info.height(), address, rowBytes)
    193         , mInfo(validateAlpha(info))
    194         , mPixelStorageType(PixelStorageType::Ashmem) {
    195     mPixelStorage.ashmem.address = address;
    196     mPixelStorage.ashmem.fd = fd;
    197     mPixelStorage.ashmem.size = mappedSize;
    198 }
    199 
    200 Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info)
    201         : SkPixelRef(info.width(), info.height(), nullptr,
    202                      bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride())
    203         , mInfo(validateAlpha(info))
    204         , mPixelStorageType(PixelStorageType::Hardware) {
    205     mPixelStorage.hardware.buffer = buffer;
    206     buffer->incStrong(buffer);
    207     setImmutable();  // HW bitmaps are always immutable
    208     if (uirenderer::Properties::isSkiaEnabled()) {
    209         mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast<AHardwareBuffer*>(buffer),
    210                                                   mInfo.alphaType(), mInfo.refColorSpace());
    211     }
    212 }
    213 
    214 Bitmap::~Bitmap() {
    215     switch (mPixelStorageType) {
    216         case PixelStorageType::External:
    217             mPixelStorage.external.freeFunc(mPixelStorage.external.address,
    218                                             mPixelStorage.external.context);
    219             break;
    220         case PixelStorageType::Ashmem:
    221             munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
    222             close(mPixelStorage.ashmem.fd);
    223             break;
    224         case PixelStorageType::Heap:
    225             free(mPixelStorage.heap.address);
    226             break;
    227         case PixelStorageType::Hardware:
    228             auto buffer = mPixelStorage.hardware.buffer;
    229             buffer->decStrong(buffer);
    230             mPixelStorage.hardware.buffer = nullptr;
    231             break;
    232     }
    233 
    234     android::uirenderer::renderthread::RenderProxy::onBitmapDestroyed(getStableID());
    235 }
    236 
    237 bool Bitmap::hasHardwareMipMap() const {
    238     return mHasHardwareMipMap;
    239 }
    240 
    241 void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
    242     mHasHardwareMipMap = hasMipMap;
    243 }
    244 
    245 void* Bitmap::getStorage() const {
    246     switch (mPixelStorageType) {
    247         case PixelStorageType::External:
    248             return mPixelStorage.external.address;
    249         case PixelStorageType::Ashmem:
    250             return mPixelStorage.ashmem.address;
    251         case PixelStorageType::Heap:
    252             return mPixelStorage.heap.address;
    253         case PixelStorageType::Hardware:
    254             return nullptr;
    255     }
    256 }
    257 
    258 int Bitmap::getAshmemFd() const {
    259     switch (mPixelStorageType) {
    260         case PixelStorageType::Ashmem:
    261             return mPixelStorage.ashmem.fd;
    262         default:
    263             return -1;
    264     }
    265 }
    266 
    267 size_t Bitmap::getAllocationByteCount() const {
    268     switch (mPixelStorageType) {
    269         case PixelStorageType::Heap:
    270             return mPixelStorage.heap.size;
    271         default:
    272             return rowBytes() * height();
    273     }
    274 }
    275 
    276 void Bitmap::reconfigure(const SkImageInfo& info) {
    277     reconfigure(info, info.minRowBytes());
    278 }
    279 
    280 void Bitmap::setAlphaType(SkAlphaType alphaType) {
    281     if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
    282         return;
    283     }
    284 
    285     mInfo = mInfo.makeAlphaType(alphaType);
    286 }
    287 
    288 void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
    289     outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
    290     if (isHardware()) {
    291         if (uirenderer::Properties::isSkiaEnabled()) {
    292             outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(),
    293                                                      info().colorType(), info().alphaType(),
    294                                                      nullptr));
    295         } else {
    296             outBitmap->allocPixels(info());
    297         }
    298         uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
    299         if (mInfo.colorSpace()) {
    300             sk_sp<SkPixelRef> pixelRef = sk_ref_sp(outBitmap->pixelRef());
    301             outBitmap->setInfo(mInfo);
    302             outBitmap->setPixelRef(std::move(pixelRef), 0, 0);
    303         }
    304         return;
    305     }
    306     outBitmap->setInfo(mInfo, rowBytes());
    307     outBitmap->setPixelRef(sk_ref_sp(this), 0, 0);
    308 }
    309 
    310 void Bitmap::getBounds(SkRect* bounds) const {
    311     SkASSERT(bounds);
    312     bounds->set(0, 0, SkIntToScalar(width()), SkIntToScalar(height()));
    313 }
    314 
    315 GraphicBuffer* Bitmap::graphicBuffer() {
    316     if (isHardware()) {
    317         return mPixelStorage.hardware.buffer;
    318     }
    319     return nullptr;
    320 }
    321 
    322 sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) {
    323     sk_sp<SkImage> image = mImage;
    324     if (!image) {
    325         SkASSERT(!(isHardware() && uirenderer::Properties::isSkiaEnabled()));
    326         SkBitmap skiaBitmap;
    327         skiaBitmap.setInfo(info(), rowBytes());
    328         skiaBitmap.setPixelRef(sk_ref_sp(this), 0, 0);
    329         skiaBitmap.setHasHardwareMipMap(mHasHardwareMipMap);
    330         // Note we don't cache in this case, because the raster image holds a pointer to this Bitmap
    331         // internally and ~Bitmap won't be invoked.
    332         // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
    333         image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
    334     }
    335     if (uirenderer::Properties::isSkiaEnabled() && image->colorSpace() != nullptr &&
    336         !image->colorSpace()->isSRGB()) {
    337         *outputColorFilter = SkToSRGBColorFilter::Make(image->refColorSpace());
    338     }
    339     return image;
    340 }
    341 
    342 }  // namespace android
    343