2 * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
25 #include "basetexture9.h" /* for marking dirty */
26 #include "volumetexture9.h"
27 #include "nine_helpers.h"
28 #include "nine_pipe.h"
29 #include "nine_dump.h"
31 #include "util/format/u_format.h"
32 #include "util/u_surface.h"
34 #define DBG_CHANNEL DBG_VOLUME
38 NineVolume9_AllocateData( struct NineVolume9
*This
)
40 unsigned size
= This
->layer_stride
* This
->desc
.Depth
;
42 DBG("(%p(This=%p),level=%u) Allocating 0x%x bytes of system memory.\n",
43 This
->base
.container
, This
, This
->level
, size
);
45 This
->data
= (uint8_t *)align_calloc(size
, 32);
52 NineVolume9_ctor( struct NineVolume9
*This
,
53 struct NineUnknownParams
*pParams
,
54 struct NineUnknown
*pContainer
,
55 struct pipe_resource
*pResource
,
57 D3DVOLUME_DESC
*pDesc
)
61 assert(pContainer
); /* stand-alone volumes can't be created */
63 DBG("This=%p pContainer=%p pDevice=%p pResource=%p Level=%u pDesc=%p\n",
64 This
, pContainer
, pParams
->device
, pResource
, Level
, pDesc
);
66 /* Mark this as a special surface held by another internal resource. */
67 pParams
->container
= pContainer
;
69 user_assert(!(pDesc
->Usage
& D3DUSAGE_DYNAMIC
) ||
70 (pDesc
->Pool
!= D3DPOOL_MANAGED
), D3DERR_INVALIDCALL
);
72 assert(pResource
|| pDesc
->Pool
!= D3DPOOL_DEFAULT
);
74 hr
= NineUnknown_ctor(&This
->base
, pParams
);
78 pipe_resource_reference(&This
->resource
, pResource
);
80 This
->transfer
= NULL
;
84 This
->level_actual
= Level
;
87 This
->info
.screen
= pParams
->device
->screen
;
88 This
->info
.target
= PIPE_TEXTURE_3D
;
89 This
->info
.width0
= pDesc
->Width
;
90 This
->info
.height0
= pDesc
->Height
;
91 This
->info
.depth0
= pDesc
->Depth
;
92 This
->info
.last_level
= 0;
93 This
->info
.array_size
= 1;
94 This
->info
.nr_samples
= 0;
95 This
->info
.nr_storage_samples
= 0;
96 This
->info
.usage
= PIPE_USAGE_DEFAULT
;
97 This
->info
.bind
= PIPE_BIND_SAMPLER_VIEW
;
99 This
->info
.format
= d3d9_to_pipe_format_checked(This
->info
.screen
,
102 This
->info
.nr_samples
,
103 This
->info
.bind
, FALSE
,
104 pDesc
->Pool
== D3DPOOL_SCRATCH
);
106 if (This
->info
.format
== PIPE_FORMAT_NONE
)
107 return D3DERR_DRIVERINTERNALERROR
;
109 This
->stride
= util_format_get_stride(This
->info
.format
, pDesc
->Width
);
110 This
->stride
= align(This
->stride
, 4);
111 This
->layer_stride
= util_format_get_2d_size(This
->info
.format
,
112 This
->stride
, pDesc
->Height
);
114 /* Get true format */
115 This
->format_internal
= d3d9_to_pipe_format_checked(This
->info
.screen
,
118 This
->info
.nr_samples
,
119 This
->info
.bind
, FALSE
,
121 if (This
->info
.format
!= This
->format_internal
||
122 /* DYNAMIC Textures requires same stride as ram buffers.
123 * Do not use workaround by default as it eats more virtual space */
124 (pParams
->device
->workarounds
.dynamic_texture_workaround
&&
125 pDesc
->Pool
== D3DPOOL_DEFAULT
&& pDesc
->Usage
& D3DUSAGE_DYNAMIC
)) {
126 This
->stride_internal
= nine_format_get_stride(This
->format_internal
,
128 This
->layer_stride_internal
= util_format_get_2d_size(This
->format_internal
,
129 This
->stride_internal
,
131 This
->data_internal
= align_calloc(This
->layer_stride_internal
*
132 This
->desc
.Depth
, 32);
133 if (!This
->data_internal
)
134 return E_OUTOFMEMORY
;
137 if (!This
->resource
) {
138 hr
= NineVolume9_AllocateData(This
);
146 NineVolume9_dtor( struct NineVolume9
*This
)
148 DBG("This=%p\n", This
);
150 if (This
->transfer
) {
151 struct pipe_context
*pipe
= nine_context_get_pipe_multithread(This
->base
.device
);
152 pipe
->transfer_unmap(pipe
, This
->transfer
);
153 This
->transfer
= NULL
;
156 /* Note: Following condition cannot happen currently, since we
157 * refcount the volume in the functions increasing
158 * pending_uploads_counter. */
159 if (p_atomic_read(&This
->pending_uploads_counter
))
160 nine_csmt_process(This
->base
.device
);
163 align_free(This
->data
);
164 if (This
->data_internal
)
165 align_free(This
->data_internal
);
167 pipe_resource_reference(&This
->resource
, NULL
);
169 NineUnknown_dtor(&This
->base
);
173 NineVolume9_GetContainer( struct NineVolume9
*This
,
179 DBG("This=%p riid=%p id=%s ppContainer=%p\n",
180 This
, riid
, riid
? GUID_sprintf(guid_str
, riid
) : "", ppContainer
);
184 if (!NineUnknown(This
)->container
)
185 return E_NOINTERFACE
;
186 return NineUnknown_QueryInterface(NineUnknown(This
)->container
, riid
, ppContainer
);
190 NineVolume9_MarkContainerDirty( struct NineVolume9
*This
)
192 struct NineBaseTexture9
*tex
;
193 #if defined(DEBUG) || !defined(NDEBUG)
194 /* This is always contained by a NineVolumeTexture9. */
195 GUID id
= IID_IDirect3DVolumeTexture9
;
197 assert(NineUnknown_QueryInterface(This
->base
.container
, ref
, (void **)&tex
)
199 assert(NineUnknown_Release(NineUnknown(tex
)) != 0);
202 tex
= NineBaseTexture9(This
->base
.container
);
204 if (This
->desc
.Pool
== D3DPOOL_MANAGED
)
205 tex
->managed
.dirty
= TRUE
;
207 BASETEX_REGISTER_UPDATE(tex
);
211 NineVolume9_GetDesc( struct NineVolume9
*This
,
212 D3DVOLUME_DESC
*pDesc
)
214 user_assert(pDesc
!= NULL
, E_POINTER
);
220 NineVolume9_AddDirtyRegion( struct NineVolume9
*This
,
221 const struct pipe_box
*box
)
224 struct NineVolumeTexture9
*tex
= NineVolumeTexture9(This
->base
.container
);
227 NineVolumeTexture9_AddDirtyBox(tex
, NULL
);
229 dirty_region
.Left
= box
->x
<< This
->level_actual
;
230 dirty_region
.Top
= box
->y
<< This
->level_actual
;
231 dirty_region
.Front
= box
->z
<< This
->level_actual
;
232 dirty_region
.Right
= dirty_region
.Left
+ (box
->width
<< This
->level_actual
);
233 dirty_region
.Bottom
= dirty_region
.Top
+ (box
->height
<< This
->level_actual
);
234 dirty_region
.Back
= dirty_region
.Front
+ (box
->depth
<< This
->level_actual
);
235 NineVolumeTexture9_AddDirtyBox(tex
, &dirty_region
);
239 static inline unsigned
240 NineVolume9_GetSystemMemOffset(enum pipe_format format
, unsigned stride
,
241 unsigned layer_stride
,
244 unsigned x_offset
= util_format_get_stride(format
, x
);
246 y
= util_format_get_nblocksy(format
, y
);
248 return z
* layer_stride
+ y
* stride
+ x_offset
;
252 NineVolume9_LockBox( struct NineVolume9
*This
,
253 D3DLOCKED_BOX
*pLockedVolume
,
257 struct pipe_context
*pipe
;
258 struct pipe_resource
*resource
= This
->resource
;
262 DBG("This=%p(%p) pLockedVolume=%p pBox=%p[%u..%u,%u..%u,%u..%u] Flags=%s\n",
263 This
, This
->base
.container
, pLockedVolume
, pBox
,
264 pBox
? pBox
->Left
: 0, pBox
? pBox
->Right
: 0,
265 pBox
? pBox
->Top
: 0, pBox
? pBox
->Bottom
: 0,
266 pBox
? pBox
->Front
: 0, pBox
? pBox
->Back
: 0,
267 nine_D3DLOCK_to_str(Flags
));
269 /* check if it's already locked */
270 user_assert(This
->lock_count
== 0, D3DERR_INVALIDCALL
);
272 /* set pBits to NULL after lock_count check */
273 user_assert(pLockedVolume
, E_POINTER
);
274 pLockedVolume
->pBits
= NULL
;
276 user_assert(This
->desc
.Pool
!= D3DPOOL_DEFAULT
||
277 (This
->desc
.Usage
& D3DUSAGE_DYNAMIC
), D3DERR_INVALIDCALL
);
279 user_assert(!((Flags
& D3DLOCK_DISCARD
) && (Flags
& D3DLOCK_READONLY
)),
282 if (pBox
&& compressed_format (This
->desc
.Format
)) { /* For volume all pools are checked */
283 const unsigned w
= util_format_get_blockwidth(This
->info
.format
);
284 const unsigned h
= util_format_get_blockheight(This
->info
.format
);
285 user_assert((pBox
->Left
== 0 && pBox
->Right
== This
->desc
.Width
&&
286 pBox
->Top
== 0 && pBox
->Bottom
== This
->desc
.Height
) ||
287 (!(pBox
->Left
% w
) && !(pBox
->Right
% w
) &&
288 !(pBox
->Top
% h
) && !(pBox
->Bottom
% h
)),
292 if (Flags
& D3DLOCK_DISCARD
) {
293 usage
= PIPE_TRANSFER_WRITE
| PIPE_TRANSFER_DISCARD_RANGE
;
295 usage
= (Flags
& D3DLOCK_READONLY
) ?
296 PIPE_TRANSFER_READ
: PIPE_TRANSFER_READ_WRITE
;
298 if (Flags
& D3DLOCK_DONOTWAIT
)
299 usage
|= PIPE_TRANSFER_DONTBLOCK
;
302 user_assert(pBox
->Right
> pBox
->Left
, D3DERR_INVALIDCALL
);
303 user_assert(pBox
->Bottom
> pBox
->Top
, D3DERR_INVALIDCALL
);
304 user_assert(pBox
->Back
> pBox
->Front
, D3DERR_INVALIDCALL
);
305 user_assert(pBox
->Right
<= This
->desc
.Width
, D3DERR_INVALIDCALL
);
306 user_assert(pBox
->Bottom
<= This
->desc
.Height
, D3DERR_INVALIDCALL
);
307 user_assert(pBox
->Back
<= This
->desc
.Depth
, D3DERR_INVALIDCALL
);
309 d3dbox_to_pipe_box(&box
, pBox
);
310 if (u_box_clip_2d(&box
, &box
, This
->desc
.Width
, This
->desc
.Height
) < 0) {
311 DBG("Locked volume intersection empty.\n");
312 return D3DERR_INVALIDCALL
;
315 u_box_3d(0, 0, 0, This
->desc
.Width
, This
->desc
.Height
, This
->desc
.Depth
,
319 if (p_atomic_read(&This
->pending_uploads_counter
))
320 nine_csmt_process(This
->base
.device
);
322 if (This
->data_internal
|| This
->data
) {
323 enum pipe_format format
= This
->info
.format
;
324 unsigned stride
= This
->stride
;
325 unsigned layer_stride
= This
->layer_stride
;
326 uint8_t *data
= This
->data
;
327 if (This
->data_internal
) {
328 format
= This
->format_internal
;
329 stride
= This
->stride_internal
;
330 layer_stride
= This
->layer_stride_internal
;
331 data
= This
->data_internal
;
333 pLockedVolume
->RowPitch
= stride
;
334 pLockedVolume
->SlicePitch
= layer_stride
;
335 pLockedVolume
->pBits
= data
+
336 NineVolume9_GetSystemMemOffset(format
, stride
,
338 box
.x
, box
.y
, box
.z
);
340 bool no_refs
= !p_atomic_read(&This
->base
.bind
) &&
341 !p_atomic_read(&This
->base
.container
->bind
);
343 pipe
= nine_context_get_pipe_acquire(This
->base
.device
);
345 pipe
= NineDevice9_GetPipe(This
->base
.device
);
346 pLockedVolume
->pBits
=
347 pipe
->transfer_map(pipe
, resource
, This
->level
, usage
,
348 &box
, &This
->transfer
);
350 nine_context_get_pipe_release(This
->base
.device
);
351 if (!This
->transfer
) {
352 if (Flags
& D3DLOCK_DONOTWAIT
)
353 return D3DERR_WASSTILLDRAWING
;
354 return D3DERR_DRIVERINTERNALERROR
;
356 pLockedVolume
->RowPitch
= This
->transfer
->stride
;
357 pLockedVolume
->SlicePitch
= This
->transfer
->layer_stride
;
360 if (!(Flags
& (D3DLOCK_NO_DIRTY_UPDATE
| D3DLOCK_READONLY
))) {
361 NineVolume9_MarkContainerDirty(This
);
362 NineVolume9_AddDirtyRegion(This
, &box
);
370 NineVolume9_UnlockBox( struct NineVolume9
*This
)
372 struct pipe_context
*pipe
;
374 DBG("This=%p lock_count=%u\n", This
, This
->lock_count
);
375 user_assert(This
->lock_count
, D3DERR_INVALIDCALL
);
376 if (This
->transfer
) {
377 pipe
= nine_context_get_pipe_acquire(This
->base
.device
);
378 pipe
->transfer_unmap(pipe
, This
->transfer
);
379 This
->transfer
= NULL
;
380 nine_context_get_pipe_release(This
->base
.device
);
384 if (This
->data_internal
) {
387 u_box_3d(0, 0, 0, This
->desc
.Width
, This
->desc
.Height
, This
->desc
.Depth
,
392 (void) util_format_translate_3d(This
->info
.format
,
393 This
->data
, This
->stride
,
396 This
->format_internal
,
398 This
->stride_internal
,
399 This
->layer_stride_internal
,
401 This
->desc
.Width
, This
->desc
.Height
,
404 nine_context_box_upload(This
->base
.device
,
405 &This
->pending_uploads_counter
,
406 (struct NineUnknown
*)This
,
410 This
->format_internal
,
412 This
->stride_internal
,
413 This
->layer_stride_internal
,
421 /* When this function is called, we have already checked
422 * The copy regions fit the volumes */
424 NineVolume9_CopyMemToDefault( struct NineVolume9
*This
,
425 struct NineVolume9
*From
,
426 unsigned dstx
, unsigned dsty
, unsigned dstz
,
427 struct pipe_box
*pSrcBox
)
429 struct pipe_resource
*r_dst
= This
->resource
;
430 struct pipe_box src_box
;
431 struct pipe_box dst_box
;
433 DBG("This=%p From=%p dstx=%u dsty=%u dstz=%u pSrcBox=%p\n",
434 This
, From
, dstx
, dsty
, dstz
, pSrcBox
);
436 assert(This
->desc
.Pool
== D3DPOOL_DEFAULT
&&
437 From
->desc
.Pool
== D3DPOOL_SYSTEMMEM
);
449 src_box
.width
= From
->desc
.Width
;
450 src_box
.height
= From
->desc
.Height
;
451 src_box
.depth
= From
->desc
.Depth
;
454 dst_box
.width
= src_box
.width
;
455 dst_box
.height
= src_box
.height
;
456 dst_box
.depth
= src_box
.depth
;
458 nine_context_box_upload(This
->base
.device
,
459 &From
->pending_uploads_counter
,
460 (struct NineUnknown
*)From
,
465 From
->data
, From
->stride
,
469 if (This
->data_internal
)
470 (void) util_format_translate_3d(This
->format_internal
,
472 This
->stride_internal
,
473 This
->layer_stride_internal
,
476 From
->data
, From
->stride
,
478 src_box
.x
, src_box
.y
,
484 NineVolume9_MarkContainerDirty(This
);
490 NineVolume9_UploadSelf( struct NineVolume9
*This
,
491 const struct pipe_box
*damaged
)
493 struct pipe_resource
*res
= This
->resource
;
496 DBG("This=%p damaged=%p data=%p res=%p\n", This
, damaged
,
499 assert(This
->desc
.Pool
== D3DPOOL_MANAGED
);
508 box
.width
= This
->desc
.Width
;
509 box
.height
= This
->desc
.Height
;
510 box
.depth
= This
->desc
.Depth
;
513 nine_context_box_upload(This
->base
.device
,
514 &This
->pending_uploads_counter
,
515 (struct NineUnknown
*)This
,
520 This
->data
, This
->stride
,
528 IDirect3DVolume9Vtbl NineVolume9_vtable
= {
529 (void *)NineUnknown_QueryInterface
,
530 (void *)NineUnknown_AddRef
,
531 (void *)NineUnknown_Release
,
532 (void *)NineUnknown_GetDevice
, /* actually part of Volume9 iface */
533 (void *)NineUnknown_SetPrivateData
,
534 (void *)NineUnknown_GetPrivateData
,
535 (void *)NineUnknown_FreePrivateData
,
536 (void *)NineVolume9_GetContainer
,
537 (void *)NineVolume9_GetDesc
,
538 (void *)NineVolume9_LockBox
,
539 (void *)NineVolume9_UnlockBox
542 static const GUID
*NineVolume9_IIDs
[] = {
543 &IID_IDirect3DVolume9
,
549 NineVolume9_new( struct NineDevice9
*pDevice
,
550 struct NineUnknown
*pContainer
,
551 struct pipe_resource
*pResource
,
553 D3DVOLUME_DESC
*pDesc
,
554 struct NineVolume9
**ppOut
)
556 NINE_DEVICE_CHILD_NEW(Volume9
, ppOut
, pDevice
, /* args */
557 pContainer
, pResource
, Level
, pDesc
);