st/nine: Hack to generate resource if it doesn't exist when getting view
[mesa.git] / src / gallium / state_trackers / nine / basetexture9.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 "basetexture9.h"
24 #include "device9.h"
25
26 /* For UploadSelf: */
27 #include "texture9.h"
28 #include "cubetexture9.h"
29 #include "volumetexture9.h"
30
31 #ifdef DEBUG
32 #include "nine_pipe.h"
33 #include "nine_dump.h"
34 #endif
35
36 #include "util/u_format.h"
37 #include "util/u_gen_mipmap.h"
38
39 #define DBG_CHANNEL DBG_BASETEXTURE
40
41 HRESULT
42 NineBaseTexture9_ctor( struct NineBaseTexture9 *This,
43 struct NineUnknownParams *pParams,
44 struct pipe_resource *initResource,
45 D3DRESOURCETYPE Type,
46 D3DFORMAT format,
47 D3DPOOL Pool,
48 DWORD Usage)
49 {
50 BOOL alloc = (Pool == D3DPOOL_DEFAULT) && !initResource &&
51 (format != D3DFMT_NULL);
52 HRESULT hr;
53
54 DBG("This=%p, pParams=%p initResource=%p Type=%d format=%d Pool=%d Usage=%d\n",
55 This, pParams, initResource, Type, format, Pool, Usage);
56
57 user_assert(!(Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) ||
58 Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
59 user_assert(!(Usage & D3DUSAGE_DYNAMIC) ||
60 Pool != D3DPOOL_MANAGED, D3DERR_INVALIDCALL);
61
62 hr = NineResource9_ctor(&This->base, pParams, initResource, alloc, Type, Pool, Usage);
63 if (FAILED(hr))
64 return hr;
65
66 This->format = format;
67 This->pipe = pParams->device->pipe;
68 This->mipfilter = (Usage & D3DUSAGE_AUTOGENMIPMAP) ?
69 D3DTEXF_LINEAR : D3DTEXF_NONE;
70 This->lod = 0;
71 This->lod_resident = -1;
72 This->shadow = This->format != D3DFMT_INTZ && util_format_has_depth(
73 util_format_description(This->base.info.format));
74
75 list_inithead(&This->list);
76
77 return D3D_OK;
78 }
79
80 void
81 NineBaseTexture9_dtor( struct NineBaseTexture9 *This )
82 {
83 DBG("This=%p\n", This);
84
85 pipe_sampler_view_reference(&This->view[0], NULL);
86 pipe_sampler_view_reference(&This->view[1], NULL);
87
88 list_del(&This->list),
89
90 NineResource9_dtor(&This->base);
91 }
92
93 DWORD WINAPI
94 NineBaseTexture9_SetLOD( struct NineBaseTexture9 *This,
95 DWORD LODNew )
96 {
97 DWORD old = This->lod;
98
99 DBG("This=%p LODNew=%d\n", This, LODNew);
100
101 user_assert(This->base.pool == D3DPOOL_MANAGED, 0);
102
103 This->lod = MIN2(LODNew, This->base.info.last_level);
104
105 if (This->lod != old && This->bind_count && LIST_IS_EMPTY(&This->list))
106 list_add(&This->list, &This->base.base.device->update_textures);
107
108 return old;
109 }
110
111 DWORD WINAPI
112 NineBaseTexture9_GetLOD( struct NineBaseTexture9 *This )
113 {
114 DBG("This=%p\n", This);
115
116 return This->lod;
117 }
118
119 DWORD WINAPI
120 NineBaseTexture9_GetLevelCount( struct NineBaseTexture9 *This )
121 {
122 DBG("This=%p\n", This);
123
124 if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
125 return 1;
126 return This->base.info.last_level + 1;
127 }
128
129 HRESULT WINAPI
130 NineBaseTexture9_SetAutoGenFilterType( struct NineBaseTexture9 *This,
131 D3DTEXTUREFILTERTYPE FilterType )
132 {
133 DBG("This=%p FilterType=%d\n", This, FilterType);
134
135 if (!(This->base.usage & D3DUSAGE_AUTOGENMIPMAP))
136 return D3D_OK;
137 user_assert(FilterType != D3DTEXF_NONE, D3DERR_INVALIDCALL);
138
139 This->mipfilter = FilterType;
140
141 return D3D_OK;
142 }
143
144 D3DTEXTUREFILTERTYPE WINAPI
145 NineBaseTexture9_GetAutoGenFilterType( struct NineBaseTexture9 *This )
146 {
147 DBG("This=%p\n", This);
148
149 return This->mipfilter;
150 }
151
152 HRESULT
153 NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
154 {
155 HRESULT hr;
156 unsigned last_level = This->base.info.last_level;
157 unsigned l;
158
159 DBG("This=%p dirty=%i type=%s\n", This, This->dirty,
160 nine_D3DRTYPE_to_str(This->base.type));
161
162 assert(This->base.pool == D3DPOOL_MANAGED);
163
164 if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
165 last_level = 0; /* TODO: What if level 0 is not resident ? */
166
167 if (This->lod_resident != This->lod) {
168 struct pipe_resource *res;
169
170 DBG("updating LOD from %u to %u ...\n", This->lod_resident, This->lod);
171
172 pipe_sampler_view_reference(&This->view[0], NULL);
173 pipe_sampler_view_reference(&This->view[1], NULL);
174
175 if (This->bind_count) {
176 /* mark state dirty */
177 struct nine_state *state = &This->base.base.device->state;
178 unsigned s;
179 for (s = 0; s < NINE_MAX_SAMPLERS; ++s)
180 if (state->texture[s] == This)
181 state->changed.texture |= 1 << s;
182 if (state->changed.texture)
183 state->changed.group |= NINE_STATE_TEXTURE;
184 }
185
186 hr = NineBaseTexture9_CreatePipeResource(This, This->lod_resident != -1);
187 if (FAILED(hr))
188 return hr;
189 res = This->base.resource;
190
191 if (This->lod_resident == -1) /* no levels were resident */
192 This->lod_resident = This->base.info.last_level + 1;
193
194 if (This->base.type == D3DRTYPE_TEXTURE) {
195 struct NineTexture9 *tex = NineTexture9(This);
196 struct pipe_box box;
197
198 /* Mark uninitialized levels as dirty. */
199 box.x = box.y = box.z = 0;
200 box.depth = 1;
201 for (l = This->lod; l < This->lod_resident; ++l) {
202 box.width = u_minify(This->base.info.width0, l);
203 box.height = u_minify(This->base.info.height0, l);
204 NineSurface9_AddDirtyRect(tex->surfaces[l], &box);
205 }
206 for (l = 0; l < This->lod; ++l)
207 NineSurface9_SetResource(tex->surfaces[l], NULL, -1);
208 for (; l <= This->base.info.last_level; ++l)
209 NineSurface9_SetResource(tex->surfaces[l], res, l - This->lod);
210 } else
211 if (This->base.type == D3DRTYPE_CUBETEXTURE) {
212 struct NineCubeTexture9 *tex = NineCubeTexture9(This);
213 struct pipe_box box;
214 unsigned z;
215
216 /* Mark uninitialized levels as dirty. */
217 box.x = box.y = box.z = 0;
218 box.depth = 1;
219 for (l = This->lod; l < This->lod_resident; ++l) {
220 box.width = u_minify(This->base.info.width0, l);
221 box.height = u_minify(This->base.info.height0, l);
222 for (z = 0; z < 6; ++z)
223 NineSurface9_AddDirtyRect(tex->surfaces[l * 6 + z], &box);
224 }
225 for (l = 0; l < This->lod; ++l) {
226 for (z = 0; z < 6; ++z)
227 NineSurface9_SetResource(tex->surfaces[l * 6 + z],
228 NULL, -1);
229 }
230 for (; l <= This->base.info.last_level; ++l) {
231 for (z = 0; z < 6; ++z)
232 NineSurface9_SetResource(tex->surfaces[l * 6 + z],
233 res, l - This->lod);
234 }
235 } else
236 if (This->base.type == D3DRTYPE_VOLUMETEXTURE) {
237 struct NineVolumeTexture9 *tex = NineVolumeTexture9(This);
238 struct pipe_box box;
239
240 /* Mark uninitialized levels as dirty. */
241 box.x = box.y = box.z = 0;
242 for (l = This->lod; l < This->lod_resident; ++l) {
243 box.width = u_minify(This->base.info.width0, l);
244 box.height = u_minify(This->base.info.height0, l);
245 box.depth = u_minify(This->base.info.depth0, l);
246 NineVolume9_AddDirtyRegion(tex->volumes[l], &box);
247 }
248 for (l = 0; l < This->lod; ++l)
249 NineVolume9_SetResource(tex->volumes[l], NULL, -1);
250 for (; l <= This->base.info.last_level; ++l)
251 NineVolume9_SetResource(tex->volumes[l], res, l - This->lod);
252 } else {
253 assert(!"invalid texture type");
254 }
255
256 if (This->lod < This->lod_resident)
257 This->dirty = TRUE;
258 This->lod_resident = This->lod;
259 }
260 if (!This->dirty)
261 return D3D_OK;
262
263 if (This->base.type == D3DRTYPE_TEXTURE) {
264 struct NineTexture9 *tex = NineTexture9(This);
265 struct pipe_box box;
266 box.z = 0;
267 box.depth = 1;
268
269 DBG("TEXTURE: dirty rect=(%u,%u) (%ux%u)\n",
270 tex->dirty_rect.x, tex->dirty_rect.y,
271 tex->dirty_rect.width, tex->dirty_rect.height);
272
273 if (tex->dirty_rect.width) {
274 for (l = 0; l <= last_level; ++l) {
275 u_box_minify_2d(&box, &tex->dirty_rect, l);
276 NineSurface9_AddDirtyRect(tex->surfaces[l], &box);
277 }
278 memset(&tex->dirty_rect, 0, sizeof(tex->dirty_rect));
279 tex->dirty_rect.depth = 1;
280 }
281 for (l = This->lod; l <= last_level; ++l)
282 NineSurface9_UploadSelf(tex->surfaces[l]);
283 } else
284 if (This->base.type == D3DRTYPE_CUBETEXTURE) {
285 struct NineCubeTexture9 *tex = NineCubeTexture9(This);
286 unsigned z;
287 struct pipe_box box;
288 box.z = 0;
289 box.depth = 1;
290
291 for (z = 0; z < 6; ++z) {
292 DBG("FACE[%u]: dirty rect=(%u,%u) (%ux%u)\n", z,
293 tex->dirty_rect[z].x, tex->dirty_rect[z].y,
294 tex->dirty_rect[z].width, tex->dirty_rect[z].height);
295
296 if (tex->dirty_rect[z].width) {
297 for (l = 0; l <= last_level; ++l) {
298 u_box_minify_2d(&box, &tex->dirty_rect[z], l);
299 NineSurface9_AddDirtyRect(tex->surfaces[l * 6 + z], &box);
300 }
301 memset(&tex->dirty_rect[z], 0, sizeof(tex->dirty_rect[z]));
302 tex->dirty_rect[z].depth = 1;
303 }
304 for (l = This->lod; l <= last_level; ++l)
305 NineSurface9_UploadSelf(tex->surfaces[l * 6 + z]);
306 }
307 } else
308 if (This->base.type == D3DRTYPE_VOLUMETEXTURE) {
309 struct NineVolumeTexture9 *tex = NineVolumeTexture9(This);
310 struct pipe_box box;
311
312 DBG("VOLUME: dirty_box=(%u,%u,%u) (%ux%ux%u)\n",
313 tex->dirty_box.x, tex->dirty_box.y, tex->dirty_box.y,
314 tex->dirty_box.width, tex->dirty_box.height, tex->dirty_box.depth);
315
316 if (tex->dirty_box.width) {
317 for (l = 0; l <= last_level; ++l) {
318 u_box_minify_2d(&box, &tex->dirty_box, l);
319 NineVolume9_AddDirtyRegion(tex->volumes[l], &tex->dirty_box);
320 }
321 memset(&tex->dirty_box, 0, sizeof(tex->dirty_box));
322 }
323 for (l = This->lod; l <= last_level; ++l)
324 NineVolume9_UploadSelf(tex->volumes[l]);
325 } else {
326 assert(!"invalid texture type");
327 }
328 This->dirty = FALSE;
329
330 if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
331 This->dirty_mip = TRUE;
332 /* TODO: if dirty only because of lod change, only generate added levels */
333
334 DBG("DONE, generate mip maps = %i\n", This->dirty_mip);
335 return D3D_OK;
336 }
337
338 void WINAPI
339 NineBaseTexture9_GenerateMipSubLevels( struct NineBaseTexture9 *This )
340 {
341 struct pipe_resource *resource = This->base.resource;
342
343 unsigned base_level = 0;
344 unsigned last_level = This->base.info.last_level - This->lod;
345 unsigned first_layer = 0;
346 unsigned last_layer;
347 unsigned filter = This->mipfilter == D3DTEXF_POINT ? PIPE_TEX_FILTER_NEAREST
348 : PIPE_TEX_FILTER_LINEAR;
349 DBG("This=%p\n", This);
350
351 if (This->base.pool == D3DPOOL_MANAGED)
352 NineBaseTexture9_UploadSelf(This);
353 if (!This->dirty_mip)
354 return;
355 if (This->lod) {
356 ERR("AUTOGENMIPMAP if level 0 is not resident not supported yet !\n");
357 return;
358 }
359
360 if (!This->view[0])
361 NineBaseTexture9_UpdateSamplerView(This, 0);
362
363 last_layer = util_max_layer(This->view[0]->texture, base_level);
364
365 util_gen_mipmap(This->pipe, resource,
366 resource->format, base_level, last_level,
367 first_layer, last_layer, filter);
368
369 This->dirty_mip = FALSE;
370
371 NineDevice9_RestoreNonCSOState(This->base.base.device, ~0x3);
372 }
373
374 HRESULT
375 NineBaseTexture9_CreatePipeResource( struct NineBaseTexture9 *This,
376 BOOL CopyData )
377 {
378 struct pipe_context *pipe = This->pipe;
379 struct pipe_screen *screen = This->base.info.screen;
380 struct pipe_resource templ;
381 unsigned l, m;
382 struct pipe_resource *res;
383 struct pipe_resource *old = This->base.resource;
384
385 DBG("This=%p lod=%u last_level=%u\n", This,
386 This->lod, This->base.info.last_level);
387
388 assert(This->base.pool == D3DPOOL_MANAGED);
389
390 templ = This->base.info;
391
392 if (This->lod) {
393 templ.width0 = u_minify(templ.width0, This->lod);
394 templ.height0 = u_minify(templ.height0, This->lod);
395 templ.depth0 = u_minify(templ.depth0, This->lod);
396 }
397 templ.last_level = This->base.info.last_level - This->lod;
398
399 if (old) {
400 /* LOD might have changed. */
401 if (old->width0 == templ.width0 &&
402 old->height0 == templ.height0 &&
403 old->depth0 == templ.depth0)
404 return D3D_OK;
405 }
406
407 res = screen->resource_create(screen, &templ);
408 if (!res)
409 return D3DERR_OUTOFVIDEOMEMORY;
410 This->base.resource = res;
411
412 if (old && CopyData) { /* Don't return without releasing old ! */
413 struct pipe_box box;
414 box.x = 0;
415 box.y = 0;
416 box.z = 0;
417
418 l = (This->lod < This->lod_resident) ? This->lod_resident - This->lod : 0;
419 m = (This->lod < This->lod_resident) ? 0 : This->lod - This->lod_resident;
420
421 box.width = u_minify(templ.width0, l);
422 box.height = u_minify(templ.height0, l);
423 box.depth = u_minify(templ.depth0, l);
424
425 for (; l <= templ.last_level; ++l, ++m) {
426 pipe->resource_copy_region(pipe,
427 res, l, 0, 0, 0,
428 old, m, &box);
429 box.width = u_minify(box.width, 1);
430 box.height = u_minify(box.height, 1);
431 box.depth = u_minify(box.depth, 1);
432 }
433 }
434 pipe_resource_reference(&old, NULL);
435
436 return D3D_OK;
437 }
438
439 #define SWIZZLE_TO_REPLACE(s) (s == UTIL_FORMAT_SWIZZLE_0 || \
440 s == UTIL_FORMAT_SWIZZLE_1 || \
441 s == UTIL_FORMAT_SWIZZLE_NONE)
442
443 HRESULT
444 NineBaseTexture9_UpdateSamplerView( struct NineBaseTexture9 *This,
445 const int sRGB )
446 {
447 const struct util_format_description *desc;
448 struct pipe_context *pipe = This->pipe;
449 struct pipe_resource *resource = This->base.resource;
450 struct pipe_sampler_view templ;
451 unsigned i;
452 uint8_t swizzle[4];
453
454 DBG("This=%p sRGB=%d\n", This, sRGB);
455
456 if (unlikely(!resource)) {
457 if (unlikely(This->format == D3DFMT_NULL))
458 return D3D_OK;
459 NineBaseTexture9_Dump(This);
460 /* hack due to incorrect POOL_MANAGED handling */
461 NineBaseTexture9_GenerateMipSubLevels(This);
462 resource = This->base.resource;
463 }
464 assert(resource);
465
466 pipe_sampler_view_reference(&This->view[sRGB], NULL);
467
468 swizzle[0] = PIPE_SWIZZLE_RED;
469 swizzle[1] = PIPE_SWIZZLE_GREEN;
470 swizzle[2] = PIPE_SWIZZLE_BLUE;
471 swizzle[3] = PIPE_SWIZZLE_ALPHA;
472 desc = util_format_description(resource->format);
473 if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) {
474 /* msdn doc is incomplete here and wrong.
475 * The only formats that can be read directly here
476 * are DF16, DF24 and INTZ.
477 * Tested on win the swizzle is
478 * R = depth, G = B = 0, A = 1 for DF16 and DF24
479 * R = G = B = A = depth for INTZ
480 * For the other ZS formats that can't be read directly
481 * but can be used as shadow map, the result is duplicated on
482 * all channel */
483 if (This->format == D3DFMT_DF16 ||
484 This->format == D3DFMT_DF24) {
485 swizzle[1] = PIPE_SWIZZLE_ZERO;
486 swizzle[2] = PIPE_SWIZZLE_ZERO;
487 swizzle[3] = PIPE_SWIZZLE_ONE;
488 } else {
489 swizzle[1] = PIPE_SWIZZLE_RED;
490 swizzle[2] = PIPE_SWIZZLE_RED;
491 swizzle[3] = PIPE_SWIZZLE_RED;
492 }
493 } else if (resource->format != PIPE_FORMAT_A8_UNORM) {
494 /* A8 is the only exception that should have 0.0 as default values
495 * for RGB. It is already what gallium does. All the other ones
496 * should have 1.0 for non-defined values */
497 for (i = 0; i < 4; i++) {
498 if (SWIZZLE_TO_REPLACE(desc->swizzle[i]))
499 swizzle[i] = PIPE_SWIZZLE_ONE;
500 }
501 }
502
503 templ.format = sRGB ? util_format_srgb(resource->format) : resource->format;
504 templ.u.tex.first_layer = 0;
505 templ.u.tex.last_layer = resource->target == PIPE_TEXTURE_3D ?
506 resource->depth0 - 1 : resource->array_size - 1;
507 templ.u.tex.first_level = 0;
508 templ.u.tex.last_level = resource->last_level;
509 templ.swizzle_r = swizzle[0];
510 templ.swizzle_g = swizzle[1];
511 templ.swizzle_b = swizzle[2];
512 templ.swizzle_a = swizzle[3];
513 templ.target = resource->target;
514
515 This->view[sRGB] = pipe->create_sampler_view(pipe, resource, &templ);
516
517 DBG("sampler view = %p(resource = %p)\n", This->view[sRGB], resource);
518
519 return This->view ? D3D_OK : D3DERR_DRIVERINTERNALERROR;
520 }
521
522 void WINAPI
523 NineBaseTexture9_PreLoad( struct NineBaseTexture9 *This )
524 {
525 DBG("This=%p\n", This);
526
527 if (This->dirty && This->base.pool == D3DPOOL_MANAGED)
528 NineBaseTexture9_UploadSelf(This);
529 }
530
531 #ifdef DEBUG
532 void
533 NineBaseTexture9_Dump( struct NineBaseTexture9 *This )
534 {
535 DBG("\nNineBaseTexture9(%p->NULL/%p): Pool=%s Type=%s Usage=%s\n"
536 "Format=%s Dims=%ux%ux%u/%u LastLevel=%u Lod=%u(%u)\n", This,
537 This->base.resource,
538 nine_D3DPOOL_to_str(This->base.pool),
539 nine_D3DRTYPE_to_str(This->base.type),
540 nine_D3DUSAGE_to_str(This->base.usage),
541 d3dformat_to_string(This->format),
542 This->base.info.width0, This->base.info.height0, This->base.info.depth0,
543 This->base.info.array_size, This->base.info.last_level,
544 This->lod, This->lod_resident);
545 }
546 #endif /* DEBUG */