Bitmap.cpp revision ec4a4b13eae2241d1613890c1c1c096bed891845
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 20#include <cutils/log.h> 21#include <sys/mman.h> 22#include <cutils/ashmem.h> 23 24namespace android { 25 26static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) { 27 int32_t rowBytes32 = SkToS32(rowBytes); 28 int64_t bigSize = (int64_t) height * rowBytes32; 29 if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) { 30 return false; // allocation will be too large 31 } 32 33 *size = sk_64_asS32(bigSize); 34 return true; 35} 36 37typedef sk_sp<Bitmap> (*AllocPixeRef)(size_t allocSize, const SkImageInfo& info, size_t rowBytes, 38 SkColorTable* ctable); 39 40static sk_sp<Bitmap> allocateBitmap(SkBitmap* bitmap, SkColorTable* ctable, AllocPixeRef alloc) { 41 const SkImageInfo& info = bitmap->info(); 42 if (info.colorType() == kUnknown_SkColorType) { 43 LOG_ALWAYS_FATAL("unknown bitmap configuration"); 44 return nullptr; 45 } 46 47 size_t size; 48 49 // we must respect the rowBytes value already set on the bitmap instead of 50 // attempting to compute our own. 51 const size_t rowBytes = bitmap->rowBytes(); 52 if (!computeAllocationSize(rowBytes, bitmap->height(), &size)) { 53 return nullptr; 54 } 55 56 auto wrapper = alloc(size, info, rowBytes, ctable); 57 if (wrapper) { 58 wrapper->getSkBitmap(bitmap); 59 // since we're already allocated, we lockPixels right away 60 // HeapAllocator behaves this way too 61 bitmap->lockPixels(); 62 } 63 return wrapper; 64} 65 66sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap, SkColorTable* ctable) { 67 return allocateBitmap(bitmap, ctable, &Bitmap::allocateAshmemBitmap); 68} 69 70static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes, 71 SkColorTable* ctable) { 72 void* addr = calloc(size, 1); 73 if (!addr) { 74 return nullptr; 75 } 76 return sk_sp<Bitmap>(new Bitmap(addr, size, info, rowBytes, ctable)); 77} 78 79sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap, SkColorTable* ctable) { 80 return allocateBitmap(bitmap, ctable, &android::allocateHeapBitmap); 81} 82 83sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) { 84 size_t size; 85 if (!computeAllocationSize(info.minRowBytes(), info.height(), &size)) { 86 LOG_ALWAYS_FATAL("trying to allocate too large bitmap"); 87 return nullptr; 88 } 89 return android::allocateHeapBitmap(size, info, info.minRowBytes(), nullptr); 90} 91 92sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info, 93 size_t rowBytes, SkColorTable* ctable) { 94 // Create new ashmem region with read/write priv 95 int fd = ashmem_create_region("bitmap", size); 96 if (fd < 0) { 97 return nullptr; 98 } 99 100 void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 101 if (addr == MAP_FAILED) { 102 close(fd); 103 return nullptr; 104 } 105 106 if (ashmem_set_prot_region(fd, PROT_READ) < 0) { 107 munmap(addr, size); 108 close(fd); 109 return nullptr; 110 } 111 return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes, ctable)); 112} 113 114void FreePixelRef(void* addr, void* context) { 115 auto pixelRef = (SkPixelRef*) context; 116 pixelRef->unlockPixels(); 117 pixelRef->unref(); 118} 119 120sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) { 121 pixelRef.ref(); 122 pixelRef.lockPixels(); 123 return sk_sp<Bitmap>(new Bitmap((void*) pixelRef.pixels(), (void*) &pixelRef, FreePixelRef, 124 info, pixelRef.rowBytes(), pixelRef.colorTable())); 125} 126 127void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) { 128 if (kIndex_8_SkColorType != newInfo.colorType()) { 129 ctable = nullptr; 130 } 131 mRowBytes = rowBytes; 132 if (mColorTable.get() != ctable) { 133 mColorTable.reset(ctable); 134 } 135 136 // Need to validate the alpha type to filter against the color type 137 // to prevent things like a non-opaque RGB565 bitmap 138 SkAlphaType alphaType; 139 LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType( 140 newInfo.colorType(), newInfo.alphaType(), &alphaType), 141 "Failed to validate alpha type!"); 142 143 // Dirty hack is dirty 144 // TODO: Figure something out here, Skia's current design makes this 145 // really hard to work with. Skia really, really wants immutable objects, 146 // but with the nested-ref-count hackery going on that's just not 147 // feasible without going insane trying to figure it out 148 SkImageInfo* myInfo = const_cast<SkImageInfo*>(&this->info()); 149 *myInfo = newInfo; 150 changeAlphaType(alphaType); 151 152 // Docs say to only call this in the ctor, but we're going to call 153 // it anyway even if this isn't always the ctor. 154 // TODO: Fix this too as part of the above TODO 155 setPreLocked(getStorage(), mRowBytes, mColorTable.get()); 156} 157 158Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable) 159 : SkPixelRef(info) 160 , mPixelStorageType(PixelStorageType::Heap) { 161 mPixelStorage.heap.address = address; 162 mPixelStorage.heap.size = size; 163 reconfigure(info, rowBytes, ctable); 164} 165 166Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc, 167 const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable) 168 : SkPixelRef(info) 169 , mPixelStorageType(PixelStorageType::External) { 170 mPixelStorage.external.address = address; 171 mPixelStorage.external.context = context; 172 mPixelStorage.external.freeFunc = freeFunc; 173 reconfigure(info, rowBytes, ctable); 174} 175 176Bitmap::Bitmap(void* address, int fd, size_t mappedSize, 177 const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable) 178 : SkPixelRef(info) 179 , mPixelStorageType(PixelStorageType::Ashmem) { 180 mPixelStorage.ashmem.address = address; 181 mPixelStorage.ashmem.fd = fd; 182 mPixelStorage.ashmem.size = mappedSize; 183 reconfigure(info, rowBytes, ctable); 184} 185 186Bitmap::~Bitmap() { 187 switch (mPixelStorageType) { 188 case PixelStorageType::External: 189 mPixelStorage.external.freeFunc(mPixelStorage.external.address, 190 mPixelStorage.external.context); 191 break; 192 case PixelStorageType::Ashmem: 193 munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size); 194 close(mPixelStorage.ashmem.fd); 195 break; 196 case PixelStorageType::Heap: 197 free(mPixelStorage.heap.address); 198 break; 199 } 200 201 if (android::uirenderer::Caches::hasInstance()) { 202 android::uirenderer::Caches::getInstance().textureCache.releaseTexture(getStableID()); 203 } 204} 205 206bool Bitmap::hasHardwareMipMap() const { 207 return mHasHardwareMipMap; 208} 209 210void Bitmap::setHasHardwareMipMap(bool hasMipMap) { 211 mHasHardwareMipMap = hasMipMap; 212} 213 214void* Bitmap::getStorage() const { 215 switch (mPixelStorageType) { 216 case PixelStorageType::External: 217 return mPixelStorage.external.address; 218 case PixelStorageType::Ashmem: 219 return mPixelStorage.ashmem.address; 220 case PixelStorageType::Heap: 221 return mPixelStorage.heap.address; 222 } 223} 224 225bool Bitmap::onNewLockPixels(LockRec* rec) { 226 rec->fPixels = getStorage(); 227 rec->fRowBytes = mRowBytes; 228 rec->fColorTable = mColorTable.get(); 229 return true; 230} 231 232size_t Bitmap::getAllocatedSizeInBytes() const { 233 return info().getSafeSize(mRowBytes); 234} 235 236int Bitmap::getAshmemFd() const { 237 switch (mPixelStorageType) { 238 case PixelStorageType::Ashmem: 239 return mPixelStorage.ashmem.fd; 240 default: 241 return -1; 242 } 243} 244 245size_t Bitmap::getAllocationByteCount() const { 246 switch (mPixelStorageType) { 247 case PixelStorageType::Heap: 248 return mPixelStorage.heap.size; 249 default: 250 return rowBytes() * height(); 251 } 252} 253 254void Bitmap::reconfigure(const SkImageInfo& info) { 255 reconfigure(info, info.minRowBytes(), nullptr); 256} 257 258void Bitmap::setAlphaType(SkAlphaType alphaType) { 259 if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) { 260 return; 261 } 262 263 changeAlphaType(alphaType); 264} 265 266void Bitmap::getSkBitmap(SkBitmap* outBitmap) { 267 outBitmap->setInfo(info(), rowBytes()); 268 outBitmap->setPixelRef(this); 269 outBitmap->setHasHardwareMipMap(mHasHardwareMipMap); 270} 271 272void Bitmap::getBounds(SkRect* bounds) const { 273 SkASSERT(bounds); 274 bounds->set(0, 0, SkIntToScalar(info().width()), SkIntToScalar(info().height())); 275} 276 277} // namespace android