diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/evas/src/modules/engines/direct3d/evas_direct3d_vertex_buffer_cache.cpp | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/libraries/evas/src/modules/engines/direct3d/evas_direct3d_vertex_buffer_cache.cpp b/libraries/evas/src/modules/engines/direct3d/evas_direct3d_vertex_buffer_cache.cpp new file mode 100644 index 0000000..8d3dd45 --- /dev/null +++ b/libraries/evas/src/modules/engines/direct3d/evas_direct3d_vertex_buffer_cache.cpp | |||
@@ -0,0 +1,154 @@ | |||
1 | |||
2 | //#define ENABLE_LOG_PRINTF | ||
3 | |||
4 | #include "evas_direct3d_vertex_buffer_cache.h" | ||
5 | #include "evas_direct3d_device.h" | ||
6 | |||
7 | #include <assert.h> | ||
8 | |||
9 | |||
10 | Ref<D3DVertexBufferCache> D3DVertexBufferCache::_this; | ||
11 | |||
12 | D3DVertexBufferCache::D3DVertexBufferCache() | ||
13 | { | ||
14 | size_border_low = 0.6; // We can reuse buffer on 60% | ||
15 | size_border_high = 0.2; // We can reallocate the buffer on 20% | ||
16 | } | ||
17 | |||
18 | D3DVertexBufferCache::~D3DVertexBufferCache() | ||
19 | { | ||
20 | Uninitialize(); | ||
21 | } | ||
22 | |||
23 | D3DVertexBufferCache *D3DVertexBufferCache::Current() | ||
24 | { | ||
25 | if (_this.IsNull()) | ||
26 | _this = new D3DVertexBufferCache(); | ||
27 | return _this; | ||
28 | } | ||
29 | |||
30 | void D3DVertexBufferCache::SetCurrent(D3DVertexBufferCache *obj) | ||
31 | { | ||
32 | _this = obj; | ||
33 | } | ||
34 | |||
35 | void D3DVertexBufferCache::Uninitialize() | ||
36 | { | ||
37 | for (int i = 0; i < _cache.Length(); i++) | ||
38 | { | ||
39 | assert(_cache[i].vb != NULL); | ||
40 | _cache[i].vb->Release(); | ||
41 | } | ||
42 | _cache.Resize(); | ||
43 | } | ||
44 | |||
45 | bool D3DVertexBufferCache::InitBuffer(D3DDevice *d3d, BYTE *data, int size, CacheEntryInfo &info) | ||
46 | { | ||
47 | assert(d3d != NULL); | ||
48 | assert(data != NULL); | ||
49 | assert(size > 0); | ||
50 | |||
51 | int best = FindBestEntry(size); | ||
52 | CacheEntry *ce = NULL; | ||
53 | |||
54 | // Reallocate | ||
55 | if (best >= 0 && _cache[best].size < size) | ||
56 | { | ||
57 | DeleteEntry(best); | ||
58 | best = -1; | ||
59 | } | ||
60 | |||
61 | // New | ||
62 | if (best < 0) | ||
63 | { | ||
64 | CacheEntry new_entry; | ||
65 | if (!CreateEntry(d3d, new_entry, size)) | ||
66 | { | ||
67 | WRN("Failed to create new vbcache entry"); | ||
68 | return false; | ||
69 | } | ||
70 | _cache.Add(new_entry); | ||
71 | info.id = _cache.Length() - 1; | ||
72 | ce = _cache.Last(); | ||
73 | } | ||
74 | else | ||
75 | { | ||
76 | info.id = best; | ||
77 | ce = &_cache[best]; | ||
78 | } | ||
79 | |||
80 | assert(ce != NULL); | ||
81 | if (!InsertData(*ce, data, size)) | ||
82 | { | ||
83 | WRN("Failed to insert vbcache data"); | ||
84 | return false; | ||
85 | } | ||
86 | return true; | ||
87 | } | ||
88 | |||
89 | bool D3DVertexBufferCache::SelectBufferToDevice(D3DDevice *device, int id, int vertex_size) | ||
90 | { | ||
91 | if (id < 0 || id >= _cache.Length()) | ||
92 | return false; | ||
93 | return SUCCEEDED(device->GetDevice()->SetStreamSource(0, _cache[id].vb, 0, vertex_size)); | ||
94 | } | ||
95 | |||
96 | int D3DVertexBufferCache::FindBestEntry(int size) | ||
97 | { | ||
98 | // Search for buffer that fits in borders | ||
99 | for (int i = 0; i < _cache.Length(); i++) | ||
100 | { | ||
101 | const int vs = _cache[i].size; | ||
102 | if (size >= (vs - FLOAT(vs) * size_border_low) && size <= vs) | ||
103 | return i; | ||
104 | } | ||
105 | bool less_than_all = true; | ||
106 | for (int i = 0; i < _cache.Length(); i++) | ||
107 | { | ||
108 | const int vs = _cache[i].size; | ||
109 | if (size >= (vs - FLOAT(vs) * size_border_low)) | ||
110 | less_than_all = false; | ||
111 | } | ||
112 | // Requested size is too small to reuse in any buffer | ||
113 | if (less_than_all) | ||
114 | return -1; | ||
115 | // Search for buffer that can be reallocated | ||
116 | for (int i = 0; i < _cache.Length(); i++) | ||
117 | { | ||
118 | const int vs = _cache[i].size; | ||
119 | if (size <= (vs + FLOAT(vs) * size_border_high)) | ||
120 | return i; | ||
121 | } | ||
122 | // No buffer can be reused or reallocated, create a new one | ||
123 | return -1; | ||
124 | } | ||
125 | |||
126 | bool D3DVertexBufferCache::CreateEntry(D3DDevice *d3d, CacheEntry &entry, int size) | ||
127 | { | ||
128 | assert(d3d != NULL); | ||
129 | if (FAILED(d3d->GetDevice()->CreateVertexBuffer(size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, | ||
130 | 0, D3DPOOL_DEFAULT, &entry.vb, NULL))) | ||
131 | { | ||
132 | return false; | ||
133 | } | ||
134 | entry.size = size; | ||
135 | return true; | ||
136 | } | ||
137 | |||
138 | void D3DVertexBufferCache::DeleteEntry(int id) | ||
139 | { | ||
140 | if (id < 0 || id >= _cache.Length()) | ||
141 | return; | ||
142 | assert(_cache[id].vb != NULL); | ||
143 | _cache[id].vb->Release(); | ||
144 | _cache.Replace(id); | ||
145 | } | ||
146 | |||
147 | bool D3DVertexBufferCache::InsertData(CacheEntry &entry, BYTE *data, int size) | ||
148 | { | ||
149 | BYTE *ptr = NULL; | ||
150 | if (FAILED(entry.vb->Lock(0, size, (void **)&ptr, D3DLOCK_DISCARD))) | ||
151 | return false; | ||
152 | CopyMemory(ptr, data, size); | ||
153 | return SUCCEEDED(entry.vb->Unlock()); | ||
154 | } | ||