1 /*
2 * Copyright 2011 Joakim Sindholt <[email protected]>
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "device9.h"
7 #include "volume9.h"
8 #include "basetexture9.h" /* for marking dirty */
9 #include "volumetexture9.h"
10 #include "nine_helpers.h"
11 #include "nine_pipe.h"
12 #include "nine_dump.h"
13
14 #include "util/format/u_format.h"
15 #include "util/u_surface.h"
16
17 #define DBG_CHANNEL DBG_VOLUME
18
19
20 static HRESULT
NineVolume9_AllocateData(struct NineVolume9 * This)21 NineVolume9_AllocateData( struct NineVolume9 *This )
22 {
23 unsigned size = This->layer_stride * This->desc.Depth;
24
25 DBG("(%p(This=%p),level=%u) Allocating 0x%x bytes of system memory.\n",
26 This->base.container, This, This->level, size);
27
28 This->data = (uint8_t *)align_calloc(size, 32);
29 if (!This->data)
30 return E_OUTOFMEMORY;
31 return D3D_OK;
32 }
33
34 static HRESULT
NineVolume9_ctor(struct NineVolume9 * This,struct NineUnknownParams * pParams,struct NineUnknown * pContainer,struct pipe_resource * pResource,unsigned Level,D3DVOLUME_DESC * pDesc)35 NineVolume9_ctor( struct NineVolume9 *This,
36 struct NineUnknownParams *pParams,
37 struct NineUnknown *pContainer,
38 struct pipe_resource *pResource,
39 unsigned Level,
40 D3DVOLUME_DESC *pDesc )
41 {
42 HRESULT hr;
43
44 assert(pContainer); /* stand-alone volumes can't be created */
45
46 DBG("This=%p pContainer=%p pDevice=%p pResource=%p Level=%u pDesc=%p\n",
47 This, pContainer, pParams->device, pResource, Level, pDesc);
48
49 /* Mark this as a special surface held by another internal resource. */
50 pParams->container = pContainer;
51
52 user_assert(!(pDesc->Usage & D3DUSAGE_DYNAMIC) ||
53 (pDesc->Pool != D3DPOOL_MANAGED), D3DERR_INVALIDCALL);
54
55 assert(pResource || pDesc->Pool != D3DPOOL_DEFAULT);
56
57 hr = NineUnknown_ctor(&This->base, pParams);
58 if (FAILED(hr))
59 return hr;
60
61 pipe_resource_reference(&This->resource, pResource);
62
63 This->transfer = NULL;
64 This->lock_count = 0;
65
66 This->level = Level;
67 This->level_actual = Level;
68 This->desc = *pDesc;
69
70 This->info.screen = pParams->device->screen;
71 This->info.target = PIPE_TEXTURE_3D;
72 This->info.width0 = pDesc->Width;
73 This->info.height0 = pDesc->Height;
74 This->info.depth0 = pDesc->Depth;
75 This->info.last_level = 0;
76 This->info.array_size = 1;
77 This->info.nr_samples = 0;
78 This->info.nr_storage_samples = 0;
79 This->info.usage = PIPE_USAGE_DEFAULT;
80 This->info.bind = PIPE_BIND_SAMPLER_VIEW;
81 This->info.flags = 0;
82 This->info.format = d3d9_to_pipe_format_checked(This->info.screen,
83 pDesc->Format,
84 This->info.target,
85 This->info.nr_samples,
86 This->info.bind, false,
87 pDesc->Pool == D3DPOOL_SCRATCH);
88
89 if (This->info.format == PIPE_FORMAT_NONE)
90 return D3DERR_DRIVERINTERNALERROR;
91
92 This->stride = util_format_get_stride(This->info.format, pDesc->Width);
93 This->stride = align(This->stride, 4);
94 This->layer_stride = util_format_get_2d_size(This->info.format,
95 This->stride, pDesc->Height);
96
97 /* Get true format */
98 This->format_internal = d3d9_to_pipe_format_checked(This->info.screen,
99 pDesc->Format,
100 This->info.target,
101 This->info.nr_samples,
102 This->info.bind, false,
103 true);
104 if (This->info.format != This->format_internal ||
105 /* See surface9.c */
106 (pParams->device->workarounds.dynamic_texture_workaround &&
107 pDesc->Pool == D3DPOOL_DEFAULT && pDesc->Usage & D3DUSAGE_DYNAMIC)) {
108 This->stride_internal = nine_format_get_stride(This->format_internal,
109 pDesc->Width);
110 This->layer_stride_internal = util_format_get_2d_size(This->format_internal,
111 This->stride_internal,
112 pDesc->Height);
113 This->data_internal = align_calloc(This->layer_stride_internal *
114 This->desc.Depth, 32);
115 if (!This->data_internal)
116 return E_OUTOFMEMORY;
117 }
118
119 if (!This->resource) {
120 hr = NineVolume9_AllocateData(This);
121 if (FAILED(hr))
122 return hr;
123 }
124 return D3D_OK;
125 }
126
127 static void
NineVolume9_dtor(struct NineVolume9 * This)128 NineVolume9_dtor( struct NineVolume9 *This )
129 {
130 DBG("This=%p\n", This);
131
132 if (This->transfer) {
133 struct pipe_context *pipe = nine_context_get_pipe_multithread(This->base.device);
134 pipe->texture_unmap(pipe, This->transfer);
135 This->transfer = NULL;
136 }
137
138 /* Note: Following condition cannot happen currently, since we
139 * refcount the volume in the functions increasing
140 * pending_uploads_counter. */
141 if (p_atomic_read(&This->pending_uploads_counter))
142 nine_csmt_process(This->base.device);
143
144 if (This->data)
145 align_free(This->data);
146 if (This->data_internal)
147 align_free(This->data_internal);
148
149 pipe_resource_reference(&This->resource, NULL);
150
151 NineUnknown_dtor(&This->base);
152 }
153
154 HRESULT NINE_WINAPI
NineVolume9_GetContainer(struct NineVolume9 * This,REFIID riid,void ** ppContainer)155 NineVolume9_GetContainer( struct NineVolume9 *This,
156 REFIID riid,
157 void **ppContainer )
158 {
159 char guid_str[64];
160
161 DBG("This=%p riid=%p id=%s ppContainer=%p\n",
162 This, riid, riid ? GUID_sprintf(guid_str, riid) : "", ppContainer);
163
164 (void)guid_str;
165
166 if (!NineUnknown(This)->container)
167 return E_NOINTERFACE;
168 return NineUnknown_QueryInterface(NineUnknown(This)->container, riid, ppContainer);
169 }
170
171 static inline void
NineVolume9_MarkContainerDirty(struct NineVolume9 * This)172 NineVolume9_MarkContainerDirty( struct NineVolume9 *This )
173 {
174 struct NineBaseTexture9 *tex;
175 #if MESA_DEBUG || !defined(NDEBUG)
176 /* This is always contained by a NineVolumeTexture9. */
177 GUID id = IID_IDirect3DVolumeTexture9;
178 REFIID ref = &id;
179 assert(NineUnknown_QueryInterface(This->base.container, ref, (void **)&tex)
180 == S_OK);
181 assert(NineUnknown_Release(NineUnknown(tex)) != 0);
182 #endif
183
184 tex = NineBaseTexture9(This->base.container);
185 assert(tex);
186 if (This->desc.Pool == D3DPOOL_MANAGED)
187 tex->managed.dirty = true;
188
189 BASETEX_REGISTER_UPDATE(tex);
190 }
191
192 HRESULT NINE_WINAPI
NineVolume9_GetDesc(struct NineVolume9 * This,D3DVOLUME_DESC * pDesc)193 NineVolume9_GetDesc( struct NineVolume9 *This,
194 D3DVOLUME_DESC *pDesc )
195 {
196 user_assert(pDesc != NULL, E_POINTER);
197 *pDesc = This->desc;
198 return D3D_OK;
199 }
200
201 inline void
NineVolume9_AddDirtyRegion(struct NineVolume9 * This,const struct pipe_box * box)202 NineVolume9_AddDirtyRegion( struct NineVolume9 *This,
203 const struct pipe_box *box )
204 {
205 D3DBOX dirty_region;
206 struct NineVolumeTexture9 *tex = NineVolumeTexture9(This->base.container);
207
208 if (!box) {
209 NineVolumeTexture9_AddDirtyBox(tex, NULL);
210 } else {
211 dirty_region.Left = box->x << This->level_actual;
212 dirty_region.Top = box->y << This->level_actual;
213 dirty_region.Front = box->z << This->level_actual;
214 dirty_region.Right = dirty_region.Left + (box->width << This->level_actual);
215 dirty_region.Bottom = dirty_region.Top + (box->height << This->level_actual);
216 dirty_region.Back = dirty_region.Front + (box->depth << This->level_actual);
217 NineVolumeTexture9_AddDirtyBox(tex, &dirty_region);
218 }
219 }
220
221 static inline unsigned
NineVolume9_GetSystemMemOffset(enum pipe_format format,unsigned stride,unsigned layer_stride,int x,int y,int z)222 NineVolume9_GetSystemMemOffset(enum pipe_format format, unsigned stride,
223 unsigned layer_stride,
224 int x, int y, int z)
225 {
226 unsigned x_offset = util_format_get_stride(format, x);
227
228 y = util_format_get_nblocksy(format, y);
229
230 return z * layer_stride + y * stride + x_offset;
231 }
232
233 HRESULT NINE_WINAPI
NineVolume9_LockBox(struct NineVolume9 * This,D3DLOCKED_BOX * pLockedVolume,const D3DBOX * pBox,DWORD Flags)234 NineVolume9_LockBox( struct NineVolume9 *This,
235 D3DLOCKED_BOX *pLockedVolume,
236 const D3DBOX *pBox,
237 DWORD Flags )
238 {
239 struct pipe_context *pipe;
240 struct pipe_resource *resource = This->resource;
241 struct pipe_box box;
242 unsigned usage;
243
244 DBG("This=%p(%p) pLockedVolume=%p pBox=%p[%u..%u,%u..%u,%u..%u] Flags=%s\n",
245 This, This->base.container, pLockedVolume, pBox,
246 pBox ? pBox->Left : 0, pBox ? pBox->Right : 0,
247 pBox ? pBox->Top : 0, pBox ? pBox->Bottom : 0,
248 pBox ? pBox->Front : 0, pBox ? pBox->Back : 0,
249 nine_D3DLOCK_to_str(Flags));
250
251 /* check if it's already locked */
252 user_assert(This->lock_count == 0, D3DERR_INVALIDCALL);
253
254 /* set pBits to NULL after lock_count check */
255 user_assert(pLockedVolume, E_POINTER);
256 pLockedVolume->pBits = NULL;
257
258 user_assert(This->desc.Pool != D3DPOOL_DEFAULT ||
259 (This->desc.Usage & D3DUSAGE_DYNAMIC), D3DERR_INVALIDCALL);
260
261 user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)),
262 D3DERR_INVALIDCALL);
263
264 if (pBox && compressed_format (This->desc.Format)) { /* For volume all pools are checked */
265 const unsigned w = util_format_get_blockwidth(This->info.format);
266 const unsigned h = util_format_get_blockheight(This->info.format);
267 user_assert((pBox->Left == 0 && pBox->Right == This->desc.Width &&
268 pBox->Top == 0 && pBox->Bottom == This->desc.Height) ||
269 (!(pBox->Left % w) && !(pBox->Right % w) &&
270 !(pBox->Top % h) && !(pBox->Bottom % h)),
271 D3DERR_INVALIDCALL);
272 }
273
274 if (Flags & D3DLOCK_DISCARD) {
275 usage = PIPE_MAP_WRITE | PIPE_MAP_DISCARD_RANGE;
276 } else {
277 usage = (Flags & D3DLOCK_READONLY) ?
278 PIPE_MAP_READ : PIPE_MAP_READ_WRITE;
279 }
280 if (Flags & D3DLOCK_DONOTWAIT)
281 usage |= PIPE_MAP_DONTBLOCK;
282
283 if (pBox) {
284 user_assert(pBox->Right > pBox->Left, D3DERR_INVALIDCALL);
285 user_assert(pBox->Bottom > pBox->Top, D3DERR_INVALIDCALL);
286 user_assert(pBox->Back > pBox->Front, D3DERR_INVALIDCALL);
287 user_assert(pBox->Right <= This->desc.Width, D3DERR_INVALIDCALL);
288 user_assert(pBox->Bottom <= This->desc.Height, D3DERR_INVALIDCALL);
289 user_assert(pBox->Back <= This->desc.Depth, D3DERR_INVALIDCALL);
290
291 d3dbox_to_pipe_box(&box, pBox);
292 if (u_box_clip_2d(&box, &box, This->desc.Width, This->desc.Height) < 0) {
293 DBG("Locked volume intersection empty.\n");
294 return D3DERR_INVALIDCALL;
295 }
296 } else {
297 u_box_3d(0, 0, 0, This->desc.Width, This->desc.Height, This->desc.Depth,
298 &box);
299 }
300
301 if (p_atomic_read(&This->pending_uploads_counter))
302 nine_csmt_process(This->base.device);
303
304 if (This->data_internal || This->data) {
305 enum pipe_format format = This->info.format;
306 unsigned stride = This->stride;
307 unsigned layer_stride = This->layer_stride;
308 uint8_t *data = This->data;
309 if (This->data_internal) {
310 format = This->format_internal;
311 stride = This->stride_internal;
312 layer_stride = This->layer_stride_internal;
313 data = This->data_internal;
314 }
315 pLockedVolume->RowPitch = stride;
316 pLockedVolume->SlicePitch = layer_stride;
317 pLockedVolume->pBits = data +
318 NineVolume9_GetSystemMemOffset(format, stride,
319 layer_stride,
320 box.x, box.y, box.z);
321 } else {
322 bool no_refs = !p_atomic_read(&This->base.bind) &&
323 !p_atomic_read(&This->base.container->bind);
324 if (no_refs)
325 pipe = nine_context_get_pipe_acquire(This->base.device);
326 else
327 pipe = NineDevice9_GetPipe(This->base.device);
328 pLockedVolume->pBits =
329 pipe->texture_map(pipe, resource, This->level, usage,
330 &box, &This->transfer);
331 if (no_refs)
332 nine_context_get_pipe_release(This->base.device);
333 if (!This->transfer) {
334 if (Flags & D3DLOCK_DONOTWAIT)
335 return D3DERR_WASSTILLDRAWING;
336 return D3DERR_DRIVERINTERNALERROR;
337 }
338 pLockedVolume->RowPitch = This->transfer->stride;
339 pLockedVolume->SlicePitch = This->transfer->layer_stride;
340 }
341
342 if (!(Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY))) {
343 NineVolume9_MarkContainerDirty(This);
344 NineVolume9_AddDirtyRegion(This, &box);
345 }
346
347 ++This->lock_count;
348 return D3D_OK;
349 }
350
351 HRESULT NINE_WINAPI
NineVolume9_UnlockBox(struct NineVolume9 * This)352 NineVolume9_UnlockBox( struct NineVolume9 *This )
353 {
354 struct pipe_context *pipe;
355
356 DBG("This=%p lock_count=%u\n", This, This->lock_count);
357 user_assert(This->lock_count, D3DERR_INVALIDCALL);
358 if (This->transfer) {
359 pipe = nine_context_get_pipe_acquire(This->base.device);
360 pipe->texture_unmap(pipe, This->transfer);
361 This->transfer = NULL;
362 nine_context_get_pipe_release(This->base.device);
363 }
364 --This->lock_count;
365
366 if (This->data_internal) {
367 struct pipe_box box;
368
369 u_box_3d(0, 0, 0, This->desc.Width, This->desc.Height, This->desc.Depth,
370 &box);
371
372
373 if (This->data) {
374 (void) util_format_translate_3d(This->info.format,
375 This->data, This->stride,
376 This->layer_stride,
377 0, 0, 0,
378 This->format_internal,
379 This->data_internal,
380 This->stride_internal,
381 This->layer_stride_internal,
382 0, 0, 0,
383 This->desc.Width, This->desc.Height,
384 This->desc.Depth);
385 } else {
386 nine_context_box_upload(This->base.device,
387 &This->pending_uploads_counter,
388 (struct NineUnknown *)This,
389 This->resource,
390 This->level,
391 &box,
392 This->format_internal,
393 This->data_internal,
394 This->stride_internal,
395 This->layer_stride_internal,
396 &box);
397 }
398 }
399
400 return D3D_OK;
401 }
402
403 /* When this function is called, we have already checked
404 * The copy regions fit the volumes */
405 void
NineVolume9_CopyMemToDefault(struct NineVolume9 * This,struct NineVolume9 * From,unsigned dstx,unsigned dsty,unsigned dstz,struct pipe_box * pSrcBox)406 NineVolume9_CopyMemToDefault( struct NineVolume9 *This,
407 struct NineVolume9 *From,
408 unsigned dstx, unsigned dsty, unsigned dstz,
409 struct pipe_box *pSrcBox )
410 {
411 struct pipe_resource *r_dst = This->resource;
412 struct pipe_box src_box;
413 struct pipe_box dst_box;
414
415 DBG("This=%p From=%p dstx=%u dsty=%u dstz=%u pSrcBox=%p\n",
416 This, From, dstx, dsty, dstz, pSrcBox);
417
418 assert(This->desc.Pool == D3DPOOL_DEFAULT &&
419 From->desc.Pool == D3DPOOL_SYSTEMMEM);
420
421 dst_box.x = dstx;
422 dst_box.y = dsty;
423 dst_box.z = dstz;
424
425 if (pSrcBox) {
426 src_box = *pSrcBox;
427 } else {
428 src_box.x = 0;
429 src_box.y = 0;
430 src_box.z = 0;
431 src_box.width = From->desc.Width;
432 src_box.height = From->desc.Height;
433 src_box.depth = From->desc.Depth;
434 }
435
436 dst_box.width = src_box.width;
437 dst_box.height = src_box.height;
438 dst_box.depth = src_box.depth;
439
440 nine_context_box_upload(This->base.device,
441 &From->pending_uploads_counter,
442 (struct NineUnknown *)From,
443 r_dst,
444 This->level,
445 &dst_box,
446 From->info.format,
447 From->data, From->stride,
448 From->layer_stride,
449 &src_box);
450
451 if (This->data_internal)
452 (void) util_format_translate_3d(This->format_internal,
453 This->data_internal,
454 This->stride_internal,
455 This->layer_stride_internal,
456 dstx, dsty, dstz,
457 From->info.format,
458 From->data, From->stride,
459 From->layer_stride,
460 src_box.x, src_box.y,
461 src_box.z,
462 src_box.width,
463 src_box.height,
464 src_box.depth);
465
466 NineVolume9_MarkContainerDirty(This);
467
468 return;
469 }
470
471 HRESULT
NineVolume9_UploadSelf(struct NineVolume9 * This,const struct pipe_box * damaged)472 NineVolume9_UploadSelf( struct NineVolume9 *This,
473 const struct pipe_box *damaged )
474 {
475 struct pipe_resource *res = This->resource;
476 struct pipe_box box;
477
478 DBG("This=%p damaged=%p data=%p res=%p\n", This, damaged,
479 This->data, res);
480
481 assert(This->desc.Pool == D3DPOOL_MANAGED);
482 assert(res);
483
484 if (damaged) {
485 box = *damaged;
486 } else {
487 box.x = 0;
488 box.y = 0;
489 box.z = 0;
490 box.width = This->desc.Width;
491 box.height = This->desc.Height;
492 box.depth = This->desc.Depth;
493 }
494
495 nine_context_box_upload(This->base.device,
496 &This->pending_uploads_counter,
497 (struct NineUnknown *)This,
498 res,
499 This->level,
500 &box,
501 res->format,
502 This->data, This->stride,
503 This->layer_stride,
504 &box);
505
506 return D3D_OK;
507 }
508
509
510 IDirect3DVolume9Vtbl NineVolume9_vtable = {
511 (void *)NineUnknown_QueryInterface,
512 (void *)NineUnknown_AddRef,
513 (void *)NineUnknown_Release,
514 (void *)NineUnknown_GetDevice, /* actually part of Volume9 iface */
515 (void *)NineUnknown_SetPrivateData,
516 (void *)NineUnknown_GetPrivateData,
517 (void *)NineUnknown_FreePrivateData,
518 (void *)NineVolume9_GetContainer,
519 (void *)NineVolume9_GetDesc,
520 (void *)NineVolume9_LockBox,
521 (void *)NineVolume9_UnlockBox
522 };
523
524 static const GUID *NineVolume9_IIDs[] = {
525 &IID_IDirect3DVolume9,
526 &IID_IUnknown,
527 NULL
528 };
529
530 HRESULT
NineVolume9_new(struct NineDevice9 * pDevice,struct NineUnknown * pContainer,struct pipe_resource * pResource,unsigned Level,D3DVOLUME_DESC * pDesc,struct NineVolume9 ** ppOut)531 NineVolume9_new( struct NineDevice9 *pDevice,
532 struct NineUnknown *pContainer,
533 struct pipe_resource *pResource,
534 unsigned Level,
535 D3DVOLUME_DESC *pDesc,
536 struct NineVolume9 **ppOut )
537 {
538 NINE_DEVICE_CHILD_NEW(Volume9, ppOut, pDevice, /* args */
539 pContainer, pResource, Level, pDesc);
540 }
541