Implement SkAshmemDiscardableMemory
- Implement ashmem-backed SkDiscardableMemory subclass: This class in only accesible via the SkDiscardableMemory::Create() function, which replaces the mock implementation in SkDiscardableMemory_none.cpp - Added SkDiscardableMemory_ashmem.cpp to the Android port of Skia Removed SkDiscardableMemory_none.cpp from the Android port. - Added DiscardableMemoryTest. Still needs work. - SkDiscardablePixelRef Bugfix: onLockPixels() now calls SkDELETE on the SkDiscardableMemory pointer when it fails to unlock. - Improved documentation inside ashmem.h BUG= R=scroggo@google.com Review URL: https://codereview.chromium.org/83563002 git-svn-id: http://skia.googlecode.com/svn/trunk@12608 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
c9a8a7e23d
commit
bc55eec80e
@ -153,10 +153,12 @@
|
||||
[ 'skia_os == "android"', {
|
||||
'sources!': [
|
||||
'../src/ports/SkDebug_stdio.cpp',
|
||||
'../src/ports/SkDiscardableMemory_none.cpp',
|
||||
'../src/ports/SkPurgeableMemoryBlock_none.cpp',
|
||||
],
|
||||
'sources': [
|
||||
'../src/ports/SkDebug_android.cpp',
|
||||
'../src/ports/SkDiscardableMemory_ashmem.cpp',
|
||||
'../src/ports/SkFontConfigInterface_android.cpp',
|
||||
'../src/ports/SkFontConfigParser_android.cpp',
|
||||
'../src/ports/SkFontHost_fontconfig.cpp',
|
||||
|
@ -56,6 +56,7 @@
|
||||
'../tests/DequeTest.cpp',
|
||||
'../tests/DeviceLooperTest.cpp',
|
||||
'../tests/DiscardableMemoryPool.cpp',
|
||||
'../tests/DiscardableMemoryTest.cpp',
|
||||
'../tests/DocumentTest.cpp',
|
||||
'../tests/DrawBitmapRectTest.cpp',
|
||||
'../tests/DrawPathTest.cpp',
|
||||
|
114
src/ports/SkDiscardableMemory_ashmem.cpp
Normal file
114
src/ports/SkDiscardableMemory_ashmem.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include "SkDiscardableMemory.h"
|
||||
#include "SkTypes.h"
|
||||
#include "android/ashmem.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
namespace {
|
||||
/**
|
||||
* DiscardableMemory implementation that uses the Android kernel's
|
||||
* ashmem (Android shared memory).
|
||||
*/
|
||||
class SkAshmemDiscardableMemory : public SkDiscardableMemory {
|
||||
public:
|
||||
SkAshmemDiscardableMemory(int fd, void* address, size_t size);
|
||||
virtual ~SkAshmemDiscardableMemory();
|
||||
virtual bool lock() SK_OVERRIDE;
|
||||
virtual void* data() SK_OVERRIDE;
|
||||
virtual void unlock() SK_OVERRIDE;
|
||||
private:
|
||||
bool fLocked;
|
||||
int fFd;
|
||||
void* fMemory;
|
||||
const size_t fSize;
|
||||
};
|
||||
|
||||
SkAshmemDiscardableMemory::SkAshmemDiscardableMemory(int fd,
|
||||
void* address,
|
||||
size_t size)
|
||||
: fLocked(true) // Ashmem pages are pinned by default.
|
||||
, fFd(fd)
|
||||
, fMemory(address)
|
||||
, fSize(size) {
|
||||
SkASSERT(fFd >= 0);
|
||||
SkASSERT(fMemory != NULL);
|
||||
SkASSERT(fSize > 0);
|
||||
}
|
||||
|
||||
SkAshmemDiscardableMemory::~SkAshmemDiscardableMemory() {
|
||||
SkASSERT(!fLocked);
|
||||
if (NULL != fMemory) {
|
||||
munmap(fMemory, fSize);
|
||||
}
|
||||
if (fFd != -1) {
|
||||
close(fFd);
|
||||
}
|
||||
}
|
||||
|
||||
bool SkAshmemDiscardableMemory::lock() {
|
||||
SkASSERT(!fLocked);
|
||||
if (-1 == fFd) {
|
||||
fLocked = false;
|
||||
return false;
|
||||
}
|
||||
SkASSERT(fMemory != NULL);
|
||||
if (fLocked || (ASHMEM_NOT_PURGED == ashmem_pin_region(fFd, 0, 0))) {
|
||||
fLocked = true;
|
||||
return true;
|
||||
} else {
|
||||
munmap(fMemory, fSize);
|
||||
fMemory = NULL;
|
||||
|
||||
close(fFd);
|
||||
fFd = -1;
|
||||
fLocked = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void* SkAshmemDiscardableMemory::data() {
|
||||
SkASSERT(fLocked);
|
||||
return fLocked ? fMemory : NULL;
|
||||
}
|
||||
|
||||
void SkAshmemDiscardableMemory::unlock() {
|
||||
SkASSERT(fLocked);
|
||||
if (fLocked && (fFd != -1)) {
|
||||
ashmem_unpin_region(fFd, 0, 0);
|
||||
}
|
||||
fLocked = false;
|
||||
}
|
||||
} // namespace
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkDiscardableMemory* SkDiscardableMemory::Create(size_t bytes) {
|
||||
// ashmem likes lengths on page boundaries.
|
||||
const size_t mask = getpagesize() - 1;
|
||||
size_t size = (bytes + mask) & ~mask;
|
||||
|
||||
static const char name[] = "Skia_Ashmem_Discardable_Memory";
|
||||
int fd = ashmem_create_region(name, size);
|
||||
if (fd < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (0 != ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE)) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
if ((MAP_FAILED == addr) || (NULL == addr)) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return SkNEW_ARGS(SkAshmemDiscardableMemory, (fd, addr, size));
|
||||
}
|
||||
|
@ -16,6 +16,12 @@ extern "C" {
|
||||
|
||||
int ashmem_create_region(const char *name, size_t size);
|
||||
int ashmem_set_prot_region(int fd, int prot);
|
||||
|
||||
/**
|
||||
* @return ASHMEM_NOT_PURGED if the memory was not purged.
|
||||
* ASHMEM_WAS_PURGED if the memory was purged.
|
||||
* -1 on error.
|
||||
*/
|
||||
int ashmem_pin_region(int fd, size_t offset, size_t len);
|
||||
int ashmem_unpin_region(int fd, size_t offset, size_t len);
|
||||
int ashmem_get_size_region(int fd);
|
||||
|
@ -300,12 +300,12 @@ DEF_TEST(DiscardableAndCachingPixelRef, reporter) {
|
||||
REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed());
|
||||
|
||||
SkDiscardableMemoryPool* globalPool = SkGetGlobalDiscardableMemoryPool();
|
||||
// Only acts differently from NULL on a platform that has a
|
||||
// default discardable memory implementation that differs from the
|
||||
// global DM pool.
|
||||
CheckPixelRef(TestImageGenerator::kFailGetPixels_TestType,
|
||||
reporter, kSkDiscardable_PixelRefType, globalPool);
|
||||
CheckPixelRef(TestImageGenerator::kSucceedGetPixels_TestType,
|
||||
reporter, kSkDiscardable_PixelRefType, globalPool);
|
||||
|
||||
// TODO(halcanary): When ashmem-backed SkDiscardableMemory lands,
|
||||
// test that here (on platforms where it is availible).
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
34
tests/DiscardableMemoryTest.cpp
Normal file
34
tests/DiscardableMemoryTest.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkDiscardableMemory.h"
|
||||
|
||||
#include "Test.h"
|
||||
#include "TestClassDef.h"
|
||||
|
||||
DEF_TEST(DiscardableMemory, reporter) {
|
||||
const char testString[] = "HELLO, WORLD!";
|
||||
const size_t len = sizeof(testString);
|
||||
SkAutoTDelete<SkDiscardableMemory> dm(SkDiscardableMemory::Create(len));
|
||||
REPORTER_ASSERT(reporter, dm.get() != NULL);
|
||||
if (NULL == dm.get()) {
|
||||
return;
|
||||
}
|
||||
void* ptr = dm->data();
|
||||
REPORTER_ASSERT(reporter, ptr != NULL);
|
||||
memcpy(ptr, testString, sizeof(testString));
|
||||
dm->unlock();
|
||||
bool success = dm->lock();
|
||||
REPORTER_ASSERT(reporter, success);
|
||||
if (!success) {
|
||||
return;
|
||||
}
|
||||
ptr = dm->data();
|
||||
REPORTER_ASSERT(reporter, 0 == memcmp(ptr, testString, len));
|
||||
dm->unlock();
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
__SK_FORCE_IMAGE_DECODER_LINKING;
|
||||
|
||||
// TODO(halcanary) Use this flag when ashmem-backed discardable memory lands.
|
||||
DEFINE_bool(useVolatileCache, false, "Use a volatile cache for deferred image decoding pixels. "
|
||||
"Only meaningful if --deferImageDecoding is set to true and the platform has an "
|
||||
"implementation.");
|
||||
@ -39,9 +38,11 @@ bool sk_tools::LazyDecodeBitmap(const void* src,
|
||||
return false;
|
||||
}
|
||||
SkDiscardableMemory::Factory* pool = NULL;
|
||||
if (info.fWidth * info.fHeight > 32 * 1024) {
|
||||
if ((!FLAGS_useVolatileCache) || (info.fWidth * info.fHeight < 32 * 1024)) {
|
||||
// how to do switching with SkDiscardableMemory.
|
||||
pool = SkGetGlobalDiscardableMemoryPool();
|
||||
// Only meaningful if platform has a default discardable
|
||||
// memory implementation that differs from the global DM pool.
|
||||
}
|
||||
return SkDiscardablePixelRef::Install(gen.detach(), dst, pool);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user