1
0
mirror of https://github.com/microsoft/DirectXTex synced 2024-11-21 12:00:06 +00:00

Add CompressEx and ConvertEx methods that report progress (#375)

This commit is contained in:
Nicholas Hayes 2023-08-18 15:43:30 -06:00 committed by GitHub
parent 7e7b11db04
commit 1d1d4d0134
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 437 additions and 50 deletions

View File

@ -664,12 +664,26 @@ namespace DirectX
constexpr float TEX_THRESHOLD_DEFAULT = 0.5f;
// Default value for alpha threshold used when converting to 1-bit alpha
struct ConvertOptions
{
TEX_FILTER_FLAGS filter;
float threshold;
};
HRESULT __cdecl Convert(
_In_ const Image& srcImage, _In_ DXGI_FORMAT format, _In_ TEX_FILTER_FLAGS filter, _In_ float threshold,
_Out_ ScratchImage& image) noexcept;
HRESULT __cdecl Convert(
_In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,
_In_ DXGI_FORMAT format, _In_ TEX_FILTER_FLAGS filter, _In_ float threshold, _Out_ ScratchImage& result) noexcept;
HRESULT __cdecl ConvertEx(
_In_ const Image& srcImage, _In_ DXGI_FORMAT format, _In_ const ConvertOptions& options,
_Out_ ScratchImage& image, _In_opt_ std::function<bool __cdecl(size_t, size_t)> statusCallBack = nullptr);
HRESULT __cdecl ConvertEx(
_In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,
_In_ DXGI_FORMAT format, _In_ const ConvertOptions& options, _Out_ ScratchImage& result,
_In_opt_ std::function<bool __cdecl(size_t, size_t)> statusCallBack = nullptr);
// Convert the image to a new format
HRESULT __cdecl ConvertToSinglePlane(_In_ const Image& srcImage, _Out_ ScratchImage& image) noexcept;
@ -756,6 +770,16 @@ namespace DirectX
// Compress is free to use multithreading to improve performance (by default it does not use multithreading)
};
constexpr float TEX_ALPHA_WEIGHT_DEFAULT = 1.0f;
// Default value for alpha weight used for GPU BC7 compression
struct CompressOptions
{
TEX_COMPRESS_FLAGS flags;
float threshold;
float alphaWeight;
};
HRESULT __cdecl Compress(
_In_ const Image& srcImage, _In_ DXGI_FORMAT format, _In_ TEX_COMPRESS_FLAGS compress, _In_ float threshold,
_Out_ ScratchImage& cImage) noexcept;
@ -764,6 +788,14 @@ namespace DirectX
_In_ DXGI_FORMAT format, _In_ TEX_COMPRESS_FLAGS compress, _In_ float threshold, _Out_ ScratchImage& cImages) noexcept;
// Note that threshold is only used by BC1. TEX_THRESHOLD_DEFAULT is a typical value to use
HRESULT __cdecl CompressEx(
_In_ const Image& srcImage, _In_ DXGI_FORMAT format, _In_ const CompressOptions& options,
_Out_ ScratchImage& cImage, _In_opt_ std::function<bool __cdecl(size_t, size_t)> statusCallBack = nullptr);
HRESULT __cdecl CompressEx(
_In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,
_In_ DXGI_FORMAT format, _In_ const CompressOptions& options, _Out_ ScratchImage& cImages,
_In_opt_ std::function<bool __cdecl(size_t, size_t)> statusCallBack = nullptr);
#if defined(__d3d11_h__) || defined(__d3d11_x_h__)
HRESULT __cdecl Compress(
_In_ ID3D11Device* pDevice, _In_ const Image& srcImage, _In_ DXGI_FORMAT format, _In_ TEX_COMPRESS_FLAGS compress,
@ -772,6 +804,14 @@ namespace DirectX
_In_ ID3D11Device* pDevice, _In_ const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,
_In_ DXGI_FORMAT format, _In_ TEX_COMPRESS_FLAGS compress, _In_ float alphaWeight, _Out_ ScratchImage& cImages) noexcept;
// DirectCompute-based compression (alphaWeight is only used by BC7. 1.0 is the typical value to use)
HRESULT __cdecl CompressEx(
_In_ ID3D11Device* pDevice, _In_ const Image& srcImage, _In_ DXGI_FORMAT format, _In_ const CompressOptions& options,
_Out_ ScratchImage& image, _In_opt_ std::function<bool __cdecl(size_t, size_t)> statusCallBack = nullptr);
HRESULT __cdecl CompressEx(
_In_ ID3D11Device* pDevice, _In_ const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,
_In_ DXGI_FORMAT format, _In_ const CompressOptions& options, _Out_ ScratchImage& cImages,
_In_opt_ std::function<bool __cdecl(size_t, size_t)> statusCallBack = nullptr);
#endif
HRESULT __cdecl Decompress(_In_ const Image& cImage, _In_ DXGI_FORMAT format, _Out_ ScratchImage& image) noexcept;

