#include "SkGLCanvas.h"
#include "SkGLDevice.h"
#include "SkBlitter.h"
#include "SkDraw.h"
#include "SkDrawProcs.h"
#include "SkGL.h"
#include "SkGlyphCache.h"
#include "SkTemplates.h"
#include "SkUtils.h"
#include "SkXfermode.h"
#ifdef SK_GL_DEVICE_FBO
#define USE_FBO_DEVICE
#include "SkGLDevice_FBO.h"
#else
#define USE_SWLAYER_DEVICE
#include "SkGLDevice_SWLayer.h"
#endif
// maximum number of entries in our texture cache (before purging)
#define kTexCountMax_Default 256
// maximum number of bytes used (by gl) for the texture cache (before purging)
#define kTexSizeMax_Default (4 * 1024 * 1024)
///////////////////////////////////////////////////////////////////////////////
SkGLCanvas::SkGLCanvas() {
glEnable(GL_TEXTURE_2D);
glEnable(GL_SCISSOR_TEST);
glEnableClientState(GL_VERTEX_ARRAY);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
fViewportSize.set(0, 0);
}
SkGLCanvas::~SkGLCanvas() {
// call this now, while our override of restore() is in effect
this->restoreToCount(1);
}
///////////////////////////////////////////////////////////////////////////////
bool SkGLCanvas::getViewport(SkIPoint* size) const {
if (size) {
*size = fViewportSize;
}
return true;
}
bool SkGLCanvas::setViewport(int width, int height) {
fViewportSize.set(width, height);
const bool isOpaque = false; // should this be a parameter to setViewport?
const bool isForLayer = false; // viewport is the base layer
SkDevice* device = this->createDevice(SkBitmap::kARGB_8888_Config, width,
height, isOpaque, isForLayer);
this->setDevice(device)->unref();
return true;
}
SkDevice* SkGLCanvas::createDevice(SkBitmap::Config, int width, int height,
bool isOpaque, bool isForLayer) {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
bitmap.setIsOpaque(isOpaque);
#ifdef USE_FBO_DEVICE
return SkNEW_ARGS(SkGLDevice_FBO, (bitmap, isForLayer));
#elif defined(USE_SWLAYER_DEVICE)
if (isForLayer) {
bitmap.allocPixels();
if (!bitmap.isOpaque()) {
bitmap.eraseColor(0);
}
return SkNEW_ARGS(SkGLDevice_SWLayer, (bitmap));
} else {
return SkNEW_ARGS(SkGLDevice, (bitmap, isForLayer));
}
#else
return SkNEW_ARGS(SkGLDevice, (bitmap, isForLayer));
#endif
}
///////////////////////////////////////////////////////////////////////////////
#include "SkTextureCache.h"
#include "SkThread.h"
static SkMutex gTextureCacheMutex;
static SkTextureCache gTextureCache(kTexCountMax_Default, kTexSizeMax_Default);
SkGLDevice::TexCache* SkGLDevice::LockTexCache(const SkBitmap& bitmap,
GLuint* name, SkPoint* size) {
SkAutoMutexAcquire amc(gTextureCacheMutex);
SkTextureCache::Entry* entry = gTextureCache.lock(bitmap);
if (NULL != entry) {
if (name) {
*name = entry->name();
}
if (size) {
*size = entry->texSize();
}
}
return (TexCache*)entry;
}
void SkGLDevice::UnlockTexCache(TexCache* cache) {
SkAutoMutexAcquire amc(gTextureCacheMutex);
gTextureCache.unlock((SkTextureCache::Entry*)cache);
}
// public exposure of texture cache settings
size_t SkGLCanvas::GetTextureCacheMaxCount() {
SkAutoMutexAcquire amc(gTextureCacheMutex);
return gTextureCache.getMaxCount();
}
size_t SkGLCanvas::GetTextureCacheMaxSize() {
SkAutoMutexAcquire amc(gTextureCacheMutex);
return gTextureCache.getMaxSize();
}
void SkGLCanvas::SetTextureCacheMaxCount(size_t count) {
SkAutoMutexAcquire amc(gTextureCacheMutex);
gTextureCache.setMaxCount(count);
}
void SkGLCanvas::SetTextureCacheMaxSize(size_t size) {
SkAutoMutexAcquire amc(gTextureCacheMutex);
gTextureCache.setMaxSize(size);
}
///////////////////////////////////////////////////////////////////////////////
#include "SkGLTextCache.h"
static bool deleteCachesProc(SkGlyphCache* cache, void* texturesAreValid) {
void* auxData;
if (cache->getAuxProcData(SkGLDevice::GlyphCacheAuxProc, &auxData)) {
bool valid = texturesAreValid != NULL;
SkGLTextCache* textCache = static_cast<SkGLTextCache*>(auxData);
// call this before delete, in case valid is false
textCache->deleteAllStrikes(valid);
// now free the memory for the cache itself
SkDELETE(textCache);
// now remove the entry in the glyphcache (does not call the proc)
cache->removeAuxProc(SkGLDevice::GlyphCacheAuxProc);
}
return false; // keep going
}
void SkGLCanvas::DeleteAllTextures() {
// free the textures in our cache
gTextureCacheMutex.acquire();
gTextureCache.deleteAllCaches(true);
gTextureCacheMutex.release();
// now free the textures in the font cache
SkGlyphCache::VisitAllCaches(deleteCachesProc, reinterpret_cast<void*>(true));
}
void SkGLCanvas::AbandonAllTextures() {
// abandon the textures in our cache
gTextureCacheMutex.acquire();
gTextureCache.deleteAllCaches(false);
gTextureCacheMutex.release();
// abandon the textures in the font cache
SkGlyphCache::VisitAllCaches(deleteCachesProc, reinterpret_cast<void*>(false));
}