mirror of https://github.com/buggins/dlangui.git
GL caches refactoring
This commit is contained in:
parent
e4f27b1966
commit
31e1693074
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue