]> git.cworth.org Git - apitrace/blob - thirdparty/directxtex/DirectXTex/DirectXTexImage.cpp
fb1b383c0611939840456e8e8071b112f1357c39
[apitrace] / thirdparty / directxtex / DirectXTex / DirectXTexImage.cpp
1 //-------------------------------------------------------------------------------------
2 // DirectXTexImage.cpp
3 //  
4 // DirectX Texture Library - Image container
5 //
6 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
7 // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
8 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
9 // PARTICULAR PURPOSE.
10 //
11 // Copyright (c) Microsoft Corporation. All rights reserved.
12 //
13 // http://go.microsoft.com/fwlink/?LinkId=248926
14 //-------------------------------------------------------------------------------------
15
16 #include "directxtexp.h"
17
18 namespace DirectX
19 {
20
21 extern bool _CalculateMipLevels( _In_ size_t width, _In_ size_t height, _Inout_ size_t& mipLevels );
22 extern bool _CalculateMipLevels3D( _In_ size_t width, _In_ size_t height, _In_ size_t depth, _Inout_ size_t& mipLevels );
23
24 //-------------------------------------------------------------------------------------
25 // Determines number of image array entries and pixel size
26 //-------------------------------------------------------------------------------------
27 void _DetermineImageArray( const TexMetadata& metadata, DWORD cpFlags,
28                            size_t& nImages, size_t& pixelSize )
29 {
30     assert( metadata.width > 0 && metadata.height > 0 && metadata.depth > 0 );
31     assert( metadata.arraySize > 0 );
32     assert( metadata.mipLevels > 0 );
33
34     size_t _pixelSize = 0;
35     size_t _nimages = 0;
36
37     switch( metadata.dimension )
38     {
39     case TEX_DIMENSION_TEXTURE1D:
40     case TEX_DIMENSION_TEXTURE2D:
41         for( size_t item = 0; item < metadata.arraySize; ++item )
42         {
43             size_t w = metadata.width;
44             size_t h = metadata.height;
45
46             for( size_t level=0; level < metadata.mipLevels; ++level )
47             {
48                 size_t rowPitch, slicePitch;
49                 ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags );
50
51                 _pixelSize += slicePitch;
52                 ++_nimages;
53
54                 if ( h > 1 )
55                     h >>= 1;
56
57                 if ( w > 1 )
58                     w >>= 1;
59             }
60         }
61         break;
62
63     case TEX_DIMENSION_TEXTURE3D:
64         {
65             size_t w = metadata.width;
66             size_t h = metadata.height;
67             size_t d = metadata.depth;
68
69             for( size_t level=0; level < metadata.mipLevels; ++level )
70             {
71                 size_t rowPitch, slicePitch;
72                 ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags );
73
74                 for( size_t slice=0; slice < d; ++slice )
75                 {
76                     _pixelSize += slicePitch;
77                     ++_nimages;
78                 }
79
80                 if ( h > 1 )
81                     h >>= 1;
82
83                 if ( w > 1 )
84                     w >>= 1;
85
86                 if ( d > 1 )
87                     d >>= 1;
88             }
89         }
90         break;
91
92     default:
93         assert( false );
94         break;
95     }
96
97     nImages = _nimages;
98     pixelSize = _pixelSize;
99 }
100
101
102 //-------------------------------------------------------------------------------------
103 // Fills in the image array entries
104 //-------------------------------------------------------------------------------------
105 bool _SetupImageArray( uint8_t *pMemory, size_t pixelSize,
106                        const TexMetadata& metadata, DWORD cpFlags,
107                        Image* images, size_t nImages )
108 {
109     assert( pMemory );
110     assert( pixelSize > 0 );
111     assert( nImages > 0 );
112
113     if ( !images )
114         return false;
115
116     size_t index = 0;
117     uint8_t* pixels = pMemory;
118     const uint8_t* pEndBits = pMemory + pixelSize;
119
120     switch( metadata.dimension )
121     {
122     case TEX_DIMENSION_TEXTURE1D:
123     case TEX_DIMENSION_TEXTURE2D:
124         if (metadata.arraySize == 0 || metadata.mipLevels == 0)
125         {
126             return false;
127         }
128
129         for( size_t item = 0; item < metadata.arraySize; ++item )
130         {
131             size_t w = metadata.width;
132             size_t h = metadata.height;
133
134             for( size_t level=0; level < metadata.mipLevels; ++level )
135             {
136                 if ( index >= nImages )
137                 {
138                     return false;
139                 }
140
141                 size_t rowPitch, slicePitch;
142                 ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags );
143
144                 images[index].width = w;
145                 images[index].height = h;
146                 images[index].format = metadata.format;
147                 images[index].rowPitch = rowPitch;
148                 images[index].slicePitch = slicePitch;
149                 images[index].pixels = pixels;
150                 ++index;
151
152                 pixels += slicePitch;
153                 if ( pixels > pEndBits )
154                 {
155                     return false;
156                 }
157             
158                 if ( h > 1 )
159                     h >>= 1;
160
161                 if ( w > 1 )
162                     w >>= 1;
163             }
164         }
165         return true;
166
167     case TEX_DIMENSION_TEXTURE3D:
168         {
169             if (metadata.mipLevels == 0 || metadata.depth == 0)
170             {
171                 return false;
172             }
173
174             size_t w = metadata.width;
175             size_t h = metadata.height;
176             size_t d = metadata.depth;
177
178             for( size_t level=0; level < metadata.mipLevels; ++level )
179             {
180                 size_t rowPitch, slicePitch;
181                 ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags );
182
183                 for( size_t slice=0; slice < d; ++slice )
184                 {
185                     if ( index >= nImages )
186                     {
187                         return false;
188                     }
189
190                     // We use the same memory organization that Direct3D 11 needs for D3D11_SUBRESOURCE_DATA
191                     // with all slices of a given miplevel being continuous in memory
192                     images[index].width = w;
193                     images[index].height = h;
194                     images[index].format = metadata.format;
195                     images[index].rowPitch = rowPitch;
196                     images[index].slicePitch = slicePitch;
197                     images[index].pixels = pixels;
198                     ++index;
199
200                     pixels += slicePitch;
201                     if ( pixels > pEndBits )
202                     {
203                         return false;
204                     }
205                 }
206             
207                 if ( h > 1 )
208                     h >>= 1;
209
210                 if ( w > 1 )
211                     w >>= 1;
212
213                 if ( d > 1 )
214                     d >>= 1;
215             }
216         }
217         return true;
218
219     default:
220         return false;
221     }
222 }
223
224
225 //=====================================================================================
226 // ScratchImage - Bitmap image container
227 //=====================================================================================
228
229 //-------------------------------------------------------------------------------------
230 // Methods
231 //-------------------------------------------------------------------------------------
232 HRESULT ScratchImage::Initialize( const TexMetadata& mdata )
233 {
234     if ( !IsValid(mdata.format) || IsVideo(mdata.format) )
235         return E_INVALIDARG;
236
237     size_t mipLevels = mdata.mipLevels;
238
239     switch( mdata.dimension )
240     {
241     case TEX_DIMENSION_TEXTURE1D:
242         if ( !mdata.width || mdata.height != 1 || mdata.depth != 1 || !mdata.arraySize )
243             return E_INVALIDARG;
244
245         if ( !_CalculateMipLevels(mdata.width,1,mipLevels) )
246             return E_INVALIDARG;
247         break;
248
249     case TEX_DIMENSION_TEXTURE2D:
250         if ( !mdata.width || !mdata.height || mdata.depth != 1 || !mdata.arraySize )
251             return E_INVALIDARG;
252
253         if ( mdata.miscFlags & TEX_MISC_TEXTURECUBE )
254         {
255             if ( (mdata.arraySize % 6) != 0 )
256                 return E_INVALIDARG;
257         }
258
259         if ( !_CalculateMipLevels(mdata.width,mdata.height,mipLevels) )
260             return E_INVALIDARG;
261         break;
262
263     case TEX_DIMENSION_TEXTURE3D:
264         if ( !mdata.width || !mdata.height || !mdata.depth || mdata.arraySize != 1 )
265             return E_INVALIDARG;
266
267         if ( !_CalculateMipLevels3D(mdata.width,mdata.height,mdata.depth,mipLevels) )
268             return E_INVALIDARG;
269         break;
270
271     default:
272         return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
273     }
274
275     Release();
276
277     _metadata.width = mdata.width;
278     _metadata.height = mdata.height;
279     _metadata.depth = mdata.depth;
280     _metadata.arraySize = mdata.arraySize;
281     _metadata.mipLevels = mipLevels;
282     _metadata.miscFlags = mdata.miscFlags & TEX_MISC_TEXTURECUBE;
283     _metadata.format = mdata.format;
284     _metadata.dimension = mdata.dimension;
285
286     size_t pixelSize, nimages;
287     _DetermineImageArray( _metadata, CP_FLAGS_NONE, nimages, pixelSize );
288
289     _image = new Image[ nimages ];
290     if ( !_image )
291         return E_OUTOFMEMORY;
292
293     _nimages = nimages;
294     memset( _image, 0, sizeof(Image) * nimages );
295
296     _memory = reinterpret_cast<uint8_t*>( _aligned_malloc( pixelSize, 16 ) );
297     if ( !_memory )
298     {
299         Release();
300         return E_OUTOFMEMORY;
301     }
302     _size = pixelSize;
303     if ( !_SetupImageArray( _memory, pixelSize, _metadata, CP_FLAGS_NONE, _image, nimages ) )
304     {
305         Release();
306         return E_FAIL;
307     }
308
309     return S_OK;
310 }
311
312 HRESULT ScratchImage::Initialize1D( DXGI_FORMAT fmt, size_t length, size_t arraySize, size_t mipLevels )
313 {
314     if ( !IsValid(fmt) || IsVideo(fmt) || !length || !arraySize )
315         return E_INVALIDARG;
316
317     // 1D is a special case of the 2D case
318     HRESULT hr = Initialize2D( fmt, length, 1, arraySize, mipLevels );
319     if ( FAILED(hr) )
320         return hr;
321
322     _metadata.dimension = TEX_DIMENSION_TEXTURE1D;
323
324     return S_OK;
325 }
326
327 HRESULT ScratchImage::Initialize2D( DXGI_FORMAT fmt, size_t width, size_t height, size_t arraySize, size_t mipLevels )
328 {
329     if ( !IsValid(fmt) || IsVideo(fmt) || !width || !height || !arraySize )
330         return E_INVALIDARG;
331
332     if ( !_CalculateMipLevels(width,height,mipLevels) )
333         return E_INVALIDARG;
334
335     Release();
336
337     _metadata.width = width;
338     _metadata.height = height;
339     _metadata.depth = 1;
340     _metadata.arraySize = arraySize;
341     _metadata.mipLevels = mipLevels;
342     _metadata.miscFlags = 0;
343     _metadata.format = fmt;
344     _metadata.dimension = TEX_DIMENSION_TEXTURE2D;
345
346     size_t pixelSize, nimages;
347     _DetermineImageArray( _metadata, CP_FLAGS_NONE, nimages, pixelSize );
348
349     _image = new Image[ nimages ];
350     if ( !_image )
351         return E_OUTOFMEMORY;
352
353     _nimages = nimages;
354     memset( _image, 0, sizeof(Image) * nimages );
355
356     _memory = reinterpret_cast<uint8_t*>( _aligned_malloc( pixelSize, 16 ) );
357     if ( !_memory )
358     {
359         Release();
360         return E_OUTOFMEMORY;
361     }
362     _size = pixelSize;
363     if ( !_SetupImageArray( _memory, pixelSize, _metadata, CP_FLAGS_NONE, _image, nimages ) )
364     {
365         Release();
366         return E_FAIL;
367     }
368
369     return S_OK;
370 }
371
372 HRESULT ScratchImage::Initialize3D( DXGI_FORMAT fmt, size_t width, size_t height, size_t depth, size_t mipLevels )
373 {
374     if ( !IsValid(fmt) || IsVideo(fmt) || !width || !height || !depth )
375         return E_INVALIDARG;
376
377     if ( !_CalculateMipLevels3D(width,height,depth,mipLevels) )
378         return E_INVALIDARG;
379
380     Release();
381
382     _metadata.width = width;
383     _metadata.height = height;
384     _metadata.depth = depth;
385     _metadata.arraySize = 1;    // Direct3D 10.x/11 does not support arrays of 3D textures
386     _metadata.mipLevels = mipLevels;
387     _metadata.miscFlags = 0;
388     _metadata.format = fmt;
389     _metadata.dimension = TEX_DIMENSION_TEXTURE3D;
390
391     size_t pixelSize, nimages;
392     _DetermineImageArray( _metadata, CP_FLAGS_NONE, nimages, pixelSize );
393
394     _image = new Image[ nimages ];
395     if ( !_image )
396     {
397         Release();
398         return E_OUTOFMEMORY;
399     }
400     _nimages = nimages;
401     memset( _image, 0, sizeof(Image) * nimages );
402
403     _memory = reinterpret_cast<uint8_t*>( _aligned_malloc( pixelSize, 16 ) );
404     if ( !_memory )
405     {
406         Release();
407         return E_OUTOFMEMORY;
408     }
409     _size = pixelSize;
410
411     if ( !_SetupImageArray( _memory, pixelSize, _metadata, CP_FLAGS_NONE, _image, nimages ) )
412     {
413         Release();
414         return E_FAIL;
415     }
416
417     return S_OK;
418 }
419
420 HRESULT ScratchImage::InitializeCube( DXGI_FORMAT fmt, size_t width, size_t height, size_t nCubes, size_t mipLevels )
421 {
422     if ( !IsValid(fmt) || IsVideo(fmt)  || !width || !height || !nCubes )
423         return E_INVALIDARG;
424     
425     // A DirectX11 cubemap is just a 2D texture array that is a multiple of 6 for each cube
426     HRESULT hr = Initialize2D( fmt, width, height, nCubes * 6, mipLevels );
427     if ( FAILED(hr) )
428         return hr;
429
430     _metadata.miscFlags |= TEX_MISC_TEXTURECUBE;
431
432     return S_OK;
433 }
434
435 HRESULT ScratchImage::InitializeFromImage( const Image& srcImage, bool allow1D )
436 {
437     HRESULT hr = ( srcImage.height > 1 || !allow1D )
438                  ? Initialize2D( srcImage.format, srcImage.width, srcImage.height, 1, 1 )
439                  : Initialize1D( srcImage.format, srcImage.width, 1, 1 );
440
441     if ( FAILED(hr) )
442         return hr;
443
444     const uint8_t* sptr = reinterpret_cast<const uint8_t*>( srcImage.pixels );
445     if ( !sptr )
446         return E_POINTER;
447
448     uint8_t* dptr = reinterpret_cast<uint8_t*>( _image[0].pixels );
449     if ( !dptr )
450         return E_POINTER;
451
452     for( size_t y = 0; y < srcImage.height; ++y )
453     {
454         _CopyScanline( dptr, _image[0].rowPitch, sptr, srcImage.rowPitch, srcImage.format, TEXP_SCANLINE_NONE );
455         sptr += srcImage.rowPitch;
456         dptr += _image[0].rowPitch;
457     }
458
459     return S_OK;
460 }
461
462 HRESULT ScratchImage::InitializeArrayFromImages( const Image* images, size_t nImages, bool allow1D )
463 {
464     if ( !images || !nImages )
465         return E_INVALIDARG;
466
467     DXGI_FORMAT format = images[0].format;
468     size_t width = images[0].width;
469     size_t height = images[0].height;
470
471     for( size_t index=0; index < nImages; ++index )
472     {
473         if ( !images[index].pixels )
474             return E_POINTER;
475
476         if ( images[index].format != format || images[index].width != width || images[index].height != height )
477         {
478             // All images must be the same format, width, and height
479             return E_FAIL;
480         }
481     }
482
483     HRESULT hr = ( height > 1 || !allow1D )
484                  ? Initialize2D( format, width, height, nImages, 1 )
485                  : Initialize1D( format, width, nImages, 1 );
486
487     if ( FAILED(hr) )
488         return hr;
489
490     for( size_t index=0; index < nImages; ++index )
491     {
492         const uint8_t* sptr = reinterpret_cast<const uint8_t*>( images[index].pixels );
493         if ( !sptr )
494             return E_POINTER;
495
496         assert( index < _nimages );
497         uint8_t* dptr = reinterpret_cast<uint8_t*>( _image[index].pixels );
498         if ( !dptr )
499             return E_POINTER;
500
501         for( size_t y = 0; y < height; ++y )
502         {
503             _CopyScanline( dptr, _image[index].rowPitch, sptr, images[index].rowPitch, format, TEXP_SCANLINE_NONE );
504             sptr += images[index].rowPitch;
505             dptr += _image[index].rowPitch;
506         }
507     }
508
509     return S_OK;
510 }
511
512 HRESULT ScratchImage::InitializeCubeFromImages( const Image* images, size_t nImages )
513 {
514     if ( !images || !nImages )
515         return E_INVALIDARG;
516
517     // A DirectX11 cubemap is just a 2D texture array that is a multiple of 6 for each cube
518     if ( ( nImages % 6 ) != 0 )
519         return E_INVALIDARG;
520
521     HRESULT hr = InitializeArrayFromImages( images, nImages, false );
522     if ( FAILED(hr) )
523         return hr;
524
525     _metadata.miscFlags |= TEX_MISC_TEXTURECUBE;
526
527     return S_OK;
528 }
529
530 HRESULT ScratchImage::Initialize3DFromImages( const Image* images, size_t depth )
531 {
532     if ( !images || !depth )
533         return E_INVALIDARG;
534
535     DXGI_FORMAT format = images[0].format;
536     size_t width = images[0].width;
537     size_t height = images[0].height;
538
539     for( size_t slice=0; slice < depth; ++slice )
540     {
541         if ( !images[slice].pixels )
542             return E_POINTER;
543
544         if ( images[slice].format != format || images[slice].width != width || images[slice].height != height )
545         {
546             // All images must be the same format, width, and height
547             return E_FAIL;
548         }
549     }
550
551     HRESULT hr = Initialize3D( format, width, height, depth, 1 );
552     if ( FAILED(hr) )
553         return hr;
554
555     for( size_t slice=0; slice < depth; ++slice )
556     {
557         const uint8_t* sptr = reinterpret_cast<const uint8_t*>( images[slice].pixels );
558         if ( !sptr )
559             return E_POINTER;
560
561         assert( slice < _nimages );
562         uint8_t* dptr = reinterpret_cast<uint8_t*>( _image[slice].pixels );
563         if ( !dptr )
564             return E_POINTER;
565
566         for( size_t y = 0; y < height; ++y )
567         {
568             _CopyScanline( dptr, _image[slice].rowPitch, sptr, images[slice].rowPitch, format, TEXP_SCANLINE_NONE );
569             sptr += images[slice].rowPitch;
570             dptr += _image[slice].rowPitch;
571         }
572     }
573
574     return S_OK;
575 }
576
577 void ScratchImage::Release()
578 {
579     _nimages = 0;
580     _size = 0;
581
582     if ( _image )
583     {
584         delete [] _image;
585         _image = 0;
586     }
587
588     if ( _memory )
589     {
590         _aligned_free( _memory );
591         _memory = 0;
592     }
593     
594     memset(&_metadata, 0, sizeof(_metadata));
595 }
596
597 bool ScratchImage::OverrideFormat( DXGI_FORMAT f )
598 {
599     if ( !_image )
600         return false;
601
602     if ( !IsValid( f ) || IsVideo( f ) )
603         return false;
604
605     if ( ( BitsPerPixel( f ) != BitsPerPixel( _metadata.format ) )
606          || ( IsCompressed( f ) != IsCompressed( _metadata.format ) )
607          || ( IsPacked( f ) != IsPacked( _metadata.format ) ) )
608     {
609          // Can't change the effective pitch of the format this way
610          return false;
611     }
612
613     for( size_t index = 0; index < _nimages; ++index )
614     {
615         _image[ index ].format = f;
616     }
617
618     _metadata.format = f;
619
620     return true;
621 }
622
623 const Image* ScratchImage::GetImage(size_t mip, size_t item, size_t slice) const
624 {
625     if ( mip >= _metadata.mipLevels )
626         return nullptr;
627
628     size_t index = 0;
629
630     switch( _metadata.dimension )
631     {
632     case TEX_DIMENSION_TEXTURE1D:
633     case TEX_DIMENSION_TEXTURE2D:
634         if ( slice > 0 )
635             return nullptr;
636
637         if ( item >= _metadata.arraySize )
638             return nullptr;
639
640         index = item*( _metadata.mipLevels ) + mip;
641         break;
642
643     case TEX_DIMENSION_TEXTURE3D:
644         if ( item > 0 )
645         {
646             // No support for arrays of volumes
647             return nullptr;
648         }
649         else
650         {
651             size_t d = _metadata.depth;
652
653             for( size_t level = 0; level < mip; ++level )
654             {
655                 index += d;
656                 if ( d > 1 )
657                     d >>= 1;
658             }
659
660             if ( slice >= d )
661                 return nullptr;
662
663             index += slice;
664         }
665         break;
666
667     default:
668         return nullptr;
669     }
670  
671     return &_image[index];
672 }
673
674 }; // namespace