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