wow32: Use spec file imports.
[wine.git] / dlls / d3dx10_43 / async.c
blob626278868040325b1ab021772ead77453938d492
1 /*
2 * Copyright 2016 Andrey Gusev
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
20 #include "d3d10_1.h"
21 #include "d3dx10.h"
22 #include "d3dcompiler.h"
23 #include "dxhelpers.h"
24 #include "winternl.h"
26 #include "wine/debug.h"
27 #include "wine/list.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
31 struct asyncdataloader
33 ID3DX10DataLoader ID3DX10DataLoader_iface;
35 union
37 struct
39 WCHAR *path;
40 } file;
41 struct
43 HMODULE module;
44 HRSRC rsrc;
45 } resource;
46 } u;
47 void *data;
48 DWORD size;
51 static inline struct asyncdataloader *impl_from_ID3DX10DataLoader(ID3DX10DataLoader *iface)
53 return CONTAINING_RECORD(iface, struct asyncdataloader, ID3DX10DataLoader_iface);
56 static HRESULT WINAPI memorydataloader_Load(ID3DX10DataLoader *iface)
58 TRACE("iface %p.\n", iface);
59 return S_OK;
62 static HRESULT WINAPI memorydataloader_Decompress(ID3DX10DataLoader *iface, void **data, SIZE_T *size)
64 struct asyncdataloader *loader = impl_from_ID3DX10DataLoader(iface);
66 TRACE("iface %p, data %p, size %p.\n", iface, data, size);
68 *data = loader->data;
69 *size = loader->size;
71 return S_OK;
74 static HRESULT WINAPI memorydataloader_Destroy(ID3DX10DataLoader *iface)
76 struct asyncdataloader *loader = impl_from_ID3DX10DataLoader(iface);
78 TRACE("iface %p.\n", iface);
80 free(loader);
81 return S_OK;
84 static const ID3DX10DataLoaderVtbl memorydataloadervtbl =
86 memorydataloader_Load,
87 memorydataloader_Decompress,
88 memorydataloader_Destroy
91 HRESULT load_file(const WCHAR *path, void **data, DWORD *size)
93 DWORD read_len;
94 HANDLE file;
95 BOOL ret;
97 file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
98 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
99 if (file == INVALID_HANDLE_VALUE)
100 return D3D10_ERROR_FILE_NOT_FOUND;
102 *size = GetFileSize(file, NULL);
103 *data = malloc(*size);
104 if (!*data)
106 CloseHandle(file);
107 return E_OUTOFMEMORY;
110 ret = ReadFile(file, *data, *size, &read_len, NULL);
111 CloseHandle(file);
112 if (!ret || read_len != *size)
114 WARN("Failed to read file contents.\n");
115 free(*data);
116 return E_FAIL;
118 return S_OK;
121 static HRESULT WINAPI filedataloader_Load(ID3DX10DataLoader *iface)
123 struct asyncdataloader *loader = impl_from_ID3DX10DataLoader(iface);
124 void *data;
125 DWORD size;
126 HRESULT hr;
128 TRACE("iface %p.\n", iface);
130 /* Always buffer file contents, even if Load() was already called. */
131 if (FAILED((hr = load_file(loader->u.file.path, &data, &size))))
132 return hr;
134 free(loader->data);
135 loader->data = data;
136 loader->size = size;
138 return S_OK;
141 static HRESULT WINAPI filedataloader_Decompress(ID3DX10DataLoader *iface, void **data, SIZE_T *size)
143 struct asyncdataloader *loader = impl_from_ID3DX10DataLoader(iface);
145 TRACE("iface %p, data %p, size %p.\n", iface, data, size);
147 if (!loader->data)
148 return E_FAIL;
150 *data = loader->data;
151 *size = loader->size;
153 return S_OK;
156 static HRESULT WINAPI filedataloader_Destroy(ID3DX10DataLoader *iface)
158 struct asyncdataloader *loader = impl_from_ID3DX10DataLoader(iface);
160 TRACE("iface %p.\n", iface);
162 free(loader->u.file.path);
163 free(loader->data);
164 free(loader);
166 return S_OK;
169 static const ID3DX10DataLoaderVtbl filedataloadervtbl =
171 filedataloader_Load,
172 filedataloader_Decompress,
173 filedataloader_Destroy
176 static HRESULT load_resource_initA(HMODULE module, const char *resource, HRSRC *rsrc)
178 if (!(*rsrc = FindResourceA(module, resource, (const char *)RT_RCDATA)))
179 *rsrc = FindResourceA(module, resource, (const char *)RT_BITMAP);
180 if (!*rsrc)
182 WARN("Failed to find resource.\n");
183 return D3DX10_ERR_INVALID_DATA;
185 return S_OK;
188 static HRESULT load_resource_initW(HMODULE module, const WCHAR *resource, HRSRC *rsrc)
190 if (!(*rsrc = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)))
191 *rsrc = FindResourceW(module, resource, (const WCHAR *)RT_BITMAP);
192 if (!*rsrc)
194 WARN("Failed to find resource.\n");
195 return D3DX10_ERR_INVALID_DATA;
197 return S_OK;
200 static HRESULT load_resource(HMODULE module, HRSRC rsrc, void **data, DWORD *size)
202 HGLOBAL hglobal;
204 if (!(*size = SizeofResource(module, rsrc)))
205 return D3DX10_ERR_INVALID_DATA;
206 if (!(hglobal = LoadResource(module, rsrc)))
207 return D3DX10_ERR_INVALID_DATA;
208 if (!(*data = LockResource(hglobal)))
209 return D3DX10_ERR_INVALID_DATA;
210 return S_OK;
213 HRESULT load_resourceA(HMODULE module, const char *resource, void **data, DWORD *size)
215 HRESULT hr;
216 HRSRC rsrc;
218 if (FAILED((hr = load_resource_initA(module, resource, &rsrc))))
219 return hr;
220 return load_resource(module, rsrc, data, size);
223 HRESULT load_resourceW(HMODULE module, const WCHAR *resource, void **data, DWORD *size)
225 HRESULT hr;
226 HRSRC rsrc;
228 if ((FAILED(hr = load_resource_initW(module, resource, &rsrc))))
229 return hr;
230 return load_resource(module, rsrc, data, size);
233 static HRESULT WINAPI resourcedataloader_Load(ID3DX10DataLoader *iface)
235 struct asyncdataloader *loader = impl_from_ID3DX10DataLoader(iface);
237 TRACE("iface %p.\n", iface);
239 if (loader->data)
240 return S_OK;
242 return load_resource(loader->u.resource.module, loader->u.resource.rsrc,
243 &loader->data, &loader->size);
246 static HRESULT WINAPI resourcedataloader_Decompress(ID3DX10DataLoader *iface, void **data, SIZE_T *size)
248 struct asyncdataloader *loader = impl_from_ID3DX10DataLoader(iface);
250 TRACE("iface %p, data %p, size %p.\n", iface, data, size);
252 if (!loader->data)
253 return E_FAIL;
255 *data = loader->data;
256 *size = loader->size;
258 return S_OK;
261 static HRESULT WINAPI resourcedataloader_Destroy(ID3DX10DataLoader *iface)
263 struct asyncdataloader *loader = impl_from_ID3DX10DataLoader(iface);
265 TRACE("iface %p.\n", iface);
267 free(loader);
269 return S_OK;
272 static const ID3DX10DataLoaderVtbl resourcedataloadervtbl =
274 resourcedataloader_Load,
275 resourcedataloader_Decompress,
276 resourcedataloader_Destroy
279 struct texture_info_processor
281 ID3DX10DataProcessor ID3DX10DataProcessor_iface;
282 D3DX10_IMAGE_INFO *info;
285 static inline struct texture_info_processor *impl_from_ID3DX10DataProcessor(ID3DX10DataProcessor *iface)
287 return CONTAINING_RECORD(iface, struct texture_info_processor, ID3DX10DataProcessor_iface);
290 static HRESULT WINAPI texture_info_processor_Process(ID3DX10DataProcessor *iface, void *data, SIZE_T size)
292 struct texture_info_processor *processor = impl_from_ID3DX10DataProcessor(iface);
294 TRACE("iface %p, data %p, size %Iu.\n", iface, data, size);
295 return get_image_info(data, size, processor->info);
298 static HRESULT WINAPI texture_info_processor_CreateDeviceObject(ID3DX10DataProcessor *iface, void **object)
300 TRACE("iface %p, object %p.\n", iface, object);
301 return S_OK;
304 static HRESULT WINAPI texture_info_processor_Destroy(ID3DX10DataProcessor *iface)
306 struct texture_info_processor *processor = impl_from_ID3DX10DataProcessor(iface);
308 TRACE("iface %p.\n", iface);
310 free(processor);
311 return S_OK;
314 static ID3DX10DataProcessorVtbl texture_info_processor_vtbl =
316 texture_info_processor_Process,
317 texture_info_processor_CreateDeviceObject,
318 texture_info_processor_Destroy
321 struct texture_processor
323 ID3DX10DataProcessor ID3DX10DataProcessor_iface;
324 ID3D10Device *device;
325 D3DX10_IMAGE_LOAD_INFO load_info;
326 D3D10_SUBRESOURCE_DATA *resource_data;
329 static inline struct texture_processor *texture_processor_from_ID3DX10DataProcessor(ID3DX10DataProcessor *iface)
331 return CONTAINING_RECORD(iface, struct texture_processor, ID3DX10DataProcessor_iface);
334 static HRESULT WINAPI texture_processor_Process(ID3DX10DataProcessor *iface, void *data, SIZE_T size)
336 struct texture_processor *processor = texture_processor_from_ID3DX10DataProcessor(iface);
338 TRACE("iface %p, data %p, size %Iu.\n", iface, data, size);
340 if (processor->resource_data)
342 WARN("Called multiple times.\n");
343 free(processor->resource_data);
344 processor->resource_data = NULL;
346 return load_texture_data(data, size, &processor->load_info, &processor->resource_data);
349 static HRESULT WINAPI texture_processor_CreateDeviceObject(ID3DX10DataProcessor *iface, void **object)
351 struct texture_processor *processor = texture_processor_from_ID3DX10DataProcessor(iface);
353 TRACE("iface %p, object %p.\n", iface, object);
355 if (!processor->resource_data)
356 return E_FAIL;
358 return create_d3d_texture(processor->device, &processor->load_info,
359 processor->resource_data, (ID3D10Resource **)object);
362 static HRESULT WINAPI texture_processor_Destroy(ID3DX10DataProcessor *iface)
364 struct texture_processor *processor = texture_processor_from_ID3DX10DataProcessor(iface);
366 TRACE("iface %p.\n", iface);
368 ID3D10Device_Release(processor->device);
369 free(processor->resource_data);
370 free(processor);
371 return S_OK;
374 static ID3DX10DataProcessorVtbl texture_processor_vtbl =
376 texture_processor_Process,
377 texture_processor_CreateDeviceObject,
378 texture_processor_Destroy
381 HRESULT WINAPI D3DX10CompileFromMemory(const char *data, SIZE_T data_size, const char *filename,
382 const D3D10_SHADER_MACRO *defines, ID3D10Include *include, const char *entry_point,
383 const char *target, UINT sflags, UINT eflags, ID3DX10ThreadPump *pump, ID3D10Blob **shader,
384 ID3D10Blob **error_messages, HRESULT *hresult)
386 TRACE("data %s, data_size %Iu, filename %s, defines %p, include %p, entry_point %s, target %s, "
387 "sflags %#x, eflags %#x, pump %p, shader %p, error_messages %p, hresult %p.\n",
388 debugstr_an(data, data_size), data_size, debugstr_a(filename), defines, include,
389 debugstr_a(entry_point), debugstr_a(target), sflags, eflags, pump, shader,
390 error_messages, hresult);
392 if (pump)
393 FIXME("Unimplemented ID3DX10ThreadPump handling.\n");
395 return D3DCompile(data, data_size, filename, defines, include, entry_point, target,
396 sflags, eflags, shader, error_messages);
399 HRESULT WINAPI D3DX10CreateEffectPoolFromFileA(const char *filename, const D3D10_SHADER_MACRO *defines,
400 ID3D10Include *include, const char *profile, UINT hlslflags, UINT fxflags, ID3D10Device *device,
401 ID3DX10ThreadPump *pump, ID3D10EffectPool **effectpool, ID3D10Blob **errors, HRESULT *hresult)
403 FIXME("filename %s, defines %p, include %p, profile %s, hlslflags %#x, fxflags %#x, device %p, "
404 "pump %p, effectpool %p, errors %p, hresult %p, stub!\n",
405 debugstr_a(filename), defines, include, debugstr_a(profile), hlslflags, fxflags, device,
406 pump, effectpool, errors, hresult);
408 return E_NOTIMPL;
411 HRESULT WINAPI D3DX10CreateEffectPoolFromFileW(const WCHAR *filename, const D3D10_SHADER_MACRO *defines,
412 ID3D10Include *include, const char *profile, UINT hlslflags, UINT fxflags, ID3D10Device *device,
413 ID3DX10ThreadPump *pump, ID3D10EffectPool **effectpool, ID3D10Blob **errors, HRESULT *hresult)
415 FIXME("filename %s, defines %p, include %p, profile %s, hlslflags %#x, fxflags %#x, device %p, "
416 "pump %p, effectpool %p, errors %p, hresult %p, stub!\n",
417 debugstr_w(filename), defines, include, debugstr_a(profile), hlslflags, fxflags, device,
418 pump, effectpool, errors, hresult);
420 return E_NOTIMPL;
423 HRESULT WINAPI D3DX10CreateAsyncMemoryLoader(const void *data, SIZE_T data_size, ID3DX10DataLoader **loader)
425 struct asyncdataloader *object;
427 TRACE("data %p, data_size %Iu, loader %p.\n", data, data_size, loader);
429 if (!data || !loader)
430 return E_FAIL;
432 object = calloc(1, sizeof(*object));
433 if (!object)
434 return E_OUTOFMEMORY;
436 object->ID3DX10DataLoader_iface.lpVtbl = &memorydataloadervtbl;
437 object->data = (void *)data;
438 object->size = data_size;
440 *loader = &object->ID3DX10DataLoader_iface;
442 return S_OK;
445 HRESULT WINAPI D3DX10CreateAsyncFileLoaderA(const char *filename, ID3DX10DataLoader **loader)
447 WCHAR *filename_w;
448 HRESULT hr;
449 int len;
451 TRACE("filename %s, loader %p.\n", debugstr_a(filename), loader);
453 if (!filename || !loader)
454 return E_FAIL;
456 len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
457 filename_w = malloc(len * sizeof(*filename_w));
458 MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len);
460 hr = D3DX10CreateAsyncFileLoaderW(filename_w, loader);
462 free(filename_w);
464 return hr;
467 HRESULT WINAPI D3DX10CreateAsyncFileLoaderW(const WCHAR *filename, ID3DX10DataLoader **loader)
469 struct asyncdataloader *object;
471 TRACE("filename %s, loader %p.\n", debugstr_w(filename), loader);
473 if (!filename || !loader)
474 return E_FAIL;
476 object = calloc(1, sizeof(*object));
477 if (!object)
478 return E_OUTOFMEMORY;
480 object->ID3DX10DataLoader_iface.lpVtbl = &filedataloadervtbl;
481 object->u.file.path = malloc((lstrlenW(filename) + 1) * sizeof(WCHAR));
482 if (!object->u.file.path)
484 free(object);
485 return E_OUTOFMEMORY;
487 lstrcpyW(object->u.file.path, filename);
488 object->data = NULL;
489 object->size = 0;
491 *loader = &object->ID3DX10DataLoader_iface;
493 return S_OK;
496 HRESULT WINAPI D3DX10CreateAsyncResourceLoaderA(HMODULE module, const char *resource, ID3DX10DataLoader **loader)
498 struct asyncdataloader *object;
499 HRSRC rsrc;
500 HRESULT hr;
502 TRACE("module %p, resource %s, loader %p.\n", module, debugstr_a(resource), loader);
504 if (!loader)
505 return E_FAIL;
507 object = calloc(1, sizeof(*object));
508 if (!object)
509 return E_OUTOFMEMORY;
511 if (FAILED((hr = load_resource_initA(module, resource, &rsrc))))
513 free(object);
514 return hr;
517 object->ID3DX10DataLoader_iface.lpVtbl = &resourcedataloadervtbl;
518 object->u.resource.module = module;
519 object->u.resource.rsrc = rsrc;
520 object->data = NULL;
521 object->size = 0;
523 *loader = &object->ID3DX10DataLoader_iface;
525 return S_OK;
528 HRESULT WINAPI D3DX10CreateAsyncResourceLoaderW(HMODULE module, const WCHAR *resource, ID3DX10DataLoader **loader)
530 struct asyncdataloader *object;
531 HRSRC rsrc;
532 HRESULT hr;
534 TRACE("module %p, resource %s, loader %p.\n", module, debugstr_w(resource), loader);
536 if (!loader)
537 return E_FAIL;
539 object = calloc(1, sizeof(*object));
540 if (!object)
541 return E_OUTOFMEMORY;
543 if (FAILED((hr = load_resource_initW(module, resource, &rsrc))))
545 free(object);
546 return hr;
549 object->ID3DX10DataLoader_iface.lpVtbl = &resourcedataloadervtbl;
550 object->u.resource.module = module;
551 object->u.resource.rsrc = rsrc;
552 object->data = NULL;
553 object->size = 0;
555 *loader = &object->ID3DX10DataLoader_iface;
557 return S_OK;
560 HRESULT WINAPI D3DX10CreateAsyncTextureInfoProcessor(D3DX10_IMAGE_INFO *info, ID3DX10DataProcessor **processor)
562 struct texture_info_processor *object;
564 TRACE("info %p, processor %p.\n", info, processor);
566 if (!processor)
567 return E_INVALIDARG;
569 object = malloc(sizeof(*object));
570 if (!object)
571 return E_OUTOFMEMORY;
573 object->ID3DX10DataProcessor_iface.lpVtbl = &texture_info_processor_vtbl;
574 object->info = info;
576 *processor = &object->ID3DX10DataProcessor_iface;
577 return S_OK;
580 HRESULT WINAPI D3DX10CreateAsyncTextureProcessor(ID3D10Device *device,
581 D3DX10_IMAGE_LOAD_INFO *load_info, ID3DX10DataProcessor **processor)
583 struct texture_processor *object;
585 TRACE("device %p, load_info %p, processor %p.\n", device, load_info, processor);
587 if (!device || !processor)
588 return E_INVALIDARG;
590 object = calloc(1, sizeof(*object));
591 if (!object)
592 return E_OUTOFMEMORY;
594 object->ID3DX10DataProcessor_iface.lpVtbl = &texture_processor_vtbl;
595 object->device = device;
596 ID3D10Device_AddRef(device);
597 init_load_info(load_info, &object->load_info);
599 *processor = &object->ID3DX10DataProcessor_iface;
600 return S_OK;
603 struct work_item
605 struct list entry;
607 ID3DX10DataLoader *loader;
608 ID3DX10DataProcessor *processor;
609 HRESULT *result;
610 void **object;
613 static inline void work_item_free(struct work_item *work_item, BOOL cancel)
615 ID3DX10DataLoader_Destroy(work_item->loader);
616 ID3DX10DataProcessor_Destroy(work_item->processor);
617 if (cancel && work_item->result)
618 *work_item->result = S_FALSE;
619 free(work_item);
622 #define THREAD_PUMP_EXITING UINT_MAX
623 struct thread_pump
625 ID3DX10ThreadPump ID3DX10ThreadPump_iface;
626 LONG refcount;
628 LONG processing_count;
630 SRWLOCK io_lock;
631 CONDITION_VARIABLE io_cv;
632 unsigned int io_count;
633 struct list io_queue;
635 SRWLOCK proc_lock;
636 CONDITION_VARIABLE proc_cv;
637 unsigned int proc_count;
638 struct list proc_queue;
640 SRWLOCK device_lock;
641 unsigned int device_count;
642 struct list device_queue;
644 unsigned int thread_count;
645 HANDLE threads[1];
648 static inline struct thread_pump *impl_from_ID3DX10ThreadPump(ID3DX10ThreadPump *iface)
650 return CONTAINING_RECORD(iface, struct thread_pump, ID3DX10ThreadPump_iface);
653 static HRESULT WINAPI thread_pump_QueryInterface(ID3DX10ThreadPump *iface, REFIID riid, void **out)
655 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
657 if (IsEqualGUID(riid, &IID_ID3DX10ThreadPump)
658 || IsEqualGUID(riid, &IID_IUnknown))
660 ID3DX10ThreadPump_AddRef(iface);
661 *out = iface;
662 return S_OK;
665 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
666 *out = NULL;
667 return E_NOINTERFACE;
670 static ULONG WINAPI thread_pump_AddRef(ID3DX10ThreadPump *iface)
672 struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface);
673 ULONG refcount = InterlockedIncrement(&thread_pump->refcount);
675 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
677 return refcount;
680 static ULONG WINAPI thread_pump_Release(ID3DX10ThreadPump *iface)
682 struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface);
683 ULONG refcount = InterlockedDecrement(&thread_pump->refcount);
684 struct work_item *item, *next;
685 struct list list;
686 unsigned int i;
688 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
690 if (!refcount)
692 AcquireSRWLockExclusive(&thread_pump->io_lock);
693 thread_pump->io_count = THREAD_PUMP_EXITING;
694 ReleaseSRWLockExclusive(&thread_pump->io_lock);
695 WakeAllConditionVariable(&thread_pump->io_cv);
697 AcquireSRWLockExclusive(&thread_pump->proc_lock);
698 thread_pump->proc_count = THREAD_PUMP_EXITING;
699 ReleaseSRWLockExclusive(&thread_pump->proc_lock);
700 WakeAllConditionVariable(&thread_pump->proc_cv);
702 AcquireSRWLockExclusive(&thread_pump->device_lock);
703 thread_pump->device_count = THREAD_PUMP_EXITING;
704 ReleaseSRWLockExclusive(&thread_pump->device_lock);
706 for (i = 0; i < thread_pump->thread_count; ++i)
708 if (!thread_pump->threads[i])
709 continue;
711 WaitForSingleObject(thread_pump->threads[i], INFINITE);
712 CloseHandle(thread_pump->threads[i]);
715 list_init(&list);
716 list_move_tail(&list, &thread_pump->io_queue);
717 list_move_tail(&list, &thread_pump->proc_queue);
718 list_move_tail(&list, &thread_pump->device_queue);
719 LIST_FOR_EACH_ENTRY_SAFE(item, next, &list, struct work_item, entry)
721 list_remove(&item->entry);
722 work_item_free(item, TRUE);
725 free(thread_pump);
728 return refcount;
731 static HRESULT WINAPI thread_pump_AddWorkItem(ID3DX10ThreadPump *iface, ID3DX10DataLoader *loader,
732 ID3DX10DataProcessor *processor, HRESULT *result, void **object)
734 struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface);
735 struct work_item *work_item;
737 TRACE("iface %p, loader %p, processor %p, result %p, object %p.\n",
738 iface, loader, processor, result, object);
740 work_item = malloc(sizeof(*work_item));
741 if (!work_item)
742 return E_OUTOFMEMORY;
744 work_item->loader = loader;
745 work_item->processor = processor;
746 work_item->result = result;
747 work_item->object = object;
749 if (object)
750 *object = NULL;
752 InterlockedIncrement(&thread_pump->processing_count);
753 AcquireSRWLockExclusive(&thread_pump->io_lock);
754 ++thread_pump->io_count;
755 list_add_tail(&thread_pump->io_queue, &work_item->entry);
756 ReleaseSRWLockExclusive(&thread_pump->io_lock);
757 WakeConditionVariable(&thread_pump->io_cv);
758 return S_OK;
761 static UINT WINAPI thread_pump_GetWorkItemCount(ID3DX10ThreadPump *iface)
763 struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface);
764 UINT ret;
766 TRACE("iface %p.\n", iface);
768 AcquireSRWLockExclusive(&thread_pump->device_lock);
769 ret = thread_pump->processing_count + thread_pump->device_count;
770 ReleaseSRWLockExclusive(&thread_pump->device_lock);
771 return ret;
774 static HRESULT WINAPI thread_pump_WaitForAllItems(ID3DX10ThreadPump *iface)
776 struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface);
777 HRESULT hr;
778 LONG v;
780 TRACE("iface %p.\n", iface);
782 for (;;)
784 if (FAILED((hr = ID3DX10ThreadPump_ProcessDeviceWorkItems(iface, UINT_MAX))))
785 return hr;
787 AcquireSRWLockExclusive(&thread_pump->device_lock);
788 if (thread_pump->device_count)
790 ReleaseSRWLockExclusive(&thread_pump->device_lock);
791 continue;
793 v = thread_pump->processing_count;
794 ReleaseSRWLockExclusive(&thread_pump->device_lock);
795 if (!v)
796 break;
798 RtlWaitOnAddress(&thread_pump->processing_count, &v, sizeof(v), NULL);
801 return S_OK;
804 static HRESULT WINAPI thread_pump_ProcessDeviceWorkItems(ID3DX10ThreadPump *iface, UINT count)
806 struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface);
807 struct work_item *work_item;
808 HRESULT hr;
809 UINT i;
811 TRACE("iface %p, count %u.\n", iface, count);
813 for (i = 0; i < count; ++i)
815 AcquireSRWLockExclusive(&thread_pump->device_lock);
816 if (!thread_pump->device_count)
818 ReleaseSRWLockExclusive(&thread_pump->device_lock);
819 break;
822 --thread_pump->device_count;
823 work_item = LIST_ENTRY(list_head(&thread_pump->device_queue), struct work_item, entry);
824 list_remove(&work_item->entry);
825 ReleaseSRWLockExclusive(&thread_pump->device_lock);
827 hr = ID3DX10DataProcessor_CreateDeviceObject(work_item->processor, work_item->object);
828 if (work_item->result)
829 *work_item->result = hr;
830 work_item_free(work_item, FALSE);
833 return S_OK;
836 static void purge_list(struct list *list, LONG *count)
838 struct work_item *work_item;
840 while (!list_empty(list))
842 work_item = LIST_ENTRY(list_head(list), struct work_item, entry);
843 list_remove(&work_item->entry);
844 work_item_free(work_item, TRUE);
846 if (count && !InterlockedDecrement(count))
847 RtlWakeAddressAll(count);
851 static HRESULT WINAPI thread_pump_PurgeAllItems(ID3DX10ThreadPump *iface)
853 struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface);
854 LONG v;
856 TRACE("iface %p.\n", iface);
858 for (;;)
860 AcquireSRWLockExclusive(&thread_pump->io_lock);
861 purge_list(&thread_pump->io_queue, &thread_pump->processing_count);
862 thread_pump->io_count = 0;
863 ReleaseSRWLockExclusive(&thread_pump->io_lock);
865 AcquireSRWLockExclusive(&thread_pump->proc_lock);
866 purge_list(&thread_pump->proc_queue, &thread_pump->processing_count);
867 thread_pump->proc_count = 0;
868 ReleaseSRWLockExclusive(&thread_pump->proc_lock);
870 AcquireSRWLockExclusive(&thread_pump->device_lock);
871 purge_list(&thread_pump->device_queue, NULL);
872 thread_pump->device_count = 0;
873 v = thread_pump->processing_count;
874 ReleaseSRWLockExclusive(&thread_pump->device_lock);
875 if (!v)
876 break;
878 RtlWaitOnAddress(&thread_pump->processing_count, &v, sizeof(v), NULL);
881 return S_OK;
884 static HRESULT WINAPI thread_pump_GetQueueStatus(ID3DX10ThreadPump *iface,
885 UINT *io_queue, UINT *process_queue, UINT *device_queue)
887 struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface);
889 TRACE("iface %p, io_queue %p, process_queue %p, device_queue %p.\n",
890 iface, io_queue, process_queue, device_queue);
892 *io_queue = thread_pump->io_count;
893 *process_queue = thread_pump->proc_count;
894 *device_queue = thread_pump->device_count;
895 return S_OK;
898 static const ID3DX10ThreadPumpVtbl thread_pump_vtbl =
900 thread_pump_QueryInterface,
901 thread_pump_AddRef,
902 thread_pump_Release,
903 thread_pump_AddWorkItem,
904 thread_pump_GetWorkItemCount,
905 thread_pump_WaitForAllItems,
906 thread_pump_ProcessDeviceWorkItems,
907 thread_pump_PurgeAllItems,
908 thread_pump_GetQueueStatus
911 static DWORD WINAPI io_thread(void *arg)
913 struct thread_pump *thread_pump = arg;
914 struct work_item *work_item;
915 HRESULT hr;
917 TRACE("%p thread started.\n", thread_pump);
919 for (;;)
921 AcquireSRWLockExclusive(&thread_pump->io_lock);
923 while (!thread_pump->io_count)
924 SleepConditionVariableSRW(&thread_pump->io_cv, &thread_pump->io_lock, INFINITE, 0);
926 if (thread_pump->io_count == THREAD_PUMP_EXITING)
928 ReleaseSRWLockExclusive(&thread_pump->io_lock);
929 return 0;
932 --thread_pump->io_count;
933 work_item = LIST_ENTRY(list_head(&thread_pump->io_queue), struct work_item, entry);
934 list_remove(&work_item->entry);
935 ReleaseSRWLockExclusive(&thread_pump->io_lock);
937 if (FAILED(hr = ID3DX10DataLoader_Load(work_item->loader)))
939 if (work_item->result)
940 *work_item->result = hr;
941 work_item_free(work_item, FALSE);
942 if (!InterlockedDecrement(&thread_pump->processing_count))
943 RtlWakeAddressAll(&thread_pump->processing_count);
944 continue;
947 AcquireSRWLockExclusive(&thread_pump->proc_lock);
948 if (thread_pump->proc_count == THREAD_PUMP_EXITING)
950 ReleaseSRWLockExclusive(&thread_pump->proc_lock);
951 work_item_free(work_item, TRUE);
952 return 0;
955 list_add_tail(&thread_pump->proc_queue, &work_item->entry);
956 ++thread_pump->proc_count;
957 ReleaseSRWLockExclusive(&thread_pump->proc_lock);
958 WakeConditionVariable(&thread_pump->proc_cv);
960 return 0;
963 static DWORD WINAPI proc_thread(void *arg)
965 struct thread_pump *thread_pump = arg;
966 struct work_item *work_item;
967 SIZE_T size;
968 void *data;
969 HRESULT hr;
971 TRACE("%p thread started.\n", thread_pump);
973 for (;;)
975 AcquireSRWLockExclusive(&thread_pump->proc_lock);
977 while (!thread_pump->proc_count)
978 SleepConditionVariableSRW(&thread_pump->proc_cv, &thread_pump->proc_lock, INFINITE, 0);
980 if (thread_pump->proc_count == THREAD_PUMP_EXITING)
982 ReleaseSRWLockExclusive(&thread_pump->proc_lock);
983 return 0;
986 --thread_pump->proc_count;
987 work_item = LIST_ENTRY(list_head(&thread_pump->proc_queue), struct work_item, entry);
988 list_remove(&work_item->entry);
989 ReleaseSRWLockExclusive(&thread_pump->proc_lock);
991 if (FAILED(hr = ID3DX10DataLoader_Decompress(work_item->loader, &data, &size)))
993 if (work_item->result)
994 *work_item->result = hr;
995 work_item_free(work_item, FALSE);
996 if (!InterlockedDecrement(&thread_pump->processing_count))
997 RtlWakeAddressAll(&thread_pump->processing_count);
998 continue;
1001 if (thread_pump->device_count == THREAD_PUMP_EXITING)
1003 work_item_free(work_item, TRUE);
1004 return 0;
1007 if (FAILED(hr = ID3DX10DataProcessor_Process(work_item->processor, data, size)))
1009 if (work_item->result)
1010 *work_item->result = hr;
1011 work_item_free(work_item, FALSE);
1012 if (!InterlockedDecrement(&thread_pump->processing_count))
1013 RtlWakeAddressAll(&thread_pump->processing_count);
1014 continue;
1017 AcquireSRWLockExclusive(&thread_pump->device_lock);
1018 if (thread_pump->device_count == THREAD_PUMP_EXITING)
1020 ReleaseSRWLockExclusive(&thread_pump->device_lock);
1021 work_item_free(work_item, TRUE);
1022 return 0;
1025 list_add_tail(&thread_pump->device_queue, &work_item->entry);
1026 ++thread_pump->device_count;
1027 InterlockedDecrement(&thread_pump->processing_count);
1028 RtlWakeAddressAll(&thread_pump->processing_count);
1029 ReleaseSRWLockExclusive(&thread_pump->device_lock);
1031 return 0;
1034 HRESULT WINAPI D3DX10CreateThreadPump(UINT io_threads, UINT proc_threads, ID3DX10ThreadPump **pump)
1036 struct thread_pump *object;
1037 unsigned int i;
1039 TRACE("io_threads %u, proc_threads %u, pump %p.\n", io_threads, proc_threads, pump);
1041 if (io_threads >= 1024 || proc_threads >= 1024)
1042 return E_FAIL;
1044 if (!io_threads)
1045 io_threads = 1;
1046 if (!proc_threads)
1048 SYSTEM_INFO info;
1050 GetSystemInfo(&info);
1051 proc_threads = info.dwNumberOfProcessors;
1054 if (!(object = calloc(1, FIELD_OFFSET(struct thread_pump, threads[io_threads + proc_threads]))))
1055 return E_OUTOFMEMORY;
1057 object->ID3DX10ThreadPump_iface.lpVtbl = &thread_pump_vtbl;
1058 object->refcount = 1;
1059 InitializeSRWLock(&object->io_lock);
1060 InitializeConditionVariable(&object->io_cv);
1061 list_init(&object->io_queue);
1062 InitializeSRWLock(&object->proc_lock);
1063 InitializeConditionVariable(&object->proc_cv);
1064 list_init(&object->proc_queue);
1065 InitializeSRWLock(&object->device_lock);
1066 list_init(&object->device_queue);
1067 object->thread_count = io_threads + proc_threads;
1069 for (i = 0; i < object->thread_count; ++i)
1071 object->threads[i] = CreateThread(NULL, 0, i < io_threads ? io_thread : proc_thread, object, 0, NULL);
1072 if (!object->threads[i])
1074 ID3DX10ThreadPump_Release(&object->ID3DX10ThreadPump_iface);
1075 return E_FAIL;
1079 *pump = &object->ID3DX10ThreadPump_iface;
1080 return S_OK;