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