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
6 * Copyright 2013 Stefan Dösinger for CodeWeavers
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.
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.
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
24 #include "wine/port.h"
25 #include "wined3d_private.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface
);
28 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf
);
30 /* Context activation is done by the caller. */
31 static void volume_bind_and_dirtify(const struct wined3d_volume
*volume
,
32 struct wined3d_context
*context
, BOOL srgb
)
36 /* We don't need a specific texture unit, but after binding the texture the current unit is dirty.
37 * Read the unit back instead of switching to 0, this avoids messing around with the state manager's
38 * gl states. The current texture unit should always be a valid one.
40 * To be more specific, this is tricky because we can implicitly be called
41 * from sampler() in state.c. This means we can't touch anything other than
42 * whatever happens to be the currently active texture, or we would risk
43 * marking already applied sampler states dirty again. */
44 active_sampler
= context
->rev_tex_unit_map
[context
->active_texture
];
46 if (active_sampler
!= WINED3D_UNMAPPED_STAGE
)
47 context_invalidate_state(context
, STATE_SAMPLER(active_sampler
));
49 wined3d_texture_bind(volume
->container
, context
, srgb
);
52 void volume_set_container(struct wined3d_volume
*volume
, struct wined3d_texture
*container
)
54 TRACE("volume %p, container %p.\n", volume
, container
);
56 volume
->container
= container
;
59 static BOOL
volume_prepare_system_memory(struct wined3d_volume
*volume
)
61 if (volume
->resource
.heap_memory
)
64 if (!wined3d_resource_allocate_sysmem(&volume
->resource
))
66 ERR("Failed to allocate system memory.\n");
72 /* Context activation is done by the caller. */
73 static void wined3d_volume_allocate_texture(struct wined3d_volume
*volume
,
74 const struct wined3d_context
*context
, BOOL srgb
)
76 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
77 const struct wined3d_format
*format
= volume
->resource
.format
;
80 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
] && !format
->convert
81 && volume_prepare_system_memory(volume
))
83 TRACE("Enabling GL_UNPACK_CLIENT_STORAGE_APPLE for volume %p\n", volume
);
84 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
85 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
86 mem
= volume
->resource
.heap_memory
;
87 volume
->flags
|= WINED3D_VFLAG_CLIENT_STORAGE
;
90 GL_EXTCALL(glTexImage3DEXT(GL_TEXTURE_3D
, volume
->texture_level
,
91 srgb
? format
->glGammaInternal
: format
->glInternal
,
92 volume
->resource
.width
, volume
->resource
.height
, volume
->resource
.depth
,
93 0, format
->glFormat
, format
->glType
, mem
));
94 checkGLcall("glTexImage3D");
98 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
99 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
103 static void wined3d_volume_get_pitch(const struct wined3d_volume
*volume
, UINT
*row_pitch
,
106 const struct wined3d_format
*format
= volume
->resource
.format
;
108 if (format
->flags
& WINED3DFMT_FLAG_BLOCKS
)
110 /* Since compressed formats are block based, pitch means the amount of
111 * bytes to the next row of block rather than the next row of pixels. */
112 UINT row_block_count
= (volume
->resource
.width
+ format
->block_width
- 1) / format
->block_width
;
113 UINT slice_block_count
= (volume
->resource
.height
+ format
->block_height
- 1) / format
->block_height
;
114 *row_pitch
= row_block_count
* format
->block_byte_count
;
115 *slice_pitch
= *row_pitch
* slice_block_count
;
119 unsigned char alignment
= volume
->resource
.device
->surface_alignment
;
120 *row_pitch
= format
->byte_count
* volume
->resource
.width
; /* Bytes / row */
121 *row_pitch
= (*row_pitch
+ alignment
- 1) & ~(alignment
- 1);
122 *slice_pitch
= *row_pitch
* volume
->resource
.height
;
125 TRACE("Returning row pitch %u, slice pitch %u.\n", *row_pitch
, *slice_pitch
);
128 /* Context activation is done by the caller. */
129 void wined3d_volume_upload_data(struct wined3d_volume
*volume
, const struct wined3d_context
*context
,
130 const struct wined3d_bo_address
*data
)
132 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
133 const struct wined3d_format
*format
= volume
->resource
.format
;
134 UINT width
= volume
->resource
.width
;
135 UINT height
= volume
->resource
.height
;
136 UINT depth
= volume
->resource
.depth
;
137 BYTE
*mem
= data
->addr
;
139 TRACE("volume %p, context %p, level %u, format %s (%#x).\n",
140 volume
, context
, volume
->texture_level
, debug_d3dformat(format
->id
),
145 UINT dst_row_pitch
, dst_slice_pitch
;
146 UINT src_row_pitch
, src_slice_pitch
;
147 UINT alignment
= volume
->resource
.device
->surface_alignment
;
149 if (data
->buffer_object
)
150 ERR("Loading a converted volume from a PBO.\n");
151 if (format
->flags
& WINED3DFMT_FLAG_BLOCKS
)
152 ERR("Converting a block-based format.\n");
154 dst_row_pitch
= width
* format
->conv_byte_count
;
155 dst_row_pitch
= (dst_row_pitch
+ alignment
- 1) & ~(alignment
- 1);
156 dst_slice_pitch
= dst_row_pitch
* height
;
158 wined3d_volume_get_pitch(volume
, &src_row_pitch
, &src_slice_pitch
);
160 mem
= HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch
* depth
);
161 format
->convert(data
->addr
, mem
, src_row_pitch
, src_slice_pitch
,
162 dst_row_pitch
, dst_slice_pitch
, width
, height
, depth
);
165 if (data
->buffer_object
)
167 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, data
->buffer_object
));
168 checkGLcall("glBindBufferARB");
171 GL_EXTCALL(glTexSubImage3DEXT(GL_TEXTURE_3D
, volume
->texture_level
, 0, 0, 0,
172 width
, height
, depth
,
173 format
->glFormat
, format
->glType
, mem
));
174 checkGLcall("glTexSubImage3D");
176 if (data
->buffer_object
)
178 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
179 checkGLcall("glBindBufferARB");
182 if (mem
!= data
->addr
)
183 HeapFree(GetProcessHeap(), 0, mem
);
186 static void wined3d_volume_validate_location(struct wined3d_volume
*volume
, DWORD location
)
188 TRACE("Volume %p, setting %s.\n", volume
, wined3d_debug_location(location
));
189 volume
->locations
|= location
;
190 TRACE("new location flags are %s.\n", wined3d_debug_location(volume
->locations
));
193 void wined3d_volume_invalidate_location(struct wined3d_volume
*volume
, DWORD location
)
195 TRACE("Volume %p, clearing %s.\n", volume
, wined3d_debug_location(location
));
196 volume
->locations
&= ~location
;
197 TRACE("new location flags are %s.\n", wined3d_debug_location(volume
->locations
));
200 /* Context activation is done by the caller. */
201 static void wined3d_volume_download_data(struct wined3d_volume
*volume
,
202 const struct wined3d_context
*context
, const struct wined3d_bo_address
*data
)
204 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
205 const struct wined3d_format
*format
= volume
->resource
.format
;
209 FIXME("Attempting to download a converted volume, format %s.\n",
210 debug_d3dformat(format
->id
));
214 if (data
->buffer_object
)
216 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, data
->buffer_object
));
217 checkGLcall("glBindBufferARB");
220 gl_info
->gl_ops
.gl
.p_glGetTexImage(GL_TEXTURE_3D
, volume
->texture_level
,
221 format
->glFormat
, format
->glType
, data
->addr
);
222 checkGLcall("glGetTexImage");
224 if (data
->buffer_object
)
226 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
227 checkGLcall("glBindBufferARB");
232 static void wined3d_volume_evict_sysmem(struct wined3d_volume
*volume
)
234 wined3d_resource_free_sysmem(&volume
->resource
);
235 wined3d_volume_invalidate_location(volume
, WINED3D_LOCATION_SYSMEM
);
238 static DWORD
volume_access_from_location(DWORD location
)
242 case WINED3D_LOCATION_DISCARDED
:
245 case WINED3D_LOCATION_SYSMEM
:
246 return WINED3D_RESOURCE_ACCESS_CPU
;
248 case WINED3D_LOCATION_BUFFER
:
249 case WINED3D_LOCATION_TEXTURE_RGB
:
250 case WINED3D_LOCATION_TEXTURE_SRGB
:
251 return WINED3D_RESOURCE_ACCESS_GPU
;
254 FIXME("Unhandled location %#x.\n", location
);
259 /* Context activation is done by the caller. */
260 static void wined3d_volume_srgb_transfer(struct wined3d_volume
*volume
,
261 struct wined3d_context
*context
, BOOL dest_is_srgb
)
263 struct wined3d_bo_address data
;
264 /* Optimizations are possible, but the effort should be put into either
265 * implementing EXT_SRGB_DECODE in the driver or finding out why we
266 * picked the wrong copy for the original upload and fixing that.
268 * Also keep in mind that we want to avoid using resource.heap_memory
269 * for DEFAULT pool surfaces. */
271 WARN_(d3d_perf
)("Performing slow rgb/srgb volume transfer.\n");
272 data
.buffer_object
= 0;
273 data
.addr
= HeapAlloc(GetProcessHeap(), 0, volume
->resource
.size
);
277 volume_bind_and_dirtify(volume
, context
, !dest_is_srgb
);
278 wined3d_volume_download_data(volume
, context
, &data
);
279 volume_bind_and_dirtify(volume
, context
, dest_is_srgb
);
280 wined3d_volume_upload_data(volume
, context
, &data
);
282 HeapFree(GetProcessHeap(), 0, data
.addr
);
285 static BOOL
wined3d_volume_can_evict(const struct wined3d_volume
*volume
)
287 if (volume
->resource
.pool
!= WINED3D_POOL_MANAGED
)
289 if (volume
->download_count
>= 10)
291 if (volume
->resource
.format
->convert
)
293 if (volume
->flags
& WINED3D_VFLAG_CLIENT_STORAGE
)
298 /* Context activation is done by the caller. */
299 static void wined3d_volume_load_location(struct wined3d_volume
*volume
,
300 struct wined3d_context
*context
, DWORD location
)
302 DWORD required_access
= volume_access_from_location(location
);
304 TRACE("Volume %p, loading %s, have %s.\n", volume
, wined3d_debug_location(location
),
305 wined3d_debug_location(volume
->locations
));
307 if ((volume
->locations
& location
) == location
)
309 TRACE("Location(s) already up to date.\n");
313 if ((volume
->resource
.access_flags
& required_access
) != required_access
)
315 ERR("Operation requires %#x access, but volume only has %#x.\n",
316 required_access
, volume
->resource
.access_flags
);
322 case WINED3D_LOCATION_TEXTURE_RGB
:
323 case WINED3D_LOCATION_TEXTURE_SRGB
:
324 if ((location
== WINED3D_LOCATION_TEXTURE_RGB
325 && !(volume
->flags
& WINED3D_VFLAG_ALLOCATED
))
326 || (location
== WINED3D_LOCATION_TEXTURE_SRGB
327 && !(volume
->flags
& WINED3D_VFLAG_SRGB_ALLOCATED
)))
328 ERR("Trying to load (s)RGB texture without prior allocation.\n");
330 if (volume
->locations
& WINED3D_LOCATION_DISCARDED
)
332 TRACE("Volume previously discarded, nothing to do.\n");
333 wined3d_volume_invalidate_location(volume
, WINED3D_LOCATION_DISCARDED
);
335 else if (volume
->locations
& WINED3D_LOCATION_SYSMEM
)
337 struct wined3d_bo_address data
= {0, volume
->resource
.heap_memory
};
338 wined3d_volume_upload_data(volume
, context
, &data
);
340 else if (volume
->locations
& WINED3D_LOCATION_BUFFER
)
342 struct wined3d_bo_address data
= {volume
->pbo
, NULL
};
343 wined3d_volume_upload_data(volume
, context
, &data
);
345 else if (volume
->locations
& WINED3D_LOCATION_TEXTURE_RGB
)
347 wined3d_volume_srgb_transfer(volume
, context
, TRUE
);
349 else if (volume
->locations
& WINED3D_LOCATION_TEXTURE_SRGB
)
351 wined3d_volume_srgb_transfer(volume
, context
, FALSE
);
355 FIXME("Implement texture loading from %s.\n", wined3d_debug_location(volume
->locations
));
358 wined3d_volume_validate_location(volume
, location
);
360 if (wined3d_volume_can_evict(volume
))
361 wined3d_volume_evict_sysmem(volume
);
365 case WINED3D_LOCATION_SYSMEM
:
366 if (!volume
->resource
.heap_memory
)
367 ERR("Trying to load WINED3D_LOCATION_SYSMEM without setting it up first.\n");
369 if (volume
->locations
& WINED3D_LOCATION_DISCARDED
)
371 TRACE("Volume previously discarded, nothing to do.\n");
372 wined3d_volume_invalidate_location(volume
, WINED3D_LOCATION_DISCARDED
);
374 else if (volume
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
376 struct wined3d_bo_address data
= {0, volume
->resource
.heap_memory
};
378 if (volume
->locations
& WINED3D_LOCATION_TEXTURE_RGB
)
379 volume_bind_and_dirtify(volume
, context
, FALSE
);
381 volume_bind_and_dirtify(volume
, context
, TRUE
);
383 volume
->download_count
++;
384 wined3d_volume_download_data(volume
, context
, &data
);
388 FIXME("Implement WINED3D_LOCATION_SYSMEM loading from %s.\n",
389 wined3d_debug_location(volume
->locations
));
392 wined3d_volume_validate_location(volume
, WINED3D_LOCATION_SYSMEM
);
395 case WINED3D_LOCATION_BUFFER
:
396 if (!volume
->pbo
|| !(volume
->flags
& WINED3D_VFLAG_PBO
))
397 ERR("Trying to load WINED3D_LOCATION_BUFFER without setting it up first.\n");
399 if (volume
->locations
& WINED3D_LOCATION_DISCARDED
)
401 TRACE("Volume previously discarded, nothing to do.\n");
402 wined3d_volume_invalidate_location(volume
, WINED3D_LOCATION_DISCARDED
);
404 else if (volume
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
406 struct wined3d_bo_address data
= {volume
->pbo
, NULL
};
408 if (volume
->locations
& WINED3D_LOCATION_TEXTURE_RGB
)
409 volume_bind_and_dirtify(volume
, context
, FALSE
);
411 volume_bind_and_dirtify(volume
, context
, TRUE
);
413 wined3d_volume_download_data(volume
, context
, &data
);
417 FIXME("Implement WINED3D_LOCATION_BUFFER loading from %s.\n",
418 wined3d_debug_location(volume
->locations
));
421 wined3d_volume_validate_location(volume
, WINED3D_LOCATION_BUFFER
);
425 FIXME("Implement %s loading from %s.\n", wined3d_debug_location(location
),
426 wined3d_debug_location(volume
->locations
));
430 /* Context activation is done by the caller. */
431 void wined3d_volume_load(struct wined3d_volume
*volume
, struct wined3d_context
*context
, BOOL srgb_mode
)
433 volume_bind_and_dirtify(volume
, context
, srgb_mode
);
437 if (!(volume
->flags
& WINED3D_VFLAG_SRGB_ALLOCATED
))
439 wined3d_volume_allocate_texture(volume
, context
, TRUE
);
440 volume
->flags
|= WINED3D_VFLAG_SRGB_ALLOCATED
;
443 wined3d_volume_load_location(volume
, context
, WINED3D_LOCATION_TEXTURE_SRGB
);
447 if (!(volume
->flags
& WINED3D_VFLAG_ALLOCATED
))
449 wined3d_volume_allocate_texture(volume
, context
, FALSE
);
450 volume
->flags
|= WINED3D_VFLAG_ALLOCATED
;
453 wined3d_volume_load_location(volume
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
457 /* Context activation is done by the caller. */
458 static void wined3d_volume_prepare_pbo(struct wined3d_volume
*volume
, struct wined3d_context
*context
)
460 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
465 GL_EXTCALL(glGenBuffersARB(1, &volume
->pbo
));
466 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, volume
->pbo
));
467 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, volume
->resource
.size
, NULL
, GL_STREAM_DRAW_ARB
));
468 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
469 checkGLcall("Create PBO");
471 TRACE("Created PBO %u for volume %p.\n", volume
->pbo
, volume
);
474 static void wined3d_volume_free_pbo(struct wined3d_volume
*volume
)
476 struct wined3d_context
*context
= context_acquire(volume
->resource
.device
, NULL
);
477 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
479 TRACE("Deleting PBO %u belonging to volume %p.\n", volume
->pbo
, volume
);
480 GL_EXTCALL(glDeleteBuffersARB(1, &volume
->pbo
));
481 checkGLcall("glDeleteBuffersARB");
483 context_release(context
);
486 static void volume_unload(struct wined3d_resource
*resource
)
488 struct wined3d_volume
*volume
= volume_from_resource(resource
);
489 struct wined3d_device
*device
= volume
->resource
.device
;
490 struct wined3d_context
*context
;
492 if (volume
->resource
.pool
== WINED3D_POOL_DEFAULT
)
493 ERR("Unloading DEFAULT pool volume.\n");
495 TRACE("texture %p.\n", resource
);
497 if (volume_prepare_system_memory(volume
))
499 context
= context_acquire(device
, NULL
);
500 wined3d_volume_load_location(volume
, context
, WINED3D_LOCATION_SYSMEM
);
501 context_release(context
);
502 wined3d_volume_invalidate_location(volume
, ~WINED3D_LOCATION_SYSMEM
);
506 ERR("Out of memory when unloading volume %p.\n", volume
);
507 wined3d_volume_validate_location(volume
, WINED3D_LOCATION_DISCARDED
);
508 wined3d_volume_invalidate_location(volume
, ~WINED3D_LOCATION_DISCARDED
);
513 /* Should not happen because only dynamic default pool volumes
514 * have a buffer, and those are not evicted by device_evit_managed_resources
515 * and must be freed before a non-ex device reset. */
516 ERR("Unloading a volume with a buffer\n");
517 wined3d_volume_free_pbo(volume
);
520 /* The texture name is managed by the container. */
521 volume
->flags
&= ~(WINED3D_VFLAG_ALLOCATED
| WINED3D_VFLAG_SRGB_ALLOCATED
522 | WINED3D_VFLAG_CLIENT_STORAGE
);
524 resource_unload(resource
);
527 ULONG CDECL
wined3d_volume_incref(struct wined3d_volume
*volume
)
531 if (volume
->container
)
533 TRACE("Forwarding to container %p.\n", volume
->container
);
534 return wined3d_texture_incref(volume
->container
);
537 refcount
= InterlockedIncrement(&volume
->resource
.ref
);
539 TRACE("%p increasing refcount to %u.\n", volume
, refcount
);
544 ULONG CDECL
wined3d_volume_decref(struct wined3d_volume
*volume
)
548 if (volume
->container
)
550 TRACE("Forwarding to container %p.\n", volume
->container
);
551 return wined3d_texture_decref(volume
->container
);
554 refcount
= InterlockedDecrement(&volume
->resource
.ref
);
556 TRACE("%p decreasing refcount to %u.\n", volume
, refcount
);
561 wined3d_volume_free_pbo(volume
);
563 resource_cleanup(&volume
->resource
);
564 volume
->resource
.parent_ops
->wined3d_object_destroyed(volume
->resource
.parent
);
565 HeapFree(GetProcessHeap(), 0, volume
);
571 void * CDECL
wined3d_volume_get_parent(const struct wined3d_volume
*volume
)
573 TRACE("volume %p.\n", volume
);
575 return volume
->resource
.parent
;
578 DWORD CDECL
wined3d_volume_set_priority(struct wined3d_volume
*volume
, DWORD priority
)
580 return resource_set_priority(&volume
->resource
, priority
);
583 DWORD CDECL
wined3d_volume_get_priority(const struct wined3d_volume
*volume
)
585 return resource_get_priority(&volume
->resource
);
588 void CDECL
wined3d_volume_preload(struct wined3d_volume
*volume
)
590 FIXME("volume %p stub!\n", volume
);
593 struct wined3d_resource
* CDECL
wined3d_volume_get_resource(struct wined3d_volume
*volume
)
595 TRACE("volume %p.\n", volume
);
597 return &volume
->resource
;
600 static BOOL
volume_check_block_align(const struct wined3d_volume
*volume
,
601 const struct wined3d_box
*box
)
603 UINT width_mask
, height_mask
;
604 const struct wined3d_format
*format
= volume
->resource
.format
;
609 /* This assumes power of two block sizes, but NPOT block sizes would be
612 * This also assumes that the format's block depth is 1. */
613 width_mask
= format
->block_width
- 1;
614 height_mask
= format
->block_height
- 1;
616 if (box
->left
& width_mask
)
618 if (box
->top
& height_mask
)
620 if (box
->right
& width_mask
&& box
->right
!= volume
->resource
.width
)
622 if (box
->bottom
& height_mask
&& box
->bottom
!= volume
->resource
.height
)
628 static BOOL
wined3d_volume_check_box_dimensions(const struct wined3d_volume
*volume
,
629 const struct wined3d_box
*box
)
634 if (box
->left
>= box
->right
)
636 if (box
->top
>= box
->bottom
)
638 if (box
->front
>= box
->back
)
640 if (box
->right
> volume
->resource
.width
)
642 if (box
->bottom
> volume
->resource
.height
)
644 if (box
->back
> volume
->resource
.depth
)
650 HRESULT CDECL
wined3d_volume_map(struct wined3d_volume
*volume
,
651 struct wined3d_map_desc
*map_desc
, const struct wined3d_box
*box
, DWORD flags
)
653 struct wined3d_device
*device
= volume
->resource
.device
;
654 struct wined3d_context
*context
;
655 const struct wined3d_gl_info
*gl_info
;
657 const struct wined3d_format
*format
= volume
->resource
.format
;
659 TRACE("volume %p, map_desc %p, box %p, flags %#x.\n",
660 volume
, map_desc
, box
, flags
);
662 map_desc
->data
= NULL
;
663 if (!(volume
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
))
665 WARN("Volume %p is not CPU accessible.\n", volume
);
666 return WINED3DERR_INVALIDCALL
;
668 if (volume
->resource
.map_count
)
670 WARN("Volume is already mapped.\n");
671 return WINED3DERR_INVALIDCALL
;
673 if (!wined3d_volume_check_box_dimensions(volume
, box
))
675 WARN("Map box is invalid.\n");
676 return WINED3DERR_INVALIDCALL
;
678 if ((format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && !volume_check_block_align(volume
, box
))
680 WARN("Map box is misaligned for %ux%u blocks.\n",
681 format
->block_width
, format
->block_height
);
682 return WINED3DERR_INVALIDCALL
;
685 flags
= wined3d_resource_sanitize_map_flags(&volume
->resource
, flags
);
687 if (volume
->flags
& WINED3D_VFLAG_PBO
)
689 context
= context_acquire(device
, NULL
);
690 gl_info
= context
->gl_info
;
692 wined3d_volume_prepare_pbo(volume
, context
);
693 if (flags
& WINED3D_MAP_DISCARD
)
694 wined3d_volume_validate_location(volume
, WINED3D_LOCATION_BUFFER
);
696 wined3d_volume_load_location(volume
, context
, WINED3D_LOCATION_BUFFER
);
698 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, volume
->pbo
));
700 if (gl_info
->supported
[ARB_MAP_BUFFER_RANGE
])
702 GLbitfield mapflags
= wined3d_resource_gl_map_flags(flags
);
703 mapflags
&= ~GL_MAP_FLUSH_EXPLICIT_BIT
;
704 base_memory
= GL_EXTCALL(glMapBufferRange(GL_PIXEL_UNPACK_BUFFER_ARB
,
705 0, volume
->resource
.size
, mapflags
));
709 GLenum access
= wined3d_resource_gl_legacy_map_flags(flags
);
710 base_memory
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, access
));
713 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
714 checkGLcall("Map PBO");
716 context_release(context
);
720 if (!volume_prepare_system_memory(volume
))
722 WARN("Out of memory.\n");
723 map_desc
->data
= NULL
;
724 return E_OUTOFMEMORY
;
727 if (flags
& WINED3D_MAP_DISCARD
)
729 wined3d_volume_validate_location(volume
, WINED3D_LOCATION_SYSMEM
);
731 else if (!(volume
->locations
& WINED3D_LOCATION_SYSMEM
))
733 context
= context_acquire(device
, NULL
);
734 wined3d_volume_load_location(volume
, context
, WINED3D_LOCATION_SYSMEM
);
735 context_release(context
);
737 base_memory
= volume
->resource
.heap_memory
;
740 TRACE("Base memory pointer %p.\n", base_memory
);
742 if (format
->flags
& WINED3DFMT_FLAG_BROKEN_PITCH
)
744 map_desc
->row_pitch
= volume
->resource
.width
* format
->byte_count
;
745 map_desc
->slice_pitch
= map_desc
->row_pitch
* volume
->resource
.height
;
749 wined3d_volume_get_pitch(volume
, &map_desc
->row_pitch
, &map_desc
->slice_pitch
);
754 TRACE("No box supplied - all is ok\n");
755 map_desc
->data
= base_memory
;
759 TRACE("Lock Box (%p) = l %u, t %u, r %u, b %u, fr %u, ba %u\n",
760 box
, box
->left
, box
->top
, box
->right
, box
->bottom
, box
->front
, box
->back
);
762 if ((format
->flags
& (WINED3DFMT_FLAG_BLOCKS
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_BLOCKS
)
764 /* Compressed textures are block based, so calculate the offset of
765 * the block that contains the top-left pixel of the locked rectangle. */
766 map_desc
->data
= base_memory
767 + (box
->front
* map_desc
->slice_pitch
)
768 + ((box
->top
/ format
->block_height
) * map_desc
->row_pitch
)
769 + ((box
->left
/ format
->block_width
) * format
->block_byte_count
);
773 map_desc
->data
= base_memory
774 + (map_desc
->slice_pitch
* box
->front
)
775 + (map_desc
->row_pitch
* box
->top
)
776 + (box
->left
* volume
->resource
.format
->byte_count
);
780 if (!(flags
& (WINED3D_MAP_NO_DIRTY_UPDATE
| WINED3D_MAP_READONLY
)))
782 wined3d_texture_set_dirty(volume
->container
);
784 if (volume
->flags
& WINED3D_VFLAG_PBO
)
785 wined3d_volume_invalidate_location(volume
, ~WINED3D_LOCATION_BUFFER
);
787 wined3d_volume_invalidate_location(volume
, ~WINED3D_LOCATION_SYSMEM
);
790 volume
->resource
.map_count
++;
792 TRACE("Returning memory %p, row pitch %d, slice pitch %d.\n",
793 map_desc
->data
, map_desc
->row_pitch
, map_desc
->slice_pitch
);
798 struct wined3d_volume
* CDECL
wined3d_volume_from_resource(struct wined3d_resource
*resource
)
800 return volume_from_resource(resource
);
803 HRESULT CDECL
wined3d_volume_unmap(struct wined3d_volume
*volume
)
805 TRACE("volume %p.\n", volume
);
807 if (!volume
->resource
.map_count
)
809 WARN("Trying to unlock an unlocked volume %p.\n", volume
);
810 return WINED3DERR_INVALIDCALL
;
813 if (volume
->flags
& WINED3D_VFLAG_PBO
)
815 struct wined3d_device
*device
= volume
->resource
.device
;
816 struct wined3d_context
*context
= context_acquire(device
, NULL
);
817 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
819 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, volume
->pbo
));
820 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
821 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
822 checkGLcall("Unmap PBO");
824 context_release(context
);
827 volume
->resource
.map_count
--;
832 static const struct wined3d_resource_ops volume_resource_ops
=
837 static HRESULT
volume_init(struct wined3d_volume
*volume
, struct wined3d_device
*device
, UINT width
,
838 UINT height
, UINT depth
, UINT level
, DWORD usage
, enum wined3d_format_id format_id
,
839 enum wined3d_pool pool
, void *parent
, const struct wined3d_parent_ops
*parent_ops
)
841 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
842 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, format_id
);
846 if (!gl_info
->supported
[EXT_TEXTURE3D
])
848 WARN("Volume cannot be created - no volume texture support.\n");
849 return WINED3DERR_INVALIDCALL
;
851 /* TODO: Write tests for other resources and move this check
852 * to resource_init, if applicable. */
853 if (usage
& WINED3DUSAGE_DYNAMIC
854 && (pool
== WINED3D_POOL_MANAGED
|| pool
== WINED3D_POOL_SCRATCH
))
856 WARN("Attempted to create a DYNAMIC texture in pool %u.\n", pool
);
857 return WINED3DERR_INVALIDCALL
;
860 size
= wined3d_format_calculate_size(format
, device
->surface_alignment
, width
, height
, depth
);
862 hr
= resource_init(&volume
->resource
, device
, WINED3D_RTYPE_VOLUME
, format
,
863 WINED3D_MULTISAMPLE_NONE
, 0, usage
, pool
, width
, height
, depth
,
864 size
, parent
, parent_ops
, &volume_resource_ops
);
867 WARN("Failed to initialize resource, returning %#x.\n", hr
);
871 volume
->texture_level
= level
;
872 volume
->locations
= WINED3D_LOCATION_DISCARDED
;
874 if (pool
== WINED3D_POOL_DEFAULT
&& usage
& WINED3DUSAGE_DYNAMIC
875 && gl_info
->supported
[ARB_PIXEL_BUFFER_OBJECT
]
878 wined3d_resource_free_sysmem(&volume
->resource
);
879 volume
->flags
|= WINED3D_VFLAG_PBO
;
885 HRESULT CDECL
wined3d_volume_create(struct wined3d_device
*device
, UINT width
, UINT height
,
886 UINT depth
, UINT level
, DWORD usage
, enum wined3d_format_id format_id
, enum wined3d_pool pool
,
887 void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_volume
**volume
)
889 struct wined3d_volume
*object
;
892 TRACE("device %p, width %u, height %u, depth %u, usage %#x, format %s, pool %s\n",
893 device
, width
, height
, depth
, usage
, debug_d3dformat(format_id
), debug_d3dpool(pool
));
894 TRACE("parent %p, parent_ops %p, volume %p.\n", parent
, parent_ops
, volume
);
896 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
900 return WINED3DERR_OUTOFVIDEOMEMORY
;
903 hr
= volume_init(object
, device
, width
, height
, depth
, level
,
904 usage
, format_id
, pool
, parent
, parent_ops
);
907 WARN("Failed to initialize volume, returning %#x.\n", hr
);
908 HeapFree(GetProcessHeap(), 0, object
);
912 TRACE("Created volume %p.\n", object
);