aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/modules/engines/direct3d/evas_direct3d_image_cache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/evas/src/modules/engines/direct3d/evas_direct3d_image_cache.cpp')
-rw-r--r--libraries/evas/src/modules/engines/direct3d/evas_direct3d_image_cache.cpp436
1 files changed, 436 insertions, 0 deletions
diff --git a/libraries/evas/src/modules/engines/direct3d/evas_direct3d_image_cache.cpp b/libraries/evas/src/modules/engines/direct3d/evas_direct3d_image_cache.cpp
new file mode 100644
index 0000000..aa44eb9
--- /dev/null
+++ b/libraries/evas/src/modules/engines/direct3d/evas_direct3d_image_cache.cpp
@@ -0,0 +1,436 @@
1#include "evas_direct3d_image_cache.h"
2
3#include "evas_direct3d_device.h"
4
5#include <assert.h>
6
7Ref<D3DImageCache> D3DImageCache::_this;
8
9D3DImageCache::D3DImageCache()
10{
11 _max_width = 512;
12 _max_height = 512;
13 _margin = 0;
14}
15
16D3DImageCache::~D3DImageCache()
17{
18 Uninitialize();
19}
20
21D3DImageCache *D3DImageCache::Current()
22{
23 if (_this.IsNull())
24 _this = new D3DImageCache();
25 return _this;
26}
27
28void D3DImageCache::SetCurrent(D3DImageCache *obj)
29{
30 _this = obj;
31}
32
33void D3DImageCache::Uninitialize()
34{
35 for (int i = 0; i < _cache.Length(); i++)
36 {
37 // In normal case they all will be NULL
38 if (_cache[i].texture != NULL)
39 _cache[i].texture->Release();
40 }
41 _cache.Resize();
42}
43
44bool D3DImageCache::SelectImageToDevice(D3DDevice *d3d, int id)
45{
46 if (id < 0 || id >= _cache.Length())
47 return false;
48 assert(_cache[id].texture != NULL);
49 return SUCCEEDED(d3d->SetTexture(_cache[id].stage, _cache[id].texture));
50}
51
52void D3DImageCache::RemoveImageUser(int id)
53{
54 if (id < 0 || id >= _cache.Length())
55 return;
56 assert(_cache[id].texture != NULL);
57 _cache[id].users--;
58 if (_cache[id].users == 0)
59 {
60 _cache[id].texture->Release();
61 ZeroMemory(&_cache[id], sizeof(_cache[id]));
62 }
63}
64
65void D3DImageCache::AddImageUser(int id)
66{
67 if (id < 0 || id >= _cache.Length())
68 return;
69 assert(_cache[id].texture != NULL);
70 _cache[id].users++;
71}
72
73bool D3DImageCache::InsertImage(D3DDevice *d3d, DWORD *data, int w, int h, CacheEntryInfo &info)
74{
75 CacheEntry *ce = NULL;
76 int id = -1;
77 for (int i = 0; i < _cache.Length(); i++)
78 {
79 if (!_cache[i].locked && RequestInsert(_cache[i], w, h))
80 {
81 ce = &_cache[i];
82 id = i;
83 break;
84 }
85 }
86 if (ce == NULL)
87 {
88 CacheEntry new_entry;
89 if (!CreateEntry(d3d, new_entry, w, h))
90 return false;
91 for (id = 0; id < _cache.Length(); id++)
92 {
93 if (_cache[id].texture == NULL)
94 break;
95 }
96
97 if (id < _cache.Length())
98 {
99 _cache[id] = new_entry;
100 ce = &_cache[id];
101 }
102 else
103 {
104 _cache.Add(new_entry);
105 ce = _cache.Last();
106 id = _cache.Length() - 1;
107 }
108 }
109
110 assert(ce != NULL && ce->texture != NULL);
111
112 if (!InsertData(*ce, data, w, h))
113 return false;
114
115 info.id = id;
116 info.u = FLOAT(ce->cur_x) / FLOAT(ce->width);
117 info.v = FLOAT(ce->cur_y) / FLOAT(ce->height);
118 info.du = FLOAT(w) / FLOAT(ce->width);
119 info.dv = FLOAT(h) / FLOAT(ce->height);
120 info.width = w;
121 info.height = h;
122
123 UpdateInsert(*ce, w, h);
124 return true;
125}
126
127bool D3DImageCache::InsertImage(D3DDevice *d3d, int id, DWORD *data, int w, int h, CacheEntryInfo &info)
128{
129 if (id < 0 || id >= _cache.Length())
130 return false;
131 assert(_cache[id].texture != NULL);
132 CacheEntry *ce = &_cache[id];
133 if (!RequestInsert(*ce, w, h))
134 return false;
135 if (!InsertData(*ce, data, w, h))
136 return false;
137
138 info.id = id;
139 info.u = FLOAT(ce->cur_x) / FLOAT(ce->width);
140 info.v = FLOAT(ce->cur_y) / FLOAT(ce->height);
141 info.du = FLOAT(w) / FLOAT(ce->width);
142 info.dv = FLOAT(h) / FLOAT(ce->height);
143 info.width = w;
144 info.height = h;
145
146 UpdateInsert(*ce, w, h);
147 return true;
148}
149
150bool D3DImageCache::CreateImage(D3DDevice *d3d, int w, int h, bool locked, CacheEntryInfo &info)
151{
152 int id;
153 CacheEntry new_entry;
154 CacheEntry *ce = NULL;
155
156 if (!CreateEntry(d3d, new_entry, w, h, true))
157 return false;
158 for (id = 0; id < _cache.Length(); id++)
159 {
160 if (_cache[id].texture == NULL)
161 break;
162 }
163
164 if (id < _cache.Length())
165 {
166 _cache[id] = new_entry;
167 ce = &_cache[id];
168 }
169 else
170 {
171 _cache.Add(new_entry);
172 ce = _cache.Last();
173 id = _cache.Length() - 1;
174 }
175
176 assert(ce != NULL && ce->texture != NULL);
177
178 // Fill with zero
179 if (!InsertData(*ce, NULL, w, h))
180 return false;
181
182 info.id = id;
183 info.u = 0;
184 info.v = 0;
185 info.du = 1;
186 info.dv = 1;
187 info.width = w;
188 info.height = h;
189
190 UpdateInsert(*ce, 0, 0);
191 ce->locked = locked;
192 return true;
193}
194
195bool D3DImageCache::ResizeImage(D3DDevice *d3d, int nw, int nh, int id)
196{
197 if (id < 0 || id >= _cache.Length())
198 return false;
199 assert(_cache[id].texture != NULL);
200 CacheEntry *ce = &_cache[id];
201
202 if (ce->width == nw && ce->height == nh)
203 return true;
204
205 LPDIRECT3DTEXTURE9 tex = NULL;
206
207 HRESULT hr;
208 if (FAILED(hr = d3d->GetDevice()->CreateTexture(nw, nh, 0, 0, D3DFMT_A8R8G8B8,
209 D3DPOOL_MANAGED, &tex, NULL)))
210 {
211 WRN("Failed to create texture: %X", hr);
212 return false;
213 }
214 assert(tex != NULL);
215
216 ce->texture->Release();
217 ce->texture = tex;
218 ce->width = nw;
219 ce->height = nh;
220 return true;
221}
222
223bool D3DImageCache::RequestInsert(CacheEntry &entry, int w, int h)
224{
225 // If we already have large image entry
226 if (entry.width > _max_width || entry.height > _max_height)
227 return false;
228 // If requested size does not fit into this entry at all
229 if (entry.height - entry.cur_h < h + _margin * 2 || entry.width < w + _margin * 2)
230 return false;
231
232 // If requested size does not fit into the current line of the entry
233 if (entry.width - entry.cur_x < w + _margin * 2)
234 {
235 entry.cur_y = entry.cur_h + _margin;
236 entry.cur_x = _margin;
237 return true;
238 }
239 entry.cur_x += _margin;
240
241 return true;
242}
243
244bool D3DImageCache::CreateEntry(D3DDevice *d3d, CacheEntry &entry, int w, int h, bool exact_size)
245{
246 int width = exact_size ? w : max(_max_width, w);
247 int height = exact_size ? h : max(_max_height, h);
248 HRESULT hr;
249 if (FAILED(hr = d3d->GetDevice()->CreateTexture(width, height, 0, 0, D3DFMT_A8R8G8B8,
250 D3DPOOL_MANAGED, &entry.texture, NULL)))
251 {
252 WRN("Failed to create texture: %X", hr);
253 return false;
254 }
255
256 entry.cur_x = entry.cur_y = entry.cur_h = 0;
257 entry.width = width;
258 entry.height = height;
259 entry.users = 0;
260 entry.locked = false;
261 entry.stage = 0;
262 return true;
263}
264
265bool D3DImageCache::InsertData(CacheEntry &entry, DWORD *data, int w, int h)
266{
267 if (entry.texture == NULL)
268 return false;
269
270 RECT rc = {entry.cur_x, entry.cur_y, entry.cur_x + w, entry.cur_y + h};
271 D3DLOCKED_RECT lr;
272 if (FAILED(entry.texture->LockRect(0, &lr, &rc, 0)))
273 {
274 WRN("Failed to lock texture");
275 return false;
276 }
277
278 if (data != NULL)
279 {
280 for (int i = 0; i < h; i++)
281 CopyMemory(((BYTE *)lr.pBits) + i * lr.Pitch, data + i * w, sizeof(DWORD) * w);
282 }
283 else
284 {
285 for (int i = 0; i < h; i++)
286 ZeroMemory(((BYTE *)lr.pBits) + i * lr.Pitch, sizeof(DWORD) * w);
287 }
288
289 if (FAILED(entry.texture->UnlockRect(0)))
290 {
291 WRN("Failed to unlock texture");
292 return false;
293 }
294 return true;
295}
296
297
298bool D3DImageCache::RetrieveData(CacheEntry &entry, DWORD *data, int w, int h)
299{
300 if (entry.texture == NULL || data == NULL)
301 return false;
302
303 RECT rc = {entry.cur_x, entry.cur_y, entry.cur_x + w, entry.cur_y + h};
304 D3DLOCKED_RECT lr;
305 if (FAILED(entry.texture->LockRect(0, &lr, &rc, D3DLOCK_READONLY)))
306 {
307 WRN("Failed to lock texture");
308 return false;
309 }
310
311 for (int i = 0; i < h; i++)
312 CopyMemory(data + i * w, ((BYTE *)lr.pBits) + i * lr.Pitch, sizeof(DWORD) * w);
313
314 if (FAILED(entry.texture->UnlockRect(0)))
315 {
316 WRN("Failed to unlock texture");
317 return false;
318 }
319 return true;
320}
321
322void D3DImageCache::UpdateInsert(CacheEntry &entry, int w, int h)
323{
324 entry.cur_h = max(entry.cur_h, entry.cur_y + h + _margin);
325 entry.cur_x += w + _margin;
326 entry.users++;
327}
328
329bool D3DImageCache::UpdateImageData(CacheEntryInfo &info, DWORD *data)
330{
331 assert(data != NULL);
332 if (info.id < 0 || info.id >= _cache.Length())
333 return false;
334 CacheEntry ce_copy = _cache[info.id];
335 ce_copy.cur_x = int(info.u * FLOAT(ce_copy.width));
336 ce_copy.cur_y = int(info.v * FLOAT(ce_copy.height));
337 return InsertData(ce_copy, data, info.width, info.height);
338}
339
340bool D3DImageCache::UpdateImageDataWithDirtyInfo(CacheEntryInfo &info, DWORD *data, POINT *dirty)
341{
342 if (info.id < 0 || info.id >= _cache.Length())
343 return false;
344 CacheEntry &entry = _cache[info.id];
345 if (entry.texture == NULL)
346 return false;
347
348 RECT rc = {0, 0, entry.width, entry.height};
349 D3DLOCKED_RECT lr;
350 if (FAILED(entry.texture->LockRect(0, &lr, &rc, 0)))
351 {
352 WRN("Failed to lock texture");
353 return false;
354 }
355
356 if (data != NULL)
357 {
358 for (int i = 0; i < rc.bottom; i++)
359 {
360 if (dirty[i].x < 0 && dirty[i].y < 0)
361 continue;
362 if (dirty[i].x >= 0 && dirty[i].y >= 0)
363 {
364 CopyMemory(((BYTE *)lr.pBits) + i * lr.Pitch + dirty[i].x * 4,
365 data + i * rc.right + dirty[i].x, sizeof(DWORD) * (dirty[i].y - dirty[i].x + 1));
366 dirty[i].y = -dirty[i].y;
367 }
368 else if (dirty[i].x >= 0 && dirty[i].y < 0)
369 {
370 ZeroMemory(((BYTE *)lr.pBits) + i * lr.Pitch + dirty[i].x * 4,
371 sizeof(DWORD) * (-dirty[i].y - dirty[i].x + 1));
372 dirty[i].x = -dirty[i].x;
373 }
374 }
375 }
376 else
377 {
378 for (int i = 0; i < rc.bottom; i++)
379 {
380 if (dirty[i].x < 0 || dirty[i].y < 0)
381 continue;
382 ZeroMemory(((BYTE *)lr.pBits) + i * lr.Pitch + dirty[i].x * 4,
383 sizeof(DWORD) * (dirty[i].y - dirty[i].x + 1));
384 }
385 }
386
387 if (FAILED(entry.texture->UnlockRect(0)))
388 {
389 WRN("Failed to unlock texture");
390 return false;
391 }
392 return true;
393}
394
395bool D3DImageCache::UpdateImageDataDiscard(CacheEntryInfo &info, DWORD *data)
396{
397 assert(data != NULL);
398 if (info.id < 0 || info.id >= _cache.Length())
399 return false;
400 CacheEntry &entry = _cache[info.id];
401 if (entry.texture == NULL)
402 return false;
403
404 RECT rc = {0, 0, entry.width, entry.height};
405 D3DLOCKED_RECT lr;
406 if (FAILED(entry.texture->LockRect(0, &lr, &rc, 0)))
407 {
408 WRN("Failed to lock texture");
409 return false;
410 }
411
412 for (int i = 0; i < rc.bottom; i++)
413 {
414 CopyMemory(((BYTE *)lr.pBits) + i * lr.Pitch,
415 data + i * rc.right, sizeof(DWORD) * rc.right);
416 }
417
418 if (FAILED(entry.texture->UnlockRect(0)))
419 {
420 WRN("Failed to unlock texture");
421 return false;
422 }
423 return true;
424}
425
426bool D3DImageCache::GetImageData(CacheEntryInfo &info, TArray<DWORD> &data)
427{
428 if (info.id < 0 || info.id >= _cache.Length())
429 return false;
430 CacheEntry ce_copy = _cache[info.id];
431 ce_copy.cur_x = int(info.u * FLOAT(ce_copy.width));
432 ce_copy.cur_y = int(info.v * FLOAT(ce_copy.height));
433 data.Allocate(info.width * info.height);
434
435 return RetrieveData(ce_copy, data.Data(), info.width, info.height);
436}