X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=thirdparty%2Fdirectxtex%2FDirectXTex%2FDirectXTexImage.cpp;fp=thirdparty%2Fdirectxtex%2FDirectXTex%2FDirectXTexImage.cpp;h=95d54267aa6b55a5e289b0289ad8f1ea20f55a6a;hb=d7c738e13decf8a8a891008c51b437ccbe3434fb;hp=0000000000000000000000000000000000000000;hpb=4f9982f5ec3dccae65d5a49dfd5a81b9737d90cd;p=apitrace diff --git a/thirdparty/directxtex/DirectXTex/DirectXTexImage.cpp b/thirdparty/directxtex/DirectXTex/DirectXTexImage.cpp new file mode 100644 index 0000000..95d5426 --- /dev/null +++ b/thirdparty/directxtex/DirectXTex/DirectXTexImage.cpp @@ -0,0 +1,674 @@ +//------------------------------------------------------------------------------------- +// DirectXTexImage.cpp +// +// DirectX Texture Library - Image container +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// http://go.microsoft.com/fwlink/?LinkId=248926 +//------------------------------------------------------------------------------------- + +#include "DirectXTexP.h" + +namespace DirectX +{ + +extern bool _CalculateMipLevels( _In_ size_t width, _In_ size_t height, _Inout_ size_t& mipLevels ); +extern bool _CalculateMipLevels3D( _In_ size_t width, _In_ size_t height, _In_ size_t depth, _Inout_ size_t& mipLevels ); + +//------------------------------------------------------------------------------------- +// Determines number of image array entries and pixel size +//------------------------------------------------------------------------------------- +void _DetermineImageArray( const TexMetadata& metadata, DWORD cpFlags, + size_t& nImages, size_t& pixelSize ) +{ + assert( metadata.width > 0 && metadata.height > 0 && metadata.depth > 0 ); + assert( metadata.arraySize > 0 ); + assert( metadata.mipLevels > 0 ); + + size_t _pixelSize = 0; + size_t _nimages = 0; + + switch( metadata.dimension ) + { + case TEX_DIMENSION_TEXTURE1D: + case TEX_DIMENSION_TEXTURE2D: + for( size_t item = 0; item < metadata.arraySize; ++item ) + { + size_t w = metadata.width; + size_t h = metadata.height; + + for( size_t level=0; level < metadata.mipLevels; ++level ) + { + size_t rowPitch, slicePitch; + ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags ); + + _pixelSize += slicePitch; + ++_nimages; + + if ( h > 1 ) + h >>= 1; + + if ( w > 1 ) + w >>= 1; + } + } + break; + + case TEX_DIMENSION_TEXTURE3D: + { + size_t w = metadata.width; + size_t h = metadata.height; + size_t d = metadata.depth; + + for( size_t level=0; level < metadata.mipLevels; ++level ) + { + size_t rowPitch, slicePitch; + ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags ); + + for( size_t slice=0; slice < d; ++slice ) + { + _pixelSize += slicePitch; + ++_nimages; + } + + if ( h > 1 ) + h >>= 1; + + if ( w > 1 ) + w >>= 1; + + if ( d > 1 ) + d >>= 1; + } + } + break; + + default: + assert( false ); + break; + } + + nImages = _nimages; + pixelSize = _pixelSize; +} + + +//------------------------------------------------------------------------------------- +// Fills in the image array entries +//------------------------------------------------------------------------------------- +bool _SetupImageArray( uint8_t *pMemory, size_t pixelSize, + const TexMetadata& metadata, DWORD cpFlags, + Image* images, size_t nImages ) +{ + assert( pMemory ); + assert( pixelSize > 0 ); + assert( nImages > 0 ); + + if ( !images ) + return false; + + size_t index = 0; + uint8_t* pixels = pMemory; + const uint8_t* pEndBits = pMemory + pixelSize; + + switch( metadata.dimension ) + { + case TEX_DIMENSION_TEXTURE1D: + case TEX_DIMENSION_TEXTURE2D: + if (metadata.arraySize == 0 || metadata.mipLevels == 0) + { + return false; + } + + for( size_t item = 0; item < metadata.arraySize; ++item ) + { + size_t w = metadata.width; + size_t h = metadata.height; + + for( size_t level=0; level < metadata.mipLevels; ++level ) + { + if ( index >= nImages ) + { + return false; + } + + size_t rowPitch, slicePitch; + ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags ); + + images[index].width = w; + images[index].height = h; + images[index].format = metadata.format; + images[index].rowPitch = rowPitch; + images[index].slicePitch = slicePitch; + images[index].pixels = pixels; + ++index; + + pixels += slicePitch; + if ( pixels > pEndBits ) + { + return false; + } + + if ( h > 1 ) + h >>= 1; + + if ( w > 1 ) + w >>= 1; + } + } + return true; + + case TEX_DIMENSION_TEXTURE3D: + { + if (metadata.mipLevels == 0 || metadata.depth == 0) + { + return false; + } + + size_t w = metadata.width; + size_t h = metadata.height; + size_t d = metadata.depth; + + for( size_t level=0; level < metadata.mipLevels; ++level ) + { + size_t rowPitch, slicePitch; + ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags ); + + for( size_t slice=0; slice < d; ++slice ) + { + if ( index >= nImages ) + { + return false; + } + + // We use the same memory organization that Direct3D 11 needs for D3D11_SUBRESOURCE_DATA + // with all slices of a given miplevel being continuous in memory + images[index].width = w; + images[index].height = h; + images[index].format = metadata.format; + images[index].rowPitch = rowPitch; + images[index].slicePitch = slicePitch; + images[index].pixels = pixels; + ++index; + + pixels += slicePitch; + if ( pixels > pEndBits ) + { + return false; + } + } + + if ( h > 1 ) + h >>= 1; + + if ( w > 1 ) + w >>= 1; + + if ( d > 1 ) + d >>= 1; + } + } + return true; + + default: + return false; + } +} + + +//===================================================================================== +// ScratchImage - Bitmap image container +//===================================================================================== + +//------------------------------------------------------------------------------------- +// Methods +//------------------------------------------------------------------------------------- +HRESULT ScratchImage::Initialize( const TexMetadata& mdata ) +{ + if ( !IsValid(mdata.format) || IsVideo(mdata.format) ) + return E_INVALIDARG; + + size_t mipLevels = mdata.mipLevels; + + switch( mdata.dimension ) + { + case TEX_DIMENSION_TEXTURE1D: + if ( !mdata.width || mdata.height != 1 || mdata.depth != 1 || !mdata.arraySize ) + return E_INVALIDARG; + + if ( !_CalculateMipLevels(mdata.width,1,mipLevels) ) + return E_INVALIDARG; + break; + + case TEX_DIMENSION_TEXTURE2D: + if ( !mdata.width || !mdata.height || mdata.depth != 1 || !mdata.arraySize ) + return E_INVALIDARG; + + if ( mdata.miscFlags & TEX_MISC_TEXTURECUBE ) + { + if ( (mdata.arraySize % 6) != 0 ) + return E_INVALIDARG; + } + + if ( !_CalculateMipLevels(mdata.width,mdata.height,mipLevels) ) + return E_INVALIDARG; + break; + + case TEX_DIMENSION_TEXTURE3D: + if ( !mdata.width || !mdata.height || !mdata.depth || mdata.arraySize != 1 ) + return E_INVALIDARG; + + if ( !_CalculateMipLevels3D(mdata.width,mdata.height,mdata.depth,mipLevels) ) + return E_INVALIDARG; + break; + + default: + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + } + + Release(); + + _metadata.width = mdata.width; + _metadata.height = mdata.height; + _metadata.depth = mdata.depth; + _metadata.arraySize = mdata.arraySize; + _metadata.mipLevels = mipLevels; + _metadata.miscFlags = mdata.miscFlags & TEX_MISC_TEXTURECUBE; + _metadata.format = mdata.format; + _metadata.dimension = mdata.dimension; + + size_t pixelSize, nimages; + _DetermineImageArray( _metadata, CP_FLAGS_NONE, nimages, pixelSize ); + + _image = new Image[ nimages ]; + if ( !_image ) + return E_OUTOFMEMORY; + + _nimages = nimages; + memset( _image, 0, sizeof(Image) * nimages ); + + _memory = reinterpret_cast( _aligned_malloc( pixelSize, 16 ) ); + if ( !_memory ) + { + Release(); + return E_OUTOFMEMORY; + } + _size = pixelSize; + if ( !_SetupImageArray( _memory, pixelSize, _metadata, CP_FLAGS_NONE, _image, nimages ) ) + { + Release(); + return E_FAIL; + } + + return S_OK; +} + +HRESULT ScratchImage::Initialize1D( DXGI_FORMAT fmt, size_t length, size_t arraySize, size_t mipLevels ) +{ + if ( !IsValid(fmt) || IsVideo(fmt) || !length || !arraySize ) + return E_INVALIDARG; + + // 1D is a special case of the 2D case + HRESULT hr = Initialize2D( fmt, length, 1, arraySize, mipLevels ); + if ( FAILED(hr) ) + return hr; + + _metadata.dimension = TEX_DIMENSION_TEXTURE1D; + + return S_OK; +} + +HRESULT ScratchImage::Initialize2D( DXGI_FORMAT fmt, size_t width, size_t height, size_t arraySize, size_t mipLevels ) +{ + if ( !IsValid(fmt) || IsVideo(fmt) || !width || !height || !arraySize ) + return E_INVALIDARG; + + if ( !_CalculateMipLevels(width,height,mipLevels) ) + return E_INVALIDARG; + + Release(); + + _metadata.width = width; + _metadata.height = height; + _metadata.depth = 1; + _metadata.arraySize = arraySize; + _metadata.mipLevels = mipLevels; + _metadata.miscFlags = 0; + _metadata.format = fmt; + _metadata.dimension = TEX_DIMENSION_TEXTURE2D; + + size_t pixelSize, nimages; + _DetermineImageArray( _metadata, CP_FLAGS_NONE, nimages, pixelSize ); + + _image = new Image[ nimages ]; + if ( !_image ) + return E_OUTOFMEMORY; + + _nimages = nimages; + memset( _image, 0, sizeof(Image) * nimages ); + + _memory = reinterpret_cast( _aligned_malloc( pixelSize, 16 ) ); + if ( !_memory ) + { + Release(); + return E_OUTOFMEMORY; + } + _size = pixelSize; + if ( !_SetupImageArray( _memory, pixelSize, _metadata, CP_FLAGS_NONE, _image, nimages ) ) + { + Release(); + return E_FAIL; + } + + return S_OK; +} + +HRESULT ScratchImage::Initialize3D( DXGI_FORMAT fmt, size_t width, size_t height, size_t depth, size_t mipLevels ) +{ + if ( !IsValid(fmt) || IsVideo(fmt) || !width || !height || !depth ) + return E_INVALIDARG; + + if ( !_CalculateMipLevels3D(width,height,depth,mipLevels) ) + return E_INVALIDARG; + + Release(); + + _metadata.width = width; + _metadata.height = height; + _metadata.depth = depth; + _metadata.arraySize = 1; // Direct3D 10.x/11 does not support arrays of 3D textures + _metadata.mipLevels = mipLevels; + _metadata.miscFlags = 0; + _metadata.format = fmt; + _metadata.dimension = TEX_DIMENSION_TEXTURE3D; + + size_t pixelSize, nimages; + _DetermineImageArray( _metadata, CP_FLAGS_NONE, nimages, pixelSize ); + + _image = new Image[ nimages ]; + if ( !_image ) + { + Release(); + return E_OUTOFMEMORY; + } + _nimages = nimages; + memset( _image, 0, sizeof(Image) * nimages ); + + _memory = reinterpret_cast( _aligned_malloc( pixelSize, 16 ) ); + if ( !_memory ) + { + Release(); + return E_OUTOFMEMORY; + } + _size = pixelSize; + + if ( !_SetupImageArray( _memory, pixelSize, _metadata, CP_FLAGS_NONE, _image, nimages ) ) + { + Release(); + return E_FAIL; + } + + return S_OK; +} + +HRESULT ScratchImage::InitializeCube( DXGI_FORMAT fmt, size_t width, size_t height, size_t nCubes, size_t mipLevels ) +{ + if ( !IsValid(fmt) || IsVideo(fmt) || !width || !height || !nCubes ) + return E_INVALIDARG; + + // A DirectX11 cubemap is just a 2D texture array that is a multiple of 6 for each cube + HRESULT hr = Initialize2D( fmt, width, height, nCubes * 6, mipLevels ); + if ( FAILED(hr) ) + return hr; + + _metadata.miscFlags |= TEX_MISC_TEXTURECUBE; + + return S_OK; +} + +HRESULT ScratchImage::InitializeFromImage( const Image& srcImage, bool allow1D ) +{ + HRESULT hr = ( srcImage.height > 1 || !allow1D ) + ? Initialize2D( srcImage.format, srcImage.width, srcImage.height, 1, 1 ) + : Initialize1D( srcImage.format, srcImage.width, 1, 1 ); + + if ( FAILED(hr) ) + return hr; + + const uint8_t* sptr = reinterpret_cast( srcImage.pixels ); + if ( !sptr ) + return E_POINTER; + + uint8_t* dptr = reinterpret_cast( _image[0].pixels ); + if ( !dptr ) + return E_POINTER; + + for( size_t y = 0; y < srcImage.height; ++y ) + { + _CopyScanline( dptr, _image[0].rowPitch, sptr, srcImage.rowPitch, srcImage.format, TEXP_SCANLINE_NONE ); + sptr += srcImage.rowPitch; + dptr += _image[0].rowPitch; + } + + return S_OK; +} + +HRESULT ScratchImage::InitializeArrayFromImages( const Image* images, size_t nImages, bool allow1D ) +{ + if ( !images || !nImages ) + return E_INVALIDARG; + + DXGI_FORMAT format = images[0].format; + size_t width = images[0].width; + size_t height = images[0].height; + + for( size_t index=0; index < nImages; ++index ) + { + if ( !images[index].pixels ) + return E_POINTER; + + if ( images[index].format != format || images[index].width != width || images[index].height != height ) + { + // All images must be the same format, width, and height + return E_FAIL; + } + } + + HRESULT hr = ( height > 1 || !allow1D ) + ? Initialize2D( format, width, height, nImages, 1 ) + : Initialize1D( format, width, nImages, 1 ); + + if ( FAILED(hr) ) + return hr; + + for( size_t index=0; index < nImages; ++index ) + { + const uint8_t* sptr = reinterpret_cast( images[index].pixels ); + if ( !sptr ) + return E_POINTER; + + assert( index < _nimages ); + uint8_t* dptr = reinterpret_cast( _image[index].pixels ); + if ( !dptr ) + return E_POINTER; + + for( size_t y = 0; y < height; ++y ) + { + _CopyScanline( dptr, _image[index].rowPitch, sptr, images[index].rowPitch, format, TEXP_SCANLINE_NONE ); + sptr += images[index].rowPitch; + dptr += _image[index].rowPitch; + } + } + + return S_OK; +} + +HRESULT ScratchImage::InitializeCubeFromImages( const Image* images, size_t nImages ) +{ + if ( !images || !nImages ) + return E_INVALIDARG; + + // A DirectX11 cubemap is just a 2D texture array that is a multiple of 6 for each cube + if ( ( nImages % 6 ) != 0 ) + return E_INVALIDARG; + + HRESULT hr = InitializeArrayFromImages( images, nImages, false ); + if ( FAILED(hr) ) + return hr; + + _metadata.miscFlags |= TEX_MISC_TEXTURECUBE; + + return S_OK; +} + +HRESULT ScratchImage::Initialize3DFromImages( const Image* images, size_t depth ) +{ + if ( !images || !depth ) + return E_INVALIDARG; + + DXGI_FORMAT format = images[0].format; + size_t width = images[0].width; + size_t height = images[0].height; + + for( size_t slice=0; slice < depth; ++slice ) + { + if ( !images[slice].pixels ) + return E_POINTER; + + if ( images[slice].format != format || images[slice].width != width || images[slice].height != height ) + { + // All images must be the same format, width, and height + return E_FAIL; + } + } + + HRESULT hr = Initialize3D( format, width, height, depth, 1 ); + if ( FAILED(hr) ) + return hr; + + for( size_t slice=0; slice < depth; ++slice ) + { + const uint8_t* sptr = reinterpret_cast( images[slice].pixels ); + if ( !sptr ) + return E_POINTER; + + assert( slice < _nimages ); + uint8_t* dptr = reinterpret_cast( _image[slice].pixels ); + if ( !dptr ) + return E_POINTER; + + for( size_t y = 0; y < height; ++y ) + { + _CopyScanline( dptr, _image[slice].rowPitch, sptr, images[slice].rowPitch, format, TEXP_SCANLINE_NONE ); + sptr += images[slice].rowPitch; + dptr += _image[slice].rowPitch; + } + } + + return S_OK; +} + +void ScratchImage::Release() +{ + _nimages = 0; + _size = 0; + + if ( _image ) + { + delete [] _image; + _image = 0; + } + + if ( _memory ) + { + _aligned_free( _memory ); + _memory = 0; + } + + memset(&_metadata, 0, sizeof(_metadata)); +} + +bool ScratchImage::OverrideFormat( DXGI_FORMAT f ) +{ + if ( !_image ) + return false; + + if ( !IsValid( f ) || IsVideo( f ) ) + return false; + + if ( ( BitsPerPixel( f ) != BitsPerPixel( _metadata.format ) ) + || ( IsCompressed( f ) != IsCompressed( _metadata.format ) ) + || ( IsPacked( f ) != IsPacked( _metadata.format ) ) ) + { + // Can't change the effective pitch of the format this way + return false; + } + + for( size_t index = 0; index < _nimages; ++index ) + { + _image[ index ].format = f; + } + + _metadata.format = f; + + return true; +} + +const Image* ScratchImage::GetImage(size_t mip, size_t item, size_t slice) const +{ + if ( mip >= _metadata.mipLevels ) + return nullptr; + + size_t index = 0; + + switch( _metadata.dimension ) + { + case TEX_DIMENSION_TEXTURE1D: + case TEX_DIMENSION_TEXTURE2D: + if ( slice > 0 ) + return nullptr; + + if ( item >= _metadata.arraySize ) + return nullptr; + + index = item*( _metadata.mipLevels ) + mip; + break; + + case TEX_DIMENSION_TEXTURE3D: + if ( item > 0 ) + { + // No support for arrays of volumes + return nullptr; + } + else + { + size_t d = _metadata.depth; + + for( size_t level = 0; level < mip; ++level ) + { + index += d; + if ( d > 1 ) + d >>= 1; + } + + if ( slice >= d ) + return nullptr; + + index += slice; + } + break; + + default: + return nullptr; + } + + return &_image[index]; +} + +}; // namespace