/dlls/wined3d/resource.c

https://github.com/cournape/wine · C · 435 lines · 340 code · 67 blank · 28 comment · 53 complexity · e83cd14730fb791f016824546c3c05a8 MD5 · raw file

  1. /*
  2. * Copyright 2002-2004 Jason Edmeades
  3. * Copyright 2003-2004 Raphael Junqueira
  4. * Copyright 2004 Christian Costa
  5. * Copyright 2005 Oliver Stieber
  6. * Copyright 2009-2010 Henri Verbeet for CodeWeavers
  7. * Copyright 2006-2008, 2013 Stefan Dösinger for CodeWeavers
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation; either
  12. * version 2.1 of the License, or (at your option) any later version.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include "config.h"
  24. #include "wine/port.h"
  25. #include "wined3d_private.h"
  26. WINE_DEFAULT_DEBUG_CHANNEL(d3d);
  27. struct private_data
  28. {
  29. struct list entry;
  30. GUID tag;
  31. DWORD flags; /* DDSPD_* */
  32. union
  33. {
  34. void *data;
  35. IUnknown *object;
  36. } ptr;
  37. DWORD size;
  38. };
  39. static DWORD resource_access_from_pool(enum wined3d_pool pool)
  40. {
  41. switch (pool)
  42. {
  43. case WINED3D_POOL_DEFAULT:
  44. return WINED3D_RESOURCE_ACCESS_GPU;
  45. case WINED3D_POOL_MANAGED:
  46. return WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_CPU;
  47. case WINED3D_POOL_SCRATCH:
  48. case WINED3D_POOL_SYSTEM_MEM:
  49. return WINED3D_RESOURCE_ACCESS_CPU;
  50. default:
  51. FIXME("Unhandled pool %#x.\n", pool);
  52. return 0;
  53. }
  54. }
  55. static void resource_check_usage(DWORD usage)
  56. {
  57. static const DWORD handled = WINED3DUSAGE_RENDERTARGET
  58. | WINED3DUSAGE_DEPTHSTENCIL
  59. | WINED3DUSAGE_DYNAMIC
  60. | WINED3DUSAGE_AUTOGENMIPMAP
  61. | WINED3DUSAGE_STATICDECL
  62. | WINED3DUSAGE_OVERLAY
  63. | WINED3DUSAGE_TEXTURE;
  64. if (usage & ~handled)
  65. FIXME("Unhandled usage flags %#x.\n", usage & ~handled);
  66. }
  67. HRESULT resource_init(struct wined3d_resource *resource, struct wined3d_device *device,
  68. enum wined3d_resource_type type, const struct wined3d_format *format,
  69. enum wined3d_multisample_type multisample_type, UINT multisample_quality,
  70. DWORD usage, enum wined3d_pool pool, UINT width, UINT height, UINT depth, UINT size,
  71. void *parent, const struct wined3d_parent_ops *parent_ops,
  72. const struct wined3d_resource_ops *resource_ops)
  73. {
  74. const struct wined3d *d3d = device->wined3d;
  75. resource_check_usage(usage);
  76. if (pool != WINED3D_POOL_SCRATCH)
  77. {
  78. if ((usage & WINED3DUSAGE_RENDERTARGET) && !(format->flags & WINED3DFMT_FLAG_RENDERTARGET))
  79. return WINED3DERR_INVALIDCALL;
  80. if ((usage & WINED3DUSAGE_DEPTHSTENCIL) && !(format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
  81. return WINED3DERR_INVALIDCALL;
  82. if ((usage & WINED3DUSAGE_TEXTURE) && !(format->flags & WINED3DFMT_FLAG_TEXTURE))
  83. return WINED3DERR_INVALIDCALL;
  84. }
  85. resource->ref = 1;
  86. resource->device = device;
  87. resource->type = type;
  88. resource->format = format;
  89. resource->multisample_type = multisample_type;
  90. resource->multisample_quality = multisample_quality;
  91. resource->usage = usage;
  92. resource->pool = pool;
  93. resource->access_flags = resource_access_from_pool(pool);
  94. if (usage & WINED3DUSAGE_DYNAMIC)
  95. resource->access_flags |= WINED3D_RESOURCE_ACCESS_CPU;
  96. resource->width = width;
  97. resource->height = height;
  98. resource->depth = depth;
  99. resource->size = size;
  100. resource->priority = 0;
  101. resource->parent = parent;
  102. resource->parent_ops = parent_ops;
  103. resource->resource_ops = resource_ops;
  104. list_init(&resource->privateData);
  105. if (size)
  106. {
  107. if (!wined3d_resource_allocate_sysmem(resource))
  108. {
  109. ERR("Failed to allocate system memory.\n");
  110. return E_OUTOFMEMORY;
  111. }
  112. }
  113. else
  114. {
  115. resource->heap_memory = NULL;
  116. }
  117. resource->allocatedMemory = resource->heap_memory;
  118. /* Check that we have enough video ram left */
  119. if (pool == WINED3D_POOL_DEFAULT && d3d->flags & WINED3D_VIDMEM_ACCOUNTING)
  120. {
  121. if (size > wined3d_device_get_available_texture_mem(device))
  122. {
  123. ERR("Out of adapter memory\n");
  124. wined3d_resource_free_sysmem(resource);
  125. return WINED3DERR_OUTOFVIDEOMEMORY;
  126. }
  127. adapter_adjust_memory(device->adapter, size);
  128. }
  129. device_resource_add(device, resource);
  130. return WINED3D_OK;
  131. }
  132. void resource_cleanup(struct wined3d_resource *resource)
  133. {
  134. const struct wined3d *d3d = resource->device->wined3d;
  135. struct private_data *data;
  136. struct list *e1, *e2;
  137. HRESULT hr;
  138. TRACE("Cleaning up resource %p.\n", resource);
  139. if (resource->pool == WINED3D_POOL_DEFAULT && d3d->flags & WINED3D_VIDMEM_ACCOUNTING)
  140. {
  141. TRACE("Decrementing device memory pool by %u.\n", resource->size);
  142. adapter_adjust_memory(resource->device->adapter, 0 - resource->size);
  143. }
  144. LIST_FOR_EACH_SAFE(e1, e2, &resource->privateData)
  145. {
  146. data = LIST_ENTRY(e1, struct private_data, entry);
  147. hr = wined3d_resource_free_private_data(resource, &data->tag);
  148. if (FAILED(hr))
  149. ERR("Failed to free private data when destroying resource %p, hr = %#x.\n", resource, hr);
  150. }
  151. wined3d_resource_free_sysmem(resource);
  152. resource->allocatedMemory = NULL;
  153. device_resource_released(resource->device, resource);
  154. }
  155. void resource_unload(struct wined3d_resource *resource)
  156. {
  157. if (resource->map_count)
  158. ERR("Resource %p is being unloaded while mapped.\n", resource);
  159. context_resource_unloaded(resource->device,
  160. resource, resource->type);
  161. }
  162. static struct private_data *resource_find_private_data(const struct wined3d_resource *resource, REFGUID tag)
  163. {
  164. struct private_data *data;
  165. struct list *entry;
  166. TRACE("Searching for private data %s\n", debugstr_guid(tag));
  167. LIST_FOR_EACH(entry, &resource->privateData)
  168. {
  169. data = LIST_ENTRY(entry, struct private_data, entry);
  170. if (IsEqualGUID(&data->tag, tag)) {
  171. TRACE("Found %p\n", data);
  172. return data;
  173. }
  174. }
  175. TRACE("Not found\n");
  176. return NULL;
  177. }
  178. HRESULT CDECL wined3d_resource_set_private_data(struct wined3d_resource *resource, REFGUID guid,
  179. const void *data, DWORD data_size, DWORD flags)
  180. {
  181. struct private_data *d;
  182. TRACE("resource %p, riid %s, data %p, data_size %u, flags %#x.\n",
  183. resource, debugstr_guid(guid), data, data_size, flags);
  184. wined3d_resource_free_private_data(resource, guid);
  185. d = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*d));
  186. if (!d) return E_OUTOFMEMORY;
  187. d->tag = *guid;
  188. d->flags = flags;
  189. if (flags & WINED3DSPD_IUNKNOWN)
  190. {
  191. if (data_size != sizeof(IUnknown *))
  192. {
  193. WARN("IUnknown data with size %u, returning WINED3DERR_INVALIDCALL.\n", data_size);
  194. HeapFree(GetProcessHeap(), 0, d);
  195. return WINED3DERR_INVALIDCALL;
  196. }
  197. d->ptr.object = (IUnknown *)data;
  198. d->size = sizeof(IUnknown *);
  199. IUnknown_AddRef(d->ptr.object);
  200. }
  201. else
  202. {
  203. d->ptr.data = HeapAlloc(GetProcessHeap(), 0, data_size);
  204. if (!d->ptr.data)
  205. {
  206. HeapFree(GetProcessHeap(), 0, d);
  207. return E_OUTOFMEMORY;
  208. }
  209. d->size = data_size;
  210. memcpy(d->ptr.data, data, data_size);
  211. }
  212. list_add_tail(&resource->privateData, &d->entry);
  213. return WINED3D_OK;
  214. }
  215. HRESULT CDECL wined3d_resource_get_private_data(const struct wined3d_resource *resource, REFGUID guid,
  216. void *data, DWORD *data_size)
  217. {
  218. const struct private_data *d;
  219. TRACE("resource %p, guid %s, data %p, data_size %p.\n",
  220. resource, debugstr_guid(guid), data, data_size);
  221. d = resource_find_private_data(resource, guid);
  222. if (!d) return WINED3DERR_NOTFOUND;
  223. if (*data_size < d->size)
  224. {
  225. *data_size = d->size;
  226. return WINED3DERR_MOREDATA;
  227. }
  228. if (d->flags & WINED3DSPD_IUNKNOWN)
  229. {
  230. *(IUnknown **)data = d->ptr.object;
  231. if (resource->device->wined3d->dxVersion != 7)
  232. {
  233. /* D3D8 and D3D9 addref the private data, DDraw does not. This
  234. * can't be handled in ddraw because it doesn't know if the
  235. * pointer returned is an IUnknown * or just a blob. */
  236. IUnknown_AddRef(d->ptr.object);
  237. }
  238. }
  239. else
  240. {
  241. memcpy(data, d->ptr.data, d->size);
  242. }
  243. return WINED3D_OK;
  244. }
  245. HRESULT CDECL wined3d_resource_free_private_data(struct wined3d_resource *resource, REFGUID guid)
  246. {
  247. struct private_data *data;
  248. TRACE("resource %p, guid %s.\n", resource, debugstr_guid(guid));
  249. data = resource_find_private_data(resource, guid);
  250. if (!data) return WINED3DERR_NOTFOUND;
  251. if (data->flags & WINED3DSPD_IUNKNOWN)
  252. {
  253. if (data->ptr.object)
  254. IUnknown_Release(data->ptr.object);
  255. }
  256. else
  257. {
  258. HeapFree(GetProcessHeap(), 0, data->ptr.data);
  259. }
  260. list_remove(&data->entry);
  261. HeapFree(GetProcessHeap(), 0, data);
  262. return WINED3D_OK;
  263. }
  264. DWORD resource_set_priority(struct wined3d_resource *resource, DWORD priority)
  265. {
  266. DWORD prev = resource->priority;
  267. resource->priority = priority;
  268. TRACE("resource %p, new priority %u, returning old priority %u.\n", resource, priority, prev);
  269. return prev;
  270. }
  271. DWORD resource_get_priority(const struct wined3d_resource *resource)
  272. {
  273. TRACE("resource %p, returning %u.\n", resource, resource->priority);
  274. return resource->priority;
  275. }
  276. void * CDECL wined3d_resource_get_parent(const struct wined3d_resource *resource)
  277. {
  278. return resource->parent;
  279. }
  280. void CDECL wined3d_resource_set_parent(struct wined3d_resource *resource, void *parent)
  281. {
  282. resource->parent = parent;
  283. }
  284. void CDECL wined3d_resource_get_desc(const struct wined3d_resource *resource, struct wined3d_resource_desc *desc)
  285. {
  286. desc->resource_type = resource->type;
  287. desc->format = resource->format->id;
  288. desc->multisample_type = resource->multisample_type;
  289. desc->multisample_quality = resource->multisample_quality;
  290. desc->usage = resource->usage;
  291. desc->pool = resource->pool;
  292. desc->width = resource->width;
  293. desc->height = resource->height;
  294. desc->depth = resource->depth;
  295. desc->size = resource->size;
  296. }
  297. BOOL wined3d_resource_allocate_sysmem(struct wined3d_resource *resource)
  298. {
  299. void **p;
  300. SIZE_T align = RESOURCE_ALIGNMENT - 1 + sizeof(*p);
  301. void *mem;
  302. if (!(mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, resource->size + align)))
  303. return FALSE;
  304. p = (void **)(((ULONG_PTR)mem + align) & ~(RESOURCE_ALIGNMENT - 1)) - 1;
  305. *p = mem;
  306. resource->heap_memory = ++p;
  307. return TRUE;
  308. }
  309. void wined3d_resource_free_sysmem(struct wined3d_resource *resource)
  310. {
  311. void **p = resource->heap_memory;
  312. if (!p)
  313. return;
  314. HeapFree(GetProcessHeap(), 0, *(--p));
  315. resource->heap_memory = NULL;
  316. }
  317. DWORD wined3d_resource_sanitize_map_flags(const struct wined3d_resource *resource, DWORD flags)
  318. {
  319. /* Not all flags make sense together, but Windows never returns an error.
  320. * Catch the cases that could cause issues. */
  321. if (flags & WINED3D_MAP_READONLY)
  322. {
  323. if (flags & WINED3D_MAP_DISCARD)
  324. {
  325. WARN("WINED3D_MAP_READONLY combined with WINED3D_MAP_DISCARD, ignoring flags.\n");
  326. return 0;
  327. }
  328. if (flags & WINED3D_MAP_NOOVERWRITE)
  329. {
  330. WARN("WINED3D_MAP_READONLY combined with WINED3D_MAP_NOOVERWRITE, ignoring flags.\n");
  331. return 0;
  332. }
  333. }
  334. else if ((flags & (WINED3D_MAP_DISCARD | WINED3D_MAP_NOOVERWRITE))
  335. == (WINED3D_MAP_DISCARD | WINED3D_MAP_NOOVERWRITE))
  336. {
  337. WARN("WINED3D_MAP_DISCARD and WINED3D_MAP_NOOVERWRITE used together, ignoring.\n");
  338. return 0;
  339. }
  340. else if (flags & (WINED3D_MAP_DISCARD | WINED3D_MAP_NOOVERWRITE)
  341. && !(resource->usage & WINED3DUSAGE_DYNAMIC))
  342. {
  343. WARN("DISCARD or NOOVERWRITE map on non-dynamic buffer, ignoring.\n");
  344. return 0;
  345. }
  346. return flags;
  347. }
  348. GLbitfield wined3d_resource_gl_map_flags(DWORD d3d_flags)
  349. {
  350. GLbitfield ret = 0;
  351. if (!(d3d_flags & WINED3D_MAP_READONLY))
  352. ret |= GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT;
  353. if (!(d3d_flags & (WINED3D_MAP_DISCARD | WINED3D_MAP_NOOVERWRITE)))
  354. ret |= GL_MAP_READ_BIT;
  355. if (d3d_flags & WINED3D_MAP_DISCARD)
  356. ret |= GL_MAP_INVALIDATE_BUFFER_BIT;
  357. if (d3d_flags & WINED3D_MAP_NOOVERWRITE)
  358. ret |= GL_MAP_UNSYNCHRONIZED_BIT;
  359. return ret;
  360. }
  361. GLenum wined3d_resource_gl_legacy_map_flags(DWORD d3d_flags)
  362. {
  363. if (d3d_flags & WINED3D_MAP_READONLY)
  364. return GL_READ_ONLY_ARB;
  365. if (d3d_flags & (WINED3D_MAP_DISCARD | WINED3D_MAP_NOOVERWRITE))
  366. return GL_WRITE_ONLY_ARB;
  367. return GL_READ_WRITE_ARB;
  368. }