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