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