[texconv] Implemented alpha coverage preservation option (#82)

This commit is contained in:
Julian McKinlay
2019-01-28 19:57:19 +00:00
committed by Chuck Walbourn
parent a79989a4f0
commit f2c4d94a35
3 changed files with 331 additions and 5 deletions

View File

@@ -101,6 +101,7 @@ enum OPTIONS
OPT_COLORKEY,
OPT_TONEMAP,
OPT_X2_BIAS,
OPT_PRESERVE_ALPHA_COVERAGE,
OPT_INVERT_Y,
OPT_FILELIST,
OPT_ROTATE_COLOR,
@@ -187,6 +188,7 @@ const SValue g_pOptions[] =
{ L"c", OPT_COLORKEY },
{ L"tonemap", OPT_TONEMAP },
{ L"x2bias", OPT_X2_BIAS },
{ L"keepcoverage", OPT_PRESERVE_ALPHA_COVERAGE },
{ L"inverty", OPT_INVERT_Y },
{ L"flist", OPT_FILELIST },
{ L"rotatecolor", OPT_ROTATE_COLOR },
@@ -751,6 +753,7 @@ namespace
wprintf(L" -nits <value> paper-white value in nits to use for HDR10 (def: 200.0)\n");
wprintf(L" -tonemap Apply a tonemap operator based on maximum luminance\n");
wprintf(L" -x2bias Enable *2 - 1 conversion cases for unorm/pos-only-float\n");
wprintf(L" -keepcoverage <ref> Preserve alpha coverage in generated mips for alpha test ref\n");
wprintf(L" -inverty Invert Y (i.e. green) channel values\n");
wprintf(L" -flist <filename> use text file with a list of input files (one per line)\n");
@@ -1116,6 +1119,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
DWORD colorKey = 0;
DWORD dwRotateColor = 0;
float paperWhiteNits = 200.f;
float preserveAlphaCoverageRef = 0.0f;
wchar_t szPrefix[MAX_PATH];
wchar_t szSuffix[MAX_PATH];
@@ -1183,6 +1187,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
case OPT_FILELIST:
case OPT_ROTATE_COLOR:
case OPT_PAPER_WHITE_NITS:
case OPT_PRESERVE_ALPHA_COVERAGE:
if (!*pValue)
{
if ((iArg + 1 >= argc))
@@ -1569,15 +1574,27 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
case OPT_PAPER_WHITE_NITS:
if (swscanf_s(pValue, L"%f", &paperWhiteNits) != 1)
{
wprintf(L"Invalid value specified with -nits (%ls)\n", pValue);
wprintf(L"\n");
wprintf(L"Invalid value specified with -nits (%ls)\n\n", pValue);
PrintUsage();
return 1;
}
else if (paperWhiteNits > 10000.f || paperWhiteNits <= 0.f)
{
wprintf(L"-nits (%ls) parameter must be between 0 and 10000\n", pValue);
wprintf(L"\n");
wprintf(L"-nits (%ls) parameter must be between 0 and 10000\n\n", pValue);
return 1;
}
break;
case OPT_PRESERVE_ALPHA_COVERAGE:
if (swscanf_s(pValue, L"%f", &preserveAlphaCoverageRef) != 1)
{
wprintf(L"Invalid value specified with -keepcoverage (%ls)\n\n", pValue);
PrintUsage();
return 1;
}
else if (preserveAlphaCoverageRef < 0.0f || preserveAlphaCoverageRef > 1.0f)
{
wprintf(L"-keepcoverage (%ls) parameter must be between 0.0 and 1.0\n\n", pValue);
return 1;
}
break;
@@ -1655,6 +1672,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
// Convert images
bool nonpow2warn = false;
bool non4bc = false;
bool preserveAlphaCoverage = false;
ComPtr<ID3D11Device> pDevice;
for (auto pConv = conversion.begin(); pConv != conversion.end(); ++pConv)
@@ -2526,6 +2544,12 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
cimage.reset();
}
// --- Determine whether preserve alpha coverage is required (if requested) ----
if (preserveAlphaCoverageRef > 0.0f && HasAlpha(info.format) && !image->IsAlphaAllOpaque())
{
preserveAlphaCoverage = true;
}
// --- Generate mips -----------------------------------------------------------
DWORD dwFilter3D = dwFilter;
if (!ispow2(info.width) || !ispow2(info.height) || !ispow2(info.depth))
@@ -2542,9 +2566,11 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
}
}
if ((!tMips || info.mipLevels != tMips) && (info.mipLevels != 1))
if ((!tMips || info.mipLevels != tMips || preserveAlphaCoverage) && (info.mipLevels != 1))
{
// Mips generation only works on a single base image, so strip off existing mip levels
// Also required for preserve alpha coverage so that existing mips are regenerated
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage)
{
@@ -2670,6 +2696,59 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
cimage.reset();
}
// --- Preserve mipmap alpha coverage (if requested) ---------------------------
if (preserveAlphaCoverage && info.mipLevels != 1)
{
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage)
{
wprintf(L"\nERROR: Memory allocation failed\n");
return 1;
}
hr = timage->Initialize(image->GetMetadata());
if (FAILED(hr))
{
wprintf(L" FAILED [keepcoverage] (%x)\n", hr);
return 1;
}
const size_t items = image->GetMetadata().arraySize;
for (size_t item = 0; item < items; ++item)
{
auto img = image->GetImage(0, item, 0);
assert(img);
hr = CopyRectangle(*img, Rect(0, 0, info.width, info.height), *timage->GetImage(0, item, 0), TEX_FILTER_DEFAULT, 0, 0);
if (FAILED(hr))
{
wprintf(L" FAILED [keepcoverage] (%x)\n", hr);
return 1;
}
hr = ScaleMipMapsAlphaForCoverage(img, info, item, preserveAlphaCoverageRef, *timage);
if (FAILED(hr))
{
wprintf(L" FAILED [keepcoverage] (%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)