2 * Copyright 2002-2005 Jason Edmeades
3 * Copyright 2002-2005 Raphael Junqueira
4 * Copyright 2005 Oliver Stieber
5 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/port.h"
24 #include "wined3d_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface
);
28 /* Context activation is done by the caller. */
29 static void volume_bind_and_dirtify(const struct wined3d_volume
*volume
, struct wined3d_context
*context
)
31 struct wined3d_texture
*container
= volume
->container
;
34 /* We don't need a specific texture unit, but after binding the texture the current unit is dirty.
35 * Read the unit back instead of switching to 0, this avoids messing around with the state manager's
36 * gl states. The current texture unit should always be a valid one.
38 * To be more specific, this is tricky because we can implicitly be called
39 * from sampler() in state.c. This means we can't touch anything other than
40 * whatever happens to be the currently active texture, or we would risk
41 * marking already applied sampler states dirty again. */
42 active_sampler
= volume
->resource
.device
->rev_tex_unit_map
[context
->active_texture
];
44 if (active_sampler
!= WINED3D_UNMAPPED_STAGE
)
45 device_invalidate_state(volume
->resource
.device
, STATE_SAMPLER(active_sampler
));
47 container
->texture_ops
->texture_bind(container
, context
, FALSE
);
50 void volume_add_dirty_box(struct wined3d_volume
*volume
, const struct wined3d_box
*dirty_box
)
55 volume
->lockedBox
.left
= min(volume
->lockedBox
.left
, dirty_box
->left
);
56 volume
->lockedBox
.top
= min(volume
->lockedBox
.top
, dirty_box
->top
);
57 volume
->lockedBox
.front
= min(volume
->lockedBox
.front
, dirty_box
->front
);
58 volume
->lockedBox
.right
= max(volume
->lockedBox
.right
, dirty_box
->right
);
59 volume
->lockedBox
.bottom
= max(volume
->lockedBox
.bottom
, dirty_box
->bottom
);
60 volume
->lockedBox
.back
= max(volume
->lockedBox
.back
, dirty_box
->back
);
64 volume
->lockedBox
.left
= 0;
65 volume
->lockedBox
.top
= 0;
66 volume
->lockedBox
.front
= 0;
67 volume
->lockedBox
.right
= volume
->resource
.width
;
68 volume
->lockedBox
.bottom
= volume
->resource
.height
;
69 volume
->lockedBox
.back
= volume
->resource
.depth
;
73 void volume_set_container(struct wined3d_volume
*volume
, struct wined3d_texture
*container
)
75 TRACE("volume %p, container %p.\n", volume
, container
);
77 volume
->container
= container
;
80 /* Context activation is done by the caller. */
81 void volume_load(const struct wined3d_volume
*volume
, struct wined3d_context
*context
, UINT level
, BOOL srgb_mode
)
83 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
84 const struct wined3d_format
*format
= volume
->resource
.format
;
86 TRACE("volume %p, context %p, level %u, srgb %#x, format %s (%#x).\n",
87 volume
, context
, level
, srgb_mode
, debug_d3dformat(format
->id
), format
->id
);
89 volume_bind_and_dirtify(volume
, context
);
91 GL_EXTCALL(glTexImage3DEXT(GL_TEXTURE_3D
, level
, format
->glInternal
,
92 volume
->resource
.width
, volume
->resource
.height
, volume
->resource
.depth
,
93 0, format
->glFormat
, format
->glType
, volume
->resource
.allocatedMemory
));
94 checkGLcall("glTexImage3D");
96 /* When adding code releasing volume->resource.allocatedMemory to save
97 * data keep in mind that GL_UNPACK_CLIENT_STORAGE_APPLE is enabled by
98 * default if supported(GL_APPLE_client_storage). Thus do not release
99 * volume->resource.allocatedMemory if GL_APPLE_client_storage is
103 /* Do not call while under the GL lock. */
104 static void volume_unload(struct wined3d_resource
*resource
)
106 TRACE("texture %p.\n", resource
);
108 /* The whole content is shadowed on This->resource.allocatedMemory, and
109 * the texture name is managed by the VolumeTexture container. */
111 resource_unload(resource
);
114 ULONG CDECL
wined3d_volume_incref(struct wined3d_volume
*volume
)
118 if (volume
->container
)
120 TRACE("Forwarding to container %p.\n", volume
->container
);
121 return wined3d_texture_incref(volume
->container
);
124 refcount
= InterlockedIncrement(&volume
->resource
.ref
);
126 TRACE("%p increasing refcount to %u.\n", volume
, refcount
);
131 /* Do not call while under the GL lock. */
132 ULONG CDECL
wined3d_volume_decref(struct wined3d_volume
*volume
)
136 if (volume
->container
)
138 TRACE("Forwarding to container %p.\n", volume
->container
);
139 return wined3d_texture_decref(volume
->container
);
142 refcount
= InterlockedDecrement(&volume
->resource
.ref
);
144 TRACE("%p decreasing refcount to %u.\n", volume
, refcount
);
148 resource_cleanup(&volume
->resource
);
149 volume
->resource
.parent_ops
->wined3d_object_destroyed(volume
->resource
.parent
);
150 HeapFree(GetProcessHeap(), 0, volume
);
156 void * CDECL
wined3d_volume_get_parent(const struct wined3d_volume
*volume
)
158 TRACE("volume %p.\n", volume
);
160 return volume
->resource
.parent
;
163 DWORD CDECL
wined3d_volume_set_priority(struct wined3d_volume
*volume
, DWORD priority
)
165 return resource_set_priority(&volume
->resource
, priority
);
168 DWORD CDECL
wined3d_volume_get_priority(const struct wined3d_volume
*volume
)
170 return resource_get_priority(&volume
->resource
);
173 /* Do not call while under the GL lock. */
174 void CDECL
wined3d_volume_preload(struct wined3d_volume
*volume
)
176 FIXME("volume %p stub!\n", volume
);
179 struct wined3d_resource
* CDECL
wined3d_volume_get_resource(struct wined3d_volume
*volume
)
181 TRACE("volume %p.\n", volume
);
183 return &volume
->resource
;
186 HRESULT CDECL
wined3d_volume_map(struct wined3d_volume
*volume
,
187 struct wined3d_map_desc
*map_desc
, const struct wined3d_box
*box
, DWORD flags
)
189 TRACE("volume %p, map_desc %p, box %p, flags %#x.\n",
190 volume
, map_desc
, box
, flags
);
192 if (!volume
->resource
.allocatedMemory
)
193 volume
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, volume
->resource
.size
);
195 TRACE("allocatedMemory %p.\n", volume
->resource
.allocatedMemory
);
197 map_desc
->row_pitch
= volume
->resource
.format
->byte_count
* volume
->resource
.width
; /* Bytes / row */
198 map_desc
->slice_pitch
= volume
->resource
.format
->byte_count
199 * volume
->resource
.width
* volume
->resource
.height
; /* Bytes / slice */
202 TRACE("No box supplied - all is ok\n");
203 map_desc
->data
= volume
->resource
.allocatedMemory
;
204 volume
->lockedBox
.left
= 0;
205 volume
->lockedBox
.top
= 0;
206 volume
->lockedBox
.front
= 0;
207 volume
->lockedBox
.right
= volume
->resource
.width
;
208 volume
->lockedBox
.bottom
= volume
->resource
.height
;
209 volume
->lockedBox
.back
= volume
->resource
.depth
;
213 TRACE("Lock Box (%p) = l %u, t %u, r %u, b %u, fr %u, ba %u\n",
214 box
, box
->left
, box
->top
, box
->right
, box
->bottom
, box
->front
, box
->back
);
215 map_desc
->data
= volume
->resource
.allocatedMemory
216 + (map_desc
->slice_pitch
* box
->front
) /* FIXME: is front < back or vica versa? */
217 + (map_desc
->row_pitch
* box
->top
)
218 + (box
->left
* volume
->resource
.format
->byte_count
);
219 volume
->lockedBox
.left
= box
->left
;
220 volume
->lockedBox
.top
= box
->top
;
221 volume
->lockedBox
.front
= box
->front
;
222 volume
->lockedBox
.right
= box
->right
;
223 volume
->lockedBox
.bottom
= box
->bottom
;
224 volume
->lockedBox
.back
= box
->back
;
227 if (!(flags
& (WINED3D_MAP_NO_DIRTY_UPDATE
| WINED3D_MAP_READONLY
)))
229 volume_add_dirty_box(volume
, &volume
->lockedBox
);
230 wined3d_texture_set_dirty(volume
->container
, TRUE
);
233 volume
->locked
= TRUE
;
235 TRACE("Returning memory %p, row pitch %d, slice pitch %d.\n",
236 map_desc
->data
, map_desc
->row_pitch
, map_desc
->slice_pitch
);
241 struct wined3d_volume
* CDECL
wined3d_volume_from_resource(struct wined3d_resource
*resource
)
243 return volume_from_resource(resource
);
246 HRESULT CDECL
wined3d_volume_unmap(struct wined3d_volume
*volume
)
248 TRACE("volume %p.\n", volume
);
252 WARN("Trying to unlock unlocked volume %p.\n", volume
);
253 return WINED3DERR_INVALIDCALL
;
256 volume
->locked
= FALSE
;
257 memset(&volume
->lockedBox
, 0, sizeof(volume
->lockedBox
));
262 static const struct wined3d_resource_ops volume_resource_ops
=
267 static HRESULT
volume_init(struct wined3d_volume
*volume
, struct wined3d_device
*device
, UINT width
,
268 UINT height
, UINT depth
, DWORD usage
, enum wined3d_format_id format_id
, enum wined3d_pool pool
,
269 void *parent
, const struct wined3d_parent_ops
*parent_ops
)
271 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
272 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, format_id
);
275 if (!gl_info
->supported
[EXT_TEXTURE3D
])
277 WARN("Volume cannot be created - no volume texture support.\n");
278 return WINED3DERR_INVALIDCALL
;
281 hr
= resource_init(&volume
->resource
, device
, WINED3D_RTYPE_VOLUME
, format
,
282 WINED3D_MULTISAMPLE_NONE
, 0, usage
, pool
, width
, height
, depth
,
283 width
* height
* depth
* format
->byte_count
, parent
, parent_ops
,
284 &volume_resource_ops
);
287 WARN("Failed to initialize resource, returning %#x.\n", hr
);
291 volume
->lockable
= TRUE
;
292 volume
->locked
= FALSE
;
293 memset(&volume
->lockedBox
, 0, sizeof(volume
->lockedBox
));
294 volume
->dirty
= TRUE
;
296 volume_add_dirty_box(volume
, NULL
);
301 HRESULT CDECL
wined3d_volume_create(struct wined3d_device
*device
, UINT width
, UINT height
,
302 UINT depth
, DWORD usage
, enum wined3d_format_id format_id
, enum wined3d_pool pool
, void *parent
,
303 const struct wined3d_parent_ops
*parent_ops
, struct wined3d_volume
**volume
)
305 struct wined3d_volume
*object
;
308 TRACE("device %p, width %u, height %u, depth %u, usage %#x, format %s, pool %s\n",
309 device
, width
, height
, depth
, usage
, debug_d3dformat(format_id
), debug_d3dpool(pool
));
310 TRACE("parent %p, parent_ops %p, volume %p.\n", parent
, parent_ops
, volume
);
312 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
316 return WINED3DERR_OUTOFVIDEOMEMORY
;
319 hr
= volume_init(object
, device
, width
, height
, depth
, usage
, format_id
, pool
, parent
, parent_ops
);
322 WARN("Failed to initialize volume, returning %#x.\n", hr
);
323 HeapFree(GetProcessHeap(), 0, object
);
327 TRACE("Created volume %p.\n", object
);