diff options
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.cpp | 436 |
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 | |||
7 | Ref<D3DImageCache> D3DImageCache::_this; | ||
8 | |||
9 | D3DImageCache::D3DImageCache() | ||
10 | { | ||
11 | _max_width = 512; | ||
12 | _max_height = 512; | ||
13 | _margin = 0; | ||
14 | } | ||
15 | |||
16 | D3DImageCache::~D3DImageCache() | ||
17 | { | ||
18 | Uninitialize(); | ||
19 | } | ||
20 | |||
21 | D3DImageCache *D3DImageCache::Current() | ||
22 | { | ||
23 | if (_this.IsNull()) | ||
24 | _this = new D3DImageCache(); | ||
25 | return _this; | ||
26 | } | ||
27 | |||
28 | void D3DImageCache::SetCurrent(D3DImageCache *obj) | ||
29 | { | ||
30 | _this = obj; | ||
31 | } | ||
32 | |||
33 | void 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 | |||
44 | bool 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 | |||
52 | void 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 | |||
65 | void 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 | |||
73 | bool 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 | |||
127 | bool 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 | |||
150 | bool 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 | |||
195 | bool 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 | |||
223 | bool 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 | |||
244 | bool 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 | |||
265 | bool 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 | |||
298 | bool 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 | |||
322 | void 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 | |||
329 | bool 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 | |||
340 | bool 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 | |||
395 | bool 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 | |||
426 | bool 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 | } | ||