1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/images/SkImageRef_ashmem.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,230 @@ 1.4 +/* 1.5 + * Copyright 2011 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkImageRef_ashmem.h" 1.12 +#include "SkImageDecoder.h" 1.13 +#include "SkReadBuffer.h" 1.14 +#include "SkWriteBuffer.h" 1.15 +#include "SkThread.h" 1.16 + 1.17 +#include "android/ashmem.h" 1.18 + 1.19 +#include <sys/mman.h> 1.20 +#include <unistd.h> 1.21 + 1.22 +//#define TRACE_ASH_PURGE // just trace purges 1.23 + 1.24 +#ifdef DUMP_IMAGEREF_LIFECYCLE 1.25 + #define DUMP_ASHMEM_LIFECYCLE 1.26 +#else 1.27 +// #define DUMP_ASHMEM_LIFECYCLE 1.28 +#endif 1.29 + 1.30 +// ashmem likes lengths on page boundaries 1.31 +static size_t roundToPageSize(size_t size) { 1.32 + const size_t mask = getpagesize() - 1; 1.33 + size_t newsize = (size + mask) & ~mask; 1.34 +// SkDebugf("---- oldsize %d newsize %d\n", size, newsize); 1.35 + return newsize; 1.36 +} 1.37 + 1.38 +SkImageRef_ashmem::SkImageRef_ashmem(const SkImageInfo& info, 1.39 + SkStreamRewindable* stream, 1.40 + int sampleSize) 1.41 + : SkImageRef(info, stream, sampleSize) 1.42 +{ 1.43 + fRec.fFD = -1; 1.44 + fRec.fAddr = NULL; 1.45 + fRec.fSize = 0; 1.46 + fRec.fPinned = false; 1.47 + 1.48 + fCT = NULL; 1.49 +} 1.50 + 1.51 +SkImageRef_ashmem::~SkImageRef_ashmem() { 1.52 + SkSafeUnref(fCT); 1.53 + this->closeFD(); 1.54 +} 1.55 + 1.56 +void SkImageRef_ashmem::closeFD() { 1.57 + if (-1 != fRec.fFD) { 1.58 +#ifdef DUMP_ASHMEM_LIFECYCLE 1.59 + SkDebugf("=== ashmem close %d\n", fRec.fFD); 1.60 +#endif 1.61 + SkASSERT(fRec.fAddr); 1.62 + SkASSERT(fRec.fSize); 1.63 + munmap(fRec.fAddr, fRec.fSize); 1.64 + close(fRec.fFD); 1.65 + fRec.fFD = -1; 1.66 + } 1.67 +} 1.68 + 1.69 +/////////////////////////////////////////////////////////////////////////////// 1.70 + 1.71 +class AshmemAllocator : public SkBitmap::Allocator { 1.72 +public: 1.73 + AshmemAllocator(SkAshmemRec* rec, const char name[]) 1.74 + : fRec(rec), fName(name) {} 1.75 + 1.76 + virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) { 1.77 + const size_t size = roundToPageSize(bm->getSize()); 1.78 + int fd = fRec->fFD; 1.79 + void* addr = fRec->fAddr; 1.80 + 1.81 + SkASSERT(!fRec->fPinned); 1.82 + 1.83 + if (-1 == fd) { 1.84 + SkASSERT(NULL == addr); 1.85 + SkASSERT(0 == fRec->fSize); 1.86 + 1.87 + fd = ashmem_create_region(fName, size); 1.88 +#ifdef DUMP_ASHMEM_LIFECYCLE 1.89 + SkDebugf("=== ashmem_create_region %s size=%d fd=%d\n", fName, size, fd); 1.90 +#endif 1.91 + if (-1 == fd) { 1.92 + SkDebugf("------- imageref_ashmem create failed <%s> %d\n", 1.93 + fName, size); 1.94 + return false; 1.95 + } 1.96 + 1.97 + int err = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE); 1.98 + if (err) { 1.99 + SkDebugf("------ ashmem_set_prot_region(%d) failed %d\n", 1.100 + fd, err); 1.101 + close(fd); 1.102 + return false; 1.103 + } 1.104 + 1.105 + addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 1.106 + if (-1 == (long)addr) { 1.107 + SkDebugf("---------- mmap failed for imageref_ashmem size=%d\n", 1.108 + size); 1.109 + close(fd); 1.110 + return false; 1.111 + } 1.112 + 1.113 + fRec->fFD = fd; 1.114 + fRec->fAddr = addr; 1.115 + fRec->fSize = size; 1.116 + } else { 1.117 + SkASSERT(addr); 1.118 + SkASSERT(size == fRec->fSize); 1.119 + (void)ashmem_pin_region(fd, 0, 0); 1.120 + } 1.121 + 1.122 + bm->setPixels(addr, ct); 1.123 + fRec->fPinned = true; 1.124 + return true; 1.125 + } 1.126 + 1.127 +private: 1.128 + // we just point to our caller's memory, these are not copies 1.129 + SkAshmemRec* fRec; 1.130 + const char* fName; 1.131 +}; 1.132 + 1.133 +bool SkImageRef_ashmem::onDecode(SkImageDecoder* codec, SkStreamRewindable* stream, 1.134 + SkBitmap* bitmap, SkBitmap::Config config, 1.135 + SkImageDecoder::Mode mode) { 1.136 + 1.137 + if (SkImageDecoder::kDecodeBounds_Mode == mode) { 1.138 + return this->INHERITED::onDecode(codec, stream, bitmap, config, mode); 1.139 + } 1.140 + 1.141 + // Ashmem memory is guaranteed to be initialized to 0. 1.142 + codec->setSkipWritingZeroes(true); 1.143 + 1.144 + AshmemAllocator alloc(&fRec, this->getURI()); 1.145 + 1.146 + codec->setAllocator(&alloc); 1.147 + bool success = this->INHERITED::onDecode(codec, stream, bitmap, config, 1.148 + mode); 1.149 + // remove the allocator, since its on the stack 1.150 + codec->setAllocator(NULL); 1.151 + 1.152 + if (success) { 1.153 + // remember the colortable (if any) 1.154 + SkRefCnt_SafeAssign(fCT, bitmap->getColorTable()); 1.155 + return true; 1.156 + } else { 1.157 + if (fRec.fPinned) { 1.158 + ashmem_unpin_region(fRec.fFD, 0, 0); 1.159 + fRec.fPinned = false; 1.160 + } 1.161 + this->closeFD(); 1.162 + return false; 1.163 + } 1.164 +} 1.165 + 1.166 +bool SkImageRef_ashmem::onNewLockPixels(LockRec* rec) { 1.167 + SkASSERT(fBitmap.getPixels() == NULL); 1.168 + SkASSERT(fBitmap.getColorTable() == NULL); 1.169 + 1.170 + // fast case: check if we can just pin and get the cached data 1.171 + if (-1 != fRec.fFD) { 1.172 + SkASSERT(fRec.fAddr); 1.173 + SkASSERT(!fRec.fPinned); 1.174 + int pin = ashmem_pin_region(fRec.fFD, 0, 0); 1.175 + 1.176 + if (ASHMEM_NOT_PURGED == pin) { // yea, fast case! 1.177 + fBitmap.setPixels(fRec.fAddr, fCT); 1.178 + fRec.fPinned = true; 1.179 + } else if (ASHMEM_WAS_PURGED == pin) { 1.180 + ashmem_unpin_region(fRec.fFD, 0, 0); 1.181 + // let go of our colortable if we lost the pixels. Well get it back 1.182 + // again when we re-decode 1.183 + if (fCT) { 1.184 + fCT->unref(); 1.185 + fCT = NULL; 1.186 + } 1.187 +#if defined(DUMP_ASHMEM_LIFECYCLE) || defined(TRACE_ASH_PURGE) 1.188 + SkDebugf("===== ashmem purged %d\n", fBitmap.getSize()); 1.189 +#endif 1.190 + } else { 1.191 + SkDebugf("===== ashmem pin_region(%d) returned %d\n", fRec.fFD, pin); 1.192 + return false; 1.193 + } 1.194 + } else { 1.195 + // no FD, will create an ashmem region in allocator 1.196 + } 1.197 + 1.198 + return this->INHERITED::onNewLockPixels(rec); 1.199 +} 1.200 + 1.201 +void SkImageRef_ashmem::onUnlockPixels() { 1.202 + this->INHERITED::onUnlockPixels(); 1.203 + 1.204 + if (-1 != fRec.fFD) { 1.205 + SkASSERT(fRec.fAddr); 1.206 + SkASSERT(fRec.fPinned); 1.207 + 1.208 + ashmem_unpin_region(fRec.fFD, 0, 0); 1.209 + fRec.fPinned = false; 1.210 + } 1.211 + 1.212 + // we clear this with or without an error, since we've either closed or 1.213 + // unpinned the region 1.214 + fBitmap.setPixels(NULL, NULL); 1.215 +} 1.216 + 1.217 +void SkImageRef_ashmem::flatten(SkWriteBuffer& buffer) const { 1.218 + this->INHERITED::flatten(buffer); 1.219 + buffer.writeString(getURI()); 1.220 +} 1.221 + 1.222 +SkImageRef_ashmem::SkImageRef_ashmem(SkReadBuffer& buffer) 1.223 + : INHERITED(buffer) { 1.224 + fRec.fFD = -1; 1.225 + fRec.fAddr = NULL; 1.226 + fRec.fSize = 0; 1.227 + fRec.fPinned = false; 1.228 + fCT = NULL; 1.229 + 1.230 + SkString uri; 1.231 + buffer.readString(&uri); 1.232 + this->setURI(uri); 1.233 +}