GL caches refactoring

This commit is contained in:
Vadim Lopatin 2014-03-12 09:12:43 +04:00
parent e4f27b1966
commit 31e1693074
1 changed files with 389 additions and 376 deletions

View File

@ -8,10 +8,13 @@ private import std.algorithm;
/// drawing buffer - image container which allows to perform some drawing operations
class GLDrawBuf : DrawBuf {
int _dx;
int _dy;
bool _framebuffer;
Scene _scene;
protected int _dx;
protected int _dy;
protected bool _framebuffer;
protected Scene _scene;
/// get current scene (exists only between beforeDrawing() and afterDrawing() calls
@property Scene scene() { return _scene; }
this(int dx, int dy, bool framebuffer = false) {
_dx = dx;
@ -38,6 +41,8 @@ class GLDrawBuf : DrawBuf {
setOrthoProjection(_dx, _dy);
_scene.draw();
flushGL();
destroy(_scene);
_scene = null;
}
/// resize buffer
@ -63,10 +68,8 @@ class GLDrawBuf : DrawBuf {
Rect srcrect = Rect(0, 0, glyph.blackBoxX, glyph.blackBoxY);
//Log.v("GLDrawBuf.frawFragment dst=", dstrect, " src=", srcrect);
if (applyClipping(dstrect, srcrect)) {
GLGlyphCacheItem item = glGlyphCache.get(glyph.id);
if (item is null)
item = glGlyphCache.set(glyph);
// TODO: clipping
if (!glGlyphCache.get(glyph.id))
glGlyphCache.put(glyph);
_scene.add(new GlyphSceneItem(glyph.id, dstrect, srcrect, color, null));
}
}
@ -76,10 +79,8 @@ class GLDrawBuf : DrawBuf {
Rect dstrect = Rect(x, y, x + srcrect.width, y + srcrect.height);
//Log.v("GLDrawBuf.frawFragment dst=", dstrect, " src=", srcrect);
if (applyClipping(dstrect, srcrect)) {
GLImageCacheItem item = glImageCache.get(src.id);
if (item is null)
item = glImageCache.set(src);
// TODO: clipping
if (glImageCache.get(src.id))
glImageCache.put(src);
_scene.add(new TextureSceneItem(src.id, dstrect, srcrect, 0xFFFFFF, 0, null, 0));
}
}
@ -88,9 +89,8 @@ class GLDrawBuf : DrawBuf {
assert(_scene !is null);
//Log.v("GLDrawBuf.frawRescaled dst=", dstrect, " src=", srcrect);
if (applyClipping(dstrect, srcrect)) {
GLImageCacheItem item = glImageCache.get(src.id);
if (item is null)
item = glImageCache.set(src);
if (glImageCache.get(src.id))
glImageCache.put(src);
_scene.add(new TextureSceneItem(src.id, dstrect, srcrect, 0xFFFFFF, 0, null, 0));
}
}
@ -128,11 +128,9 @@ bool hasActiveScene() {
return activeSceneCount > 0;
}
immutable int MIN_TEX_SIZE = 64;
immutable int MAX_TEX_SIZE = 4096;
int nearestPOT(int n) {
private int nearestPOT(int n) {
for (int i = MIN_TEX_SIZE; i <= MAX_TEX_SIZE; i *= 2) {
if (n <= i)
return i;
@ -164,136 +162,34 @@ void LVGLClearImageCache() {
glGlyphCache.clear();
}
private class GLImageCacheItem {
GLImageCachePage _page;
public:
/// OpenGL texture cache for ColorDrawBuf objects
private class GLImageCache {
static class GLImageCacheItem {
private GLImageCachePage _page;
@property GLImageCachePage page() { return _page; }
uint _objectId;
// image size
Rect _rc;
bool _deleted;
this(GLImageCachePage page, uint objectId) { _page = page; _objectId = objectId; }
};
private class GLImageCache {
GLImageCacheItem[uint] _map;
GLImageCachePage[] _pages;
GLImageCachePage _activePage;
int tdx;
int tdy;
void removePage(GLImageCachePage page) {
if (_activePage == page)
_activePage = null;
for (int i = 0; i < _pages.length; i++)
if (_pages[i] == page) {
_pages.remove(i);
break;
}
destroy(page);
}
void updateTextureSize() {
if (!tdx) {
// TODO
tdx = tdy = 1024; //getMaxTextureSize();
if (tdx > 1024)
tdx = tdy = 1024;
}
}
public:
this() {
}
~this() {
clear();
}
GLImageCacheItem get(uint obj) {
if (obj in _map)
return _map[obj];
return null;
}
GLImageCacheItem set(DrawBuf img) {
updateTextureSize();
GLImageCacheItem res = null;
if (img.width <= tdx / 3 && img.height < tdy / 3) {
// trying to reuse common page for small images
if (_activePage is null) {
_activePage = new GLImageCachePage(this, tdx, tdy);
_pages ~= _activePage;
}
res = _activePage.addItem(img);
if (!res) {
_activePage = new GLImageCachePage(this, tdx, tdy);
_pages ~= _activePage;
res = _activePage.addItem(img);
}
} else {
// use separate page for big image
GLImageCachePage page = new GLImageCachePage(this, img.width, img.height);
_pages ~= page;
res = page.addItem(img);
page.close();
}
_map[img.id] = res;
return res;
}
void clear() {
for (int i = 0; i < _pages.length; i++) {
destroy(_pages[i]);
_pages[i] = null;
}
_pages.clear();
_map.clear();
}
/// draw cached item
void drawItem(uint objectId, Rect dstrc, Rect srcrc, uint color, int options, Rect * clip, int rotationAngle) {
if (objectId in _map) {
GLImageCacheItem item = _map[objectId];
item.page.drawItem(item, dstrc, srcrc, color, options, clip, rotationAngle);
}
}
/// handle cached object deletion, mark as deleted
void onCachedObjectDeleted(uint objectId) {
if (objectId in _map) {
GLImageCacheItem item = _map[objectId];
if (hasActiveScene()) {
item._deleted = true;
} else {
int itemsLeft = item.page.deleteItem(item);
//CRLog::trace("itemsLeft = %d", itemsLeft);
if (itemsLeft <= 0) {
//CRLog::trace("removing page");
removePage(item.page);
}
_map.remove(objectId);
delete item;
}
}
}
/// remove deleted items - remove page if contains only deleted items
void removeDeletedItems() {
uint[] list;
foreach (GLImageCacheItem item; _map) {
if (item._deleted)
list ~= item._objectId;
}
for (int i = 0 ; i < list.length; i++) {
onCachedObjectDeleted(list[i]);
}
}
};
static class GLImageCachePage {
private GLImageCache _cache;
private int _tdx;
private int _tdy;
private ColorDrawBuf _drawbuf;
private int _currentLine;
private int _nextLine;
private int _x;
private bool _closed;
private bool _needUpdateTexture;
private uint _textureId;
private int _itemCount;
private class GLImageCachePage {
GLImageCache _cache;
int _tdx;
int _tdy;
ColorDrawBuf _drawbuf;
int _currentLine;
int _nextLine;
int _x;
bool _closed;
bool _needUpdateTexture;
uint _textureId;
int _itemCount;
public:
this(GLImageCache cache, int dx, int dy) {
_cache = cache;
Log.v("created image cache page ", dx, "x", dy);
@ -335,6 +231,7 @@ public:
_drawbuf = null;
}
}
void invertAlpha(GLImageCacheItem item) {
Rect rc = item._rc;
for (int y = rc.top; y < rc.bottom; y++) {
@ -348,6 +245,7 @@ public:
}
}
}
GLImageCacheItem reserveSpace(uint objectId, int width, int height) {
GLImageCacheItem cacheItem = new GLImageCacheItem(this, objectId);
if (_closed)
@ -449,59 +347,15 @@ public:
if (_needUpdateTexture)
updateTexture();
}
};
private class TextureSceneItem : SceneItem {
uint objectId;
//CacheableObject * img;
Rect dstrc;
Rect srcrc;
uint color;
uint options;
Rect * clip;
int rotationAngle;
public:
override void draw() {
if (glImageCache)
glImageCache.drawItem(objectId, dstrc, srcrc, color, options, clip, rotationAngle);
}
this(uint _objectId, Rect _dstrc, Rect _srcrc, uint _color, uint _options, Rect * _clip, int _rotationAngle)
{
objectId = _objectId;
dstrc = _dstrc;
srcrc = _srcrc;
color = _color;
options = _options;
clip = _clip;
rotationAngle = _rotationAngle;
}
~this() {
}
};
private GLImageCacheItem[uint] _map;
private GLImageCachePage[] _pages;
private GLImageCachePage _activePage;
private int tdx;
private int tdy;
private class GLGlyphCacheItem {
GLGlyphCachePage _page;
public:
@property GLGlyphCachePage page() { return _page; }
uint _objectId;
// image size
Rect _rc;
bool _deleted;
this(GLGlyphCachePage page, uint objectId) { _page = page; _objectId = objectId; }
};
private class GLGlyphCache {
GLGlyphCacheItem[uint] _map;
GLGlyphCachePage[] _pages;
GLGlyphCachePage _activePage;
int tdx;
int tdy;
void removePage(GLGlyphCachePage page) {
private void removePage(GLImageCachePage page) {
if (_activePage == page)
_activePage = null;
for (int i = 0; i < _pages.length; i++)
@ -511,7 +365,8 @@ private class GLGlyphCache {
}
destroy(page);
}
void updateTextureSize() {
private void updateTextureSize() {
if (!tdx) {
// TODO
tdx = tdy = 1024; //getMaxTextureSize();
@ -519,33 +374,44 @@ private class GLGlyphCache {
tdx = tdy = 1024;
}
}
public:
this() {
}
~this() {
clear();
}
GLGlyphCacheItem get(uint obj) {
/// returns true if object exists in cache
bool get(uint obj) {
if (obj in _map)
return _map[obj];
return null;
return true;
return false;
}
GLGlyphCacheItem set(Glyph * glyph) {
/// put new object to cache
void put(DrawBuf img) {
updateTextureSize();
GLGlyphCacheItem res = null;
GLImageCacheItem res = null;
if (img.width <= tdx / 3 && img.height < tdy / 3) {
// trying to reuse common page for small images
if (_activePage is null) {
_activePage = new GLGlyphCachePage(this, tdx, tdy);
_activePage = new GLImageCachePage(this, tdx, tdy);
_pages ~= _activePage;
}
res = _activePage.addItem(glyph);
res = _activePage.addItem(img);
if (!res) {
_activePage = new GLGlyphCachePage(this, tdx, tdy);
_activePage = new GLImageCachePage(this, tdx, tdy);
_pages ~= _activePage;
res = _activePage.addItem(glyph);
res = _activePage.addItem(img);
}
_map[glyph.id] = res;
return res;
} else {
// use separate page for big image
GLImageCachePage page = new GLImageCachePage(this, img.width, img.height);
_pages ~= page;
res = page.addItem(img);
page.close();
}
_map[img.id] = res;
}
/// clears cache
void clear() {
for (int i = 0; i < _pages.length; i++) {
destroy(_pages[i]);
@ -555,16 +421,16 @@ public:
_map.clear();
}
/// draw cached item
void drawItem(uint objectId, Rect dstrc, Rect srcrc, uint color, Rect * clip) {
void drawItem(uint objectId, Rect dstrc, Rect srcrc, uint color, int options, Rect * clip, int rotationAngle) {
if (objectId in _map) {
GLGlyphCacheItem item = _map[objectId];
item.page.drawItem(item, dstrc, srcrc, color, clip);
GLImageCacheItem item = _map[objectId];
item.page.drawItem(item, dstrc, srcrc, color, options, clip, rotationAngle);
}
}
/// handle cached object deletion, mark as deleted
void onCachedObjectDeleted(uint objectId) {
if (objectId in _map) {
GLGlyphCacheItem item = _map[objectId];
GLImageCacheItem item = _map[objectId];
if (hasActiveScene()) {
item._deleted = true;
} else {
@ -582,7 +448,7 @@ public:
/// remove deleted items - remove page if contains only deleted items
void removeDeletedItems() {
uint[] list;
foreach (GLGlyphCacheItem item; _map) {
foreach (GLImageCacheItem item; _map) {
if (item._deleted)
list ~= item._objectId;
}
@ -592,19 +458,68 @@ public:
}
};
private class GLGlyphCachePage {
GLGlyphCache _cache;
int _tdx;
int _tdy;
GrayDrawBuf _drawbuf;
int _currentLine;
int _nextLine;
int _x;
bool _closed;
bool _needUpdateTexture;
uint _textureId;
int _itemCount;
private class TextureSceneItem : SceneItem {
private uint objectId;
//CacheableObject * img;
private Rect dstrc;
private Rect srcrc;
private uint color;
private uint options;
private Rect * clip;
private int rotationAngle;
override void draw() {
if (glImageCache)
glImageCache.drawItem(objectId, dstrc, srcrc, color, options, clip, rotationAngle);
}
this(uint _objectId, Rect _dstrc, Rect _srcrc, uint _color, uint _options, Rect * _clip, int _rotationAngle)
{
objectId = _objectId;
dstrc = _dstrc;
srcrc = _srcrc;
color = _color;
options = _options;
clip = _clip;
rotationAngle = _rotationAngle;
}
~this() {
}
};
private class GLGlyphCache {
static class GLGlyphCacheItem {
GLGlyphCachePage _page;
public:
@property GLGlyphCachePage page() { return _page; }
uint _objectId;
// image size
Rect _rc;
bool _deleted;
this(GLGlyphCachePage page, uint objectId) { _page = page; _objectId = objectId; }
};
static class GLGlyphCachePage {
private GLGlyphCache _cache;
private int _tdx;
private int _tdy;
private GrayDrawBuf _drawbuf;
private int _currentLine;
private int _nextLine;
private int _x;
private bool _closed;
private bool _needUpdateTexture;
private uint _textureId;
private int _itemCount;
this(GLGlyphCache cache, int dx, int dy) {
_cache = cache;
Log.v("created image cache page ", dx, "x", dy);
@ -729,6 +644,103 @@ public:
if (_needUpdateTexture)
updateTexture();
}
}
GLGlyphCacheItem[uint] _map;
GLGlyphCachePage[] _pages;
GLGlyphCachePage _activePage;
int tdx;
int tdy;
void removePage(GLGlyphCachePage page) {
if (_activePage == page)
_activePage = null;
for (int i = 0; i < _pages.length; i++)
if (_pages[i] == page) {
_pages.remove(i);
break;
}
destroy(page);
}
private void updateTextureSize() {
if (!tdx) {
// TODO
tdx = tdy = 1024; //getMaxTextureSize();
if (tdx > 1024)
tdx = tdy = 1024;
}
}
this() {
}
~this() {
clear();
}
/// check if item is in cache
bool get(uint obj) {
if (obj in _map)
return false;
return true;
}
/// put new item to cache
void put(Glyph * glyph) {
updateTextureSize();
GLGlyphCacheItem res = null;
if (_activePage is null) {
_activePage = new GLGlyphCachePage(this, tdx, tdy);
_pages ~= _activePage;
}
res = _activePage.addItem(glyph);
if (!res) {
_activePage = new GLGlyphCachePage(this, tdx, tdy);
_pages ~= _activePage;
res = _activePage.addItem(glyph);
}
_map[glyph.id] = res;
}
void clear() {
for (int i = 0; i < _pages.length; i++) {
destroy(_pages[i]);
_pages[i] = null;
}
_pages.clear();
_map.clear();
}
/// draw cached item
void drawItem(uint objectId, Rect dstrc, Rect srcrc, uint color, Rect * clip) {
if (objectId in _map) {
GLGlyphCacheItem item = _map[objectId];
item.page.drawItem(item, dstrc, srcrc, color, clip);
}
}
/// handle cached object deletion, mark as deleted
void onCachedObjectDeleted(uint objectId) {
if (objectId in _map) {
GLGlyphCacheItem item = _map[objectId];
if (hasActiveScene()) {
item._deleted = true;
} else {
int itemsLeft = item.page.deleteItem(item);
//CRLog::trace("itemsLeft = %d", itemsLeft);
if (itemsLeft <= 0) {
//CRLog::trace("removing page");
removePage(item.page);
}
_map.remove(objectId);
delete item;
}
}
}
/// remove deleted items - remove page if contains only deleted items
void removeDeletedItems() {
uint[] list;
foreach (GLGlyphCacheItem item; _map) {
if (item._deleted)
list ~= item._objectId;
}
for (int i = 0 ; i < list.length; i++) {
onCachedObjectDeleted(list[i]);
}
}
};
@ -736,6 +748,7 @@ public:
class SolidRectSceneItem : SceneItem {
Rect _rc;
uint _color;