efl/src/modules/evas/engines/direct3d/evas_direct3d_vertex_buffer...

155 lines
3.5 KiB
C++

//#define ENABLE_LOG_PRINTF
#include "evas_direct3d_vertex_buffer_cache.h"
#include "evas_direct3d_device.h"
#include <assert.h>
Ref<D3DVertexBufferCache> D3DVertexBufferCache::_this;
D3DVertexBufferCache::D3DVertexBufferCache()
{
size_border_low = 0.6; // We can reuse buffer on 60%
size_border_high = 0.2; // We can reallocate the buffer on 20%
}
D3DVertexBufferCache::~D3DVertexBufferCache()
{
Uninitialize();
}
D3DVertexBufferCache *D3DVertexBufferCache::Current()
{
if (_this.IsNull())
_this = new D3DVertexBufferCache();
return _this;
}
void D3DVertexBufferCache::SetCurrent(D3DVertexBufferCache *obj)
{
_this = obj;
}
void D3DVertexBufferCache::Uninitialize()
{
for (int i = 0; i < _cache.Length(); i++)
{
assert(_cache[i].vb != NULL);
_cache[i].vb->Release();
}
_cache.Resize();
}
bool D3DVertexBufferCache::InitBuffer(D3DDevice *d3d, BYTE *data, int size, CacheEntryInfo &info)
{
assert(d3d != NULL);
assert(data != NULL);
assert(size > 0);
int best = FindBestEntry(size);
CacheEntry *ce = NULL;
// Reallocate
if (best >= 0 && _cache[best].size < size)
{
DeleteEntry(best);
best = -1;
}
// New
if (best < 0)
{
CacheEntry new_entry;
if (!CreateEntry(d3d, new_entry, size))
{
WRN("Failed to create new vbcache entry");
return false;
}
_cache.Add(new_entry);
info.id = _cache.Length() - 1;
ce = _cache.Last();
}
else
{
info.id = best;
ce = &_cache[best];
}
assert(ce != NULL);
if (!InsertData(*ce, data, size))
{
WRN("Failed to insert vbcache data");
return false;
}
return true;
}
bool D3DVertexBufferCache::SelectBufferToDevice(D3DDevice *device, int id, int vertex_size)
{
if (id < 0 || id >= _cache.Length())
return false;
return SUCCEEDED(device->GetDevice()->SetStreamSource(0, _cache[id].vb, 0, vertex_size));
}
int D3DVertexBufferCache::FindBestEntry(int size)
{
// Search for buffer that fits in borders
for (int i = 0; i < _cache.Length(); i++)
{
const int vs = _cache[i].size;
if (size >= (vs - FLOAT(vs) * size_border_low) && size <= vs)
return i;
}
bool less_than_all = true;
for (int i = 0; i < _cache.Length(); i++)
{
const int vs = _cache[i].size;
if (size >= (vs - FLOAT(vs) * size_border_low))
less_than_all = false;
}
// Requested size is too small to reuse in any buffer
if (less_than_all)
return -1;
// Search for buffer that can be reallocated
for (int i = 0; i < _cache.Length(); i++)
{
const int vs = _cache[i].size;
if (size <= (vs + FLOAT(vs) * size_border_high))
return i;
}
// No buffer can be reused or reallocated, create a new one
return -1;
}
bool D3DVertexBufferCache::CreateEntry(D3DDevice *d3d, CacheEntry &entry, int size)
{
assert(d3d != NULL);
if (FAILED(d3d->GetDevice()->CreateVertexBuffer(size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
0, D3DPOOL_DEFAULT, &entry.vb, NULL)))
{
return false;
}
entry.size = size;
return true;
}
void D3DVertexBufferCache::DeleteEntry(int id)
{
if (id < 0 || id >= _cache.Length())
return;
assert(_cache[id].vb != NULL);
_cache[id].vb->Release();
_cache.Replace(id);
}
bool D3DVertexBufferCache::InsertData(CacheEntry &entry, BYTE *data, int size)
{
BYTE *ptr = NULL;
if (FAILED(entry.vb->Lock(0, size, (void **)&ptr, D3DLOCK_DISCARD)))
return false;
CopyMemory(ptr, data, size);
return SUCCEEDED(entry.vb->Unlock());
}