aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/modules/engines/direct3d/evas_direct3d_vertex_buffer_cache.cpp
blob: 8d3dd451ac6fe19e39eaf3520af5eda5b1517af0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

//#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());
}