View File

@ -74,7 +74,8 @@ namespace
const Image& result,
uint32_t bcflags,
TEX_FILTER_FLAGS srgb,
float threshold) noexcept
float threshold,
const std::function<bool __cdecl(size_t, size_t)>& statusCallback) noexcept
{
if (!image.pixels || !result.pixels)
return E_POINTER;
@ -111,6 +112,14 @@ namespace
const size_t rowPitch = image.rowPitch;
for (size_t h = 0; h < image.height; h += 4)
{
if (statusCallback)
{
if (!statusCallback(h, image.height))
{
return E_ABORT;
}
}
const uint8_t *sptr = pSrc;
uint8_t* dptr = pDest;
const size_t ph = std::min<size_t>(4, image.height - h);
@ -203,7 +212,8 @@ namespace
const Image& result,
uint32_t bcflags,
TEX_FILTER_FLAGS srgb,
float threshold) noexcept
float threshold,
const std::function<bool __cdecl(size_t, size_t)>& statusCallback) noexcept
{
if (!image.pixels || !result.pixels)
return E_POINTER;
@ -239,9 +249,22 @@ namespace
bool fail = false;
#pragma omp parallel for
size_t progress = 0;
bool abort = false;
const size_t progressTotal = std::max<size_t>(1, (image.height + 3) / 4);
#pragma omp parallel for shared(progress)
for (int nb = 0; nb < static_cast<int>(nBlocks); ++nb)
{
#pragma omp flush (abort)
if (abort)
{
// Short circuit the loop body if an abort is requested.
// OpenMP 2.0 does not support cancellation of a 'parallel for' loop.
continue;
}
const int nbWidth = std::max<int>(1, int((image.width + 3) / 4));
int y = nb / nbWidth;
@ -323,9 +346,29 @@ namespace
pfEncode(pDest, temp, bcflags);
else
D3DXEncodeBC1(pDest, temp, threshold, bcflags);
// Report progress when a new row is reached.
if (x == 0 && statusCallback)
{
#pragma omp atomic
progress += 4;
if (!statusCallback(progress, progressTotal))
{
abort = true;
#pragma omp flush (abort)
}
}
}
return (fail) ? E_FAIL : S_OK;
if (abort)
{
return E_ABORT;
}
else
{
return (fail) ? E_FAIL : S_OK;
}
}
#endif // _OPENMP
@ -592,6 +635,38 @@ HRESULT DirectX::Compress(
TEX_COMPRESS_FLAGS compress,
float threshold,
ScratchImage& image) noexcept
{
CompressOptions options = {};
options.flags = compress;
options.threshold = threshold;
return CompressEx(srcImage, format, options, image, nullptr);
}
_Use_decl_annotations_
HRESULT DirectX::Compress(
const Image* srcImages,
size_t nimages,
const TexMetadata& metadata,
DXGI_FORMAT format,
TEX_COMPRESS_FLAGS compress,
float threshold,
ScratchImage& cImages) noexcept
{
CompressOptions options = {};
options.flags = compress;
options.threshold = threshold;
return CompressEx(srcImages, nimages, metadata, format, options, cImages, nullptr);
}
_Use_decl_annotations_
HRESULT DirectX::CompressEx(
const Image& srcImage,
DXGI_FORMAT format,
const CompressOptions& options,
ScratchImage& image,
std::function<bool __cdecl(size_t, size_t)> statusCallback)
{
if (IsCompressed(srcImage.format) || !IsCompressed(format))
return E_INVALIDARG;
@ -612,35 +687,56 @@ HRESULT DirectX::Compress(
return E_POINTER;
}
if (statusCallback)
{
if (!statusCallback(0, img->height))
{
image.Release();
return E_ABORT;
}
}
// Compress single image
if (compress & TEX_COMPRESS_PARALLEL)
if (options.flags & TEX_COMPRESS_PARALLEL)
{
#ifndef _OPENMP
return E_NOTIMPL;
hr = E_NOTIMPL;
#else
hr = CompressBC_Parallel(srcImage, *img, GetBCFlags(compress), GetSRGBFlags(compress), threshold);
hr = CompressBC_Parallel(srcImage, *img, GetBCFlags(options.flags), GetSRGBFlags(options.flags), options.threshold, statusCallback);
#endif // _OPENMP
}
else
{
hr = CompressBC(srcImage, *img, GetBCFlags(compress), GetSRGBFlags(compress), threshold);
hr = CompressBC(srcImage, *img, GetBCFlags(options.flags), GetSRGBFlags(options.flags), options.threshold, statusCallback);
}
if (FAILED(hr))
{
image.Release();
return hr;
}
return hr;
if (statusCallback)
{
if (!statusCallback(img->height, img->height))
{
image.Release();
return E_ABORT;
}
}
return S_OK;
}
_Use_decl_annotations_
HRESULT DirectX::Compress(
HRESULT DirectX::CompressEx(
const Image* srcImages,
size_t nimages,
const TexMetadata& metadata,
DXGI_FORMAT format,
TEX_COMPRESS_FLAGS compress,
float threshold,
ScratchImage& cImages) noexcept
const CompressOptions& options,
ScratchImage& cImages,
std::function<bool __cdecl(size_t, size_t)> statusCallback)
{
if (!srcImages || !nimages)
return E_INVALIDARG;
@ -654,6 +750,19 @@ HRESULT DirectX::Compress(
cImages.Release();
if (statusCallback
&& nimages == 1
&& !metadata.IsVolumemap()
&& metadata.mipLevels == 1
&& metadata.arraySize == 1)
{
// If progress reporting is requested when compressing a single 1D or 2D image, call
// the CompressEx overload that takes a single image.
// This provides a better user experience as progress will be reported as the image
// is being processed, instead of after processing has been completed.
return CompressEx(srcImages[0], format, options, cImages, statusCallback);
}
TexMetadata mdata2 = metadata;
mdata2.format = format;
HRESULT hr = cImages.Initialize(mdata2);
@ -673,6 +782,15 @@ HRESULT DirectX::Compress(
return E_POINTER;
}
if (statusCallback)
{
if (!statusCallback(0, nimages))
{
cImages.Release();
return E_ABORT;
}
}
for (size_t index = 0; index < nimages; ++index)
{
assert(dest[index].format == format);
@ -685,33 +803,44 @@ HRESULT DirectX::Compress(
return E_FAIL;
}
if ((compress & TEX_COMPRESS_PARALLEL))
if (options.flags & TEX_COMPRESS_PARALLEL)
{
#ifndef _OPENMP
return E_NOTIMPL;
hr = E_NOTIMPL;
#else
if (compress & TEX_COMPRESS_PARALLEL)
{
hr = CompressBC_Parallel(src, dest[index], GetBCFlags(compress), GetSRGBFlags(compress), threshold);
if (FAILED(hr))
{
cImages.Release();
return hr;
}
}
hr = CompressBC_Parallel(src, dest[index], GetBCFlags(options.flags), GetSRGBFlags(options.flags), options.threshold, nullptr);
#endif // _OPENMP
}
else
{
hr = CompressBC(src, dest[index], GetBCFlags(compress), GetSRGBFlags(compress), threshold);
if (FAILED(hr))
hr = CompressBC(src, dest[index], GetBCFlags(options.flags), GetSRGBFlags(options.flags), options.threshold, nullptr);
}
if (FAILED(hr))
{
cImages.Release();
return hr;
}
if (statusCallback)
{
if (!statusCallback(index, nimages))
{
cImages.Release();
return hr;
return E_ABORT;
}
}
}
if (statusCallback)
{
if (!statusCallback(nimages, nimages))
{
cImages.Release();
return E_ABORT;
}
}
return S_OK;
}

View File

@ -219,6 +219,40 @@ HRESULT DirectX::Compress(
TEX_COMPRESS_FLAGS compress,
float alphaWeight,
ScratchImage& image) noexcept
{
CompressOptions options = {};
options.flags = compress;
options.alphaWeight = alphaWeight;
return CompressEx(pDevice, srcImage, format, options, image, nullptr);
}
_Use_decl_annotations_
HRESULT DirectX::Compress(
ID3D11Device* pDevice,
const Image* srcImages,
size_t nimages,
const TexMetadata& metadata,
DXGI_FORMAT format,
TEX_COMPRESS_FLAGS compress,
float alphaWeight,
ScratchImage& cImages) noexcept
{
CompressOptions options = {};
options.flags = compress;
options.alphaWeight = alphaWeight;
return CompressEx(pDevice, srcImages, nimages, metadata, format, options, cImages);
}
_Use_decl_annotations_
HRESULT DirectX::CompressEx(
ID3D11Device* pDevice,
const Image& srcImage,
DXGI_FORMAT format,
const CompressOptions& options,
ScratchImage& image,
std::function<bool __cdecl(size_t, size_t)> statusCallback)
{
if (!pDevice || IsCompressed(srcImage.format) || !IsCompressed(format))
return E_INVALIDARG;
@ -236,7 +270,7 @@ HRESULT DirectX::Compress(
if (FAILED(hr))
return hr;
hr = gpubc->Prepare(srcImage.width, srcImage.height, compress, format, alphaWeight);
hr = gpubc->Prepare(srcImage.width, srcImage.height, options.flags, format, options.alphaWeight);
if (FAILED(hr))
return hr;
@ -252,23 +286,45 @@ HRESULT DirectX::Compress(
return E_POINTER;
}
hr = GPUCompress(gpubc.get(), srcImage, *img, compress);
if (FAILED(hr))
image.Release();
if (statusCallback)
{
if (!statusCallback(0, 100))
{
image.Release();
return E_ABORT;
}
}
return hr;
hr = GPUCompress(gpubc.get(), srcImage, *img, options.flags);
if (FAILED(hr))
{
image.Release();
return hr;
}
if (statusCallback)
{
if (!statusCallback(100, 100))
{
image.Release();
return E_ABORT;
}
}
return S_OK;
}
_Use_decl_annotations_
HRESULT DirectX::Compress(
HRESULT DirectX::CompressEx(
ID3D11Device* pDevice,
const Image* srcImages,
size_t nimages,
const TexMetadata& metadata,
DXGI_FORMAT format,
TEX_COMPRESS_FLAGS compress,
float alphaWeight,
ScratchImage& cImages) noexcept
const CompressOptions& options,
ScratchImage& cImages,
std::function<bool __cdecl(size_t, size_t)> statusCallback)
{
if (!pDevice || !srcImages || !nimages)
return E_INVALIDARG;
@ -311,6 +367,15 @@ HRESULT DirectX::Compress(
return E_POINTER;
}
if (statusCallback)
{
if (!statusCallback(0, nimages))
{
cImages.Release();
return E_ABORT;
}
}
// Process images (ordered by size)
switch (metadata.dimension)
{
@ -319,10 +384,11 @@ HRESULT DirectX::Compress(
{
size_t w = metadata.width;
size_t h = metadata.height;
size_t progress = 0;
for (size_t level = 0; level < metadata.mipLevels; ++level)
{
hr = gpubc->Prepare(w, h, compress, format, alphaWeight);
hr = gpubc->Prepare(w, h, options.flags, format, options.alphaWeight);
if (FAILED(hr))
{
cImages.Release();
@ -348,12 +414,21 @@ HRESULT DirectX::Compress(
return E_FAIL;
}
hr = GPUCompress(gpubc.get(), src, dest[index], compress);
hr = GPUCompress(gpubc.get(), src, dest[index], options.flags);
if (FAILED(hr))
{
cImages.Release();
return hr;
}
if (statusCallback)
{
if (!statusCallback(progress++, nimages))
{
cImages.Release();
return E_ABORT;
}
}
}
if (h > 1)
@ -370,10 +445,11 @@ HRESULT DirectX::Compress(
size_t w = metadata.width;
size_t h = metadata.height;
size_t d = metadata.depth;
size_t progress = 0;
for (size_t level = 0; level < metadata.mipLevels; ++level)
{
hr = gpubc->Prepare(w, h, compress, format, alphaWeight);
hr = gpubc->Prepare(w, h, options.flags, format, options.alphaWeight);
if (FAILED(hr))
{
cImages.Release();
@ -399,12 +475,21 @@ HRESULT DirectX::Compress(
return E_FAIL;
}
hr = GPUCompress(gpubc.get(), src, dest[index], compress);
hr = GPUCompress(gpubc.get(), src, dest[index], options.flags);
if (FAILED(hr))
{
cImages.Release();
return hr;
}
if (statusCallback)
{
if (!statusCallback(progress++, nimages))
{
cImages.Release();
return E_ABORT;
}
}
}
if (h > 1)
@ -423,5 +508,14 @@ HRESULT DirectX::Compress(
return HRESULT_E_NOT_SUPPORTED;
}
if (statusCallback)
{
if (!statusCallback(nimages, nimages))
{
cImages.Release();
return E_ABORT;
}
}
return S_OK;
}

View File

@ -4798,7 +4798,8 @@ namespace
_In_ TEX_FILTER_FLAGS filter,
_In_ const Image& destImage,
_In_ float threshold,
size_t z) noexcept
size_t z,
const std::function<bool __cdecl(size_t, size_t)>& statusCallback) noexcept
{
assert(srcImage.width == destImage.width);
assert(srcImage.height == destImage.height);
@ -4822,6 +4823,14 @@ namespace
for (size_t h = 0; h < srcImage.height; ++h)
{
if (statusCallback)
{
if (!statusCallback(h, srcImage.height))
{
return E_ABORT;
}
}
if (!LoadScanline(scanline.get(), width, pSrc, srcImage.rowPitch, srcImage.format))
return E_FAIL;
@ -4845,6 +4854,14 @@ namespace
// Ordered dithering
for (size_t h = 0; h < srcImage.height; ++h)
{
if (statusCallback)
{
if (!statusCallback(h, srcImage.height))
{
return E_ABORT;
}
}
if (!LoadScanline(scanline.get(), width, pSrc, srcImage.rowPitch, srcImage.format))
return E_FAIL;
@ -4862,6 +4879,14 @@ namespace
// No dithering
for (size_t h = 0; h < srcImage.height; ++h)
{
if (statusCallback)
{
if (!statusCallback(h, srcImage.height))
{
return E_ABORT;
}
}
if (!LoadScanline(scanline.get(), width, pSrc, srcImage.rowPitch, srcImage.format))
return E_FAIL;
@ -5061,6 +5086,21 @@ HRESULT DirectX::Convert(
TEX_FILTER_FLAGS filter,
float threshold,
ScratchImage& image) noexcept
{
ConvertOptions options = {};
options.filter = filter;
options.threshold = threshold;
return ConvertEx(srcImage, format, options, image, nullptr);
}
_Use_decl_annotations_
HRESULT DirectX::ConvertEx(
const Image& srcImage,
DXGI_FORMAT format,
const ConvertOptions& options,
ScratchImage& image,
std::function<bool __cdecl(size_t, size_t)> statusCallback)
{
if ((srcImage.format == format) || !IsValid(format))
return E_INVALIDARG;
@ -5088,14 +5128,23 @@ HRESULT DirectX::Convert(
return E_POINTER;
}
WICPixelFormatGUID pfGUID, targetGUID;
if (UseWICConversion(filter, srcImage.format, format, pfGUID, targetGUID))
if (statusCallback)
{
hr = ConvertUsingWIC(srcImage, pfGUID, targetGUID, filter, threshold, *rimage);
if (!statusCallback(0, rimage->height))
{
image.Release();
return E_ABORT;
}
}
WICPixelFormatGUID pfGUID, targetGUID;
if (UseWICConversion(options.filter, srcImage.format, format, pfGUID, targetGUID))
{
hr = ConvertUsingWIC(srcImage, pfGUID, targetGUID, options.filter, options.threshold, *rimage);
}
else
{
hr = ConvertCustom(srcImage, filter, *rimage, threshold, 0);
hr = ConvertCustom(srcImage, options.filter, *rimage, options.threshold, 0, statusCallback);
}
if (FAILED(hr))
@ -5104,6 +5153,15 @@ HRESULT DirectX::Convert(
return hr;
}
if (statusCallback)
{
if (!statusCallback(rimage->height, rimage->height))
{
image.Release();
return E_ABORT;
}
}
return S_OK;
}
@ -5120,6 +5178,23 @@ HRESULT DirectX::Convert(
TEX_FILTER_FLAGS filter,
float threshold,
ScratchImage& result) noexcept
{
ConvertOptions options = {};
options.filter = filter;
options.threshold = threshold;
return ConvertEx(srcImages, nimages, metadata, format, options, result, nullptr);
}
_Use_decl_annotations_
HRESULT DirectX::ConvertEx(
const Image* srcImages,
size_t nimages,
const TexMetadata& metadata,
DXGI_FORMAT format,
const ConvertOptions& options,
ScratchImage& result,
std::function<bool __cdecl(size_t, size_t)> statusCallback)
{
if (!srcImages || !nimages || (metadata.format == format) || !IsValid(format))
return E_INVALIDARG;
@ -5133,6 +5208,19 @@ HRESULT DirectX::Convert(
if ((metadata.width > UINT32_MAX) || (metadata.height > UINT32_MAX))
return E_INVALIDARG;
if (statusCallback
&& nimages == 1
&& !metadata.IsVolumemap()
&& metadata.mipLevels == 1
&& metadata.arraySize == 1)
{
// If progress reporting is requested when converting a single 1D or 2D image, call
// the ConvertEx overload that takes a single image.
// This provides a better user experience as progress will be reported as the image
// is being processed, instead of after processing has been completed.
return ConvertEx(srcImages[0], format, options, result, statusCallback);
}
TexMetadata mdata2 = metadata;
mdata2.format = format;
HRESULT hr = result.Initialize(mdata2);
@ -5152,8 +5240,17 @@ HRESULT DirectX::Convert(
return E_POINTER;
}
if (statusCallback)
{
if (!statusCallback(0, nimages))
{
result.Release();
return E_ABORT;
}
}
WICPixelFormatGUID pfGUID, targetGUID;
const bool usewic = !metadata.IsPMAlpha() && UseWICConversion(filter, metadata.format, format, pfGUID, targetGUID);
const bool usewic = !metadata.IsPMAlpha() && UseWICConversion(options.filter, metadata.format, format, pfGUID, targetGUID);
switch (metadata.dimension)
{
@ -5185,11 +5282,11 @@ HRESULT DirectX::Convert(
if (usewic)
{
hr = ConvertUsingWIC(src, pfGUID, targetGUID, filter, threshold, dst);
hr = ConvertUsingWIC(src, pfGUID, targetGUID, options.filter, options.threshold, dst);
}
else
{
hr = ConvertCustom(src, filter, dst, threshold, 0);
hr = ConvertCustom(src, options.filter, dst, options.threshold, 0, nullptr);
}
if (FAILED(hr))
@ -5197,6 +5294,15 @@ HRESULT DirectX::Convert(
result.Release();
return hr;
}
if (statusCallback)
{
if (!statusCallback(index, nimages))
{
result.Release();
return E_ABORT;
}
}
}
break;
@ -5238,11 +5344,11 @@ HRESULT DirectX::Convert(
if (usewic)
{
hr = ConvertUsingWIC(src, pfGUID, targetGUID, filter, threshold, dst);
hr = ConvertUsingWIC(src, pfGUID, targetGUID, options.filter, options.threshold, dst);
}
else
{
hr = ConvertCustom(src, filter, dst, threshold, slice);
hr = ConvertCustom(src, options.filter, dst, options.threshold, slice, nullptr);
}
if (FAILED(hr))
@ -5250,6 +5356,15 @@ HRESULT DirectX::Convert(
result.Release();
return hr;
}
if (statusCallback)
{
if (!statusCallback(index, nimages))
{
result.Release();
return E_ABORT;
}
}
}
if (d > 1)
@ -5263,6 +5378,15 @@ HRESULT DirectX::Convert(
return E_FAIL;
}
if (statusCallback)
{
if (!statusCallback(nimages, nimages))
{
result.Release();
return E_ABORT;
}
}
return S_OK;
}