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 "wined3d_private.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface
);
27 /* Context activation is done by the caller. */
28 static void volume_bind_and_dirtify(const struct wined3d_volume
*volume
, struct wined3d_context
*context
)
30 struct wined3d_texture
*container
= volume
->container
;
33 /* We don't need a specific texture unit, but after binding the texture the current unit is dirty.
34 * Read the unit back instead of switching to 0, this avoids messing around with the state manager's
35 * gl states. The current texture unit should always be a valid one.
37 * To be more specific, this is tricky because we can implicitly be called
38 * from sampler() in state.c. This means we can't touch anything other than
39 * whatever happens to be the currently active texture, or we would risk
40 * marking already applied sampler states dirty again. */
41 active_sampler
= volume
->resource
.device
->rev_tex_unit_map
[context
->active_texture
];
43 if (active_sampler
!= WINED3D_UNMAPPED_STAGE
)
44 device_invalidate_state(volume
->resource
.device
, STATE_SAMPLER(active_sampler
));
46 container
->texture_ops
->texture_bind(container
, context
, FALSE
);
49 void volume_add_dirty_box(struct wined3d_volume
*volume
, const struct wined3d_box
*dirty_box
)
54 volume
->lockedBox
.left
= min(volume
->lockedBox
.left
, dirty_box
->left
);
55 volume
->lockedBox
.top
= min(volume
->lockedBox
.top
, dirty_box
->top
);
56 volume
->lockedBox
.front
= min(volume
->lockedBox
.front
, dirty_box
->front
);
57 volume
->lockedBox
.right
= max(volume
->lockedBox
.right
, dirty_box
->right
);
58 volume
->lockedBox
.bottom
= max(volume
->lockedBox
.bottom
, dirty_box
->bottom
);
59 volume
->lockedBox
.back
= max(volume
->lockedBox
.back
, dirty_box
->back
);
63 volume
->lockedBox
.left
= 0;
64 volume
->lockedBox
.top
= 0;
65 volume
->lockedBox
.front
= 0;
66 volume
->lockedBox
.right
= volume
->resource
.width
;
67 volume
->lockedBox
.bottom
= volume
->resource
.height
;
68 volume
->lockedBox
.back
= volume
->resource
.depth
;
72 void volume_set_container(struct wined3d_volume
*volume
, struct wined3d_texture
*container
)
74 TRACE("volume %p, container %p.\n", volume
, container
);
76 volume
->container
= container
;
79 /* Context activation is done by the caller. */
80 void volume_load(const struct wined3d_volume
*volume
, struct wined3d_context
*context
, UINT level
, BOOL srgb_mode
)
82 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
83 const struct wined3d_format
*format
= volume
->resource
.format
;
85 TRACE("volume %p, context %p, level %u, srgb %#x, format %s (%#x).\n",
86 volume
, context
, level
, srgb_mode
, debug_d3dformat(format
->id
), format
->id
);
88 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");
97 /* When adding code releasing volume->resource.allocatedMemory to save
98 * data keep in mind that GL_UNPACK_CLIENT_STORAGE_APPLE is enabled by
99 * default if supported(GL_APPLE_client_storage). Thus do not release
100 * volume->resource.allocatedMemory if GL_APPLE_client_storage is
104 /* Do not call while under the GL lock. */
105 static void volume_unload(struct wined3d_resource
*resource
)
107 TRACE("texture %p.\n", resource
);
109 /* The whole content is shadowed on This->resource.allocatedMemory, and
110 * the texture name is managed by the VolumeTexture container. */
112 resource_unload(resource
);
115 ULONG CDECL
wined3d_volume_incref(struct wined3d_volume
*volume
)
119 if (volume
->container
)
121 TRACE("Forwarding to container %p.\n", volume
->container
);
122 return wined3d_texture_incref(volume
->container
);
125 refcount
= InterlockedIncrement(&volume
->resource
.ref
);
127 TRACE("%p increasing refcount to %u.\n", volume
, refcount
);
132 /* Do not call while under the GL lock. */
133 ULONG CDECL
wined3d_volume_decref(struct wined3d_volume
*volume
)
137 if (volume
->container
)
139 TRACE("Forwarding to container %p.\n", volume
->container
);
140 return wined3d_texture_decref(volume
->container
);
143 refcount
= InterlockedDecrement(&volume
->resource
.ref
);
145 TRACE("%p decreasing refcount to %u.\n", volume
, refcount
);
149 resource_cleanup(&volume
->resource
);
150 volume
->resource
.parent_ops
->wined3d_object_destroyed(volume
->resource
.parent
);
151 HeapFree(GetProcessHeap(), 0, volume
);
157 void * CDECL
wined3d_volume_get_parent(const struct wined3d_volume
*volume
)
159 TRACE("volume %p.\n", volume
);
161 return volume
->resource
.parent
;
164 DWORD CDECL
wined3d_volume_set_priority(struct wined3d_volume
*volume
, DWORD priority
)
166 return resource_set_priority(&volume
->resource
, priority
);
169 DWORD CDECL
wined3d_volume_get_priority(const struct wined3d_volume
*volume
)
171 return resource_get_priority(&volume
->resource
);
174 /* Do not call while under the GL lock. */
175 void CDECL
wined3d_volume_preload(struct wined3d_volume
*volume
)
177 FIXME("volume %p stub!\n", volume
);
180 struct wined3d_resource
* CDECL
wined3d_volume_get_resource(struct wined3d_volume
*volume
)
182 TRACE("volume %p.\n", volume
);
184 return &volume
->resource
;
187 HRESULT CDECL
wined3d_volume_map(struct wined3d_volume
*volume
,
188 struct wined3d_mapped_box
*mapped_box
, const struct wined3d_box
*box
, DWORD flags
)
190 TRACE("volume %p, mapped_box %p, box %p, flags %#x.\n",
191 volume
, mapped_box
, box
, flags
);
193 if (!volume
->resource
.allocatedMemory
)
194 volume
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, volume
->resource
.size
);
196 TRACE("allocatedMemory %p.\n", volume
->resource
.allocatedMemory
);
198 mapped_box
->row_pitch
= volume
->resource
.format
->byte_count
* volume
->resource
.width
; /* Bytes / row */
199 mapped_box
->slice_pitch
= volume
->resource
.format
->byte_count
200 * volume
->resource
.width
* volume
->resource
.height
; /* Bytes / slice */
203 TRACE("No box supplied - all is ok\n");
204 mapped_box
->data
= volume
->resource
.allocatedMemory
;
205 volume
->lockedBox
.left
= 0;
206 volume
->lockedBox
.top
= 0;
207 volume
->lockedBox
.front
= 0;
208 volume
->lockedBox
.right
= volume
->resource
.width
;
209 volume
->lockedBox
.bottom
= volume
->resource
.height
;
210 volume
->lockedBox
.back
= volume
->resource
.depth
;
214 TRACE("Lock Box (%p) = l %u, t %u, r %u, b %u, fr %u, ba %u\n",
215 box
, box
->left
, box
->top
, box
->right
, box
->bottom
, box
->front
, box
->back
);
216 mapped_box
->data
= volume
->resource
.allocatedMemory
217 + (mapped_box
->slice_pitch
* box
->front
) /* FIXME: is front < back or vica versa? */
218 + (mapped_box
->row_pitch
* box
->top
)
219 + (box
->left
* volume
->resource
.format
->byte_count
);
220 volume
->lockedBox
.left
= box
->left
;
221 volume
->lockedBox
.top
= box
->top
;
222 volume
->lockedBox
.front
= box
->front
;
223 volume
->lockedBox
.right
= box
->right
;
224 volume
->lockedBox
.bottom
= box
->bottom
;
225 volume
->lockedBox
.back
= box
->back
;
228 if (!(flags
& (WINED3DLOCK_NO_DIRTY_UPDATE
| WINED3DLOCK_READONLY
)))
230 volume_add_dirty_box(volume
, &volume
->lockedBox
);
231 wined3d_texture_set_dirty(volume
->container
, TRUE
);
234 volume
->locked
= TRUE
;
236 TRACE("Returning memory %p, row pitch %d, slice pitch %d.\n",
237 mapped_box
->data
, mapped_box
->row_pitch
, mapped_box
->slice_pitch
);
242 struct wined3d_volume
* CDECL
wined3d_volume_from_resource(struct wined3d_resource
*resource
)
244 return volume_from_resource(resource
);
247 HRESULT CDECL
wined3d_volume_unmap(struct wined3d_volume
*volume
)
249 TRACE("volume %p.\n", volume
);
253 WARN("Trying to unlock unlocked volume %p.\n", volume
);
254 return WINED3DERR_INVALIDCALL
;
257 volume
->locked
= FALSE
;
258 memset(&volume
->lockedBox
, 0, sizeof(volume
->lockedBox
));
263 static const struct wined3d_resource_ops volume_resource_ops
=
268 static HRESULT
volume_init(struct wined3d_volume
*volume
, struct wined3d_device
*device
, UINT width
,
269 UINT height
, UINT depth
, DWORD usage
, enum wined3d_format_id format_id
, WINED3DPOOL pool
,
270 void *parent
, const struct wined3d_parent_ops
*parent_ops
)
272 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
273 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, format_id
);
276 if (!gl_info
->supported
[EXT_TEXTURE3D
])
278 WARN("Volume cannot be created - no volume texture support.\n");
279 return WINED3DERR_INVALIDCALL
;
282 hr
= resource_init(&volume
->resource
, device
, WINED3DRTYPE_VOLUME
, format
,
283 WINED3DMULTISAMPLE_NONE
, 0, usage
, pool
, width
, height
, depth
,
284 width
* height
* depth
* format
->byte_count
, parent
, parent_ops
,
285 &volume_resource_ops
);
288 WARN("Failed to initialize resource, returning %#x.\n", hr
);
292 volume
->lockable
= TRUE
;
293 volume
->locked
= FALSE
;
294 memset(&volume
->lockedBox
, 0, sizeof(volume
->lockedBox
));
295 volume
->dirty
= TRUE
;
297 volume_add_dirty_box(volume
, NULL
);
302 HRESULT CDECL
wined3d_volume_create(struct wined3d_device
*device
, UINT width
, UINT height
,
303 UINT depth
, DWORD usage
, enum wined3d_format_id format_id
, WINED3DPOOL pool
, void *parent
,
304 const struct wined3d_parent_ops
*parent_ops
, struct wined3d_volume
**volume
)
306 struct wined3d_volume
*object
;
309 TRACE("device %p, width %u, height %u, depth %u, usage %#x, format %s, pool %s\n",
310 device
, width
, height
, depth
, usage
, debug_d3dformat(format_id
), debug_d3dpool(pool
));
311 TRACE("parent %p, parent_ops %p, volume %p.\n", parent
, parent_ops
, volume
);
313 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
316 ERR("Out of memory\n");
318 return WINED3DERR_OUTOFVIDEOMEMORY
;
321 hr
= volume_init(object
, device
, width
, height
, depth
, usage
, format_id
, pool
, parent
, parent_ops
);
324 WARN("Failed to initialize volume, returning %#x.\n", hr
);
325 HeapFree(GetProcessHeap(), 0, object
);
329 TRACE("Created volume %p.\n", object
);