oleaut32: Convert CustData to use standard linked lists.
[wine.git] / dlls / wined3d / volume.c
blobd05a9f2f83a67ffa27f313704aeae993515fc56b
1 /*
2 * IWineD3DVolume implementation
4 * Copyright 2002-2005 Jason Edmeades
5 * Copyright 2002-2005 Raphael Junqueira
6 * Copyright 2005 Oliver Stieber
7 * Copyright 2009-2010 Henri Verbeet for CodeWeavers
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.
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.
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
24 #include "config.h"
25 #include "wined3d_private.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
29 /* Context activation is done by the caller. */
30 static void volume_bind_and_dirtify(struct IWineD3DVolumeImpl *volume, const struct wined3d_gl_info *gl_info)
32 IWineD3DBaseTextureImpl *container = (IWineD3DBaseTextureImpl *)volume->container;
33 DWORD active_sampler;
35 /* We don't need a specific texture unit, but after binding the texture the current unit is dirty.
36 * Read the unit back instead of switching to 0, this avoids messing around with the state manager's
37 * gl states. The current texture unit should always be a valid one.
39 * To be more specific, this is tricky because we can implicitly be called
40 * from sampler() in state.c. This means we can't touch anything other than
41 * whatever happens to be the currently active texture, or we would risk
42 * marking already applied sampler states dirty again.
44 * TODO: Track the current active texture per GL context instead of using glGet
46 if (gl_info->supported[ARB_MULTITEXTURE])
48 GLint active_texture;
49 ENTER_GL();
50 glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
51 LEAVE_GL();
52 active_sampler = volume->resource.device->rev_tex_unit_map[active_texture - GL_TEXTURE0_ARB];
53 } else {
54 active_sampler = 0;
57 if (active_sampler != WINED3D_UNMAPPED_STAGE)
59 IWineD3DDeviceImpl_MarkStateDirty(volume->resource.device, STATE_SAMPLER(active_sampler));
62 container->baseTexture.texture_ops->texture_bind(container, gl_info, FALSE);
65 void volume_add_dirty_box(struct IWineD3DVolumeImpl *volume, const WINED3DBOX *dirty_box)
67 volume->dirty = TRUE;
68 if (dirty_box)
70 volume->lockedBox.Left = min(volume->lockedBox.Left, dirty_box->Left);
71 volume->lockedBox.Top = min(volume->lockedBox.Top, dirty_box->Top);
72 volume->lockedBox.Front = min(volume->lockedBox.Front, dirty_box->Front);
73 volume->lockedBox.Right = max(volume->lockedBox.Right, dirty_box->Right);
74 volume->lockedBox.Bottom = max(volume->lockedBox.Bottom, dirty_box->Bottom);
75 volume->lockedBox.Back = max(volume->lockedBox.Back, dirty_box->Back);
77 else
79 volume->lockedBox.Left = 0;
80 volume->lockedBox.Top = 0;
81 volume->lockedBox.Front = 0;
82 volume->lockedBox.Right = volume->resource.width;
83 volume->lockedBox.Bottom = volume->resource.height;
84 volume->lockedBox.Back = volume->resource.depth;
88 void volume_set_container(IWineD3DVolumeImpl *volume, struct IWineD3DVolumeTextureImpl *container)
90 TRACE("volume %p, container %p.\n", volume, container);
92 volume->container = container;
95 /* Context activation is done by the caller. */
96 void volume_load(IWineD3DVolumeImpl *volume, UINT level, BOOL srgb_mode)
98 const struct wined3d_gl_info *gl_info = &volume->resource.device->adapter->gl_info;
99 const struct wined3d_format *format = volume->resource.format;
101 TRACE("volume %p, level %u, srgb %#x, format %s (%#x).\n",
102 volume, level, srgb_mode, debug_d3dformat(format->id), format->id);
104 volume_bind_and_dirtify(volume, gl_info);
106 ENTER_GL();
107 GL_EXTCALL(glTexImage3DEXT(GL_TEXTURE_3D, level, format->glInternal,
108 volume->resource.width, volume->resource.height, volume->resource.depth,
109 0, format->glFormat, format->glType, volume->resource.allocatedMemory));
110 checkGLcall("glTexImage3D");
111 LEAVE_GL();
113 /* When adding code releasing volume->resource.allocatedMemory to save
114 * data keep in mind that GL_UNPACK_CLIENT_STORAGE_APPLE is enabled by
115 * default if supported(GL_APPLE_client_storage). Thus do not release
116 * volume->resource.allocatedMemory if GL_APPLE_client_storage is
117 * supported. */
120 /* Do not call while under the GL lock. */
121 static void volume_unload(struct wined3d_resource *resource)
123 TRACE("texture %p.\n", resource);
125 /* The whole content is shadowed on This->resource.allocatedMemory, and
126 * the texture name is managed by the VolumeTexture container. */
128 resource_unload(resource);
131 /* *******************************************
132 IWineD3DVolume IUnknown parts follow
133 ******************************************* */
134 static HRESULT WINAPI IWineD3DVolumeImpl_QueryInterface(IWineD3DVolume *iface, REFIID riid, void **object)
136 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
138 if (IsEqualGUID(riid, &IID_IWineD3DVolume)
139 || IsEqualGUID(riid, &IID_IWineD3DResource)
140 || IsEqualGUID(riid, &IID_IWineD3DBase)
141 || IsEqualGUID(riid, &IID_IUnknown))
143 IUnknown_AddRef(iface);
144 *object = iface;
145 return S_OK;
148 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
150 *object = NULL;
151 return E_NOINTERFACE;
154 static ULONG WINAPI IWineD3DVolumeImpl_AddRef(IWineD3DVolume *iface) {
155 IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface;
156 TRACE("(%p) : AddRef increasing from %d\n", This, This->resource.ref);
157 return InterlockedIncrement(&This->resource.ref);
160 /* Do not call while under the GL lock. */
161 static ULONG WINAPI IWineD3DVolumeImpl_Release(IWineD3DVolume *iface) {
162 IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface;
163 ULONG ref;
164 TRACE("(%p) : Releasing from %d\n", This, This->resource.ref);
165 ref = InterlockedDecrement(&This->resource.ref);
167 if (!ref)
169 resource_cleanup(&This->resource);
170 This->resource.parent_ops->wined3d_object_destroyed(This->resource.parent);
171 HeapFree(GetProcessHeap(), 0, This);
173 return ref;
176 /* ****************************************************
177 IWineD3DVolume IWineD3DResource parts follow
178 **************************************************** */
179 static void * WINAPI IWineD3DVolumeImpl_GetParent(IWineD3DVolume *iface)
181 TRACE("iface %p.\n", iface);
183 return ((IWineD3DVolumeImpl *)iface)->resource.parent;
186 static HRESULT WINAPI IWineD3DVolumeImpl_SetPrivateData(IWineD3DVolume *iface,
187 REFGUID riid, const void *data, DWORD data_size, DWORD flags)
189 return resource_set_private_data(&((IWineD3DVolumeImpl *)iface)->resource, riid, data, data_size, flags);
192 static HRESULT WINAPI IWineD3DVolumeImpl_GetPrivateData(IWineD3DVolume *iface,
193 REFGUID guid, void *data, DWORD *data_size)
195 return resource_get_private_data(&((IWineD3DVolumeImpl *)iface)->resource, guid, data, data_size);
198 static HRESULT WINAPI IWineD3DVolumeImpl_FreePrivateData(IWineD3DVolume *iface, REFGUID refguid)
200 return resource_free_private_data(&((IWineD3DVolumeImpl *)iface)->resource, refguid);
203 static DWORD WINAPI IWineD3DVolumeImpl_SetPriority(IWineD3DVolume *iface, DWORD priority)
205 return resource_set_priority(&((IWineD3DVolumeImpl *)iface)->resource, priority);
208 static DWORD WINAPI IWineD3DVolumeImpl_GetPriority(IWineD3DVolume *iface)
210 return resource_get_priority(&((IWineD3DVolumeImpl *)iface)->resource);
213 /* Do not call while under the GL lock. */
214 static void WINAPI IWineD3DVolumeImpl_PreLoad(IWineD3DVolume *iface) {
215 FIXME("iface %p stub!\n", iface);
218 static WINED3DRESOURCETYPE WINAPI IWineD3DVolumeImpl_GetType(IWineD3DVolume *iface)
220 return resource_get_type(&((IWineD3DVolumeImpl *)iface)->resource);
223 struct wined3d_resource * WINAPI IWineD3DVolumeImpl_GetResource(IWineD3DVolume *iface)
225 TRACE("iface %p.\n", iface);
227 return &((IWineD3DVolumeImpl *)iface)->resource;
230 static HRESULT WINAPI IWineD3DVolumeImpl_Map(IWineD3DVolume *iface,
231 WINED3DLOCKED_BOX *pLockedVolume, const WINED3DBOX *pBox, DWORD flags)
233 IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface;
234 FIXME("(%p) : pBox=%p stub\n", This, pBox);
236 if(!This->resource.allocatedMemory) {
237 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->resource.size);
240 /* fixme: should we really lock as such? */
241 TRACE("(%p) : box=%p, output pbox=%p, allMem=%p\n", This, pBox, pLockedVolume, This->resource.allocatedMemory);
243 pLockedVolume->RowPitch = This->resource.format->byte_count * This->resource.width; /* Bytes / row */
244 pLockedVolume->SlicePitch = This->resource.format->byte_count
245 * This->resource.width * This->resource.height; /* Bytes / slice */
246 if (!pBox) {
247 TRACE("No box supplied - all is ok\n");
248 pLockedVolume->pBits = This->resource.allocatedMemory;
249 This->lockedBox.Left = 0;
250 This->lockedBox.Top = 0;
251 This->lockedBox.Front = 0;
252 This->lockedBox.Right = This->resource.width;
253 This->lockedBox.Bottom = This->resource.height;
254 This->lockedBox.Back = This->resource.depth;
255 } else {
256 TRACE("Lock Box (%p) = l %d, t %d, r %d, b %d, fr %d, ba %d\n", pBox, pBox->Left, pBox->Top, pBox->Right, pBox->Bottom, pBox->Front, pBox->Back);
257 pLockedVolume->pBits = This->resource.allocatedMemory
258 + (pLockedVolume->SlicePitch * pBox->Front) /* FIXME: is front < back or vica versa? */
259 + (pLockedVolume->RowPitch * pBox->Top)
260 + (pBox->Left * This->resource.format->byte_count);
261 This->lockedBox.Left = pBox->Left;
262 This->lockedBox.Top = pBox->Top;
263 This->lockedBox.Front = pBox->Front;
264 This->lockedBox.Right = pBox->Right;
265 This->lockedBox.Bottom = pBox->Bottom;
266 This->lockedBox.Back = pBox->Back;
269 if (!(flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)))
271 volume_add_dirty_box(This, &This->lockedBox);
272 basetexture_set_dirty((IWineD3DBaseTextureImpl *)This->container, TRUE);
275 This->locked = TRUE;
276 TRACE("returning memory@%p rpitch(%d) spitch(%d)\n", pLockedVolume->pBits, pLockedVolume->RowPitch, pLockedVolume->SlicePitch);
277 return WINED3D_OK;
280 static HRESULT WINAPI IWineD3DVolumeImpl_Unmap(IWineD3DVolume *iface)
282 IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface;
283 if (!This->locked)
285 WARN("Trying to unlock unlocked volume %p.\n", iface);
286 return WINED3DERR_INVALIDCALL;
288 TRACE("(%p) : unlocking volume\n", This);
289 This->locked = FALSE;
290 memset(&This->lockedBox, 0, sizeof(This->lockedBox));
291 return WINED3D_OK;
294 static const IWineD3DVolumeVtbl IWineD3DVolume_Vtbl =
296 /* IUnknown */
297 IWineD3DVolumeImpl_QueryInterface,
298 IWineD3DVolumeImpl_AddRef,
299 IWineD3DVolumeImpl_Release,
300 /* IWineD3DResource */
301 IWineD3DVolumeImpl_GetParent,
302 IWineD3DVolumeImpl_SetPrivateData,
303 IWineD3DVolumeImpl_GetPrivateData,
304 IWineD3DVolumeImpl_FreePrivateData,
305 IWineD3DVolumeImpl_SetPriority,
306 IWineD3DVolumeImpl_GetPriority,
307 IWineD3DVolumeImpl_PreLoad,
308 IWineD3DVolumeImpl_GetType,
309 /* IWineD3DVolume */
310 IWineD3DVolumeImpl_GetResource,
311 IWineD3DVolumeImpl_Map,
312 IWineD3DVolumeImpl_Unmap,
315 static const struct wined3d_resource_ops volume_resource_ops =
317 volume_unload,
320 HRESULT volume_init(IWineD3DVolumeImpl *volume, IWineD3DDeviceImpl *device, UINT width,
321 UINT height, UINT depth, DWORD usage, enum wined3d_format_id format_id, WINED3DPOOL pool,
322 void *parent, const struct wined3d_parent_ops *parent_ops)
324 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
325 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
326 HRESULT hr;
328 if (!gl_info->supported[EXT_TEXTURE3D])
330 WARN("Volume cannot be created - no volume texture support.\n");
331 return WINED3DERR_INVALIDCALL;
334 volume->lpVtbl = &IWineD3DVolume_Vtbl;
336 hr = resource_init(&volume->resource, device, WINED3DRTYPE_VOLUME, format,
337 WINED3DMULTISAMPLE_NONE, 0, usage, pool, width, height, depth,
338 width * height * depth * format->byte_count, parent, parent_ops,
339 &volume_resource_ops);
340 if (FAILED(hr))
342 WARN("Failed to initialize resource, returning %#x.\n", hr);
343 return hr;
346 volume->lockable = TRUE;
347 volume->locked = FALSE;
348 memset(&volume->lockedBox, 0, sizeof(volume->lockedBox));
349 volume->dirty = TRUE;
351 volume_add_dirty_box(volume, NULL);
353 return WINED3D_OK;