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