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