texconv -tonemap option

This commit is contained in:
Chuck Walbourn 2016-09-23 17:36:38 -07:00
parent 2f31eb519c
commit c5f238b6d4
3 changed files with 175 additions and 1 deletions

View File

@ -621,6 +621,8 @@ namespace DirectX
HRESULT __cdecl EvaluateImage( _In_ const Image& image,
_In_ std::function<void __cdecl(_In_reads_(width) const XMVECTOR* pixels, size_t width, size_t y)> pixelFunc );
HRESULT __cdecl EvaluateImage( _In_reads_(nimages) const Image* images, _In_ size_t nimages, _In_ const TexMetadata& metadata,
_In_ std::function<void __cdecl(_In_reads_(width) const XMVECTOR* pixels, size_t width, size_t y)> pixelFunc );
HRESULT __cdecl TransformImage( _In_ const Image& image,
_In_ std::function<void __cdecl(_Out_writes_(width) XMVECTOR* outPixels,

View File

@ -497,6 +497,99 @@ HRESULT DirectX::EvaluateImage(
}
}
_Use_decl_annotations_
HRESULT DirectX::EvaluateImage(
const Image* images,
size_t nimages,
const TexMetadata& metadata,
std::function<void __cdecl(_In_reads_(width) const XMVECTOR* pixels, size_t width, size_t y)> pixelFunc)
{
if (!images || !nimages)
return E_INVALIDARG;
if (!IsValid(metadata.format))
return E_INVALIDARG;
if (IsPlanar(metadata.format) || IsPalettized(metadata.format) || IsTypeless(metadata.format))
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
if (metadata.width > UINT32_MAX
|| metadata.height > UINT32_MAX)
return E_INVALIDARG;
if (metadata.IsVolumemap() && metadata.depth > UINT32_MAX)
return E_INVALIDARG;
ScratchImage temp;
DXGI_FORMAT format = metadata.format;
if (IsCompressed(format))
{
HRESULT hr = Decompress(images, nimages, metadata, DXGI_FORMAT_R32G32B32A32_FLOAT, temp);
if (FAILED(hr))
return hr;
if (nimages != temp.GetImageCount())
return E_UNEXPECTED;
images = temp.GetImages();
format = DXGI_FORMAT_R32G32B32A32_FLOAT;
}
switch (metadata.dimension)
{
case TEX_DIMENSION_TEXTURE1D:
case TEX_DIMENSION_TEXTURE2D:
for (size_t index = 0; index < nimages; ++index)
{
const Image& img = images[index];
if (img.format != format)
return E_FAIL;
if ((img.width > UINT32_MAX) || (img.height > UINT32_MAX))
return E_FAIL;
HRESULT hr = EvaluateImage_(img, pixelFunc);
if (FAILED(hr))
return hr;
}
break;
case TEX_DIMENSION_TEXTURE3D:
{
size_t index = 0;
size_t d = metadata.depth;
for (size_t level = 0; level < metadata.mipLevels; ++level)
{
for (size_t slice = 0; slice < d; ++slice, ++index)
{
if (index >= nimages)
return E_FAIL;
const Image& img = images[index];
if (img.format != format)
return E_FAIL;
if ((img.width > UINT32_MAX) || (img.height > UINT32_MAX))
return E_FAIL;
HRESULT hr = EvaluateImage_(img, pixelFunc);
if (FAILED(hr))
return hr;
}
if (d > 1)
d >>= 1;
}
}
break;
default:
return E_FAIL;
}
return S_OK;
}
//-------------------------------------------------------------------------------------
// Use a user-supplied function to compute a new image from an input image

View File

@ -86,6 +86,7 @@ enum OPTIONS
OPT_WIC_QUALITY,
OPT_WIC_LOSSLESS,
OPT_COLORKEY,
OPT_TONEMAP,
OPT_MAX
};
@ -153,6 +154,7 @@ SValue g_pOptions[] =
{ L"wicq", OPT_WIC_QUALITY },
{ L"wiclossless", OPT_WIC_LOSSLESS },
{ L"c", OPT_COLORKEY },
{ L"tonemap", OPT_TONEMAP },
{ nullptr, 0 }
};
@ -659,13 +661,14 @@ namespace
wprintf(L" -bcuniform Use uniform rather than perceptual weighting for BC1-3\n");
wprintf(L" -bcdither Use dithering for BC1-3\n");
wprintf(L" -bcmax Use exhaustive compression (BC7 only)\n");
wprintf(L" -bcquick USe quick compression (BC7 only)\n");
wprintf(L" -bcquick Use quick compression (BC7 only)\n");
wprintf(L" -wicq <quality> When writing images with WIC use quality (0.0 to 1.0)\n");
wprintf(L" -wiclossless When writing images with WIC use lossless mode\n");
wprintf(
L" -aw <weight> BC7 GPU compressor weighting for alpha error metric\n"
L" (defaults to 1.0)\n");
wprintf(L" -c <hex-RGB> colorkey (a.k.a. chromakey) transparency\n");
wprintf(L" -tonemap Apply a tonemap operator based on maximum luminance\n");
wprintf(L"\n");
wprintf(L" <format>: ");
@ -1956,6 +1959,82 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
cimage.reset();
}
// --- Tonemap (if requested) --------------------------------------------------
if (dwOptions & DWORD64(1) << OPT_TONEMAP)
{
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage)
{
wprintf(L"\nERROR: Memory allocation failed\n");
return 1;
}
// Compute max luminosity across all images
XMVECTOR maxLum = XMVectorZero();
hr = EvaluateImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),
[&](const XMVECTOR* pixels, size_t width, size_t y)
{
UNREFERENCED_PARAMETER(y);
for (size_t j = 0; j < width; ++j)
{
static const XMVECTORF32 s_luminance = { 0.3f, 0.59f, 0.11f, 0.f };
XMVECTOR v = *pixels++;
v = XMVector3Dot(v, s_luminance);
maxLum = XMVectorMax(v, maxLum);
}
});
if (FAILED(hr))
{
wprintf(L" FAILED [tonemap maxlum] (%x)\n", hr);
return 1;
}
// Reinhard et al, "Photographic Tone Reproduction for Digital Images"
// http://www.cs.utah.edu/~reinhard/cdrom/
maxLum = XMVectorMultiply(maxLum, maxLum);
hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),
[&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t width, size_t y)
{
UNREFERENCED_PARAMETER(y);
for (size_t j = 0; j < width; ++j)
{
XMVECTOR value = inPixels[j];
XMVECTOR scale = XMVectorDivide(XMVectorAdd(g_XMOne, XMVectorDivide(value, maxLum)), XMVectorAdd(g_XMOne, value));
XMVECTOR nvalue = XMVectorMultiply(value, scale);
value = XMVectorSelect(value, nvalue, g_XMSelect1110);
outPixels[j] = value;
}
}, *timage);
if (FAILED(hr))
{
wprintf(L" FAILED [tonemap apply] (%x)\n", hr);
return 1;
}
auto& tinfo = timage->GetMetadata();
tinfo;
assert(info.width == tinfo.width);
assert(info.height == tinfo.height);
assert(info.depth == tinfo.depth);
assert(info.arraySize == tinfo.arraySize);
assert(info.mipLevels == tinfo.mipLevels);
assert(info.miscFlags == tinfo.miscFlags);
assert(info.dimension == tinfo.dimension);
image.swap(timage);
cimage.reset();
}
// --- Premultiplied alpha (if requested) --------------------------------------
if ((dwOptions & (DWORD64(1) << OPT_PREMUL_ALPHA))
&& HasAlpha(info.format)