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
);
92 GL_EXTCALL(glTexImage3DEXT(GL_TEXTURE_3D
, level
, format
->glInternal
,
93 volume
->resource
.width
, volume
->resource
.height
, volume
->resource
.depth
,
94 0, format
->glFormat
, format
->glType
, volume
->resource
.allocatedMemory
));
95 checkGLcall("glTexImage3D");
98 /* When adding code releasing volume->resource.allocatedMemory to save
99 * data keep in mind that GL_UNPACK_CLIENT_STORAGE_APPLE is enabled by
100 * default if supported(GL_APPLE_client_storage). Thus do not release
101 * volume->resource.allocatedMemory if GL_APPLE_client_storage is
105 /* Do not call while under the GL lock. */
106 static void volume_unload(struct wined3d_resource
*resource
)
108 TRACE("texture %p.\n", resource
);
110 /* The whole content is shadowed on This->resource.allocatedMemory, and
111 * the texture name is managed by the VolumeTexture container. */
113 resource_unload(resource
);
116 ULONG CDECL
wined3d_volume_incref(struct wined3d_volume
*volume
)
120 if (volume
->container
)
122 TRACE("Forwarding to container %p.\n", volume
->container
);
123 return wined3d_texture_incref(volume
->container
);
126 refcount
= InterlockedIncrement(&volume
->resource
.ref
);
128 TRACE("%p increasing refcount to %u.\n", volume
, refcount
);
133 /* Do not call while under the GL lock. */
134 ULONG CDECL
wined3d_volume_decref(struct wined3d_volume
*volume
)
138 if (volume
->container
)
140 TRACE("Forwarding to container %p.\n", volume
->container
);
141 return wined3d_texture_decref(volume
->container
);
144 refcount
= InterlockedDecrement(&volume
->resource
.ref
);
146 TRACE("%p decreasing refcount to %u.\n", volume
, refcount
);
150 resource_cleanup(&volume
->resource
);
151 volume
->resource
.parent_ops
->wined3d_object_destroyed(volume
->resource
.parent
);
152 HeapFree(GetProcessHeap(), 0, volume
);
158 void * CDECL
wined3d_volume_get_parent(const struct wined3d_volume
*volume
)
160 TRACE("volume %p.\n", volume
);
162 return volume
->resource
.parent
;
165 DWORD CDECL
wined3d_volume_set_priority(struct wined3d_volume
*volume
, DWORD priority
)
167 return resource_set_priority(&volume
->resource
, priority
);
170 DWORD CDECL
wined3d_volume_get_priority(const struct wined3d_volume
*volume
)
172 return resource_get_priority(&volume
->resource
);
175 /* Do not call while under the GL lock. */
176 void CDECL
wined3d_volume_preload(struct wined3d_volume
*volume
)
178 FIXME("volume %p stub!\n", volume
);
181 struct wined3d_resource
* CDECL
wined3d_volume_get_resource(struct wined3d_volume
*volume
)
183 TRACE("volume %p.\n", volume
);
185 return &volume
->resource
;
188 HRESULT CDECL
wined3d_volume_map(struct wined3d_volume
*volume
,
189 struct wined3d_map_desc
*map_desc
, const struct wined3d_box
*box
, DWORD flags
)
191 TRACE("volume %p, map_desc %p, box %p, flags %#x.\n",
192 volume
, map_desc
, box
, flags
);
194 if (!volume
->resource
.allocatedMemory
)
195 volume
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, volume
->resource
.size
);
197 TRACE("allocatedMemory %p.\n", volume
->resource
.allocatedMemory
);
199 map_desc
->row_pitch
= volume
->resource
.format
->byte_count
* volume
->resource
.width
; /* Bytes / row */
200 map_desc
->slice_pitch
= volume
->resource
.format
->byte_count
201 * volume
->resource
.width
* volume
->resource
.height
; /* Bytes / slice */
204 TRACE("No box supplied - all is ok\n");
205 map_desc
->data
= volume
->resource
.allocatedMemory
;
206 volume
->lockedBox
.left
= 0;
207 volume
->lockedBox
.top
= 0;
208 volume
->lockedBox
.front
= 0;
209 volume
->lockedBox
.right
= volume
->resource
.width
;
210 volume
->lockedBox
.bottom
= volume
->resource
.height
;
211 volume
->lockedBox
.back
= volume
->resource
.depth
;
215 TRACE("Lock Box (%p) = l %u, t %u, r %u, b %u, fr %u, ba %u\n",
216 box
, box
->left
, box
->top
, box
->right
, box
->bottom
, box
->front
, box
->back
);
217 map_desc
->data
= volume
->resource
.allocatedMemory
218 + (map_desc
->slice_pitch
* box
->front
) /* FIXME: is front < back or vica versa? */
219 + (map_desc
->row_pitch
* box
->top
)
220 + (box
->left
* volume
->resource
.format
->byte_count
);
221 volume
->lockedBox
.left
= box
->left
;
222 volume
->lockedBox
.top
= box
->top
;
223 volume
->lockedBox
.front
= box
->front
;
224 volume
->lockedBox
.right
= box
->right
;
225 volume
->lockedBox
.bottom
= box
->bottom
;
226 volume
->lockedBox
.back
= box
->back
;
229 if (!(flags
& (WINED3D_MAP_NO_DIRTY_UPDATE
| WINED3D_MAP_READONLY
)))
231 volume_add_dirty_box(volume
, &volume
->lockedBox
);
232 wined3d_texture_set_dirty(volume
->container
, TRUE
);
235 volume
->locked
= TRUE
;
237 TRACE("Returning memory %p, row pitch %d, slice pitch %d.\n",
238 map_desc
->data
, map_desc
->row_pitch
, map_desc
->slice_pitch
);
243 struct wined3d_volume
* CDECL
wined3d_volume_from_resource(struct wined3d_resource
*resource
)
245 return volume_from_resource(resource
);
248 HRESULT CDECL
wined3d_volume_unmap(struct wined3d_volume
*volume
)
250 TRACE("volume %p.\n", volume
);
254 WARN("Trying to unlock unlocked volume %p.\n", volume
);
255 return WINED3DERR_INVALIDCALL
;
258 volume
->locked
= FALSE
;
259 memset(&volume
->lockedBox
, 0, sizeof(volume
->lockedBox
));
264 static const struct wined3d_resource_ops volume_resource_ops
=
269 static HRESULT
volume_init(struct wined3d_volume
*volume
, struct wined3d_device
*device
, UINT width
,
270 UINT height
, UINT depth
, DWORD usage
, enum wined3d_format_id format_id
, enum wined3d_pool pool
,
271 void *parent
, const struct wined3d_parent_ops
*parent_ops
)
273 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
274 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, format_id
);
277 if (!gl_info
->supported
[EXT_TEXTURE3D
])
279 WARN("Volume cannot be created - no volume texture support.\n");
280 return WINED3DERR_INVALIDCALL
;
283 hr
= resource_init(&volume
->resource
, device
, WINED3D_RTYPE_VOLUME
, format
,
284 WINED3D_MULTISAMPLE_NONE
, 0, usage
, pool
, width
, height
, depth
,
285 width
* height
* depth
* format
->byte_count
, parent
, parent_ops
,
286 &volume_resource_ops
);
289 WARN("Failed to initialize resource, returning %#x.\n", hr
);
293 volume
->lockable
= TRUE
;
294 volume
->locked
= FALSE
;
295 memset(&volume
->lockedBox
, 0, sizeof(volume
->lockedBox
));
296 volume
->dirty
= TRUE
;
298 volume_add_dirty_box(volume
, NULL
);
303 HRESULT CDECL
wined3d_volume_create(struct wined3d_device
*device
, UINT width
, UINT height
,
304 UINT depth
, DWORD usage
, enum wined3d_format_id format_id
, enum wined3d_pool pool
, void *parent
,
305 const struct wined3d_parent_ops
*parent_ops
, struct wined3d_volume
**volume
)
307 struct wined3d_volume
*object
;
310 TRACE("device %p, width %u, height %u, depth %u, usage %#x, format %s, pool %s\n",
311 device
, width
, height
, depth
, usage
, debug_d3dformat(format_id
), debug_d3dpool(pool
));
312 TRACE("parent %p, parent_ops %p, volume %p.\n", parent
, parent_ops
, volume
);
314 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
317 ERR("Out of memory\n");
319 return WINED3DERR_OUTOFVIDEOMEMORY
;
322 hr
= volume_init(object
, device
, width
, height
, depth
, usage
, format_id
, pool
, parent
, parent_ops
);
325 WARN("Failed to initialize volume, returning %#x.\n", hr
);
326 HeapFree(GetProcessHeap(), 0, object
);
330 TRACE("Created volume %p.\n", object
);