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