5204 lines
192 KiB
C++
5204 lines
192 KiB
C++
//-------------------------------------------------------------------------------------
|
|
// DirectXTexConvert.cpp
|
|
//
|
|
// DirectX Texture Library - Image pixel format conversion
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT License.
|
|
//
|
|
// http://go.microsoft.com/fwlink/?LinkId=248926
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
#include "DirectXTexP.h"
|
|
|
|
using namespace DirectX;
|
|
using namespace DirectX::PackedVector;
|
|
|
|
#if !defined(_DXTX_NOWIN)
|
|
using Microsoft::WRL::ComPtr;
|
|
#endif
|
|
|
|
namespace
|
|
{
|
|
inline uint32_t FloatTo7e3(float Value) noexcept
|
|
{
|
|
uint32_t IValue = reinterpret_cast<uint32_t *>(&Value)[0];
|
|
|
|
if (IValue & 0x80000000U)
|
|
{
|
|
// Positive only
|
|
return 0;
|
|
}
|
|
else if (IValue > 0x41FF73FFU)
|
|
{
|
|
// The number is too large to be represented as a 7e3. Saturate.
|
|
return 0x3FFU;
|
|
}
|
|
else
|
|
{
|
|
if (IValue < 0x3E800000U)
|
|
{
|
|
// The number is too small to be represented as a normalized 7e3.
|
|
// Convert it to a denormalized value.
|
|
uint32_t Shift = std::min<uint32_t>(125U - (IValue >> 23U), 24U);
|
|
IValue = (0x800000U | (IValue & 0x7FFFFFU)) >> Shift;
|
|
}
|
|
else
|
|
{
|
|
// Rebias the exponent to represent the value as a normalized 7e3.
|
|
IValue += 0xC2000000U;
|
|
}
|
|
|
|
return ((IValue + 0x7FFFU + ((IValue >> 16U) & 1U)) >> 16U) & 0x3FFU;
|
|
}
|
|
}
|
|
|
|
inline float FloatFrom7e3(uint32_t Value) noexcept
|
|
{
|
|
auto Mantissa = static_cast<uint32_t>(Value & 0x7F);
|
|
|
|
uint32_t Exponent = (Value & 0x380);
|
|
if (Exponent != 0) // The value is normalized
|
|
{
|
|
Exponent = static_cast<uint32_t>((Value >> 7) & 0x7);
|
|
}
|
|
else if (Mantissa != 0) // The value is denormalized
|
|
{
|
|
// Normalize the value in the resulting float
|
|
Exponent = 1;
|
|
|
|
do
|
|
{
|
|
Exponent--;
|
|
Mantissa <<= 1;
|
|
} while ((Mantissa & 0x80) == 0);
|
|
|
|
Mantissa &= 0x7F;
|
|
}
|
|
else // The value is zero
|
|
{
|
|
Exponent = uint32_t(-124);
|
|
}
|
|
|
|
uint32_t Result = ((Exponent + 124) << 23) | // Exponent
|
|
(Mantissa << 16); // Mantissa
|
|
|
|
return reinterpret_cast<float*>(&Result)[0];
|
|
}
|
|
|
|
inline uint32_t FloatTo6e4(float Value) noexcept
|
|
{
|
|
uint32_t IValue = reinterpret_cast<uint32_t *>(&Value)[0];
|
|
|
|
if (IValue & 0x80000000U)
|
|
{
|
|
// Positive only
|
|
return 0;
|
|
}
|
|
else if (IValue > 0x43FEFFFFU)
|
|
{
|
|
// The number is too large to be represented as a 6e4. Saturate.
|
|
return 0x3FFU;
|
|
}
|
|
else
|
|
{
|
|
if (IValue < 0x3C800000U)
|
|
{
|
|
// The number is too small to be represented as a normalized 6e4.
|
|
// Convert it to a denormalized value.
|
|
uint32_t Shift = std::min<uint32_t>(121U - (IValue >> 23U), 24U);
|
|
IValue = (0x800000U | (IValue & 0x7FFFFFU)) >> Shift;
|
|
}
|
|
else
|
|
{
|
|
// Rebias the exponent to represent the value as a normalized 6e4.
|
|
IValue += 0xC4000000U;
|
|
}
|
|
|
|
return ((IValue + 0xFFFFU + ((IValue >> 17U) & 1U)) >> 17U) & 0x3FFU;
|
|
}
|
|
}
|
|
|
|
inline float FloatFrom6e4(uint32_t Value) noexcept
|
|
{
|
|
uint32_t Mantissa = static_cast<uint32_t>(Value & 0x3F);
|
|
|
|
uint32_t Exponent = (Value & 0x3C0);
|
|
if (Exponent != 0) // The value is normalized
|
|
{
|
|
Exponent = static_cast<uint32_t>((Value >> 6) & 0xF);
|
|
}
|
|
else if (Mantissa != 0) // The value is denormalized
|
|
{
|
|
// Normalize the value in the resulting float
|
|
Exponent = 1;
|
|
|
|
do
|
|
{
|
|
Exponent--;
|
|
Mantissa <<= 1;
|
|
} while ((Mantissa & 0x40) == 0);
|
|
|
|
Mantissa &= 0x3F;
|
|
}
|
|
else // The value is zero
|
|
{
|
|
Exponent = uint32_t(-120);
|
|
}
|
|
|
|
uint32_t Result = ((Exponent + 120) << 23) | // Exponent
|
|
(Mantissa << 17); // Mantissa
|
|
|
|
return reinterpret_cast<float*>(&Result)[0];
|
|
}
|
|
|
|
#if DIRECTX_MATH_VERSION >= 310
|
|
#define StoreFloat3SE XMStoreFloat3SE
|
|
#else
|
|
inline void XM_CALLCONV StoreFloat3SE(_Out_ XMFLOAT3SE* pDestination, DirectX::FXMVECTOR V)
|
|
{
|
|
assert(pDestination);
|
|
|
|
DirectX::XMFLOAT3A tmp;
|
|
DirectX::XMStoreFloat3A(&tmp, V);
|
|
|
|
static const float maxf9 = float(0x1FF << 7);
|
|
static const float minf9 = float(1.f / (1 << 16));
|
|
|
|
float x = (tmp.x >= 0.f) ? ((tmp.x > maxf9) ? maxf9 : tmp.x) : 0.f;
|
|
float y = (tmp.y >= 0.f) ? ((tmp.y > maxf9) ? maxf9 : tmp.y) : 0.f;
|
|
float z = (tmp.z >= 0.f) ? ((tmp.z > maxf9) ? maxf9 : tmp.z) : 0.f;
|
|
|
|
const float max_xy = (x > y) ? x : y;
|
|
const float max_xyz = (max_xy > z) ? max_xy : z;
|
|
|
|
const float maxColor = (max_xyz > minf9) ? max_xyz : minf9;
|
|
|
|
union { float f; int32_t i; } fi;
|
|
fi.f = maxColor;
|
|
fi.i += 0x00004000; // round up leaving 9 bits in fraction (including assumed 1)
|
|
|
|
// Fix applied from DirectXMath 3.10
|
|
uint32_t exp = fi.i >> 23;
|
|
pDestination->e = exp - 0x6f;
|
|
|
|
fi.i = 0x83000000 - (exp << 23);
|
|
float ScaleR = fi.f;
|
|
|
|
pDestination->xm = static_cast<uint32_t>(lroundf(x * ScaleR));
|
|
pDestination->ym = static_cast<uint32_t>(lroundf(y * ScaleR));
|
|
pDestination->zm = static_cast<uint32_t>(lroundf(z * ScaleR));
|
|
}
|
|
#endif
|
|
|
|
const XMVECTORF32 g_Grayscale = { { { 0.2125f, 0.7154f, 0.0721f, 0.0f } } };
|
|
const XMVECTORF32 g_HalfMin = { { { -65504.f, -65504.f, -65504.f, -65504.f } } };
|
|
const XMVECTORF32 g_HalfMax = { { { 65504.f, 65504.f, 65504.f, 65504.f } } };
|
|
const XMVECTORF32 g_8BitBias = { { { 0.5f / 255.f, 0.5f / 255.f, 0.5f / 255.f, 0.5f / 255.f } } };
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Copies an image row with optional clearing of alpha value to 1.0
|
|
// (can be used in place as well) otherwise copies the image row unmodified.
|
|
//-------------------------------------------------------------------------------------
|
|
_Use_decl_annotations_
|
|
void DirectX::_CopyScanline(
|
|
void* pDestination,
|
|
size_t outSize,
|
|
const void* pSource,
|
|
size_t inSize,
|
|
DXGI_FORMAT format,
|
|
uint32_t tflags) noexcept
|
|
{
|
|
assert(pDestination && outSize > 0);
|
|
assert(pSource && inSize > 0);
|
|
assert(IsValid(format) && !IsPalettized(format));
|
|
|
|
if (tflags & TEXP_SCANLINE_SETALPHA)
|
|
{
|
|
switch (static_cast<int>(format))
|
|
{
|
|
//-----------------------------------------------------------------------------
|
|
case DXGI_FORMAT_R32G32B32A32_TYPELESS:
|
|
case DXGI_FORMAT_R32G32B32A32_FLOAT:
|
|
case DXGI_FORMAT_R32G32B32A32_UINT:
|
|
case DXGI_FORMAT_R32G32B32A32_SINT:
|
|
if (inSize >= 16 && outSize >= 16)
|
|
{
|
|
uint32_t alpha;
|
|
if (format == DXGI_FORMAT_R32G32B32A32_FLOAT)
|
|
alpha = 0x3f800000;
|
|
else if (format == DXGI_FORMAT_R32G32B32A32_SINT)
|
|
alpha = 0x7fffffff;
|
|
else
|
|
alpha = 0xffffffff;
|
|
|
|
if (pDestination == pSource)
|
|
{
|
|
auto dPtr = static_cast<uint32_t*>(pDestination);
|
|
for (size_t count = 0; count < (outSize - 15); count += 16)
|
|
{
|
|
dPtr += 3;
|
|
*(dPtr++) = alpha;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const uint32_t * __restrict sPtr = static_cast<const uint32_t*>(pSource);
|
|
uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);
|
|
size_t size = std::min<size_t>(outSize, inSize);
|
|
for (size_t count = 0; count < (size - 15); count += 16)
|
|
{
|
|
*(dPtr++) = *(sPtr++);
|
|
*(dPtr++) = *(sPtr++);
|
|
*(dPtr++) = *(sPtr++);
|
|
*(dPtr++) = alpha;
|
|
++sPtr;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
case DXGI_FORMAT_R16G16B16A16_TYPELESS:
|
|
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
|
case DXGI_FORMAT_R16G16B16A16_UNORM:
|
|
case DXGI_FORMAT_R16G16B16A16_UINT:
|
|
case DXGI_FORMAT_R16G16B16A16_SNORM:
|
|
case DXGI_FORMAT_R16G16B16A16_SINT:
|
|
case DXGI_FORMAT_Y416:
|
|
if (inSize >= 8 && outSize >= 8)
|
|
{
|
|
uint16_t alpha;
|
|
if (format == DXGI_FORMAT_R16G16B16A16_FLOAT)
|
|
alpha = 0x3c00;
|
|
else if (format == DXGI_FORMAT_R16G16B16A16_SNORM || format == DXGI_FORMAT_R16G16B16A16_SINT)
|
|
alpha = 0x7fff;
|
|
else
|
|
alpha = 0xffff;
|
|
|
|
if (pDestination == pSource)
|
|
{
|
|
auto dPtr = static_cast<uint16_t*>(pDestination);
|
|
for (size_t count = 0; count < (outSize - 7); count += 8)
|
|
{
|
|
dPtr += 3;
|
|
*(dPtr++) = alpha;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const uint16_t * __restrict sPtr = static_cast<const uint16_t*>(pSource);
|
|
uint16_t * __restrict dPtr = static_cast<uint16_t*>(pDestination);
|
|
size_t size = std::min<size_t>(outSize, inSize);
|
|
for (size_t count = 0; count < (size - 7); count += 8)
|
|
{
|
|
*(dPtr++) = *(sPtr++);
|
|
*(dPtr++) = *(sPtr++);
|
|
*(dPtr++) = *(sPtr++);
|
|
*(dPtr++) = alpha;
|
|
++sPtr;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
case DXGI_FORMAT_R10G10B10A2_TYPELESS:
|
|
case DXGI_FORMAT_R10G10B10A2_UNORM:
|
|
case DXGI_FORMAT_R10G10B10A2_UINT:
|
|
case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
|
|
case DXGI_FORMAT_Y410:
|
|
case XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT:
|
|
case XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT:
|
|
case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM:
|
|
if (inSize >= 4 && outSize >= 4)
|
|
{
|
|
if (pDestination == pSource)
|
|
{
|
|
auto dPtr = static_cast<uint32_t*>(pDestination);
|
|
for (size_t count = 0; count < (outSize - 3); count += 4)
|
|
{
|
|
*dPtr |= 0xC0000000;
|
|
++dPtr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const uint32_t * __restrict sPtr = static_cast<const uint32_t*>(pSource);
|
|
uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);
|
|
size_t size = std::min<size_t>(outSize, inSize);
|
|
for (size_t count = 0; count < (size - 3); count += 4)
|
|
{
|
|
*(dPtr++) = *(sPtr++) | 0xC0000000;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
case DXGI_FORMAT_R8G8B8A8_TYPELESS:
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
|
case DXGI_FORMAT_R8G8B8A8_UINT:
|
|
case DXGI_FORMAT_R8G8B8A8_SNORM:
|
|
case DXGI_FORMAT_R8G8B8A8_SINT:
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
|
case DXGI_FORMAT_B8G8R8A8_TYPELESS:
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
|
|
case DXGI_FORMAT_AYUV:
|
|
if (inSize >= 4 && outSize >= 4)
|
|
{
|
|
const uint32_t alpha = (format == DXGI_FORMAT_R8G8B8A8_SNORM || format == DXGI_FORMAT_R8G8B8A8_SINT) ? 0x7f000000 : 0xff000000;
|
|
|
|
if (pDestination == pSource)
|
|
{
|
|
auto dPtr = static_cast<uint32_t*>(pDestination);
|
|
for (size_t count = 0; count < (outSize - 3); count += 4)
|
|
{
|
|
uint32_t t = *dPtr & 0xFFFFFF;
|
|
t |= alpha;
|
|
*(dPtr++) = t;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const uint32_t * __restrict sPtr = static_cast<const uint32_t*>(pSource);
|
|
uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);
|
|
size_t size = std::min<size_t>(outSize, inSize);
|
|
for (size_t count = 0; count < (size - 3); count += 4)
|
|
{
|
|
uint32_t t = *(sPtr++) & 0xFFFFFF;
|
|
t |= alpha;
|
|
*(dPtr++) = t;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
case DXGI_FORMAT_B5G5R5A1_UNORM:
|
|
if (inSize >= 2 && outSize >= 2)
|
|
{
|
|
if (pDestination == pSource)
|
|
{
|
|
auto dPtr = static_cast<uint16_t*>(pDestination);
|
|
for (size_t count = 0; count < (outSize - 1); count += 2)
|
|
{
|
|
*(dPtr++) |= 0x8000;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const uint16_t * __restrict sPtr = static_cast<const uint16_t*>(pSource);
|
|
uint16_t * __restrict dPtr = static_cast<uint16_t*>(pDestination);
|
|
size_t size = std::min<size_t>(outSize, inSize);
|
|
for (size_t count = 0; count < (size - 1); count += 2)
|
|
{
|
|
*(dPtr++) = uint16_t(*(sPtr++) | 0x8000);
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
case DXGI_FORMAT_A8_UNORM:
|
|
memset(pDestination, 0xff, outSize);
|
|
return;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
case DXGI_FORMAT_B4G4R4A4_UNORM:
|
|
if (inSize >= 2 && outSize >= 2)
|
|
{
|
|
if (pDestination == pSource)
|
|
{
|
|
auto dPtr = static_cast<uint16_t*>(pDestination);
|
|
for (size_t count = 0; count < (outSize - 1); count += 2)
|
|
{
|
|
*(dPtr++) |= 0xF000;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const uint16_t * __restrict sPtr = static_cast<const uint16_t*>(pSource);
|
|
uint16_t * __restrict dPtr = static_cast<uint16_t*>(pDestination);
|
|
size_t size = std::min<size_t>(outSize, inSize);
|
|
for (size_t count = 0; count < (size - 1); count += 2)
|
|
{
|
|
*(dPtr++) = uint16_t(*(sPtr++) | 0xF000);
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Fall-through case is to just use memcpy (assuming this is not an in-place operation)
|
|
if (pDestination == pSource)
|
|
return;
|
|
|
|
size_t size = std::min<size_t>(outSize, inSize);
|
|
memcpy_s(pDestination, outSize, pSource, size);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Swizzles (RGB <-> BGR) an image row with optional clearing of alpha value to 1.0
|
|
// (can be used in place as well) otherwise copies the image row unmodified.
|
|
//-------------------------------------------------------------------------------------
|
|
_Use_decl_annotations_
|
|
void DirectX::_SwizzleScanline(
|
|
void* pDestination,
|
|
size_t outSize,
|
|
const void* pSource,
|
|
size_t inSize,
|
|
DXGI_FORMAT format,
|
|
uint32_t tflags) noexcept
|
|
{
|
|
assert(pDestination && outSize > 0);
|
|
assert(pSource && inSize > 0);
|
|
assert(IsValid(format) && !IsPlanar(format) && !IsPalettized(format));
|
|
|
|
switch (static_cast<int>(format))
|
|
{
|
|
//---------------------------------------------------------------------------------
|
|
case DXGI_FORMAT_R10G10B10A2_TYPELESS:
|
|
case DXGI_FORMAT_R10G10B10A2_UNORM:
|
|
case DXGI_FORMAT_R10G10B10A2_UINT:
|
|
case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
|
|
case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM:
|
|
if (inSize >= 4 && outSize >= 4)
|
|
{
|
|
if (tflags & TEXP_SCANLINE_LEGACY)
|
|
{
|
|
// Swap Red (R) and Blue (B) channel (used for D3DFMT_A2R10G10B10 legacy sources)
|
|
if (pDestination == pSource)
|
|
{
|
|
auto dPtr = static_cast<uint32_t*>(pDestination);
|
|
for (size_t count = 0; count < (outSize - 3); count += 4)
|
|
{
|
|
uint32_t t = *dPtr;
|
|
|
|
uint32_t t1 = (t & 0x3ff00000) >> 20;
|
|
uint32_t t2 = (t & 0x000003ff) << 20;
|
|
uint32_t t3 = (t & 0x000ffc00);
|
|
uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xC0000000 : (t & 0xC0000000);
|
|
|
|
*(dPtr++) = t1 | t2 | t3 | ta;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const uint32_t * __restrict sPtr = static_cast<const uint32_t*>(pSource);
|
|
uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);
|
|
size_t size = std::min<size_t>(outSize, inSize);
|
|
for (size_t count = 0; count < (size - 3); count += 4)
|
|
{
|
|
uint32_t t = *(sPtr++);
|
|
|
|
uint32_t t1 = (t & 0x3ff00000) >> 20;
|
|
uint32_t t2 = (t & 0x000003ff) << 20;
|
|
uint32_t t3 = (t & 0x000ffc00);
|
|
uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xC0000000 : (t & 0xC0000000);
|
|
|
|
*(dPtr++) = t1 | t2 | t3 | ta;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
|
|
//---------------------------------------------------------------------------------
|
|
case DXGI_FORMAT_R8G8B8A8_TYPELESS:
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
|
case DXGI_FORMAT_B8G8R8A8_TYPELESS:
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
|
|
case DXGI_FORMAT_B8G8R8X8_TYPELESS:
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
|
|
if (inSize >= 4 && outSize >= 4)
|
|
{
|
|
// Swap Red (R) and Blue (B) channels (used to convert from DXGI 1.1 BGR formats to DXGI 1.0 RGB)
|
|
if (pDestination == pSource)
|
|
{
|
|
auto dPtr = static_cast<uint32_t*>(pDestination);
|
|
for (size_t count = 0; count < (outSize - 3); count += 4)
|
|
{
|
|
uint32_t t = *dPtr;
|
|
|
|
uint32_t t1 = (t & 0x00ff0000) >> 16;
|
|
uint32_t t2 = (t & 0x000000ff) << 16;
|
|
uint32_t t3 = (t & 0x0000ff00);
|
|
uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : (t & 0xFF000000);
|
|
|
|
*(dPtr++) = t1 | t2 | t3 | ta;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const uint32_t * __restrict sPtr = static_cast<const uint32_t*>(pSource);
|
|
uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);
|
|
size_t size = std::min<size_t>(outSize, inSize);
|
|
for (size_t count = 0; count < (size - 3); count += 4)
|
|
{
|
|
uint32_t t = *(sPtr++);
|
|
|
|
uint32_t t1 = (t & 0x00ff0000) >> 16;
|
|
uint32_t t2 = (t & 0x000000ff) << 16;
|
|
uint32_t t3 = (t & 0x0000ff00);
|
|
uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : (t & 0xFF000000);
|
|
|
|
*(dPtr++) = t1 | t2 | t3 | ta;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
|
|
//---------------------------------------------------------------------------------
|
|
case DXGI_FORMAT_YUY2:
|
|
if (inSize >= 4 && outSize >= 4)
|
|
{
|
|
if (tflags & TEXP_SCANLINE_LEGACY)
|
|
{
|
|
// Reorder YUV components (used to convert legacy UYVY -> YUY2)
|
|
if (pDestination == pSource)
|
|
{
|
|
auto dPtr = static_cast<uint32_t*>(pDestination);
|
|
for (size_t count = 0; count < (outSize - 3); count += 4)
|
|
{
|
|
uint32_t t = *dPtr;
|
|
|
|
uint32_t t1 = (t & 0x000000ff) << 8;
|
|
uint32_t t2 = (t & 0x0000ff00) >> 8;
|
|
uint32_t t3 = (t & 0x00ff0000) << 8;
|
|
uint32_t t4 = (t & 0xff000000) >> 8;
|
|
|
|
*(dPtr++) = t1 | t2 | t3 | t4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const uint32_t * __restrict sPtr = static_cast<const uint32_t*>(pSource);
|
|
uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);
|
|
size_t size = std::min<size_t>(outSize, inSize);
|
|
for (size_t count = 0; count < (size - 3); count += 4)
|
|
{
|
|
uint32_t t = *(sPtr++);
|
|
|
|
uint32_t t1 = (t & 0x000000ff) << 8;
|
|
uint32_t t2 = (t & 0x0000ff00) >> 8;
|
|
uint32_t t3 = (t & 0x00ff0000) << 8;
|
|
uint32_t t4 = (t & 0xff000000) >> 8;
|
|
|
|
*(dPtr++) = t1 | t2 | t3 | t4;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Fall-through case is to just use memcpy (assuming this is not an in-place operation)
|
|
if (pDestination == pSource)
|
|
return;
|
|
|
|
size_t size = std::min<size_t>(outSize, inSize);
|
|
memcpy_s(pDestination, outSize, pSource, size);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Converts an image row with optional clearing of alpha value to 1.0
|
|
// Returns true if supported, false if expansion case not supported
|
|
//-------------------------------------------------------------------------------------
|
|
_Use_decl_annotations_
|
|
bool DirectX::_ExpandScanline(
|
|
void* pDestination,
|
|
size_t outSize,
|
|
DXGI_FORMAT outFormat,
|
|
const void* pSource,
|
|
size_t inSize,
|
|
DXGI_FORMAT inFormat,
|
|
uint32_t tflags) noexcept
|
|
{
|
|
assert(pDestination && outSize > 0);
|
|
assert(pSource && inSize > 0);
|
|
assert(IsValid(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat));
|
|
assert(IsValid(inFormat) && !IsPlanar(inFormat) && !IsPalettized(inFormat));
|
|
|
|
switch (inFormat)
|
|
{
|
|
case DXGI_FORMAT_B5G6R5_UNORM:
|
|
if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM)
|
|
return false;
|
|
|
|
// DXGI_FORMAT_B5G6R5_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM
|
|
if (inSize >= 2 && outSize >= 4)
|
|
{
|
|
const uint16_t * __restrict sPtr = static_cast<const uint16_t*>(pSource);
|
|
uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);
|
|
|
|
for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4)
|
|
{
|
|
uint16_t t = *(sPtr++);
|
|
|
|
uint32_t t1 = uint32_t(((t & 0xf800) >> 8) | ((t & 0xe000) >> 13));
|
|
uint32_t t2 = uint32_t(((t & 0x07e0) << 5) | ((t & 0x0600) >> 5));
|
|
uint32_t t3 = uint32_t(((t & 0x001f) << 19) | ((t & 0x001c) << 14));
|
|
|
|
*(dPtr++) = t1 | t2 | t3 | 0xff000000;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_B5G5R5A1_UNORM:
|
|
if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM)
|
|
return false;
|
|
|
|
// DXGI_FORMAT_B5G5R5A1_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM
|
|
if (inSize >= 2 && outSize >= 4)
|
|
{
|
|
const uint16_t * __restrict sPtr = static_cast<const uint16_t*>(pSource);
|
|
uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);
|
|
|
|
for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4)
|
|
{
|
|
uint16_t t = *(sPtr++);
|
|
|
|
uint32_t t1 = uint32_t(((t & 0x7c00) >> 7) | ((t & 0x7000) >> 12));
|
|
uint32_t t2 = uint32_t(((t & 0x03e0) << 6) | ((t & 0x0380) << 1));
|
|
uint32_t t3 = uint32_t(((t & 0x001f) << 19) | ((t & 0x001c) << 14));
|
|
uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : ((t & 0x8000) ? 0xff000000 : 0);
|
|
|
|
*(dPtr++) = t1 | t2 | t3 | ta;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_B4G4R4A4_UNORM:
|
|
if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM)
|
|
return false;
|
|
|
|
// DXGI_FORMAT_B4G4R4A4_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM
|
|
if (inSize >= 2 && outSize >= 4)
|
|
{
|
|
const uint16_t * __restrict sPtr = static_cast<const uint16_t*>(pSource);
|
|
uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);
|
|
|
|
for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4)
|
|
{
|
|
uint16_t t = *(sPtr++);
|
|
|
|
uint32_t t1 = uint32_t(((t & 0x0f00) >> 4) | ((t & 0x0f00) >> 8));
|
|
uint32_t t2 = uint32_t(((t & 0x00f0) << 8) | ((t & 0x00f0) << 4));
|
|
uint32_t t3 = uint32_t(((t & 0x000f) << 20) | ((t & 0x000f) << 16));
|
|
uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : uint32_t(((t & 0xf000) << 16) | ((t & 0xf000) << 12));
|
|
|
|
*(dPtr++) = t1 | t2 | t3 | ta;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Loads an image row into standard RGBA XMVECTOR (aligned) array
|
|
//-------------------------------------------------------------------------------------
|
|
#define LOAD_SCANLINE( type, func )\
|
|
if (size >= sizeof(type))\
|
|
{\
|
|
const type * __restrict sPtr = reinterpret_cast<const type*>(pSource);\
|
|
for(size_t icount = 0; icount < (size - sizeof(type) + 1); icount += sizeof(type))\
|
|
{\
|
|
if (dPtr >= ePtr) break;\
|
|
*(dPtr++) = func(sPtr++);\
|
|
}\
|
|
return true;\
|
|
}\
|
|
return false;
|
|
|
|
#define LOAD_SCANLINE3( type, func, defvec )\
|
|
if (size >= sizeof(type))\
|
|
{\
|
|
const type * __restrict sPtr = reinterpret_cast<const type*>(pSource);\
|
|
for(size_t icount = 0; icount < (size - sizeof(type) + 1); icount += sizeof(type))\
|
|
{\
|
|
XMVECTOR v = func(sPtr++);\
|
|
if (dPtr >= ePtr) break;\
|
|
*(dPtr++) = XMVectorSelect(defvec, v, g_XMSelect1110);\
|
|
}\
|
|
return true;\
|
|
}\
|
|
return false;
|
|
|
|
#define LOAD_SCANLINE2( type, func, defvec )\
|
|
if (size >= sizeof(type))\
|
|
{\
|
|
const type * __restrict sPtr = reinterpret_cast<const type*>(pSource);\
|
|
for(size_t icount = 0; icount < (size - sizeof(type) + 1); icount += sizeof(type))\
|
|
{\
|
|
XMVECTOR v = func(sPtr++);\
|
|
if (dPtr >= ePtr) break;\
|
|
*(dPtr++) = XMVectorSelect(defvec, v, g_XMSelect1100);\
|
|
}\
|
|
return true;\
|
|
}\
|
|
return false;
|
|
|
|
#pragma warning(suppress: 6101)
|
|
_Use_decl_annotations_ bool DirectX::_LoadScanline(
|
|
XMVECTOR* pDestination,
|
|
size_t count,
|
|
const void* pSource,
|
|
size_t size,
|
|
DXGI_FORMAT format) noexcept
|
|
{
|
|
assert(pDestination && count > 0 && ((reinterpret_cast<uintptr_t>(pDestination) & 0xF) == 0));
|
|
assert(pSource && size > 0);
|
|
assert(IsValid(format) && !IsTypeless(format, false) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format));
|
|
|
|
XMVECTOR* __restrict dPtr = pDestination;
|
|
if (!dPtr)
|
|
return false;
|
|
|
|
const XMVECTOR* ePtr = pDestination + count;
|
|
|
|
switch (static_cast<int>(format))
|
|
{
|
|
case DXGI_FORMAT_R32G32B32A32_FLOAT:
|
|
{
|
|
size_t msize = (size > (sizeof(XMVECTOR)*count)) ? (sizeof(XMVECTOR)*count) : size;
|
|
memcpy_s(dPtr, sizeof(XMVECTOR)*count, pSource, msize);
|
|
}
|
|
return true;
|
|
|
|
case DXGI_FORMAT_R32G32B32A32_UINT:
|
|
LOAD_SCANLINE(XMUINT4, XMLoadUInt4)
|
|
|
|
case DXGI_FORMAT_R32G32B32A32_SINT:
|
|
LOAD_SCANLINE(XMINT4, XMLoadSInt4)
|
|
|
|
case DXGI_FORMAT_R32G32B32_FLOAT:
|
|
LOAD_SCANLINE3(XMFLOAT3, XMLoadFloat3, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_R32G32B32_UINT:
|
|
LOAD_SCANLINE3(XMUINT3, XMLoadUInt3, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_R32G32B32_SINT:
|
|
LOAD_SCANLINE3(XMINT3, XMLoadSInt3, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
|
LOAD_SCANLINE(XMHALF4, XMLoadHalf4)
|
|
|
|
case DXGI_FORMAT_R16G16B16A16_UNORM:
|
|
LOAD_SCANLINE(XMUSHORTN4, XMLoadUShortN4)
|
|
|
|
case DXGI_FORMAT_R16G16B16A16_UINT:
|
|
LOAD_SCANLINE(XMUSHORT4, XMLoadUShort4)
|
|
|
|
case DXGI_FORMAT_R16G16B16A16_SNORM:
|
|
LOAD_SCANLINE(XMSHORTN4, XMLoadShortN4)
|
|
|
|
case DXGI_FORMAT_R16G16B16A16_SINT:
|
|
LOAD_SCANLINE(XMSHORT4, XMLoadShort4)
|
|
|
|
case DXGI_FORMAT_R32G32_FLOAT:
|
|
LOAD_SCANLINE2(XMFLOAT2, XMLoadFloat2, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_R32G32_UINT:
|
|
LOAD_SCANLINE2(XMUINT2, XMLoadUInt2, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_R32G32_SINT:
|
|
LOAD_SCANLINE2(XMINT2, XMLoadSInt2, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
|
|
{
|
|
const size_t psize = sizeof(float) + sizeof(uint32_t);
|
|
if (size >= psize)
|
|
{
|
|
auto sPtr = static_cast<const float*>(pSource);
|
|
for (size_t icount = 0; icount < (size - psize + 1); icount += psize)
|
|
{
|
|
auto ps8 = reinterpret_cast<const uint8_t*>(&sPtr[1]);
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(sPtr[0], static_cast<float>(*ps8), 0.f, 1.f);
|
|
sPtr += 2;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
|
|
{
|
|
const size_t psize = sizeof(float) + sizeof(uint32_t);
|
|
if (size >= psize)
|
|
{
|
|
auto sPtr = static_cast<const float*>(pSource);
|
|
for (size_t icount = 0; icount < (size - psize + 1); icount += psize)
|
|
{
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(sPtr[0], 0.f /* typeless component assumed zero */, 0.f, 1.f);
|
|
sPtr += 2;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
|
|
{
|
|
const size_t psize = sizeof(float) + sizeof(uint32_t);
|
|
if (size >= psize)
|
|
{
|
|
auto sPtr = static_cast<const float*>(pSource);
|
|
for (size_t icount = 0; icount < (size - psize + 1); icount += psize)
|
|
{
|
|
auto pg8 = reinterpret_cast<const uint8_t*>(&sPtr[1]);
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(0.f /* typeless component assumed zero */, static_cast<float>(*pg8), 0.f, 1.f);
|
|
sPtr += 2;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R10G10B10A2_UNORM:
|
|
LOAD_SCANLINE(XMUDECN4, XMLoadUDecN4)
|
|
|
|
case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
|
|
LOAD_SCANLINE(XMUDECN4, XMLoadUDecN4_XR)
|
|
|
|
case DXGI_FORMAT_R10G10B10A2_UINT:
|
|
LOAD_SCANLINE(XMUDEC4, XMLoadUDec4)
|
|
|
|
case DXGI_FORMAT_R11G11B10_FLOAT:
|
|
LOAD_SCANLINE3(XMFLOAT3PK, XMLoadFloat3PK, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
|
LOAD_SCANLINE(XMUBYTEN4, XMLoadUByteN4)
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_UINT:
|
|
LOAD_SCANLINE(XMUBYTE4, XMLoadUByte4)
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_SNORM:
|
|
LOAD_SCANLINE(XMBYTEN4, XMLoadByteN4)
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_SINT:
|
|
LOAD_SCANLINE(XMBYTE4, XMLoadByte4)
|
|
|
|
case DXGI_FORMAT_R16G16_FLOAT:
|
|
LOAD_SCANLINE2(XMHALF2, XMLoadHalf2, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_R16G16_UNORM:
|
|
LOAD_SCANLINE2(XMUSHORTN2, XMLoadUShortN2, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_R16G16_UINT:
|
|
LOAD_SCANLINE2(XMUSHORT2, XMLoadUShort2, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_R16G16_SNORM:
|
|
LOAD_SCANLINE2(XMSHORTN2, XMLoadShortN2, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_R16G16_SINT:
|
|
LOAD_SCANLINE2(XMSHORT2, XMLoadShort2, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_D32_FLOAT:
|
|
case DXGI_FORMAT_R32_FLOAT:
|
|
if (size >= sizeof(float))
|
|
{
|
|
const float* __restrict sPtr = static_cast<const float*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(float) + 1); icount += sizeof(float))
|
|
{
|
|
XMVECTOR v = XMLoadFloat(sPtr++);
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1000);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R32_UINT:
|
|
if (size >= sizeof(uint32_t))
|
|
{
|
|
const uint32_t* __restrict sPtr = static_cast<const uint32_t*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t))
|
|
{
|
|
XMVECTOR v = XMLoadInt(sPtr++);
|
|
v = XMConvertVectorUIntToFloat(v, 0);
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1000);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R32_SINT:
|
|
if (size >= sizeof(int32_t))
|
|
{
|
|
const int32_t * __restrict sPtr = static_cast<const int32_t*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(int32_t) + 1); icount += sizeof(int32_t))
|
|
{
|
|
XMVECTOR v = XMLoadInt(reinterpret_cast<const uint32_t*>(sPtr++));
|
|
v = XMConvertVectorIntToFloat(v, 0);
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1000);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_D24_UNORM_S8_UINT:
|
|
if (size >= sizeof(uint32_t))
|
|
{
|
|
auto sPtr = static_cast<const uint32_t*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t))
|
|
{
|
|
auto d = static_cast<float>(*sPtr & 0xFFFFFF) / 16777215.f;
|
|
auto s = static_cast<float>((*sPtr & 0xFF000000) >> 24);
|
|
++sPtr;
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(d, s, 0.f, 1.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
|
|
if (size >= sizeof(uint32_t))
|
|
{
|
|
auto sPtr = static_cast<const uint32_t*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t))
|
|
{
|
|
auto r = static_cast<float>(*sPtr & 0xFFFFFF) / 16777215.f;
|
|
++sPtr;
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(r, 0.f /* typeless component assumed zero */, 0.f, 1.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
|
|
if (size >= sizeof(uint32_t))
|
|
{
|
|
auto sPtr = static_cast<const uint32_t*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t))
|
|
{
|
|
auto g = static_cast<float>((*sPtr & 0xFF000000) >> 24);
|
|
++sPtr;
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(0.f /* typeless component assumed zero */, g, 0.f, 1.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R8G8_UNORM:
|
|
LOAD_SCANLINE2(XMUBYTEN2, XMLoadUByteN2, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_R8G8_UINT:
|
|
LOAD_SCANLINE2(XMUBYTE2, XMLoadUByte2, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_R8G8_SNORM:
|
|
LOAD_SCANLINE2(XMBYTEN2, XMLoadByteN2, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_R8G8_SINT:
|
|
LOAD_SCANLINE2(XMBYTE2, XMLoadByte2, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_R16_FLOAT:
|
|
if (size >= sizeof(HALF))
|
|
{
|
|
const HALF * __restrict sPtr = static_cast<const HALF*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(HALF) + 1); icount += sizeof(HALF))
|
|
{
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(XMConvertHalfToFloat(*sPtr++), 0.f, 0.f, 1.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_D16_UNORM:
|
|
case DXGI_FORMAT_R16_UNORM:
|
|
if (size >= sizeof(uint16_t))
|
|
{
|
|
const uint16_t* __restrict sPtr = static_cast<const uint16_t*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(uint16_t) + 1); icount += sizeof(uint16_t))
|
|
{
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(static_cast<float>(*sPtr++) / 65535.f, 0.f, 0.f, 1.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R16_UINT:
|
|
if (size >= sizeof(uint16_t))
|
|
{
|
|
const uint16_t * __restrict sPtr = static_cast<const uint16_t*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(uint16_t) + 1); icount += sizeof(uint16_t))
|
|
{
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(static_cast<float>(*sPtr++), 0.f, 0.f, 1.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R16_SNORM:
|
|
if (size >= sizeof(int16_t))
|
|
{
|
|
const int16_t * __restrict sPtr = static_cast<const int16_t*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(int16_t) + 1); icount += sizeof(int16_t))
|
|
{
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(static_cast<float>(*sPtr++) / 32767.f, 0.f, 0.f, 1.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R16_SINT:
|
|
if (size >= sizeof(int16_t))
|
|
{
|
|
const int16_t * __restrict sPtr = static_cast<const int16_t*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(int16_t) + 1); icount += sizeof(int16_t))
|
|
{
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(static_cast<float>(*sPtr++), 0.f, 0.f, 1.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R8_UNORM:
|
|
if (size >= sizeof(uint8_t))
|
|
{
|
|
const uint8_t * __restrict sPtr = static_cast<const uint8_t*>(pSource);
|
|
for (size_t icount = 0; icount < size; icount += sizeof(uint8_t))
|
|
{
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(static_cast<float>(*sPtr++) / 255.f, 0.f, 0.f, 1.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R8_UINT:
|
|
if (size >= sizeof(uint8_t))
|
|
{
|
|
const uint8_t * __restrict sPtr = static_cast<const uint8_t*>(pSource);
|
|
for (size_t icount = 0; icount < size; icount += sizeof(uint8_t))
|
|
{
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(static_cast<float>(*sPtr++), 0.f, 0.f, 1.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R8_SNORM:
|
|
if (size >= sizeof(int8_t))
|
|
{
|
|
const int8_t * __restrict sPtr = static_cast<const int8_t*>(pSource);
|
|
for (size_t icount = 0; icount < size; icount += sizeof(int8_t))
|
|
{
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(static_cast<float>(*sPtr++) / 127.f, 0.f, 0.f, 1.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R8_SINT:
|
|
if (size >= sizeof(int8_t))
|
|
{
|
|
const int8_t * __restrict sPtr = static_cast<const int8_t*>(pSource);
|
|
for (size_t icount = 0; icount < size; icount += sizeof(int8_t))
|
|
{
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(static_cast<float>(*sPtr++), 0.f, 0.f, 1.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_A8_UNORM:
|
|
if (size >= sizeof(uint8_t))
|
|
{
|
|
const uint8_t * __restrict sPtr = static_cast<const uint8_t*>(pSource);
|
|
for (size_t icount = 0; icount < size; icount += sizeof(uint8_t))
|
|
{
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(0.f, 0.f, 0.f, static_cast<float>(*sPtr++) / 255.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R1_UNORM:
|
|
if (size >= sizeof(uint8_t))
|
|
{
|
|
const uint8_t * __restrict sPtr = static_cast<const uint8_t*>(pSource);
|
|
for (size_t icount = 0; icount < size; icount += sizeof(uint8_t))
|
|
{
|
|
for (size_t bcount = 8; bcount > 0; --bcount)
|
|
{
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet((((*sPtr >> (bcount - 1)) & 0x1) ? 1.f : 0.f), 0.f, 0.f, 1.f);
|
|
}
|
|
|
|
++sPtr;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
|
|
LOAD_SCANLINE3(XMFLOAT3SE, XMLoadFloat3SE, g_XMIdentityR3)
|
|
|
|
case DXGI_FORMAT_R8G8_B8G8_UNORM:
|
|
if (size >= sizeof(XMUBYTEN4))
|
|
{
|
|
const XMUBYTEN4 * __restrict sPtr = static_cast<const XMUBYTEN4*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))
|
|
{
|
|
XMVECTOR v = XMLoadUByteN4(sPtr++);
|
|
XMVECTOR v1 = XMVectorSwizzle<0, 3, 2, 1>(v);
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1110);
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSelect(g_XMIdentityR3, v1, g_XMSelect1110);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_G8R8_G8B8_UNORM:
|
|
if (size >= sizeof(XMUBYTEN4))
|
|
{
|
|
const XMUBYTEN4 * __restrict sPtr = static_cast<const XMUBYTEN4*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))
|
|
{
|
|
XMVECTOR v = XMLoadUByteN4(sPtr++);
|
|
XMVECTOR v0 = XMVectorSwizzle<1, 0, 3, 2>(v);
|
|
XMVECTOR v1 = XMVectorSwizzle<1, 2, 3, 0>(v);
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSelect(g_XMIdentityR3, v0, g_XMSelect1110);
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSelect(g_XMIdentityR3, v1, g_XMSelect1110);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_B5G6R5_UNORM:
|
|
if (size >= sizeof(XMU565))
|
|
{
|
|
static const XMVECTORF32 s_Scale = { { { 1.f / 31.f, 1.f / 63.f, 1.f / 31.f, 1.f } } };
|
|
const XMU565 * __restrict sPtr = static_cast<const XMU565*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMU565) + 1); icount += sizeof(XMU565))
|
|
{
|
|
XMVECTOR v = XMLoadU565(sPtr++);
|
|
v = XMVectorMultiply(v, s_Scale);
|
|
v = XMVectorSwizzle<2, 1, 0, 3>(v);
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1110);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_B5G5R5A1_UNORM:
|
|
if (size >= sizeof(XMU555))
|
|
{
|
|
static const XMVECTORF32 s_Scale = { { { 1.f / 31.f, 1.f / 31.f, 1.f / 31.f, 1.f } } };
|
|
const XMU555 * __restrict sPtr = static_cast<const XMU555*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMU555) + 1); icount += sizeof(XMU555))
|
|
{
|
|
XMVECTOR v = XMLoadU555(sPtr++);
|
|
v = XMVectorMultiply(v, s_Scale);
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>(v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
|
|
if (size >= sizeof(XMUBYTEN4))
|
|
{
|
|
const XMUBYTEN4 * __restrict sPtr = static_cast<const XMUBYTEN4*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))
|
|
{
|
|
XMVECTOR v = XMLoadUByteN4(sPtr++);
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>(v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
|
|
if (size >= sizeof(XMUBYTEN4))
|
|
{
|
|
const XMUBYTEN4 * __restrict sPtr = static_cast<const XMUBYTEN4*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))
|
|
{
|
|
XMVECTOR v = XMLoadUByteN4(sPtr++);
|
|
v = XMVectorSwizzle<2, 1, 0, 3>(v);
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1110);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_AYUV:
|
|
if (size >= sizeof(XMUBYTEN4))
|
|
{
|
|
const XMUBYTEN4 * __restrict sPtr = static_cast<const XMUBYTEN4*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))
|
|
{
|
|
int v = int(sPtr->x) - 128;
|
|
int u = int(sPtr->y) - 128;
|
|
int y = int(sPtr->z) - 16;
|
|
unsigned int a = sPtr->w;
|
|
++sPtr;
|
|
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd206750.aspx
|
|
|
|
// Y' = Y - 16
|
|
// Cb' = Cb - 128
|
|
// Cr' = Cr - 128
|
|
|
|
// R = 1.1644Y' + 1.5960Cr'
|
|
// G = 1.1644Y' - 0.3917Cb' - 0.8128Cr'
|
|
// B = 1.1644Y' + 2.0172Cb'
|
|
|
|
int r = (298 * y + 409 * v + 128) >> 8;
|
|
int g = (298 * y - 100 * u - 208 * v + 128) >> 8;
|
|
int b = (298 * y + 516 * u + 128) >> 8;
|
|
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 255)) / 255.f,
|
|
float(std::min<int>(std::max<int>(g, 0), 255)) / 255.f,
|
|
float(std::min<int>(std::max<int>(b, 0), 255)) / 255.f,
|
|
float(a) / 255.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_Y410:
|
|
if (size >= sizeof(XMUDECN4))
|
|
{
|
|
const XMUDECN4 * __restrict sPtr = static_cast<const XMUDECN4*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4))
|
|
{
|
|
int64_t u = int(sPtr->x) - 512;
|
|
int64_t y = int(sPtr->y) - 64;
|
|
int64_t v = int(sPtr->z) - 512;
|
|
unsigned int a = sPtr->w;
|
|
++sPtr;
|
|
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb970578.aspx
|
|
|
|
// Y' = Y - 64
|
|
// Cb' = Cb - 512
|
|
// Cr' = Cr - 512
|
|
|
|
// R = 1.1678Y' + 1.6007Cr'
|
|
// G = 1.1678Y' - 0.3929Cb' - 0.8152Cr'
|
|
// B = 1.1678Y' + 2.0232Cb'
|
|
|
|
auto r = static_cast<int>((76533 * y + 104905 * v + 32768) >> 16);
|
|
auto g = static_cast<int>((76533 * y - 25747 * u - 53425 * v + 32768) >> 16);
|
|
auto b = static_cast<int>((76533 * y + 132590 * u + 32768) >> 16);
|
|
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 1023)) / 1023.f,
|
|
float(std::min<int>(std::max<int>(g, 0), 1023)) / 1023.f,
|
|
float(std::min<int>(std::max<int>(b, 0), 1023)) / 1023.f,
|
|
float(a) / 3.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_Y416:
|
|
if (size >= sizeof(XMUSHORTN4))
|
|
{
|
|
const XMUSHORTN4 * __restrict sPtr = static_cast<const XMUSHORTN4*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUSHORTN4) + 1); icount += sizeof(XMUSHORTN4))
|
|
{
|
|
int64_t u = int64_t(sPtr->x) - 32768;
|
|
int64_t y = int64_t(sPtr->y) - 4096;
|
|
int64_t v = int64_t(sPtr->z) - 32768;
|
|
auto a = static_cast<int>(sPtr->w);
|
|
++sPtr;
|
|
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb970578.aspx
|
|
|
|
// Y' = Y - 4096
|
|
// Cb' = Cb - 32768
|
|
// Cr' = Cr - 32768
|
|
|
|
// R = 1.1689Y' + 1.6023Cr'
|
|
// G = 1.1689Y' - 0.3933Cb' - 0.8160Cr'
|
|
// B = 1.1689Y'+ 2.0251Cb'
|
|
|
|
int r = static_cast<int>((76607 * y + 105006 * v + 32768) >> 16);
|
|
int g = static_cast<int>((76607 * y - 25772 * u - 53477 * v + 32768) >> 16);
|
|
int b = static_cast<int>((76607 * y + 132718 * u + 32768) >> 16);
|
|
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 65535)) / 65535.f,
|
|
float(std::min<int>(std::max<int>(g, 0), 65535)) / 65535.f,
|
|
float(std::min<int>(std::max<int>(b, 0), 65535)) / 65535.f,
|
|
float(std::min<int>(std::max<int>(a, 0), 65535)) / 65535.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_YUY2:
|
|
if (size >= sizeof(XMUBYTEN4))
|
|
{
|
|
const XMUBYTEN4 * __restrict sPtr = static_cast<const XMUBYTEN4*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))
|
|
{
|
|
int y0 = int(sPtr->x) - 16;
|
|
int u = int(sPtr->y) - 128;
|
|
int y1 = int(sPtr->z) - 16;
|
|
int v = int(sPtr->w) - 128;
|
|
++sPtr;
|
|
|
|
// See AYUV
|
|
int r = (298 * y0 + 409 * v + 128) >> 8;
|
|
int g = (298 * y0 - 100 * u - 208 * v + 128) >> 8;
|
|
int b = (298 * y0 + 516 * u + 128) >> 8;
|
|
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 255)) / 255.f,
|
|
float(std::min<int>(std::max<int>(g, 0), 255)) / 255.f,
|
|
float(std::min<int>(std::max<int>(b, 0), 255)) / 255.f,
|
|
1.f);
|
|
|
|
r = (298 * y1 + 409 * v + 128) >> 8;
|
|
g = (298 * y1 - 100 * u - 208 * v + 128) >> 8;
|
|
b = (298 * y1 + 516 * u + 128) >> 8;
|
|
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 255)) / 255.f,
|
|
float(std::min<int>(std::max<int>(g, 0), 255)) / 255.f,
|
|
float(std::min<int>(std::max<int>(b, 0), 255)) / 255.f,
|
|
1.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_Y210:
|
|
// Same as Y216 with least significant 6 bits set to zero
|
|
if (size >= sizeof(XMUSHORTN4))
|
|
{
|
|
const XMUSHORTN4 * __restrict sPtr = static_cast<const XMUSHORTN4*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUSHORTN4) + 1); icount += sizeof(XMUSHORTN4))
|
|
{
|
|
int64_t y0 = int64_t(sPtr->x >> 6) - 64;
|
|
int64_t u = int64_t(sPtr->y >> 6) - 512;
|
|
int64_t y1 = int64_t(sPtr->z >> 6) - 64;
|
|
int64_t v = int64_t(sPtr->w >> 6) - 512;
|
|
++sPtr;
|
|
|
|
// See Y410
|
|
auto r = static_cast<int>((76533 * y0 + 104905 * v + 32768) >> 16);
|
|
auto g = static_cast<int>((76533 * y0 - 25747 * u - 53425 * v + 32768) >> 16);
|
|
auto b = static_cast<int>((76533 * y0 + 132590 * u + 32768) >> 16);
|
|
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 1023)) / 1023.f,
|
|
float(std::min<int>(std::max<int>(g, 0), 1023)) / 1023.f,
|
|
float(std::min<int>(std::max<int>(b, 0), 1023)) / 1023.f,
|
|
1.f);
|
|
|
|
r = static_cast<int>((76533 * y1 + 104905 * v + 32768) >> 16);
|
|
g = static_cast<int>((76533 * y1 - 25747 * u - 53425 * v + 32768) >> 16);
|
|
b = static_cast<int>((76533 * y1 + 132590 * u + 32768) >> 16);
|
|
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 1023)) / 1023.f,
|
|
float(std::min<int>(std::max<int>(g, 0), 1023)) / 1023.f,
|
|
float(std::min<int>(std::max<int>(b, 0), 1023)) / 1023.f,
|
|
1.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_Y216:
|
|
if (size >= sizeof(XMUSHORTN4))
|
|
{
|
|
const XMUSHORTN4 * __restrict sPtr = static_cast<const XMUSHORTN4*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUSHORTN4) + 1); icount += sizeof(XMUSHORTN4))
|
|
{
|
|
int64_t y0 = int64_t(sPtr->x) - 4096;
|
|
int64_t u = int64_t(sPtr->y) - 32768;
|
|
int64_t y1 = int64_t(sPtr->z) - 4096;
|
|
int64_t v = int64_t(sPtr->w) - 32768;
|
|
++sPtr;
|
|
|
|
// See Y416
|
|
auto r = static_cast<int>((76607 * y0 + 105006 * v + 32768) >> 16);
|
|
auto g = static_cast<int>((76607 * y0 - 25772 * u - 53477 * v + 32768) >> 16);
|
|
auto b = static_cast<int>((76607 * y0 + 132718 * u + 32768) >> 16);
|
|
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 65535)) / 65535.f,
|
|
float(std::min<int>(std::max<int>(g, 0), 65535)) / 65535.f,
|
|
float(std::min<int>(std::max<int>(b, 0), 65535)) / 65535.f,
|
|
1.f);
|
|
|
|
r = static_cast<int>((76607 * y1 + 105006 * v + 32768) >> 16);
|
|
g = static_cast<int>((76607 * y1 - 25772 * u - 53477 * v + 32768) >> 16);
|
|
b = static_cast<int>((76607 * y1 + 132718 * u + 32768) >> 16);
|
|
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 65535)) / 65535.f,
|
|
float(std::min<int>(std::max<int>(g, 0), 65535)) / 65535.f,
|
|
float(std::min<int>(std::max<int>(b, 0), 65535)) / 65535.f,
|
|
1.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_B4G4R4A4_UNORM:
|
|
if (size >= sizeof(XMUNIBBLE4))
|
|
{
|
|
static const XMVECTORF32 s_Scale = { { { 1.f / 15.f, 1.f / 15.f, 1.f / 15.f, 1.f / 15.f } } };
|
|
const XMUNIBBLE4 * __restrict sPtr = static_cast<const XMUNIBBLE4*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUNIBBLE4) + 1); icount += sizeof(XMUNIBBLE4))
|
|
{
|
|
XMVECTOR v = XMLoadUNibble4(sPtr++);
|
|
v = XMVectorMultiply(v, s_Scale);
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>(v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT:
|
|
// Xbox One specific 7e3 format
|
|
if (size >= sizeof(XMUDECN4))
|
|
{
|
|
const XMUDECN4 * __restrict sPtr = static_cast<const XMUDECN4*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4))
|
|
{
|
|
if (dPtr >= ePtr) break;
|
|
|
|
XMVECTORF32 vResult = { { {
|
|
FloatFrom7e3(sPtr->x),
|
|
FloatFrom7e3(sPtr->y),
|
|
FloatFrom7e3(sPtr->z),
|
|
static_cast<float>(sPtr->v >> 30) / 3.0f
|
|
} } };
|
|
|
|
++sPtr;
|
|
|
|
*(dPtr++) = vResult.v;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT:
|
|
// Xbox One specific 6e4 format
|
|
if (size >= sizeof(XMUDECN4))
|
|
{
|
|
const XMUDECN4 * __restrict sPtr = static_cast<const XMUDECN4*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4))
|
|
{
|
|
if (dPtr >= ePtr) break;
|
|
|
|
XMVECTORF32 vResult = { { {
|
|
FloatFrom6e4(sPtr->x),
|
|
FloatFrom6e4(sPtr->y),
|
|
FloatFrom6e4(sPtr->z),
|
|
static_cast<float>(sPtr->v >> 30) / 3.0f
|
|
} } };
|
|
|
|
++sPtr;
|
|
|
|
*(dPtr++) = vResult.v;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM:
|
|
// Xbox One specific format
|
|
LOAD_SCANLINE(XMXDECN4, XMLoadXDecN4)
|
|
|
|
case XBOX_DXGI_FORMAT_R4G4_UNORM:
|
|
// Xbox One specific format
|
|
if (size >= sizeof(uint8_t))
|
|
{
|
|
static const XMVECTORF32 s_Scale = { { { 1.f / 15.f, 1.f / 15.f, 0.f, 0.f } } };
|
|
const uint8_t * __restrict sPtr = static_cast<const uint8_t*>(pSource);
|
|
for (size_t icount = 0; icount < (size - sizeof(uint8_t) + 1); icount += sizeof(uint8_t))
|
|
{
|
|
XMUNIBBLE4 nibble;
|
|
nibble.v = static_cast<uint16_t>(*sPtr++);
|
|
XMVECTOR v = XMLoadUNibble4(&nibble);
|
|
v = XMVectorMultiply(v, s_Scale);
|
|
if (dPtr >= ePtr) break;
|
|
*(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1100);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
// We don't support the planar or palettized formats
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#undef LOAD_SCANLINE
|
|
#undef LOAD_SCANLINE3
|
|
#undef LOAD_SCANLINE2
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Stores an image row from standard RGBA XMVECTOR (aligned) array
|
|
//-------------------------------------------------------------------------------------
|
|
#define STORE_SCANLINE( type, func )\
|
|
if (size >= sizeof(type))\
|
|
{\
|
|
type * __restrict dPtr = reinterpret_cast<type*>(pDestination);\
|
|
for(size_t icount = 0; icount < (size - sizeof(type) + 1); icount += sizeof(type))\
|
|
{\
|
|
if (sPtr >= ePtr) break;\
|
|
func(dPtr++, *sPtr++);\
|
|
}\
|
|
return true; \
|
|
}\
|
|
return false;
|
|
|
|
_Use_decl_annotations_
|
|
bool DirectX::_StoreScanline(
|
|
void* pDestination,
|
|
size_t size,
|
|
DXGI_FORMAT format,
|
|
const XMVECTOR* pSource,
|
|
size_t count,
|
|
float threshold) noexcept
|
|
{
|
|
assert(pDestination && size > 0);
|
|
assert(pSource && count > 0 && ((reinterpret_cast<uintptr_t>(pSource) & 0xF) == 0));
|
|
assert(IsValid(format) && !IsTypeless(format) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format));
|
|
|
|
const XMVECTOR* __restrict sPtr = pSource;
|
|
if (!sPtr)
|
|
return false;
|
|
|
|
const XMVECTOR* ePtr = pSource + count;
|
|
|
|
switch (static_cast<int>(format))
|
|
{
|
|
case DXGI_FORMAT_R32G32B32A32_FLOAT:
|
|
STORE_SCANLINE(XMFLOAT4, XMStoreFloat4)
|
|
|
|
case DXGI_FORMAT_R32G32B32A32_UINT:
|
|
STORE_SCANLINE(XMUINT4, XMStoreUInt4)
|
|
|
|
case DXGI_FORMAT_R32G32B32A32_SINT:
|
|
STORE_SCANLINE(XMINT4, XMStoreSInt4)
|
|
|
|
case DXGI_FORMAT_R32G32B32_FLOAT:
|
|
STORE_SCANLINE(XMFLOAT3, XMStoreFloat3)
|
|
|
|
case DXGI_FORMAT_R32G32B32_UINT:
|
|
STORE_SCANLINE(XMUINT3, XMStoreUInt3)
|
|
|
|
case DXGI_FORMAT_R32G32B32_SINT:
|
|
STORE_SCANLINE(XMINT3, XMStoreSInt3)
|
|
|
|
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
|
if (size >= sizeof(XMHALF4))
|
|
{
|
|
XMHALF4* __restrict dPtr = static_cast<XMHALF4*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMHALF4) + 1); icount += sizeof(XMHALF4))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
XMVECTOR v = *sPtr++;
|
|
v = XMVectorClamp(v, g_HalfMin, g_HalfMax);
|
|
XMStoreHalf4(dPtr++, v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R16G16B16A16_UNORM:
|
|
STORE_SCANLINE(XMUSHORTN4, XMStoreUShortN4)
|
|
|
|
case DXGI_FORMAT_R16G16B16A16_UINT:
|
|
STORE_SCANLINE(XMUSHORT4, XMStoreUShort4)
|
|
|
|
case DXGI_FORMAT_R16G16B16A16_SNORM:
|
|
STORE_SCANLINE(XMSHORTN4, XMStoreShortN4)
|
|
|
|
case DXGI_FORMAT_R16G16B16A16_SINT:
|
|
STORE_SCANLINE(XMSHORT4, XMStoreShort4)
|
|
|
|
case DXGI_FORMAT_R32G32_FLOAT:
|
|
STORE_SCANLINE(XMFLOAT2, XMStoreFloat2)
|
|
|
|
case DXGI_FORMAT_R32G32_UINT:
|
|
STORE_SCANLINE(XMUINT2, XMStoreUInt2)
|
|
|
|
case DXGI_FORMAT_R32G32_SINT:
|
|
STORE_SCANLINE(XMINT2, XMStoreSInt2)
|
|
|
|
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
|
|
{
|
|
const size_t psize = sizeof(float) + sizeof(uint32_t);
|
|
if (size >= psize)
|
|
{
|
|
auto dPtr = static_cast<float*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - psize + 1); icount += psize)
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
XMFLOAT4 f;
|
|
XMStoreFloat4(&f, *sPtr++);
|
|
dPtr[0] = f.x;
|
|
auto ps8 = reinterpret_cast<uint8_t*>(&dPtr[1]);
|
|
ps8[0] = static_cast<uint8_t>(std::min<float>(255.f, std::max<float>(0.f, f.y)));
|
|
ps8[1] = ps8[2] = ps8[3] = 0;
|
|
dPtr += 2;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R10G10B10A2_UNORM:
|
|
STORE_SCANLINE(XMUDECN4, XMStoreUDecN4)
|
|
|
|
case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
|
|
STORE_SCANLINE(XMUDECN4, XMStoreUDecN4_XR)
|
|
|
|
case DXGI_FORMAT_R10G10B10A2_UINT:
|
|
STORE_SCANLINE(XMUDEC4, XMStoreUDec4)
|
|
|
|
case DXGI_FORMAT_R11G11B10_FLOAT:
|
|
STORE_SCANLINE(XMFLOAT3PK, XMStoreFloat3PK)
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
|
if (size >= sizeof(XMUBYTEN4))
|
|
{
|
|
XMUBYTEN4 * __restrict dPtr = static_cast<XMUBYTEN4*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
XMVECTOR v = XMVectorAdd(*sPtr++, g_8BitBias);
|
|
XMStoreUByteN4(dPtr++, v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_UINT:
|
|
STORE_SCANLINE(XMUBYTE4, XMStoreUByte4)
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_SNORM:
|
|
STORE_SCANLINE(XMBYTEN4, XMStoreByteN4)
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_SINT:
|
|
STORE_SCANLINE(XMBYTE4, XMStoreByte4)
|
|
|
|
case DXGI_FORMAT_R16G16_FLOAT:
|
|
if (size >= sizeof(XMHALF2))
|
|
{
|
|
XMHALF2* __restrict dPtr = static_cast<XMHALF2*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMHALF2) + 1); icount += sizeof(XMHALF2))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
XMVECTOR v = *sPtr++;
|
|
v = XMVectorClamp(v, g_HalfMin, g_HalfMax);
|
|
XMStoreHalf2(dPtr++, v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R16G16_UNORM:
|
|
STORE_SCANLINE(XMUSHORTN2, XMStoreUShortN2)
|
|
|
|
case DXGI_FORMAT_R16G16_UINT:
|
|
STORE_SCANLINE(XMUSHORT2, XMStoreUShort2)
|
|
|
|
case DXGI_FORMAT_R16G16_SNORM:
|
|
STORE_SCANLINE(XMSHORTN2, XMStoreShortN2)
|
|
|
|
case DXGI_FORMAT_R16G16_SINT:
|
|
STORE_SCANLINE(XMSHORT2, XMStoreShort2)
|
|
|
|
case DXGI_FORMAT_D32_FLOAT:
|
|
case DXGI_FORMAT_R32_FLOAT:
|
|
if (size >= sizeof(float))
|
|
{
|
|
float * __restrict dPtr = static_cast<float*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(float) + 1); icount += sizeof(float))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
XMStoreFloat(dPtr++, *(sPtr++));
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R32_UINT:
|
|
if (size >= sizeof(uint32_t))
|
|
{
|
|
uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
XMVECTOR v = XMConvertVectorFloatToUInt(*(sPtr++), 0);
|
|
XMStoreInt(dPtr++, v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R32_SINT:
|
|
if (size >= sizeof(int32_t))
|
|
{
|
|
uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(int32_t) + 1); icount += sizeof(int32_t))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
XMVECTOR v = XMConvertVectorFloatToInt(*(sPtr++), 0);
|
|
XMStoreInt(dPtr++, v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_D24_UNORM_S8_UINT:
|
|
if (size >= sizeof(uint32_t))
|
|
{
|
|
static const XMVECTORF32 clamp = { { { 1.f, 255.f, 0.f, 0.f } } };
|
|
XMVECTOR zero = XMVectorZero();
|
|
auto dPtr = static_cast<uint32_t*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
XMFLOAT4 f;
|
|
XMStoreFloat4(&f, XMVectorClamp(*sPtr++, zero, clamp));
|
|
*dPtr++ = (static_cast<uint32_t>(f.x * 16777215.f) & 0xFFFFFF)
|
|
| ((static_cast<uint32_t>(f.y) & 0xFF) << 24);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R8G8_UNORM:
|
|
STORE_SCANLINE(XMUBYTEN2, XMStoreUByteN2)
|
|
|
|
case DXGI_FORMAT_R8G8_UINT:
|
|
STORE_SCANLINE(XMUBYTE2, XMStoreUByte2)
|
|
|
|
case DXGI_FORMAT_R8G8_SNORM:
|
|
STORE_SCANLINE(XMBYTEN2, XMStoreByteN2)
|
|
|
|
case DXGI_FORMAT_R8G8_SINT:
|
|
STORE_SCANLINE(XMBYTE2, XMStoreByte2)
|
|
|
|
case DXGI_FORMAT_R16_FLOAT:
|
|
if (size >= sizeof(HALF))
|
|
{
|
|
HALF * __restrict dPtr = static_cast<HALF*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(HALF) + 1); icount += sizeof(HALF))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
float v = XMVectorGetX(*sPtr++);
|
|
v = std::max<float>(std::min<float>(v, 65504.f), -65504.f);
|
|
*(dPtr++) = XMConvertFloatToHalf(v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_D16_UNORM:
|
|
case DXGI_FORMAT_R16_UNORM:
|
|
if (size >= sizeof(uint16_t))
|
|
{
|
|
uint16_t * __restrict dPtr = static_cast<uint16_t*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(uint16_t) + 1); icount += sizeof(uint16_t))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
float v = XMVectorGetX(*sPtr++);
|
|
v = std::max<float>(std::min<float>(v, 1.f), 0.f);
|
|
*(dPtr++) = static_cast<uint16_t>(v*65535.f + 0.5f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R16_UINT:
|
|
if (size >= sizeof(uint16_t))
|
|
{
|
|
uint16_t * __restrict dPtr = static_cast<uint16_t*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(uint16_t) + 1); icount += sizeof(uint16_t))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
float v = XMVectorGetX(*sPtr++);
|
|
v = std::max<float>(std::min<float>(v, 65535.f), 0.f);
|
|
*(dPtr++) = static_cast<uint16_t>(v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R16_SNORM:
|
|
if (size >= sizeof(int16_t))
|
|
{
|
|
int16_t * __restrict dPtr = static_cast<int16_t*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(int16_t) + 1); icount += sizeof(int16_t))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
float v = XMVectorGetX(*sPtr++);
|
|
v = std::max<float>(std::min<float>(v, 1.f), -1.f);
|
|
*(dPtr++) = static_cast<int16_t>(v * 32767.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R16_SINT:
|
|
if (size >= sizeof(int16_t))
|
|
{
|
|
int16_t * __restrict dPtr = static_cast<int16_t*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(int16_t) + 1); icount += sizeof(int16_t))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
float v = XMVectorGetX(*sPtr++);
|
|
v = std::max<float>(std::min<float>(v, 32767.f), -32767.f);
|
|
*(dPtr++) = static_cast<int16_t>(v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R8_UNORM:
|
|
if (size >= sizeof(uint8_t))
|
|
{
|
|
uint8_t * __restrict dPtr = static_cast<uint8_t*>(pDestination);
|
|
for (size_t icount = 0; icount < size; icount += sizeof(uint8_t))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
float v = XMVectorGetX(*sPtr++);
|
|
v = std::max<float>(std::min<float>(v, 1.f), 0.f);
|
|
*(dPtr++) = static_cast<uint8_t>(v * 255.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R8_UINT:
|
|
if (size >= sizeof(uint8_t))
|
|
{
|
|
uint8_t * __restrict dPtr = static_cast<uint8_t*>(pDestination);
|
|
for (size_t icount = 0; icount < size; icount += sizeof(uint8_t))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
float v = XMVectorGetX(*sPtr++);
|
|
v = std::max<float>(std::min<float>(v, 255.f), 0.f);
|
|
*(dPtr++) = static_cast<uint8_t>(v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R8_SNORM:
|
|
if (size >= sizeof(int8_t))
|
|
{
|
|
int8_t * __restrict dPtr = static_cast<int8_t*>(pDestination);
|
|
for (size_t icount = 0; icount < size; icount += sizeof(int8_t))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
float v = XMVectorGetX(*sPtr++);
|
|
v = std::max<float>(std::min<float>(v, 1.f), -1.f);
|
|
*(dPtr++) = static_cast<int8_t>(v * 127.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R8_SINT:
|
|
if (size >= sizeof(int8_t))
|
|
{
|
|
int8_t * __restrict dPtr = static_cast<int8_t*>(pDestination);
|
|
for (size_t icount = 0; icount < size; icount += sizeof(int8_t))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
float v = XMVectorGetX(*sPtr++);
|
|
v = std::max<float>(std::min<float>(v, 127.f), -127.f);
|
|
*(dPtr++) = static_cast<int8_t>(v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_A8_UNORM:
|
|
if (size >= sizeof(uint8_t))
|
|
{
|
|
uint8_t * __restrict dPtr = static_cast<uint8_t*>(pDestination);
|
|
for (size_t icount = 0; icount < size; icount += sizeof(uint8_t))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
float v = XMVectorGetW(*sPtr++);
|
|
v = std::max<float>(std::min<float>(v, 1.f), 0.f);
|
|
*(dPtr++) = static_cast<uint8_t>(v * 255.f);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R1_UNORM:
|
|
if (size >= sizeof(uint8_t))
|
|
{
|
|
uint8_t * __restrict dPtr = static_cast<uint8_t*>(pDestination);
|
|
for (size_t icount = 0; icount < size; icount += sizeof(uint8_t))
|
|
{
|
|
uint8_t pixels = 0;
|
|
for (size_t bcount = 8; bcount > 0; --bcount)
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
float v = XMVectorGetX(*sPtr++);
|
|
|
|
// Absolute thresholding generally doesn't give good results for all images
|
|
// Picking the 'right' threshold automatically requires whole-image analysis
|
|
|
|
if (v > 0.25f)
|
|
pixels |= 1 << (bcount - 1);
|
|
}
|
|
*(dPtr++) = pixels;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
|
|
STORE_SCANLINE(XMFLOAT3SE, StoreFloat3SE)
|
|
|
|
case DXGI_FORMAT_R8G8_B8G8_UNORM:
|
|
if (size >= sizeof(XMUBYTEN4))
|
|
{
|
|
XMUBYTEN4 * __restrict dPtr = static_cast<XMUBYTEN4*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
XMVECTOR v0 = *sPtr++;
|
|
XMVECTOR v1 = (sPtr < ePtr) ? XMVectorSplatY(*sPtr++) : XMVectorZero();
|
|
XMVECTOR v = XMVectorSelect(v1, v0, g_XMSelect1110);
|
|
v = XMVectorAdd(v, g_8BitBias);
|
|
XMStoreUByteN4(dPtr++, v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_G8R8_G8B8_UNORM:
|
|
if (size >= sizeof(XMUBYTEN4))
|
|
{
|
|
static XMVECTORU32 select1101 = { { { XM_SELECT_1, XM_SELECT_1, XM_SELECT_0, XM_SELECT_1 } } };
|
|
|
|
XMUBYTEN4 * __restrict dPtr = static_cast<XMUBYTEN4*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
XMVECTOR v0 = XMVectorSwizzle<1, 0, 3, 2>(*sPtr++);
|
|
XMVECTOR v1 = (sPtr < ePtr) ? XMVectorSplatY(*sPtr++) : XMVectorZero();
|
|
XMVECTOR v = XMVectorSelect(v1, v0, select1101);
|
|
v = XMVectorAdd(v, g_8BitBias);
|
|
XMStoreUByteN4(dPtr++, v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_B5G6R5_UNORM:
|
|
if (size >= sizeof(XMU565))
|
|
{
|
|
static const XMVECTORF32 s_Scale = { { { 31.f, 63.f, 31.f, 1.f } } };
|
|
XMU565 * __restrict dPtr = static_cast<XMU565*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMU565) + 1); icount += sizeof(XMU565))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(*sPtr++);
|
|
v = XMVectorMultiply(v, s_Scale);
|
|
XMStoreU565(dPtr++, v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_B5G5R5A1_UNORM:
|
|
if (size >= sizeof(XMU555))
|
|
{
|
|
static const XMVECTORF32 s_Scale = { { { 31.f, 31.f, 31.f, 1.f } } };
|
|
XMU555 * __restrict dPtr = static_cast<XMU555*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMU555) + 1); icount += sizeof(XMU555))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(*sPtr++);
|
|
v = XMVectorMultiply(v, s_Scale);
|
|
XMStoreU555(dPtr, v);
|
|
dPtr->w = (XMVectorGetW(v) > threshold) ? 1u : 0u;
|
|
++dPtr;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
|
|
if (size >= sizeof(XMUBYTEN4))
|
|
{
|
|
XMUBYTEN4 * __restrict dPtr = static_cast<XMUBYTEN4*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(*sPtr++);
|
|
v = XMVectorAdd(v, g_8BitBias);
|
|
XMStoreUByteN4(dPtr++, v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
|
|
if (size >= sizeof(XMUBYTEN4))
|
|
{
|
|
XMUBYTEN4 * __restrict dPtr = static_cast<XMUBYTEN4*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
XMVECTOR v = XMVectorPermute<2, 1, 0, 7>(*sPtr++, g_XMIdentityR3);
|
|
v = XMVectorAdd(v, g_8BitBias);
|
|
XMStoreUByteN4(dPtr++, v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_AYUV:
|
|
if (size >= sizeof(XMUBYTEN4))
|
|
{
|
|
XMUBYTEN4 * __restrict dPtr = static_cast<XMUBYTEN4*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
|
|
XMUBYTEN4 rgba;
|
|
XMStoreUByteN4(&rgba, *sPtr++);
|
|
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd206750.aspx
|
|
|
|
// Y = 0.2568R + 0.5041G + 0.1001B + 16
|
|
// Cb = -0.1482R - 0.2910G + 0.4392B + 128
|
|
// Cr = 0.4392R - 0.3678G - 0.0714B + 128
|
|
|
|
int y = ((66 * rgba.x + 129 * rgba.y + 25 * rgba.z + 128) >> 8) + 16;
|
|
int u = ((-38 * rgba.x - 74 * rgba.y + 112 * rgba.z + 128) >> 8) + 128;
|
|
int v = ((112 * rgba.x - 94 * rgba.y - 18 * rgba.z + 128) >> 8) + 128;
|
|
|
|
dPtr->x = static_cast<uint8_t>(std::min<int>(std::max<int>(v, 0), 255));
|
|
dPtr->y = static_cast<uint8_t>(std::min<int>(std::max<int>(u, 0), 255));
|
|
dPtr->z = static_cast<uint8_t>(std::min<int>(std::max<int>(y, 0), 255));
|
|
dPtr->w = rgba.w;
|
|
++dPtr;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_Y410:
|
|
if (size >= sizeof(XMUDECN4))
|
|
{
|
|
XMUDECN4 * __restrict dPtr = static_cast<XMUDECN4*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
|
|
XMUDECN4 rgba;
|
|
XMStoreUDecN4(&rgba, *sPtr++);
|
|
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb970578.aspx
|
|
|
|
// Y = 0.2560R + 0.5027G + 0.0998B + 64
|
|
// Cb = -0.1478R - 0.2902G + 0.4379B + 512
|
|
// Cr = 0.4379R - 0.3667G - 0.0712B + 512
|
|
|
|
int64_t r = rgba.x;
|
|
int64_t g = rgba.y;
|
|
int64_t b = rgba.z;
|
|
|
|
int y = static_cast<int>((16780 * r + 32942 * g + 6544 * b + 32768) >> 16) + 64;
|
|
int u = static_cast<int>((-9683 * r - 19017 * g + 28700 * b + 32768) >> 16) + 512;
|
|
int v = static_cast<int>((28700 * r - 24033 * g - 4667 * b + 32768) >> 16) + 512;
|
|
|
|
dPtr->x = static_cast<uint32_t>(std::min<int>(std::max<int>(u, 0), 1023));
|
|
dPtr->y = static_cast<uint32_t>(std::min<int>(std::max<int>(y, 0), 1023));
|
|
dPtr->z = static_cast<uint32_t>(std::min<int>(std::max<int>(v, 0), 1023));
|
|
dPtr->w = rgba.w;
|
|
++dPtr;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_Y416:
|
|
if (size >= sizeof(XMUSHORTN4))
|
|
{
|
|
XMUSHORTN4 * __restrict dPtr = static_cast<XMUSHORTN4*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUSHORTN4) + 1); icount += sizeof(XMUSHORTN4))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
|
|
XMUSHORTN4 rgba;
|
|
XMStoreUShortN4(&rgba, *sPtr++);
|
|
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb970578.aspx
|
|
|
|
// Y = 0.2558R + 0.5022G + 0.0998B + 4096
|
|
// Cb = -0.1476R - 0.2899G + 0.4375B + 32768
|
|
// Cr = 0.4375R - 0.3664G - 0.0711B + 32768
|
|
|
|
int64_t r = int64_t(rgba.x);
|
|
int64_t g = int64_t(rgba.y);
|
|
int64_t b = int64_t(rgba.z);
|
|
|
|
int y = static_cast<int>((16763 * r + 32910 * g + 6537 * b + 32768) >> 16) + 4096;
|
|
int u = static_cast<int>((-9674 * r - 18998 * g + 28672 * b + 32768) >> 16) + 32768;
|
|
int v = static_cast<int>((28672 * r - 24010 * g - 4662 * b + 32768) >> 16) + 32768;
|
|
|
|
dPtr->x = static_cast<uint16_t>(std::min<int>(std::max<int>(u, 0), 65535));
|
|
dPtr->y = static_cast<uint16_t>(std::min<int>(std::max<int>(y, 0), 65535));
|
|
dPtr->z = static_cast<uint16_t>(std::min<int>(std::max<int>(v, 0), 65535));
|
|
dPtr->w = rgba.w;
|
|
++dPtr;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_YUY2:
|
|
if (size >= sizeof(XMUBYTEN4))
|
|
{
|
|
XMUBYTEN4 * __restrict dPtr = static_cast<XMUBYTEN4*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
|
|
XMUBYTEN4 rgb1;
|
|
XMStoreUByteN4(&rgb1, *sPtr++);
|
|
|
|
// See AYUV
|
|
int y0 = ((66 * rgb1.x + 129 * rgb1.y + 25 * rgb1.z + 128) >> 8) + 16;
|
|
int u0 = ((-38 * rgb1.x - 74 * rgb1.y + 112 * rgb1.z + 128) >> 8) + 128;
|
|
int v0 = ((112 * rgb1.x - 94 * rgb1.y - 18 * rgb1.z + 128) >> 8) + 128;
|
|
|
|
XMUBYTEN4 rgb2;
|
|
if (sPtr < ePtr)
|
|
{
|
|
XMStoreUByteN4(&rgb2, *sPtr++);
|
|
}
|
|
else
|
|
{
|
|
rgb2.x = rgb2.y = rgb2.z = rgb2.w = 0;
|
|
}
|
|
|
|
int y1 = ((66 * rgb2.x + 129 * rgb2.y + 25 * rgb2.z + 128) >> 8) + 16;
|
|
int u1 = ((-38 * rgb2.x - 74 * rgb2.y + 112 * rgb2.z + 128) >> 8) + 128;
|
|
int v1 = ((112 * rgb2.x - 94 * rgb2.y - 18 * rgb2.z + 128) >> 8) + 128;
|
|
|
|
dPtr->x = static_cast<uint8_t>(std::min<int>(std::max<int>(y0, 0), 255));
|
|
dPtr->y = static_cast<uint8_t>(std::min<int>(std::max<int>((u0 + u1) >> 1, 0), 255));
|
|
dPtr->z = static_cast<uint8_t>(std::min<int>(std::max<int>(y1, 0), 255));
|
|
dPtr->w = static_cast<uint8_t>(std::min<int>(std::max<int>((v0 + v1) >> 1, 0), 255));
|
|
++dPtr;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_Y210:
|
|
// Same as Y216 with least significant 6 bits set to zero
|
|
if (size >= sizeof(XMUSHORTN4))
|
|
{
|
|
XMUSHORTN4 * __restrict dPtr = static_cast<XMUSHORTN4*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUSHORTN4) + 1); icount += sizeof(XMUSHORTN4))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
|
|
XMUDECN4 rgb1;
|
|
XMStoreUDecN4(&rgb1, *sPtr++);
|
|
|
|
// See Y410
|
|
int64_t r = rgb1.x;
|
|
int64_t g = rgb1.y;
|
|
int64_t b = rgb1.z;
|
|
|
|
int y0 = static_cast<int>((16780 * r + 32942 * g + 6544 * b + 32768) >> 16) + 64;
|
|
int u0 = static_cast<int>((-9683 * r - 19017 * g + 28700 * b + 32768) >> 16) + 512;
|
|
int v0 = static_cast<int>((28700 * r - 24033 * g - 4667 * b + 32768) >> 16) + 512;
|
|
|
|
XMUDECN4 rgb2;
|
|
if (sPtr < ePtr)
|
|
{
|
|
XMStoreUDecN4(&rgb2, *sPtr++);
|
|
}
|
|
else
|
|
{
|
|
rgb2.x = rgb2.y = rgb2.z = rgb2.w = 0;
|
|
}
|
|
|
|
r = rgb2.x;
|
|
g = rgb2.y;
|
|
b = rgb2.z;
|
|
|
|
int y1 = static_cast<int>((16780 * r + 32942 * g + 6544 * b + 32768) >> 16) + 64;
|
|
int u1 = static_cast<int>((-9683 * r - 19017 * g + 28700 * b + 32768) >> 16) + 512;
|
|
int v1 = static_cast<int>((28700 * r - 24033 * g - 4667 * b + 32768) >> 16) + 512;
|
|
|
|
dPtr->x = static_cast<uint16_t>(std::min<int>(std::max<int>(y0, 0), 1023) << 6);
|
|
dPtr->y = static_cast<uint16_t>(std::min<int>(std::max<int>((u0 + u1) >> 1, 0), 1023) << 6);
|
|
dPtr->z = static_cast<uint16_t>(std::min<int>(std::max<int>(y1, 0), 1023) << 6);
|
|
dPtr->w = static_cast<uint16_t>(std::min<int>(std::max<int>((v0 + v1) >> 1, 0), 1023) << 6);
|
|
++dPtr;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_Y216:
|
|
if (size >= sizeof(XMUSHORTN4))
|
|
{
|
|
XMUSHORTN4 * __restrict dPtr = static_cast<XMUSHORTN4*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUSHORTN4) + 1); icount += sizeof(XMUSHORTN4))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
|
|
XMUSHORTN4 rgb1;
|
|
XMStoreUShortN4(&rgb1, *sPtr++);
|
|
|
|
// See Y416
|
|
int64_t r = int64_t(rgb1.x);
|
|
int64_t g = int64_t(rgb1.y);
|
|
int64_t b = int64_t(rgb1.z);
|
|
|
|
int y0 = static_cast<int>((16763 * r + 32910 * g + 6537 * b + 32768) >> 16) + 4096;
|
|
int u0 = static_cast<int>((-9674 * r - 18998 * g + 28672 * b + 32768) >> 16) + 32768;
|
|
int v0 = static_cast<int>((28672 * r - 24010 * g - 4662 * b + 32768) >> 16) + 32768;
|
|
|
|
XMUSHORTN4 rgb2;
|
|
if (sPtr < ePtr)
|
|
{
|
|
XMStoreUShortN4(&rgb2, *sPtr++);
|
|
}
|
|
else
|
|
{
|
|
rgb2.x = rgb2.y = rgb2.z = rgb2.w = 0;
|
|
}
|
|
|
|
r = int64_t(rgb2.x);
|
|
g = int64_t(rgb2.y);
|
|
b = int64_t(rgb2.z);
|
|
|
|
int y1 = static_cast<int>((16763 * r + 32910 * g + 6537 * b + 32768) >> 16) + 4096;
|
|
int u1 = static_cast<int>((-9674 * r - 18998 * g + 28672 * b + 32768) >> 16) + 32768;
|
|
int v1 = static_cast<int>((28672 * r - 24010 * g - 4662 * b + 32768) >> 16) + 32768;
|
|
|
|
dPtr->x = static_cast<uint16_t>(std::min<int>(std::max<int>(y0, 0), 65535));
|
|
dPtr->y = static_cast<uint16_t>(std::min<int>(std::max<int>((u0 + u1) >> 1, 0), 65535));
|
|
dPtr->z = static_cast<uint16_t>(std::min<int>(std::max<int>(y1, 0), 65535));
|
|
dPtr->w = static_cast<uint16_t>(std::min<int>(std::max<int>((v0 + v1) >> 1, 0), 65535));
|
|
++dPtr;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_B4G4R4A4_UNORM:
|
|
if (size >= sizeof(XMUNIBBLE4))
|
|
{
|
|
static const XMVECTORF32 s_Scale = { { { 15.f, 15.f, 15.f, 15.f } } };
|
|
XMUNIBBLE4 * __restrict dPtr = static_cast<XMUNIBBLE4*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUNIBBLE4) + 1); icount += sizeof(XMUNIBBLE4))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(*sPtr++);
|
|
v = XMVectorMultiply(v, s_Scale);
|
|
XMStoreUNibble4(dPtr++, v);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT:
|
|
// Xbox One specific 7e3 format with alpha
|
|
if (size >= sizeof(XMUDECN4))
|
|
{
|
|
static const XMVECTORF32 Scale = { { { 1.0f, 1.0f, 1.0f, 3.0f } } };
|
|
static const XMVECTORF32 C = { { { 31.875f, 31.875f, 31.875f, 3.f } } };
|
|
|
|
XMUDECN4 * __restrict dPtr = static_cast<XMUDECN4*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
|
|
XMVECTOR V = XMVectorMultiply(*sPtr++, Scale);
|
|
V = XMVectorClamp(V, g_XMZero, C);
|
|
|
|
XMFLOAT4A tmp;
|
|
XMStoreFloat4A(&tmp, V);
|
|
|
|
dPtr->x = FloatTo7e3(tmp.x);
|
|
dPtr->y = FloatTo7e3(tmp.y);
|
|
dPtr->z = FloatTo7e3(tmp.z);
|
|
dPtr->w = static_cast<uint32_t>(tmp.w);
|
|
++dPtr;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT:
|
|
// Xbox One specific 6e4 format with alpha
|
|
if (size >= sizeof(XMUDECN4))
|
|
{
|
|
static const XMVECTORF32 Scale = { { { 1.0f, 1.0f, 1.0f, 3.0f } } };
|
|
static const XMVECTORF32 C = { { { 508.f, 508.f, 508.f, 3.f } } };
|
|
|
|
XMUDECN4 * __restrict dPtr = static_cast<XMUDECN4*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
|
|
XMVECTOR V = XMVectorMultiply(*sPtr++, Scale);
|
|
V = XMVectorClamp(V, g_XMZero, C);
|
|
|
|
XMFLOAT4A tmp;
|
|
XMStoreFloat4A(&tmp, V);
|
|
|
|
dPtr->x = FloatTo6e4(tmp.x);
|
|
dPtr->y = FloatTo6e4(tmp.y);
|
|
dPtr->z = FloatTo6e4(tmp.z);
|
|
dPtr->w = static_cast<uint32_t>(tmp.w);
|
|
++dPtr;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM:
|
|
// Xbox One specific format
|
|
STORE_SCANLINE(XMXDECN4, XMStoreXDecN4)
|
|
|
|
case XBOX_DXGI_FORMAT_R4G4_UNORM:
|
|
// Xbox One specific format
|
|
if (size >= sizeof(uint8_t))
|
|
{
|
|
static const XMVECTORF32 s_Scale = { { { 15.f, 15.f, 0.f, 0.f } } };
|
|
uint8_t * __restrict dPtr = static_cast<uint8_t*>(pDestination);
|
|
for (size_t icount = 0; icount < (size - sizeof(uint8_t) + 1); icount += sizeof(uint8_t))
|
|
{
|
|
if (sPtr >= ePtr) break;
|
|
XMVECTOR v = XMVectorMultiply(*sPtr++, s_Scale);
|
|
|
|
XMUNIBBLE4 nibble;
|
|
XMStoreUNibble4(&nibble, v);
|
|
*dPtr = static_cast<uint8_t>(nibble.v);
|
|
++dPtr;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
// We don't support the planar or palettized formats
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#undef STORE_SCANLINE
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Convert DXGI image to/from GUID_WICPixelFormat128bppRGBAFloat (no range conversions)
|
|
//-------------------------------------------------------------------------------------
|
|
_Use_decl_annotations_
|
|
HRESULT DirectX::_ConvertToR32G32B32A32(const Image& srcImage, ScratchImage& image) noexcept
|
|
{
|
|
if (!srcImage.pixels)
|
|
return E_POINTER;
|
|
|
|
HRESULT hr = image.Initialize2D(DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.width, srcImage.height, 1, 1);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
const Image *img = image.GetImage(0, 0, 0);
|
|
if (!img)
|
|
{
|
|
image.Release();
|
|
return E_POINTER;
|
|
}
|
|
|
|
uint8_t* pDest = img->pixels;
|
|
if (!pDest)
|
|
{
|
|
image.Release();
|
|
return E_POINTER;
|
|
}
|
|
|
|
const uint8_t *pSrc = srcImage.pixels;
|
|
for (size_t h = 0; h < srcImage.height; ++h)
|
|
{
|
|
if (!_LoadScanline(reinterpret_cast<XMVECTOR*>(pDest), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format))
|
|
{
|
|
image.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
pSrc += srcImage.rowPitch;
|
|
pDest += img->rowPitch;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
_Use_decl_annotations_
|
|
HRESULT DirectX::_ConvertFromR32G32B32A32(const Image& srcImage, const Image& destImage) noexcept
|
|
{
|
|
assert(srcImage.format == DXGI_FORMAT_R32G32B32A32_FLOAT);
|
|
|
|
if (!srcImage.pixels || !destImage.pixels)
|
|
return E_POINTER;
|
|
|
|
if (srcImage.width != destImage.width || srcImage.height != destImage.height)
|
|
return E_FAIL;
|
|
|
|
const uint8_t *pSrc = srcImage.pixels;
|
|
uint8_t* pDest = destImage.pixels;
|
|
|
|
for (size_t h = 0; h < srcImage.height; ++h)
|
|
{
|
|
if (!_StoreScanline(pDest, destImage.rowPitch, destImage.format, reinterpret_cast<const XMVECTOR*>(pSrc), srcImage.width))
|
|
return E_FAIL;
|
|
|
|
pSrc += srcImage.rowPitch;
|
|
pDest += destImage.rowPitch;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
_Use_decl_annotations_
|
|
HRESULT DirectX::_ConvertFromR32G32B32A32(const Image& srcImage, DXGI_FORMAT format, ScratchImage& image) noexcept
|
|
{
|
|
if (!srcImage.pixels)
|
|
return E_POINTER;
|
|
|
|
HRESULT hr = image.Initialize2D(format, srcImage.width, srcImage.height, 1, 1);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
const Image *img = image.GetImage(0, 0, 0);
|
|
if (!img)
|
|
{
|
|
image.Release();
|
|
return E_POINTER;
|
|
}
|
|
|
|
hr = _ConvertFromR32G32B32A32(srcImage, *img);
|
|
if (FAILED(hr))
|
|
{
|
|
image.Release();
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
_Use_decl_annotations_
|
|
HRESULT DirectX::_ConvertFromR32G32B32A32(
|
|
const Image* srcImages,
|
|
size_t nimages,
|
|
const TexMetadata& metadata,
|
|
DXGI_FORMAT format,
|
|
ScratchImage& result) noexcept
|
|
{
|
|
if (!srcImages)
|
|
return E_POINTER;
|
|
|
|
result.Release();
|
|
|
|
assert(metadata.format == DXGI_FORMAT_R32G32B32A32_FLOAT);
|
|
|
|
TexMetadata mdata2 = metadata;
|
|
mdata2.format = format;
|
|
HRESULT hr = result.Initialize(mdata2);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
if (nimages != result.GetImageCount())
|
|
{
|
|
result.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
const Image* dest = result.GetImages();
|
|
if (!dest)
|
|
{
|
|
result.Release();
|
|
return E_POINTER;
|
|
}
|
|
|
|
for (size_t index = 0; index < nimages; ++index)
|
|
{
|
|
const Image& src = srcImages[index];
|
|
const Image& dst = dest[index];
|
|
|
|
assert(src.format == DXGI_FORMAT_R32G32B32A32_FLOAT);
|
|
assert(dst.format == format);
|
|
|
|
if (src.width != dst.width || src.height != dst.height)
|
|
{
|
|
result.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
const uint8_t* pSrc = src.pixels;
|
|
uint8_t* pDest = dst.pixels;
|
|
if (!pSrc || !pDest)
|
|
{
|
|
result.Release();
|
|
return E_POINTER;
|
|
}
|
|
|
|
for (size_t h = 0; h < src.height; ++h)
|
|
{
|
|
if (!_StoreScanline(pDest, dst.rowPitch, format, reinterpret_cast<const XMVECTOR*>(pSrc), src.width))
|
|
{
|
|
result.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
pSrc += src.rowPitch;
|
|
pDest += dst.rowPitch;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Convert DXGI image to/from GUID_WICPixelFormat64bppRGBAHalf (no range conversions)
|
|
//-------------------------------------------------------------------------------------
|
|
_Use_decl_annotations_
|
|
HRESULT DirectX::_ConvertToR16G16B16A16(const Image& srcImage, ScratchImage& image) noexcept
|
|
{
|
|
if (!srcImage.pixels)
|
|
return E_POINTER;
|
|
|
|
HRESULT hr = image.Initialize2D(DXGI_FORMAT_R16G16B16A16_FLOAT, srcImage.width, srcImage.height, 1, 1);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
ScopedAlignedArrayXMVECTOR scanline(static_cast<XMVECTOR*>(AllocateVectorAligned((sizeof(XMVECTOR) * srcImage.width))));
|
|
if (!scanline)
|
|
{
|
|
image.Release();
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
const Image *img = image.GetImage(0, 0, 0);
|
|
if (!img)
|
|
{
|
|
image.Release();
|
|
return E_POINTER;
|
|
}
|
|
|
|
uint8_t* pDest = img->pixels;
|
|
if (!pDest)
|
|
{
|
|
image.Release();
|
|
return E_POINTER;
|
|
}
|
|
|
|
const uint8_t *pSrc = srcImage.pixels;
|
|
for (size_t h = 0; h < srcImage.height; ++h)
|
|
{
|
|
if (!_LoadScanline(scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format))
|
|
{
|
|
image.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
XMConvertFloatToHalfStream(
|
|
reinterpret_cast<HALF*>(pDest), sizeof(HALF),
|
|
reinterpret_cast<float*>(scanline.get()), sizeof(float),
|
|
srcImage.width * 4);
|
|
|
|
pSrc += srcImage.rowPitch;
|
|
pDest += img->rowPitch;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
_Use_decl_annotations_
|
|
HRESULT DirectX::_ConvertFromR16G16B16A16(const Image& srcImage, const Image& destImage) noexcept
|
|
{
|
|
assert(srcImage.format == DXGI_FORMAT_R16G16B16A16_FLOAT);
|
|
|
|
if (!srcImage.pixels || !destImage.pixels)
|
|
return E_POINTER;
|
|
|
|
if (srcImage.width != destImage.width || srcImage.height != destImage.height)
|
|
return E_FAIL;
|
|
|
|
ScopedAlignedArrayXMVECTOR scanline(static_cast<XMVECTOR*>(AllocateVectorAligned((sizeof(XMVECTOR) * srcImage.width))));
|
|
if (!scanline)
|
|
return E_OUTOFMEMORY;
|
|
|
|
const uint8_t *pSrc = srcImage.pixels;
|
|
uint8_t* pDest = destImage.pixels;
|
|
|
|
for (size_t h = 0; h < srcImage.height; ++h)
|
|
{
|
|
XMConvertHalfToFloatStream(
|
|
reinterpret_cast<float*>(scanline.get()), sizeof(float),
|
|
reinterpret_cast<const HALF*>(pSrc), sizeof(HALF),
|
|
srcImage.width * 4);
|
|
|
|
if (!_StoreScanline(pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width))
|
|
return E_FAIL;
|
|
|
|
pSrc += srcImage.rowPitch;
|
|
pDest += destImage.rowPitch;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Convert from Linear RGB to sRGB
|
|
//
|
|
// if C_linear <= 0.0031308 -> C_srgb = 12.92 * C_linear
|
|
// if C_linear > 0.0031308 -> C_srgb = ( 1 + a ) * pow( C_Linear, 1 / 2.4 ) - a
|
|
// where a = 0.055
|
|
//-------------------------------------------------------------------------------------
|
|
_Use_decl_annotations_
|
|
bool DirectX::_StoreScanlineLinear(
|
|
void* pDestination,
|
|
size_t size,
|
|
DXGI_FORMAT format,
|
|
XMVECTOR* pSource,
|
|
size_t count,
|
|
TEX_FILTER_FLAGS flags,
|
|
float threshold) noexcept
|
|
{
|
|
assert(pDestination && size > 0);
|
|
assert(pSource && count > 0 && ((reinterpret_cast<uintptr_t>(pSource) & 0xF) == 0));
|
|
assert(IsValid(format) && !IsTypeless(format) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format));
|
|
|
|
switch (format)
|
|
{
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
|
|
flags |= TEX_FILTER_SRGB;
|
|
break;
|
|
|
|
case DXGI_FORMAT_R32G32B32A32_FLOAT:
|
|
case DXGI_FORMAT_R32G32B32_FLOAT:
|
|
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
|
case DXGI_FORMAT_R16G16B16A16_UNORM:
|
|
case DXGI_FORMAT_R32G32_FLOAT:
|
|
case DXGI_FORMAT_R10G10B10A2_UNORM:
|
|
case DXGI_FORMAT_R11G11B10_FLOAT:
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
|
case DXGI_FORMAT_R16G16_FLOAT:
|
|
case DXGI_FORMAT_R16G16_UNORM:
|
|
case DXGI_FORMAT_R32_FLOAT:
|
|
case DXGI_FORMAT_R8G8_UNORM:
|
|
case DXGI_FORMAT_R16_FLOAT:
|
|
case DXGI_FORMAT_R16_UNORM:
|
|
case DXGI_FORMAT_R8_UNORM:
|
|
case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
|
|
case DXGI_FORMAT_R8G8_B8G8_UNORM:
|
|
case DXGI_FORMAT_G8R8_G8B8_UNORM:
|
|
case DXGI_FORMAT_B5G6R5_UNORM:
|
|
case DXGI_FORMAT_B5G5R5A1_UNORM:
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
|
case DXGI_FORMAT_B4G4R4A4_UNORM:
|
|
break;
|
|
|
|
default:
|
|
// can't treat A8, XR, Depth, SNORM, UINT, or SINT as sRGB
|
|
flags &= ~TEX_FILTER_SRGB;
|
|
break;
|
|
}
|
|
|
|
// sRGB output processing (Linear RGB -> sRGB)
|
|
if (flags & TEX_FILTER_SRGB_OUT)
|
|
{
|
|
// To avoid the need for another temporary scanline buffer, we allow this function to overwrite the source buffer in-place
|
|
// Given the intended usage in the filtering routines, this is not a problem.
|
|
XMVECTOR* ptr = pSource;
|
|
for (size_t i = 0; i < count; ++i, ++ptr)
|
|
{
|
|
*ptr = XMColorRGBToSRGB(*ptr);
|
|
}
|
|
}
|
|
|
|
return _StoreScanline(pDestination, size, format, pSource, count, threshold);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Convert from sRGB to Linear RGB
|
|
//
|
|
// if C_srgb <= 0.04045 -> C_linear = C_srgb / 12.92
|
|
// if C_srgb > 0.04045 -> C_linear = pow( ( C_srgb + a ) / ( 1 + a ), 2.4 )
|
|
// where a = 0.055
|
|
//-------------------------------------------------------------------------------------
|
|
_Use_decl_annotations_
|
|
bool DirectX::_LoadScanlineLinear(
|
|
XMVECTOR* pDestination,
|
|
size_t count,
|
|
const void* pSource,
|
|
size_t size,
|
|
DXGI_FORMAT format,
|
|
TEX_FILTER_FLAGS flags) noexcept
|
|
{
|
|
assert(pDestination && count > 0 && ((reinterpret_cast<uintptr_t>(pDestination) & 0xF) == 0));
|
|
assert(pSource && size > 0);
|
|
assert(IsValid(format) && !IsTypeless(format, false) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format));
|
|
|
|
switch (format)
|
|
{
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
|
|
flags |= TEX_FILTER_SRGB;
|
|
break;
|
|
|
|
case DXGI_FORMAT_R32G32B32A32_FLOAT:
|
|
case DXGI_FORMAT_R32G32B32_FLOAT:
|
|
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
|
case DXGI_FORMAT_R16G16B16A16_UNORM:
|
|
case DXGI_FORMAT_R32G32_FLOAT:
|
|
case DXGI_FORMAT_R10G10B10A2_UNORM:
|
|
case DXGI_FORMAT_R11G11B10_FLOAT:
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
|
case DXGI_FORMAT_R16G16_FLOAT:
|
|
case DXGI_FORMAT_R16G16_UNORM:
|
|
case DXGI_FORMAT_R32_FLOAT:
|
|
case DXGI_FORMAT_R8G8_UNORM:
|
|
case DXGI_FORMAT_R16_FLOAT:
|
|
case DXGI_FORMAT_R16_UNORM:
|
|
case DXGI_FORMAT_R8_UNORM:
|
|
case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
|
|
case DXGI_FORMAT_R8G8_B8G8_UNORM:
|
|
case DXGI_FORMAT_G8R8_G8B8_UNORM:
|
|
case DXGI_FORMAT_B5G6R5_UNORM:
|
|
case DXGI_FORMAT_B5G5R5A1_UNORM:
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
|
case DXGI_FORMAT_B4G4R4A4_UNORM:
|
|
break;
|
|
|
|
default:
|
|
// can't treat A8, XR, Depth, SNORM, UINT, or SINT as sRGB
|
|
flags &= ~TEX_FILTER_SRGB;
|
|
break;
|
|
}
|
|
|
|
if (_LoadScanline(pDestination, count, pSource, size, format))
|
|
{
|
|
// sRGB input processing (sRGB -> Linear RGB)
|
|
if (flags & TEX_FILTER_SRGB_IN)
|
|
{
|
|
XMVECTOR* ptr = pDestination;
|
|
for (size_t i = 0; i < count; ++i, ++ptr)
|
|
{
|
|
*ptr = XMColorSRGBToRGB(*ptr);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Convert scanline based on source/target formats
|
|
//-------------------------------------------------------------------------------------
|
|
namespace
|
|
{
|
|
struct ConvertData
|
|
{
|
|
DXGI_FORMAT format;
|
|
size_t datasize;
|
|
uint32_t flags;
|
|
};
|
|
|
|
const ConvertData g_ConvertTable[] =
|
|
{
|
|
{ DXGI_FORMAT_R32G32B32A32_FLOAT, 32, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_R32G32B32A32_UINT, 32, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_R32G32B32A32_SINT, 32, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_R32G32B32_FLOAT, 32, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B },
|
|
{ DXGI_FORMAT_R32G32B32_UINT, 32, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B },
|
|
{ DXGI_FORMAT_R32G32B32_SINT, 32, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B },
|
|
{ DXGI_FORMAT_R16G16B16A16_FLOAT, 16, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_R16G16B16A16_UNORM, 16, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_R16G16B16A16_UINT, 16, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_R16G16B16A16_SNORM, 16, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_R16G16B16A16_SINT, 16, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_R32G32_FLOAT, 32, CONVF_FLOAT | CONVF_R | CONVF_G },
|
|
{ DXGI_FORMAT_R32G32_UINT, 32, CONVF_UINT | CONVF_R | CONVF_G },
|
|
{ DXGI_FORMAT_R32G32_SINT, 32, CONVF_SINT | CONVF_R | CONVF_G },
|
|
{ DXGI_FORMAT_D32_FLOAT_S8X24_UINT, 32, CONVF_FLOAT | CONVF_DEPTH | CONVF_STENCIL },
|
|
{ DXGI_FORMAT_R10G10B10A2_UNORM, 10, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_R10G10B10A2_UINT, 10, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_R11G11B10_FLOAT, 10, CONVF_FLOAT | CONVF_POS_ONLY | CONVF_R | CONVF_G | CONVF_B },
|
|
{ DXGI_FORMAT_R8G8B8A8_UNORM, 8, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 8, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_R8G8B8A8_UINT, 8, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_R8G8B8A8_SNORM, 8, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_R8G8B8A8_SINT, 8, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_R16G16_FLOAT, 16, CONVF_FLOAT | CONVF_R | CONVF_G },
|
|
{ DXGI_FORMAT_R16G16_UNORM, 16, CONVF_UNORM | CONVF_R | CONVF_G },
|
|
{ DXGI_FORMAT_R16G16_UINT, 16, CONVF_UINT | CONVF_R | CONVF_G },
|
|
{ DXGI_FORMAT_R16G16_SNORM, 16, CONVF_SNORM | CONVF_R | CONVF_G },
|
|
{ DXGI_FORMAT_R16G16_SINT, 16, CONVF_SINT | CONVF_R | CONVF_G },
|
|
{ DXGI_FORMAT_D32_FLOAT, 32, CONVF_FLOAT | CONVF_DEPTH },
|
|
{ DXGI_FORMAT_R32_FLOAT, 32, CONVF_FLOAT | CONVF_R },
|
|
{ DXGI_FORMAT_R32_UINT, 32, CONVF_UINT | CONVF_R },
|
|
{ DXGI_FORMAT_R32_SINT, 32, CONVF_SINT | CONVF_R },
|
|
{ DXGI_FORMAT_D24_UNORM_S8_UINT, 32, CONVF_UNORM | CONVF_DEPTH | CONVF_STENCIL },
|
|
{ DXGI_FORMAT_R8G8_UNORM, 8, CONVF_UNORM | CONVF_R | CONVF_G },
|
|
{ DXGI_FORMAT_R8G8_UINT, 8, CONVF_UINT | CONVF_R | CONVF_G },
|
|
{ DXGI_FORMAT_R8G8_SNORM, 8, CONVF_SNORM | CONVF_R | CONVF_G },
|
|
{ DXGI_FORMAT_R8G8_SINT, 8, CONVF_SINT | CONVF_R | CONVF_G },
|
|
{ DXGI_FORMAT_R16_FLOAT, 16, CONVF_FLOAT | CONVF_R },
|
|
{ DXGI_FORMAT_D16_UNORM, 16, CONVF_UNORM | CONVF_DEPTH },
|
|
{ DXGI_FORMAT_R16_UNORM, 16, CONVF_UNORM | CONVF_R },
|
|
{ DXGI_FORMAT_R16_UINT, 16, CONVF_UINT | CONVF_R },
|
|
{ DXGI_FORMAT_R16_SNORM, 16, CONVF_SNORM | CONVF_R },
|
|
{ DXGI_FORMAT_R16_SINT, 16, CONVF_SINT | CONVF_R },
|
|
{ DXGI_FORMAT_R8_UNORM, 8, CONVF_UNORM | CONVF_R },
|
|
{ DXGI_FORMAT_R8_UINT, 8, CONVF_UINT | CONVF_R },
|
|
{ DXGI_FORMAT_R8_SNORM, 8, CONVF_SNORM | CONVF_R },
|
|
{ DXGI_FORMAT_R8_SINT, 8, CONVF_SINT | CONVF_R },
|
|
{ DXGI_FORMAT_A8_UNORM, 8, CONVF_UNORM | CONVF_A },
|
|
{ DXGI_FORMAT_R1_UNORM, 1, CONVF_UNORM | CONVF_R },
|
|
{ DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 9, CONVF_FLOAT | CONVF_SHAREDEXP | CONVF_POS_ONLY | CONVF_R | CONVF_G | CONVF_B },
|
|
{ DXGI_FORMAT_R8G8_B8G8_UNORM, 8, CONVF_UNORM | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B },
|
|
{ DXGI_FORMAT_G8R8_G8B8_UNORM, 8, CONVF_UNORM | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B },
|
|
{ DXGI_FORMAT_BC1_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_BC1_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_BC2_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_BC2_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_BC3_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_BC3_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_BC4_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R },
|
|
{ DXGI_FORMAT_BC4_SNORM, 8, CONVF_SNORM | CONVF_BC | CONVF_R },
|
|
{ DXGI_FORMAT_BC5_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G },
|
|
{ DXGI_FORMAT_BC5_SNORM, 8, CONVF_SNORM | CONVF_BC | CONVF_R | CONVF_G },
|
|
{ DXGI_FORMAT_B5G6R5_UNORM, 5, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B },
|
|
{ DXGI_FORMAT_B5G5R5A1_UNORM, 5, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_B8G8R8A8_UNORM, 8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_B8G8R8X8_UNORM, 8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B },
|
|
{ DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, 10, CONVF_UNORM | CONVF_XR | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B },
|
|
{ DXGI_FORMAT_BC6H_UF16, 16, CONVF_FLOAT | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_BC6H_SF16, 16, CONVF_FLOAT | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_BC7_UNORM, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_BC7_UNORM_SRGB, 8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_AYUV, 8, CONVF_UNORM | CONVF_YUV | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_Y410, 10, CONVF_UNORM | CONVF_YUV | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_Y416, 16, CONVF_UNORM | CONVF_YUV | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ DXGI_FORMAT_YUY2, 8, CONVF_UNORM | CONVF_YUV | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B },
|
|
{ DXGI_FORMAT_Y210, 10, CONVF_UNORM | CONVF_YUV | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B },
|
|
{ DXGI_FORMAT_Y216, 16, CONVF_UNORM | CONVF_YUV | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B },
|
|
{ DXGI_FORMAT_B4G4R4A4_UNORM, 4, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT, 10, CONVF_FLOAT | CONVF_POS_ONLY | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT, 10, CONVF_FLOAT | CONVF_POS_ONLY | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM,10, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
|
|
{ XBOX_DXGI_FORMAT_R4G4_UNORM, 4, CONVF_UNORM | CONVF_R | CONVF_G },
|
|
};
|
|
|
|
#pragma prefast( suppress : 25004, "Signature must match bsearch_s" );
|
|
int __cdecl ConvertCompare(void *context, const void* ptr1, const void *ptr2) noexcept
|
|
{
|
|
UNREFERENCED_PARAMETER(context);
|
|
auto p1 = static_cast<const ConvertData*>(ptr1);
|
|
auto p2 = static_cast<const ConvertData*>(ptr2);
|
|
if (p1->format == p2->format) return 0;
|
|
else return (p1->format < p2->format) ? -1 : 1;
|
|
}
|
|
}
|
|
|
|
_Use_decl_annotations_
|
|
uint32_t DirectX::_GetConvertFlags(DXGI_FORMAT format) noexcept
|
|
{
|
|
#ifdef _DEBUG
|
|
// Ensure conversion table is in ascending order
|
|
assert(_countof(g_ConvertTable) > 0);
|
|
DXGI_FORMAT lastvalue = g_ConvertTable[0].format;
|
|
for (size_t index = 1; index < _countof(g_ConvertTable); ++index)
|
|
{
|
|
assert(g_ConvertTable[index].format > lastvalue);
|
|
lastvalue = g_ConvertTable[index].format;
|
|
}
|
|
#endif
|
|
|
|
ConvertData key = { format, 0, 0 };
|
|
auto in = reinterpret_cast<const ConvertData*>(bsearch_s(&key, g_ConvertTable, _countof(g_ConvertTable), sizeof(ConvertData),
|
|
ConvertCompare, nullptr));
|
|
return (in) ? in->flags : 0;
|
|
}
|
|
|
|
_Use_decl_annotations_
|
|
void DirectX::_ConvertScanline(
|
|
XMVECTOR* pBuffer,
|
|
size_t count,
|
|
DXGI_FORMAT outFormat,
|
|
DXGI_FORMAT inFormat,
|
|
TEX_FILTER_FLAGS flags) noexcept
|
|
{
|
|
assert(pBuffer && count > 0 && ((reinterpret_cast<uintptr_t>(pBuffer) & 0xF) == 0));
|
|
assert(IsValid(outFormat) && !IsTypeless(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat));
|
|
assert(IsValid(inFormat) && !IsTypeless(inFormat) && !IsPlanar(inFormat) && !IsPalettized(inFormat));
|
|
|
|
if (!pBuffer)
|
|
return;
|
|
|
|
#ifdef _DEBUG
|
|
// Ensure conversion table is in ascending order
|
|
assert(_countof(g_ConvertTable) > 0);
|
|
DXGI_FORMAT lastvalue = g_ConvertTable[0].format;
|
|
for (size_t index = 1; index < _countof(g_ConvertTable); ++index)
|
|
{
|
|
assert(g_ConvertTable[index].format > lastvalue);
|
|
lastvalue = g_ConvertTable[index].format;
|
|
}
|
|
#endif
|
|
|
|
// Determine conversion details about source and dest formats
|
|
ConvertData key = { inFormat, 0, 0 };
|
|
auto in = reinterpret_cast<const ConvertData*>(
|
|
bsearch_s(&key, g_ConvertTable, _countof(g_ConvertTable), sizeof(ConvertData), ConvertCompare, nullptr));
|
|
key.format = outFormat;
|
|
auto out = reinterpret_cast<const ConvertData*>(
|
|
bsearch_s(&key, g_ConvertTable, _countof(g_ConvertTable), sizeof(ConvertData), ConvertCompare, nullptr));
|
|
if (!in || !out)
|
|
{
|
|
assert(false);
|
|
return;
|
|
}
|
|
|
|
assert(_GetConvertFlags(inFormat) == in->flags);
|
|
assert(_GetConvertFlags(outFormat) == out->flags);
|
|
|
|
// Handle SRGB filtering modes
|
|
switch (inFormat)
|
|
{
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
|
case DXGI_FORMAT_BC1_UNORM_SRGB:
|
|
case DXGI_FORMAT_BC2_UNORM_SRGB:
|
|
case DXGI_FORMAT_BC3_UNORM_SRGB:
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
|
|
case DXGI_FORMAT_BC7_UNORM_SRGB:
|
|
flags |= TEX_FILTER_SRGB_IN;
|
|
break;
|
|
|
|
case DXGI_FORMAT_A8_UNORM:
|
|
case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
|
|
flags &= ~TEX_FILTER_SRGB_IN;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (outFormat)
|
|
{
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
|
case DXGI_FORMAT_BC1_UNORM_SRGB:
|
|
case DXGI_FORMAT_BC2_UNORM_SRGB:
|
|
case DXGI_FORMAT_BC3_UNORM_SRGB:
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
|
|
case DXGI_FORMAT_BC7_UNORM_SRGB:
|
|
flags |= TEX_FILTER_SRGB_OUT;
|
|
break;
|
|
|
|
case DXGI_FORMAT_A8_UNORM:
|
|
case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
|
|
flags &= ~TEX_FILTER_SRGB_OUT;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ((flags & (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT)) == (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT))
|
|
{
|
|
flags &= ~(TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT);
|
|
}
|
|
|
|
// sRGB input processing (sRGB -> Linear RGB)
|
|
if (flags & TEX_FILTER_SRGB_IN)
|
|
{
|
|
if (!(in->flags & CONVF_DEPTH) && ((in->flags & CONVF_FLOAT) || (in->flags & CONVF_UNORM)))
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i, ++ptr)
|
|
{
|
|
*ptr = XMColorSRGBToRGB(*ptr);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle conversion special cases
|
|
uint32_t diffFlags = in->flags ^ out->flags;
|
|
if (diffFlags != 0)
|
|
{
|
|
if (diffFlags & CONVF_DEPTH)
|
|
{
|
|
//--- Depth conversions ---
|
|
if (in->flags & CONVF_DEPTH)
|
|
{
|
|
// CONVF_DEPTH -> !CONVF_DEPTH
|
|
if (in->flags & CONVF_STENCIL)
|
|
{
|
|
// Stencil -> Alpha
|
|
static const XMVECTORF32 S = { { { 1.f, 1.f, 1.f, 255.f } } };
|
|
|
|
if (out->flags & CONVF_UNORM)
|
|
{
|
|
// UINT -> UNORM
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSplatY(v);
|
|
v1 = XMVectorClamp(v1, g_XMZero, S);
|
|
v1 = XMVectorDivide(v1, S);
|
|
*ptr++ = XMVectorSelect(v1, v, g_XMSelect1110);
|
|
}
|
|
}
|
|
else if (out->flags & CONVF_SNORM)
|
|
{
|
|
// UINT -> SNORM
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSplatY(v);
|
|
v1 = XMVectorClamp(v1, g_XMZero, S);
|
|
v1 = XMVectorDivide(v1, S);
|
|
v1 = XMVectorMultiplyAdd(v1, g_XMTwo, g_XMNegativeOne);
|
|
*ptr++ = XMVectorSelect(v1, v, g_XMSelect1110);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSplatY(v);
|
|
*ptr++ = XMVectorSelect(v1, v, g_XMSelect1110);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Depth -> RGB
|
|
if ((out->flags & CONVF_UNORM) && (in->flags & CONVF_FLOAT))
|
|
{
|
|
// Depth FLOAT -> UNORM
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSaturate(v);
|
|
v1 = XMVectorSplatX(v1);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1110);
|
|
}
|
|
}
|
|
else if (out->flags & CONVF_SNORM)
|
|
{
|
|
if (in->flags & CONVF_UNORM)
|
|
{
|
|
// Depth UNORM -> SNORM
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorMultiplyAdd(v, g_XMTwo, g_XMNegativeOne);
|
|
v1 = XMVectorSplatX(v1);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1110);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Depth FLOAT -> SNORM
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorClamp(v, g_XMNegativeOne, g_XMOne);
|
|
v1 = XMVectorSplatX(v1);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1110);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSplatX(v);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1110);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// !CONVF_DEPTH -> CONVF_DEPTH
|
|
|
|
// RGB -> Depth (red channel)
|
|
switch (flags & (TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE))
|
|
{
|
|
case TEX_FILTER_RGB_COPY_GREEN:
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSplatY(v);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1000);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TEX_FILTER_RGB_COPY_BLUE:
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSplatZ(v);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1000);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if ((in->flags & CONVF_UNORM) && ((in->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G | CONVF_B)))
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVector3Dot(v, g_Grayscale);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1000);
|
|
}
|
|
break;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
__fallthrough;
|
|
#endif
|
|
#ifdef __clang__
|
|
[[clang::fallthrough]];
|
|
#endif
|
|
|
|
case TEX_FILTER_RGB_COPY_RED:
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSplatX(v);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1000);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Finialize type conversion for depth (red channel)
|
|
if (out->flags & CONVF_UNORM)
|
|
{
|
|
if (in->flags & CONVF_SNORM)
|
|
{
|
|
// SNORM -> UNORM
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorMultiplyAdd(v, g_XMOneHalf, g_XMOneHalf);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1000);
|
|
}
|
|
}
|
|
else if (in->flags & CONVF_FLOAT)
|
|
{
|
|
// FLOAT -> UNORM
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSaturate(v);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1000);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (out->flags & CONVF_STENCIL)
|
|
{
|
|
// Alpha -> Stencil (green channel)
|
|
static const XMVECTORU32 select0100 = { { { XM_SELECT_0, XM_SELECT_1, XM_SELECT_0, XM_SELECT_0 } } };
|
|
static const XMVECTORF32 S = { { { 255.f, 255.f, 255.f, 255.f } } };
|
|
|
|
if (in->flags & CONVF_UNORM)
|
|
{
|
|
// UNORM -> UINT
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorMultiply(v, S);
|
|
v1 = XMVectorSplatW(v1);
|
|
*ptr++ = XMVectorSelect(v, v1, select0100);
|
|
}
|
|
}
|
|
else if (in->flags & CONVF_SNORM)
|
|
{
|
|
// SNORM -> UINT
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorMultiplyAdd(v, g_XMOneHalf, g_XMOneHalf);
|
|
v1 = XMVectorMultiply(v1, S);
|
|
v1 = XMVectorSplatW(v1);
|
|
*ptr++ = XMVectorSelect(v, v1, select0100);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSplatW(v);
|
|
*ptr++ = XMVectorSelect(v, v1, select0100);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (out->flags & CONVF_DEPTH)
|
|
{
|
|
// CONVF_DEPTH -> CONVF_DEPTH
|
|
if (diffFlags & CONVF_FLOAT)
|
|
{
|
|
if (in->flags & CONVF_FLOAT)
|
|
{
|
|
// FLOAT -> UNORM depth, preserve stencil
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSaturate(v);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1000);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (out->flags & CONVF_UNORM)
|
|
{
|
|
//--- Converting to a UNORM ---
|
|
if (in->flags & CONVF_SNORM)
|
|
{
|
|
// SNORM -> UNORM
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
*ptr++ = XMVectorMultiplyAdd(v, g_XMOneHalf, g_XMOneHalf);
|
|
}
|
|
}
|
|
else if (in->flags & CONVF_FLOAT)
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
if (!(in->flags & CONVF_POS_ONLY) && (flags & TEX_FILTER_FLOAT_X2BIAS))
|
|
{
|
|
// FLOAT -> UNORM (x2 bias)
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
v = XMVectorClamp(v, g_XMNegativeOne, g_XMOne);
|
|
*ptr++ = XMVectorMultiplyAdd(v, g_XMOneHalf, g_XMOneHalf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// FLOAT -> UNORM
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
*ptr++ = XMVectorSaturate(v);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (out->flags & CONVF_SNORM)
|
|
{
|
|
//--- Converting to a SNORM ---
|
|
if (in->flags & CONVF_UNORM)
|
|
{
|
|
// UNORM -> SNORM
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
*ptr++ = XMVectorMultiplyAdd(v, g_XMTwo, g_XMNegativeOne);
|
|
}
|
|
}
|
|
else if (in->flags & CONVF_FLOAT)
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
if ((in->flags & CONVF_POS_ONLY) && (flags & TEX_FILTER_FLOAT_X2BIAS))
|
|
{
|
|
// FLOAT (positive only, x2 bias) -> SNORM
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
v = XMVectorSaturate(v);
|
|
*ptr++ = XMVectorMultiplyAdd(v, g_XMTwo, g_XMNegativeOne);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// FLOAT -> SNORM
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
*ptr++ = XMVectorClamp(v, g_XMNegativeOne, g_XMOne);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (diffFlags & CONVF_UNORM)
|
|
{
|
|
//--- Converting from a UNORM ---
|
|
assert(in->flags & CONVF_UNORM);
|
|
if (out->flags & CONVF_FLOAT)
|
|
{
|
|
if (!(out->flags & CONVF_POS_ONLY) && (flags & TEX_FILTER_FLOAT_X2BIAS))
|
|
{
|
|
// UNORM (x2 bias) -> FLOAT
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
*ptr++ = XMVectorMultiplyAdd(v, g_XMTwo, g_XMNegativeOne);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (diffFlags & CONVF_POS_ONLY)
|
|
{
|
|
if (flags & TEX_FILTER_FLOAT_X2BIAS)
|
|
{
|
|
if (in->flags & CONVF_POS_ONLY)
|
|
{
|
|
if (out->flags & CONVF_FLOAT)
|
|
{
|
|
// FLOAT (positive only, x2 bias) -> FLOAT
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
v = XMVectorSaturate(v);
|
|
*ptr++ = XMVectorMultiplyAdd(v, g_XMTwo, g_XMNegativeOne);
|
|
}
|
|
}
|
|
}
|
|
else if (out->flags & CONVF_POS_ONLY)
|
|
{
|
|
if (in->flags & CONVF_FLOAT)
|
|
{
|
|
// FLOAT -> FLOAT (positive only, x2 bias)
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
v = XMVectorClamp(v, g_XMNegativeOne, g_XMOne);
|
|
*ptr++ = XMVectorMultiplyAdd(v, g_XMOneHalf, g_XMOneHalf);
|
|
}
|
|
}
|
|
else if (in->flags & CONVF_SNORM)
|
|
{
|
|
// SNORM -> FLOAT (positive only, x2 bias)
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
*ptr++ = XMVectorMultiplyAdd(v, g_XMOneHalf, g_XMOneHalf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// !CONVF_A -> CONVF_A is handled because LoadScanline ensures alpha defaults to 1.0 for no-alpha formats
|
|
|
|
// CONVF_PACKED cases are handled because LoadScanline/StoreScanline handles packing/unpacking
|
|
|
|
if (((out->flags & CONVF_RGBA_MASK) == CONVF_A) && !(in->flags & CONVF_A))
|
|
{
|
|
// !CONVF_A -> A format
|
|
switch (flags & (TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE))
|
|
{
|
|
case TEX_FILTER_RGB_COPY_GREEN:
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
*ptr++ = XMVectorSplatY(v);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TEX_FILTER_RGB_COPY_BLUE:
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
*ptr++ = XMVectorSplatZ(v);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if ((in->flags & CONVF_UNORM) && ((in->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G | CONVF_B)))
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
*ptr++ = XMVector3Dot(v, g_Grayscale);
|
|
}
|
|
break;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
__fallthrough;
|
|
#endif
|
|
#ifdef __clang__
|
|
[[clang::fallthrough]];
|
|
#endif
|
|
|
|
case TEX_FILTER_RGB_COPY_RED:
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
*ptr++ = XMVectorSplatX(v);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if (((in->flags & CONVF_RGBA_MASK) == CONVF_A) && !(out->flags & CONVF_A))
|
|
{
|
|
// A format -> !CONVF_A
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
*ptr++ = XMVectorSplatW(v);
|
|
}
|
|
}
|
|
else if ((in->flags & CONVF_RGB_MASK) == CONVF_R)
|
|
{
|
|
if ((out->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G | CONVF_B))
|
|
{
|
|
// R format -> RGB format
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSplatX(v);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1110);
|
|
}
|
|
}
|
|
else if ((out->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G))
|
|
{
|
|
// R format -> RG format
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSplatX(v);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1100);
|
|
}
|
|
}
|
|
}
|
|
else if ((in->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G | CONVF_B))
|
|
{
|
|
if ((out->flags & CONVF_RGB_MASK) == CONVF_R)
|
|
{
|
|
// RGB format -> R format
|
|
switch (flags & (TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE))
|
|
{
|
|
case TEX_FILTER_RGB_COPY_GREEN:
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSplatY(v);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1110);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TEX_FILTER_RGB_COPY_BLUE:
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSplatZ(v);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1110);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (in->flags & CONVF_UNORM)
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVector3Dot(v, g_Grayscale);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1110);
|
|
}
|
|
break;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
__fallthrough;
|
|
#endif
|
|
#ifdef __clang__
|
|
[[clang::fallthrough]];
|
|
#endif
|
|
|
|
case TEX_FILTER_RGB_COPY_RED:
|
|
// Leave data unchanged and the store will handle this...
|
|
break;
|
|
}
|
|
}
|
|
else if ((out->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G))
|
|
{
|
|
// RGB format -> RG format
|
|
switch (static_cast<int>(flags & (TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE)))
|
|
{
|
|
case static_cast<int>(TEX_FILTER_RGB_COPY_RED) | static_cast<int>(TEX_FILTER_RGB_COPY_BLUE):
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSwizzle<0, 2, 0, 2>(v);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1100);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case static_cast<int>(TEX_FILTER_RGB_COPY_GREEN) | static_cast<int>(TEX_FILTER_RGB_COPY_BLUE):
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
XMVECTOR v = *ptr;
|
|
XMVECTOR v1 = XMVectorSwizzle<1, 2, 3, 0>(v);
|
|
*ptr++ = XMVectorSelect(v, v1, g_XMSelect1100);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case static_cast<int>(TEX_FILTER_RGB_COPY_RED) | static_cast<int>(TEX_FILTER_RGB_COPY_GREEN):
|
|
default:
|
|
// Leave data unchanged and the store will handle this...
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// sRGB output processing (Linear RGB -> sRGB)
|
|
if (flags & TEX_FILTER_SRGB_OUT)
|
|
{
|
|
if (!(out->flags & CONVF_DEPTH) && ((out->flags & CONVF_FLOAT) || (out->flags & CONVF_UNORM)))
|
|
{
|
|
XMVECTOR* ptr = pBuffer;
|
|
for (size_t i = 0; i < count; ++i, ++ptr)
|
|
{
|
|
*ptr = XMColorRGBToSRGB(*ptr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Dithering
|
|
//-------------------------------------------------------------------------------------
|
|
namespace
|
|
{
|
|
// 4X4X4 ordered dithering matrix
|
|
const float g_Dither[] =
|
|
{
|
|
// (z & 3) + ( (y & 3) * 8) + (x & 3)
|
|
0.468750f, -0.031250f, 0.343750f, -0.156250f, 0.468750f, -0.031250f, 0.343750f, -0.156250f,
|
|
-0.281250f, 0.218750f, -0.406250f, 0.093750f, -0.281250f, 0.218750f, -0.406250f, 0.093750f,
|
|
0.281250f, -0.218750f, 0.406250f, -0.093750f, 0.281250f, -0.218750f, 0.406250f, -0.093750f,
|
|
-0.468750f, 0.031250f, -0.343750f, 0.156250f, -0.468750f, 0.031250f, -0.343750f, 0.156250f,
|
|
};
|
|
|
|
const XMVECTORF32 g_Scale16pc = { { { 65535.f, 65535.f, 65535.f, 65535.f } } };
|
|
const XMVECTORF32 g_Scale15pc = { { { 32767.f, 32767.f, 32767.f, 32767.f } } };
|
|
const XMVECTORF32 g_Scale10pc = { { { 1023.f, 1023.f, 1023.f, 3.f } } };
|
|
const XMVECTORF32 g_Scale9pc = { { { 511.f, 511.f, 511.f, 3.f } } };
|
|
const XMVECTORF32 g_Scale8pc = { { { 255.f, 255.f, 255.f, 255.f } } };
|
|
const XMVECTORF32 g_Scale7pc = { { { 127.f, 127.f, 127.f, 127.f } } };
|
|
const XMVECTORF32 g_Scale565pc = { { { 31.f, 63.f, 31.f, 1.f } } };
|
|
const XMVECTORF32 g_Scale5551pc = { { { 31.f, 31.f, 31.f, 1.f } } };
|
|
const XMVECTORF32 g_Scale4pc = { { { 15.f, 15.f, 15.f, 15.f } } };
|
|
|
|
const XMVECTORF32 g_ErrorWeight3 = { { { 3.f / 16.f, 3.f / 16.f, 3.f / 16.f, 3.f / 16.f } } };
|
|
const XMVECTORF32 g_ErrorWeight5 = { { { 5.f / 16.f, 5.f / 16.f, 5.f / 16.f, 5.f / 16.f } } };
|
|
const XMVECTORF32 g_ErrorWeight1 = { { { 1.f / 16.f, 1.f / 16.f, 1.f / 16.f, 1.f / 16.f } } };
|
|
const XMVECTORF32 g_ErrorWeight7 = { { { 7.f / 16.f, 7.f / 16.f, 7.f / 16.f, 7.f / 16.f } } };
|
|
|
|
#define STORE_SCANLINE( type, scalev, clampzero, norm, itype, mask, row, bgr ) \
|
|
if (size >= sizeof(type)) \
|
|
{ \
|
|
type * __restrict dest = reinterpret_cast<type*>(pDestination); \
|
|
for(size_t i = 0; i < count; ++i) \
|
|
{ \
|
|
auto index = static_cast<ptrdiff_t>((row & 1) ? (count - i - 1) : i ); \
|
|
ptrdiff_t delta = (row & 1) ? -2 : 0; \
|
|
\
|
|
XMVECTOR v = sPtr[ index ]; \
|
|
if (bgr) { v = XMVectorSwizzle<2, 1, 0, 3>(v); } \
|
|
if (norm && clampzero) v = XMVectorSaturate(v) ; \
|
|
else if (clampzero) v = XMVectorClamp(v, g_XMZero, scalev); \
|
|
else if (norm) v = XMVectorClamp(v, g_XMNegativeOne, g_XMOne); \
|
|
else v = XMVectorClamp(v, XMVectorAdd(XMVectorNegate(scalev), g_XMOne), scalev); \
|
|
v = XMVectorAdd(v, vError); \
|
|
if (norm) v = XMVectorMultiply(v, scalev); \
|
|
\
|
|
XMVECTOR target; \
|
|
if (pDiffusionErrors) \
|
|
{ \
|
|
target = XMVectorRound(v); \
|
|
vError = XMVectorSubtract(v, target); \
|
|
if (norm) vError = XMVectorDivide(vError, scalev); \
|
|
\
|
|
/* Distribute error to next scanline and next pixel */ \
|
|
pDiffusionErrors[ index-delta ] = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[ index-delta ]); \
|
|
pDiffusionErrors[ index+1 ] = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[ index+1 ]); \
|
|
pDiffusionErrors[ index+2+delta ] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[ index+2+delta ]); \
|
|
vError = XMVectorMultiply(vError, g_ErrorWeight7); \
|
|
} \
|
|
else \
|
|
{ \
|
|
/* Applied ordered dither */ \
|
|
target = XMVectorAdd(v, ordered[ index & 3 ]); \
|
|
target = XMVectorRound(target); \
|
|
} \
|
|
\
|
|
target = XMVectorMin(scalev, target); \
|
|
target = XMVectorMax((clampzero) ? g_XMZero : (XMVectorAdd(XMVectorNegate(scalev), g_XMOne)), target); \
|
|
\
|
|
XMFLOAT4A tmp; \
|
|
XMStoreFloat4A(&tmp, target); \
|
|
\
|
|
auto dPtr = &dest[ index ]; \
|
|
if (dPtr >= ePtr) break; \
|
|
dPtr->x = itype(static_cast<itype>(tmp.x) & mask); \
|
|
dPtr->y = itype(static_cast<itype>(tmp.y) & mask); \
|
|
dPtr->z = itype(static_cast<itype>(tmp.z) & mask); \
|
|
dPtr->w = itype(static_cast<itype>(tmp.w) & mask); \
|
|
} \
|
|
return true; \
|
|
} \
|
|
return false;
|
|
|
|
#define STORE_SCANLINE2( type, scalev, clampzero, norm, itype, mask, row ) \
|
|
/* The 2 component cases are always bgr=false */ \
|
|
if (size >= sizeof(type)) \
|
|
{ \
|
|
type * __restrict dest = reinterpret_cast<type*>(pDestination); \
|
|
for(size_t i = 0; i < count; ++i) \
|
|
{ \
|
|
auto index = static_cast<ptrdiff_t>((row & 1) ? (count - i - 1) : i ); \
|
|
ptrdiff_t delta = (row & 1) ? -2 : 0; \
|
|
\
|
|
XMVECTOR v = sPtr[ index ]; \
|
|
if (norm && clampzero) v = XMVectorSaturate(v) ; \
|
|
else if (clampzero) v = XMVectorClamp(v, g_XMZero, scalev); \
|
|
else if (norm) v = XMVectorClamp(v, g_XMNegativeOne, g_XMOne); \
|
|
else v = XMVectorClamp(v, XMVectorAdd(XMVectorNegate(scalev), g_XMOne), scalev); \
|
|
v = XMVectorAdd(v, vError); \
|
|
if (norm) v = XMVectorMultiply(v, scalev); \
|
|
\
|
|
XMVECTOR target; \
|
|
if (pDiffusionErrors) \
|
|
{ \
|
|
target = XMVectorRound(v); \
|
|
vError = XMVectorSubtract(v, target); \
|
|
if (norm) vError = XMVectorDivide(vError, scalev); \
|
|
\
|
|
/* Distribute error to next scanline and next pixel */ \
|
|
pDiffusionErrors[ index-delta ] = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[ index-delta ]); \
|
|
pDiffusionErrors[ index+1 ] = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[ index+1 ]); \
|
|
pDiffusionErrors[ index+2+delta ] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[ index+2+delta ]); \
|
|
vError = XMVectorMultiply(vError, g_ErrorWeight7); \
|
|
} \
|
|
else \
|
|
{ \
|
|
/* Applied ordered dither */ \
|
|
target = XMVectorAdd(v, ordered[ index & 3 ]); \
|
|
target = XMVectorRound(target); \
|
|
} \
|
|
\
|
|
target = XMVectorMin(scalev, target); \
|
|
target = XMVectorMax((clampzero) ? g_XMZero : (XMVectorAdd(XMVectorNegate(scalev), g_XMOne)), target); \
|
|
\
|
|
XMFLOAT4A tmp; \
|
|
XMStoreFloat4A(&tmp, target); \
|
|
\
|
|
auto dPtr = &dest[ index ]; \
|
|
if (dPtr >= ePtr) break; \
|
|
dPtr->x = itype(static_cast<itype>(tmp.x) & mask); \
|
|
dPtr->y = itype(static_cast<itype>(tmp.y) & mask); \
|
|
} \
|
|
return true; \
|
|
} \
|
|
return false;
|
|
|
|
#define STORE_SCANLINE1( type, scalev, clampzero, norm, mask, row, selectw ) \
|
|
/* The 1 component cases are always bgr=false */ \
|
|
if (size >= sizeof(type)) \
|
|
{ \
|
|
type * __restrict dest = reinterpret_cast<type*>(pDestination); \
|
|
for(size_t i = 0; i < count; ++i) \
|
|
{ \
|
|
auto index = static_cast<ptrdiff_t>((row & 1) ? (count - i - 1) : i ); \
|
|
ptrdiff_t delta = (row & 1) ? -2 : 0; \
|
|
\
|
|
XMVECTOR v = sPtr[ index ]; \
|
|
if (norm && clampzero) v = XMVectorSaturate(v) ; \
|
|
else if (clampzero) v = XMVectorClamp(v, g_XMZero, scalev); \
|
|
else if (norm) v = XMVectorClamp(v, g_XMNegativeOne, g_XMOne); \
|
|
else v = XMVectorClamp(v, XMVectorAdd(XMVectorNegate(scalev), g_XMOne), scalev); \
|
|
v = XMVectorAdd(v, vError); \
|
|
if (norm) v = XMVectorMultiply(v, scalev); \
|
|
\
|
|
XMVECTOR target; \
|
|
if (pDiffusionErrors) \
|
|
{ \
|
|
target = XMVectorRound(v); \
|
|
vError = XMVectorSubtract(v, target); \
|
|
if (norm) vError = XMVectorDivide(vError, scalev); \
|
|
\
|
|
/* Distribute error to next scanline and next pixel */ \
|
|
pDiffusionErrors[ index-delta ] = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[ index-delta ]); \
|
|
pDiffusionErrors[ index+1 ] = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[ index+1 ]); \
|
|
pDiffusionErrors[ index+2+delta ] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[ index+2+delta ]); \
|
|
vError = XMVectorMultiply(vError, g_ErrorWeight7); \
|
|
} \
|
|
else \
|
|
{ \
|
|
/* Applied ordered dither */ \
|
|
target = XMVectorAdd(v, ordered[ index & 3 ]); \
|
|
target = XMVectorRound(target); \
|
|
} \
|
|
\
|
|
target = XMVectorMin(scalev, target); \
|
|
target = XMVectorMax((clampzero) ? g_XMZero : (XMVectorAdd(XMVectorNegate(scalev), g_XMOne)), target); \
|
|
\
|
|
auto dPtr = &dest[ index ]; \
|
|
if (dPtr >= ePtr) break; \
|
|
*dPtr = type(static_cast<type>((selectw) ? XMVectorGetW(target) : XMVectorGetX(target)) & mask); \
|
|
} \
|
|
return true; \
|
|
} \
|
|
return false;
|
|
}
|
|
|
|
#pragma warning(push)
|
|
#pragma warning( disable : 4127 )
|
|
|
|
_Use_decl_annotations_
|
|
bool DirectX::_StoreScanlineDither(
|
|
void* pDestination,
|
|
size_t size,
|
|
DXGI_FORMAT format,
|
|
XMVECTOR* pSource,
|
|
size_t count,
|
|
float threshold,
|
|
size_t y,
|
|
size_t z,
|
|
XMVECTOR* pDiffusionErrors) noexcept
|
|
{
|
|
assert(pDestination && size > 0);
|
|
assert(pSource && count > 0 && ((reinterpret_cast<uintptr_t>(pSource) & 0xF) == 0));
|
|
assert(IsValid(format) && !IsTypeless(format) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format));
|
|
|
|
XMVECTOR ordered[4];
|
|
if (pDiffusionErrors)
|
|
{
|
|
// If pDiffusionErrors != 0, then this function performs error diffusion dithering (aka Floyd-Steinberg dithering)
|
|
|
|
// To avoid the need for another temporary scanline buffer, we allow this function to overwrite the source buffer in-place
|
|
// Given the intended usage in the conversion routines, this is not a problem.
|
|
|
|
XMVECTOR* ptr = pSource;
|
|
const XMVECTOR* err = pDiffusionErrors + 1;
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
// Add contribution from previous scanline
|
|
XMVECTOR v = XMVectorAdd(*ptr, *err++);
|
|
*ptr++ = v;
|
|
}
|
|
|
|
// Reset errors for next scanline
|
|
memset(pDiffusionErrors, 0, sizeof(XMVECTOR)*(count + 2));
|
|
}
|
|
else
|
|
{
|
|
// If pDiffusionErrors == 0, then this function performs ordered dithering
|
|
|
|
XMVECTOR dither = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(g_Dither + (z & 3) + ((y & 3) * 8)));
|
|
|
|
ordered[0] = XMVectorSplatX(dither);
|
|
ordered[1] = XMVectorSplatY(dither);
|
|
ordered[2] = XMVectorSplatZ(dither);
|
|
ordered[3] = XMVectorSplatW(dither);
|
|
}
|
|
|
|
const XMVECTOR* __restrict sPtr = pSource;
|
|
if (!sPtr)
|
|
return false;
|
|
|
|
const void* ePtr = static_cast<const uint8_t*>(pDestination) + size;
|
|
|
|
XMVECTOR vError = XMVectorZero();
|
|
|
|
switch (static_cast<int>(format))
|
|
{
|
|
case DXGI_FORMAT_R16G16B16A16_UNORM:
|
|
STORE_SCANLINE(XMUSHORTN4, g_Scale16pc, true, true, uint16_t, 0xFFFF, y, false)
|
|
|
|
case DXGI_FORMAT_R16G16B16A16_UINT:
|
|
STORE_SCANLINE(XMUSHORT4, g_Scale16pc, true, false, uint16_t, 0xFFFF, y, false)
|
|
|
|
case DXGI_FORMAT_R16G16B16A16_SNORM:
|
|
STORE_SCANLINE(XMSHORTN4, g_Scale15pc, false, true, int16_t, 0xFFFF, y, false)
|
|
|
|
case DXGI_FORMAT_R16G16B16A16_SINT:
|
|
STORE_SCANLINE(XMSHORT4, g_Scale15pc, false, false, int16_t, 0xFFFF, y, false)
|
|
|
|
case DXGI_FORMAT_R10G10B10A2_UNORM:
|
|
STORE_SCANLINE(XMUDECN4, g_Scale10pc, true, true, uint16_t, 0x3FF, y, false)
|
|
|
|
case DXGI_FORMAT_R10G10B10A2_UINT:
|
|
STORE_SCANLINE(XMUDEC4, g_Scale10pc, true, false, uint16_t, 0x3FF, y, false)
|
|
|
|
case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
|
|
if (size >= sizeof(XMUDEC4))
|
|
{
|
|
static const XMVECTORF32 Scale = { { { 510.0f, 510.0f, 510.0f, 3.0f } } };
|
|
static const XMVECTORF32 Bias = { { { 384.0f, 384.0f, 384.0f, 0.0f } } };
|
|
static const XMVECTORF32 MinXR = { { { -0.7529f, -0.7529f, -0.7529f, 0.f } } };
|
|
static const XMVECTORF32 MaxXR = { { { 1.2529f, 1.2529f, 1.2529f, 1.0f } } };
|
|
|
|
XMUDEC4 * __restrict dest = static_cast<XMUDEC4*>(pDestination);
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
auto index = static_cast<ptrdiff_t>((y & 1) ? (count - i - 1) : i);
|
|
ptrdiff_t delta = (y & 1) ? -2 : 0;
|
|
|
|
XMVECTOR v = XMVectorClamp(sPtr[index], MinXR, MaxXR);
|
|
v = XMVectorMultiplyAdd(v, Scale, vError);
|
|
|
|
XMVECTOR target;
|
|
if (pDiffusionErrors)
|
|
{
|
|
target = XMVectorRound(v);
|
|
vError = XMVectorSubtract(v, target);
|
|
vError = XMVectorDivide(vError, Scale);
|
|
|
|
// Distribute error to next scanline and next pixel
|
|
pDiffusionErrors[index - delta] = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[index - delta]);
|
|
pDiffusionErrors[index + 1] = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[index + 1]);
|
|
pDiffusionErrors[index + 2 + delta] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[index + 2 + delta]);
|
|
vError = XMVectorMultiply(vError, g_ErrorWeight7);
|
|
}
|
|
else
|
|
{
|
|
// Applied ordered dither
|
|
target = XMVectorAdd(v, ordered[index & 3]);
|
|
target = XMVectorRound(target);
|
|
}
|
|
|
|
target = XMVectorAdd(target, Bias);
|
|
target = XMVectorClamp(target, g_XMZero, g_Scale10pc);
|
|
|
|
XMFLOAT4A tmp;
|
|
XMStoreFloat4A(&tmp, target);
|
|
|
|
auto dPtr = &dest[index];
|
|
if (dPtr >= ePtr) break;
|
|
dPtr->x = uint16_t(static_cast<uint16_t>(tmp.x) & 0x3FF);
|
|
dPtr->y = uint16_t(static_cast<uint16_t>(tmp.y) & 0x3FF);
|
|
dPtr->z = uint16_t(static_cast<uint16_t>(tmp.z) & 0x3FF);
|
|
dPtr->w = static_cast<uint16_t>(tmp.w);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
|
STORE_SCANLINE(XMUBYTEN4, g_Scale8pc, true, true, uint8_t, 0xFF, y, false)
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_UINT:
|
|
STORE_SCANLINE(XMUBYTE4, g_Scale8pc, true, false, uint8_t, 0xFF, y, false)
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_SNORM:
|
|
STORE_SCANLINE(XMBYTEN4, g_Scale7pc, false, true, int8_t, 0xFF, y, false)
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_SINT:
|
|
STORE_SCANLINE(XMBYTE4, g_Scale7pc, false, false, int8_t, 0xFF, y, false)
|
|
|
|
case DXGI_FORMAT_R16G16_UNORM:
|
|
STORE_SCANLINE2(XMUSHORTN2, g_Scale16pc, true, true, uint16_t, 0xFFFF, y)
|
|
|
|
case DXGI_FORMAT_R16G16_UINT:
|
|
STORE_SCANLINE2(XMUSHORT2, g_Scale16pc, true, false, uint16_t, 0xFFFF, y)
|
|
|
|
case DXGI_FORMAT_R16G16_SNORM:
|
|
STORE_SCANLINE2(XMSHORTN2, g_Scale15pc, false, true, int16_t, 0xFFFF, y)
|
|
|
|
case DXGI_FORMAT_R16G16_SINT:
|
|
STORE_SCANLINE2(XMSHORT2, g_Scale15pc, false, false, int16_t, 0xFFFF, y)
|
|
|
|
case DXGI_FORMAT_D24_UNORM_S8_UINT:
|
|
if (size >= sizeof(uint32_t))
|
|
{
|
|
static const XMVECTORF32 Clamp = { { { 1.f, 255.f, 0.f, 0.f } } };
|
|
static const XMVECTORF32 Scale = { { { 16777215.f, 1.f, 0.f, 0.f } } };
|
|
static const XMVECTORF32 Scale2 = { { { 16777215.f, 255.f, 0.f, 0.f } } };
|
|
|
|
uint32_t * __restrict dest = static_cast<uint32_t*>(pDestination);
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
auto index = static_cast<ptrdiff_t>((y & 1) ? (count - i - 1) : i);
|
|
ptrdiff_t delta = (y & 1) ? -2 : 0;
|
|
|
|
XMVECTOR v = XMVectorClamp(sPtr[index], g_XMZero, Clamp);
|
|
v = XMVectorAdd(v, vError);
|
|
v = XMVectorMultiply(v, Scale);
|
|
|
|
XMVECTOR target;
|
|
if (pDiffusionErrors)
|
|
{
|
|
target = XMVectorRound(v);
|
|
vError = XMVectorSubtract(v, target);
|
|
vError = XMVectorDivide(vError, Scale);
|
|
|
|
// Distribute error to next scanline and next pixel
|
|
pDiffusionErrors[index - delta] = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[index - delta]);
|
|
pDiffusionErrors[index + 1] = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[index + 1]);
|
|
pDiffusionErrors[index + 2 + delta] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[index + 2 + delta]);
|
|
vError = XMVectorMultiply(vError, g_ErrorWeight7);
|
|
}
|
|
else
|
|
{
|
|
// Applied ordered dither
|
|
target = XMVectorAdd(v, ordered[index & 3]);
|
|
target = XMVectorRound(target);
|
|
}
|
|
|
|
target = XMVectorClamp(target, g_XMZero, Scale2);
|
|
|
|
XMFLOAT4A tmp;
|
|
XMStoreFloat4A(&tmp, target);
|
|
|
|
auto dPtr = &dest[index];
|
|
if (dPtr >= ePtr) break;
|
|
*dPtr = (static_cast<uint32_t>(tmp.x) & 0xFFFFFF)
|
|
| ((static_cast<uint32_t>(tmp.y) & 0xFF) << 24);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_R8G8_UNORM:
|
|
STORE_SCANLINE2(XMUBYTEN2, g_Scale8pc, true, true, uint8_t, 0xFF, y)
|
|
|
|
case DXGI_FORMAT_R8G8_UINT:
|
|
STORE_SCANLINE2(XMUBYTE2, g_Scale8pc, true, false, uint8_t, 0xFF, y)
|
|
|
|
case DXGI_FORMAT_R8G8_SNORM:
|
|
STORE_SCANLINE2(XMBYTEN2, g_Scale7pc, false, true, int8_t, 0xFF, y)
|
|
|
|
case DXGI_FORMAT_R8G8_SINT:
|
|
STORE_SCANLINE2(XMBYTE2, g_Scale7pc, false, false, int8_t, 0xFF, y)
|
|
|
|
case DXGI_FORMAT_D16_UNORM:
|
|
case DXGI_FORMAT_R16_UNORM:
|
|
STORE_SCANLINE1(uint16_t, g_Scale16pc, true, true, 0xFFFF, y, false)
|
|
|
|
case DXGI_FORMAT_R16_UINT:
|
|
STORE_SCANLINE1(uint16_t, g_Scale16pc, true, false, 0xFFFF, y, false)
|
|
|
|
case DXGI_FORMAT_R16_SNORM:
|
|
STORE_SCANLINE1(int16_t, g_Scale15pc, false, true, 0xFFFF, y, false)
|
|
|
|
case DXGI_FORMAT_R16_SINT:
|
|
STORE_SCANLINE1(int16_t, g_Scale15pc, false, false, 0xFFFF, y, false)
|
|
|
|
case DXGI_FORMAT_R8_UNORM:
|
|
STORE_SCANLINE1(uint8_t, g_Scale8pc, true, true, 0xFF, y, false)
|
|
|
|
case DXGI_FORMAT_R8_UINT:
|
|
STORE_SCANLINE1(uint8_t, g_Scale8pc, true, false, 0xFF, y, false)
|
|
|
|
case DXGI_FORMAT_R8_SNORM:
|
|
STORE_SCANLINE1(int8_t, g_Scale7pc, false, true, 0xFF, y, false)
|
|
|
|
case DXGI_FORMAT_R8_SINT:
|
|
STORE_SCANLINE1(int8_t, g_Scale7pc, false, false, 0xFF, y, false)
|
|
|
|
case DXGI_FORMAT_A8_UNORM:
|
|
STORE_SCANLINE1(uint8_t, g_Scale8pc, true, true, 0xFF, y, true)
|
|
|
|
case DXGI_FORMAT_B5G6R5_UNORM:
|
|
if (size >= sizeof(XMU565))
|
|
{
|
|
XMU565 * __restrict dest = static_cast<XMU565*>(pDestination);
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
auto index = static_cast<ptrdiff_t>((y & 1) ? (count - i - 1) : i);
|
|
ptrdiff_t delta = (y & 1) ? -2 : 0;
|
|
|
|
XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(sPtr[index]);
|
|
v = XMVectorSaturate(v);
|
|
v = XMVectorAdd(v, vError);
|
|
v = XMVectorMultiply(v, g_Scale565pc);
|
|
|
|
XMVECTOR target;
|
|
if (pDiffusionErrors)
|
|
{
|
|
target = XMVectorRound(v);
|
|
vError = XMVectorSubtract(v, target);
|
|
vError = XMVectorDivide(vError, g_Scale565pc);
|
|
|
|
// Distribute error to next scanline and next pixel
|
|
pDiffusionErrors[index - delta] = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[index - delta]);
|
|
pDiffusionErrors[index + 1] = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[index + 1]);
|
|
pDiffusionErrors[index + 2 + delta] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[index + 2 + delta]);
|
|
vError = XMVectorMultiply(vError, g_ErrorWeight7);
|
|
}
|
|
else
|
|
{
|
|
// Applied ordered dither
|
|
target = XMVectorAdd(v, ordered[index & 3]);
|
|
target = XMVectorRound(target);
|
|
}
|
|
|
|
target = XMVectorClamp(target, g_XMZero, g_Scale565pc);
|
|
|
|
XMFLOAT4A tmp;
|
|
XMStoreFloat4A(&tmp, target);
|
|
|
|
auto dPtr = &dest[index];
|
|
if (dPtr >= ePtr) break;
|
|
dPtr->x = uint16_t(static_cast<uint16_t>(tmp.x) & 0x1F);
|
|
dPtr->y = uint16_t(static_cast<uint16_t>(tmp.y) & 0x3F);
|
|
dPtr->z = uint16_t(static_cast<uint16_t>(tmp.z) & 0x1F);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_B5G5R5A1_UNORM:
|
|
if (size >= sizeof(XMU555))
|
|
{
|
|
XMU555 * __restrict dest = static_cast<XMU555*>(pDestination);
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
auto index = static_cast<ptrdiff_t>((y & 1) ? (count - i - 1) : i);
|
|
ptrdiff_t delta = (y & 1) ? -2 : 0;
|
|
|
|
XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(sPtr[index]);
|
|
v = XMVectorSaturate(v);
|
|
v = XMVectorAdd(v, vError);
|
|
v = XMVectorMultiply(v, g_Scale5551pc);
|
|
|
|
XMVECTOR target;
|
|
if (pDiffusionErrors)
|
|
{
|
|
target = XMVectorRound(v);
|
|
vError = XMVectorSubtract(v, target);
|
|
vError = XMVectorDivide(vError, g_Scale5551pc);
|
|
|
|
// Distribute error to next scanline and next pixel
|
|
pDiffusionErrors[index - delta] = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[index - delta]);
|
|
pDiffusionErrors[index + 1] = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[index + 1]);
|
|
pDiffusionErrors[index + 2 + delta] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[index + 2 + delta]);
|
|
vError = XMVectorMultiply(vError, g_ErrorWeight7);
|
|
}
|
|
else
|
|
{
|
|
// Applied ordered dither
|
|
target = XMVectorAdd(v, ordered[index & 3]);
|
|
target = XMVectorRound(target);
|
|
}
|
|
|
|
target = XMVectorClamp(target, g_XMZero, g_Scale5551pc);
|
|
|
|
XMFLOAT4A tmp;
|
|
XMStoreFloat4A(&tmp, target);
|
|
|
|
auto dPtr = &dest[index];
|
|
if (dPtr >= ePtr) break;
|
|
dPtr->x = uint16_t(static_cast<uint16_t>(tmp.x) & 0x1F);
|
|
dPtr->y = uint16_t(static_cast<uint16_t>(tmp.y) & 0x1F);
|
|
dPtr->z = uint16_t(static_cast<uint16_t>(tmp.z) & 0x1F);
|
|
dPtr->w = (XMVectorGetW(target) > threshold) ? 1u : 0u;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
|
|
STORE_SCANLINE(XMUBYTEN4, g_Scale8pc, true, true, uint8_t, 0xFF, y, true)
|
|
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
|
|
if (size >= sizeof(XMUBYTEN4))
|
|
{
|
|
XMUBYTEN4 * __restrict dest = static_cast<XMUBYTEN4*>(pDestination);
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
auto index = static_cast<ptrdiff_t>((y & 1) ? (count - i - 1) : i);
|
|
ptrdiff_t delta = (y & 1) ? -2 : 0;
|
|
|
|
XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(sPtr[index]);
|
|
v = XMVectorSaturate(v);
|
|
v = XMVectorAdd(v, vError);
|
|
v = XMVectorMultiply(v, g_Scale8pc);
|
|
|
|
XMVECTOR target;
|
|
if (pDiffusionErrors)
|
|
{
|
|
target = XMVectorRound(v);
|
|
vError = XMVectorSubtract(v, target);
|
|
vError = XMVectorDivide(vError, g_Scale8pc);
|
|
|
|
// Distribute error to next scanline and next pixel
|
|
pDiffusionErrors[index - delta] = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[index - delta]);
|
|
pDiffusionErrors[index + 1] = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[index + 1]);
|
|
pDiffusionErrors[index + 2 + delta] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[index + 2 + delta]);
|
|
vError = XMVectorMultiply(vError, g_ErrorWeight7);
|
|
}
|
|
else
|
|
{
|
|
// Applied ordered dither
|
|
target = XMVectorAdd(v, ordered[index & 3]);
|
|
target = XMVectorRound(target);
|
|
}
|
|
|
|
target = XMVectorClamp(target, g_XMZero, g_Scale8pc);
|
|
|
|
XMFLOAT4A tmp;
|
|
XMStoreFloat4A(&tmp, target);
|
|
|
|
auto dPtr = &dest[index];
|
|
if (dPtr >= ePtr) break;
|
|
dPtr->x = uint8_t(static_cast<uint8_t>(tmp.x) & 0xFF);
|
|
dPtr->y = uint8_t(static_cast<uint8_t>(tmp.y) & 0xFF);
|
|
dPtr->z = uint8_t(static_cast<uint8_t>(tmp.z) & 0xFF);
|
|
dPtr->w = 0;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
case DXGI_FORMAT_B4G4R4A4_UNORM:
|
|
STORE_SCANLINE(XMUNIBBLE4, g_Scale4pc, true, true, uint8_t, 0xF, y, true)
|
|
|
|
case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM:
|
|
STORE_SCANLINE(XMXDECN4, g_Scale9pc, false, true, uint16_t, 0x3FF, y, false)
|
|
|
|
case XBOX_DXGI_FORMAT_R4G4_UNORM:
|
|
if (size >= sizeof(uint8_t))
|
|
{
|
|
uint8_t * __restrict dest = static_cast<uint8_t*>(pDestination);
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
auto index = static_cast<ptrdiff_t>((y & 1) ? (count - i - 1) : i);
|
|
ptrdiff_t delta = (y & 1) ? -2 : 0;
|
|
|
|
XMVECTOR v = XMVectorSaturate(sPtr[index]);
|
|
v = XMVectorAdd(v, vError);
|
|
v = XMVectorMultiply(v, g_Scale4pc);
|
|
|
|
XMVECTOR target;
|
|
if (pDiffusionErrors)
|
|
{
|
|
target = XMVectorRound(v);
|
|
vError = XMVectorSubtract(v, target);
|
|
vError = XMVectorDivide(vError, g_Scale4pc);
|
|
|
|
// Distribute error to next scanline and next pixel
|
|
pDiffusionErrors[index - delta] = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[index - delta]);
|
|
pDiffusionErrors[index + 1] = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[index + 1]);
|
|
pDiffusionErrors[index + 2 + delta] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[index + 2 + delta]);
|
|
vError = XMVectorMultiply(vError, g_ErrorWeight7);
|
|
}
|
|
else
|
|
{
|
|
// Applied ordered dither
|
|
target = XMVectorAdd(v, ordered[index & 3]);
|
|
target = XMVectorRound(target);
|
|
}
|
|
|
|
target = XMVectorClamp(target, g_XMZero, g_Scale4pc);
|
|
|
|
XMFLOAT4A tmp;
|
|
XMStoreFloat4A(&tmp, target);
|
|
|
|
auto dPtr = &dest[index];
|
|
if (dPtr >= ePtr) break;
|
|
*dPtr = static_cast<uint8_t>((unsigned(tmp.x) & 0xF) | ((unsigned(tmp.y) & 0xF) << 4));
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
default:
|
|
return _StoreScanline(pDestination, size, format, pSource, count, threshold);
|
|
}
|
|
}
|
|
|
|
#pragma warning(pop)
|
|
|
|
#undef STORE_SCANLINE
|
|
#undef STORE_SCANLINE2
|
|
#undef STORE_SCANLINE1
|
|
|
|
namespace
|
|
{
|
|
|
|
#if !defined(_DXTX_NOWIN)
|
|
//-------------------------------------------------------------------------------------
|
|
// Selection logic for using WIC vs. our own routines
|
|
//-------------------------------------------------------------------------------------
|
|
inline bool UseWICConversion(
|
|
_In_ TEX_FILTER_FLAGS filter,
|
|
_In_ DXGI_FORMAT sformat,
|
|
_In_ DXGI_FORMAT tformat,
|
|
_Out_ WICPixelFormatGUID& pfGUID,
|
|
_Out_ WICPixelFormatGUID& targetGUID) noexcept
|
|
{
|
|
memset(&pfGUID, 0, sizeof(GUID));
|
|
memset(&targetGUID, 0, sizeof(GUID));
|
|
|
|
if (filter & TEX_FILTER_FORCE_NON_WIC)
|
|
{
|
|
// Explicit flag indicates use of non-WIC code paths
|
|
return false;
|
|
}
|
|
|
|
if (!_DXGIToWIC(sformat, pfGUID) || !_DXGIToWIC(tformat, targetGUID))
|
|
{
|
|
// Source or target format are not WIC supported native pixel formats
|
|
return false;
|
|
}
|
|
|
|
if (filter & TEX_FILTER_FORCE_WIC)
|
|
{
|
|
// Explicit flag to use WIC code paths, skips all the case checks below
|
|
return true;
|
|
}
|
|
|
|
if (filter & TEX_FILTER_SEPARATE_ALPHA)
|
|
{
|
|
// Alpha is not premultiplied, so use non-WIC code paths
|
|
return false;
|
|
}
|
|
|
|
if (filter & TEX_FILTER_FLOAT_X2BIAS)
|
|
{
|
|
// X2 Scale & Bias conversions not supported by WIC code paths
|
|
return false;
|
|
}
|
|
|
|
// Check for special cases
|
|
#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)
|
|
if (sformat == DXGI_FORMAT_R16G16B16A16_FLOAT
|
|
|| sformat == DXGI_FORMAT_R16_FLOAT
|
|
|| tformat == DXGI_FORMAT_R16G16B16A16_FLOAT
|
|
|| tformat == DXGI_FORMAT_R16_FLOAT)
|
|
{
|
|
// Use non-WIC code paths as these conversions are not supported by Xbox version of WIC
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
switch (sformat)
|
|
{
|
|
case DXGI_FORMAT_R32G32B32A32_FLOAT:
|
|
case DXGI_FORMAT_R32G32B32_FLOAT:
|
|
case DXGI_FORMAT_R32G32_FLOAT:
|
|
case DXGI_FORMAT_R32_FLOAT:
|
|
case DXGI_FORMAT_D32_FLOAT:
|
|
switch (tformat)
|
|
{
|
|
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
|
case DXGI_FORMAT_R16G16_FLOAT:
|
|
case DXGI_FORMAT_R16_FLOAT:
|
|
// WIC conversions for FP32->FP16 can result in NaN values instead of clamping for min/max value
|
|
return false;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (sformat)
|
|
{
|
|
case DXGI_FORMAT_R32G32B32A32_FLOAT:
|
|
case DXGI_FORMAT_R32G32B32_FLOAT:
|
|
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
|
switch (tformat)
|
|
{
|
|
case DXGI_FORMAT_R16_FLOAT:
|
|
case DXGI_FORMAT_R32_FLOAT:
|
|
case DXGI_FORMAT_D32_FLOAT:
|
|
// WIC converts via UNORM formats and ends up converting colorspaces for these cases
|
|
case DXGI_FORMAT_A8_UNORM:
|
|
// Conversion logic for these kinds of textures is unintuitive for WIC code paths
|
|
return false;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case DXGI_FORMAT_R16_FLOAT:
|
|
switch (tformat)
|
|
{
|
|
case DXGI_FORMAT_R32_FLOAT:
|
|
case DXGI_FORMAT_D32_FLOAT:
|
|
// WIC converts via UNORM formats and ends up converting colorspaces for these cases
|
|
case DXGI_FORMAT_A8_UNORM:
|
|
// Conversion logic for these kinds of textures is unintuitive for WIC code paths
|
|
return false;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case DXGI_FORMAT_A8_UNORM:
|
|
// Conversion logic for these kinds of textures is unintuitive for WIC code paths
|
|
return false;
|
|
|
|
default:
|
|
switch (tformat)
|
|
{
|
|
case DXGI_FORMAT_A8_UNORM:
|
|
// Conversion logic for these kinds of textures is unintuitive for WIC code paths
|
|
return false;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check for implicit color space changes
|
|
if (IsSRGB(sformat))
|
|
filter |= TEX_FILTER_SRGB_IN;
|
|
|
|
if (IsSRGB(tformat))
|
|
filter |= TEX_FILTER_SRGB_OUT;
|
|
|
|
if ((filter & (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT)) == (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT))
|
|
{
|
|
filter &= ~(TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT);
|
|
}
|
|
|
|
auto wicsrgb = _CheckWICColorSpace(pfGUID, targetGUID);
|
|
|
|
if (wicsrgb != (filter & (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT)))
|
|
{
|
|
// WIC will perform a colorspace conversion we didn't request
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Convert the source image using WIC
|
|
//-------------------------------------------------------------------------------------
|
|
HRESULT ConvertUsingWIC(
|
|
_In_ const Image& srcImage,
|
|
_In_ const WICPixelFormatGUID& pfGUID,
|
|
_In_ const WICPixelFormatGUID& targetGUID,
|
|
_In_ TEX_FILTER_FLAGS filter,
|
|
_In_ float threshold,
|
|
_In_ const Image& destImage)
|
|
{
|
|
assert(srcImage.width == destImage.width);
|
|
assert(srcImage.height == destImage.height);
|
|
|
|
bool iswic2 = false;
|
|
auto pWIC = GetWICFactory(iswic2);
|
|
if (!pWIC)
|
|
return E_NOINTERFACE;
|
|
|
|
ComPtr<IWICFormatConverter> FC;
|
|
HRESULT hr = pWIC->CreateFormatConverter(FC.GetAddressOf());
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// Note that WIC conversion ignores the TEX_FILTER_SRGB_IN and TEX_FILTER_SRGB_OUT flags,
|
|
// but also always assumes UNORM <-> FLOAT conversions are changing color spaces sRGB <-> scRGB
|
|
|
|
BOOL canConvert = FALSE;
|
|
hr = FC->CanConvert(pfGUID, targetGUID, &canConvert);
|
|
if (FAILED(hr) || !canConvert)
|
|
{
|
|
// This case is not an issue for the subset of WIC formats that map directly to DXGI
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
if (srcImage.rowPitch > UINT32_MAX || srcImage.slicePitch > UINT32_MAX
|
|
|| destImage.rowPitch > UINT32_MAX || destImage.slicePitch > UINT32_MAX)
|
|
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
|
|
|
|
ComPtr<IWICBitmap> source;
|
|
hr = pWIC->CreateBitmapFromMemory(static_cast<UINT>(srcImage.width), static_cast<UINT>(srcImage.height), pfGUID,
|
|
static_cast<UINT>(srcImage.rowPitch), static_cast<UINT>(srcImage.slicePitch),
|
|
srcImage.pixels, source.GetAddressOf());
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = FC->Initialize(source.Get(), targetGUID, _GetWICDither(filter), nullptr, static_cast<double>(threshold) * 100.0, WICBitmapPaletteTypeMedianCut);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = FC->CopyPixels(nullptr, static_cast<UINT>(destImage.rowPitch), static_cast<UINT>(destImage.slicePitch), destImage.pixels);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Convert the source image (not using WIC)
|
|
//-------------------------------------------------------------------------------------
|
|
HRESULT ConvertCustom(
|
|
_In_ const Image& srcImage,
|
|
_In_ TEX_FILTER_FLAGS filter,
|
|
_In_ const Image& destImage,
|
|
_In_ float threshold,
|
|
size_t z) noexcept
|
|
{
|
|
assert(srcImage.width == destImage.width);
|
|
assert(srcImage.height == destImage.height);
|
|
|
|
const uint8_t *pSrc = srcImage.pixels;
|
|
uint8_t *pDest = destImage.pixels;
|
|
if (!pSrc || !pDest)
|
|
return E_POINTER;
|
|
|
|
size_t width = srcImage.width;
|
|
|
|
if (filter & TEX_FILTER_DITHER_DIFFUSION)
|
|
{
|
|
// Error diffusion dithering (aka Floyd-Steinberg dithering)
|
|
ScopedAlignedArrayXMVECTOR scanline(static_cast<XMVECTOR*>(AllocateVectorAligned((sizeof(XMVECTOR)*(width * 2 + 2)))));
|
|
if (!scanline)
|
|
return E_OUTOFMEMORY;
|
|
|
|
XMVECTOR* pDiffusionErrors = scanline.get() + width;
|
|
memset(pDiffusionErrors, 0, sizeof(XMVECTOR)*(width + 2));
|
|
|
|
for (size_t h = 0; h < srcImage.height; ++h)
|
|
{
|
|
if (!_LoadScanline(scanline.get(), width, pSrc, srcImage.rowPitch, srcImage.format))
|
|
return E_FAIL;
|
|
|
|
_ConvertScanline(scanline.get(), width, destImage.format, srcImage.format, filter);
|
|
|
|
if (!_StoreScanlineDither(pDest, destImage.rowPitch, destImage.format, scanline.get(), width, threshold, h, z, pDiffusionErrors))
|
|
return E_FAIL;
|
|
|
|
pSrc += srcImage.rowPitch;
|
|
pDest += destImage.rowPitch;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ScopedAlignedArrayXMVECTOR scanline(static_cast<XMVECTOR*>(AllocateVectorAligned((sizeof(XMVECTOR)*width))));
|
|
if (!scanline)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (filter & TEX_FILTER_DITHER)
|
|
{
|
|
// Ordered dithering
|
|
for (size_t h = 0; h < srcImage.height; ++h)
|
|
{
|
|
if (!_LoadScanline(scanline.get(), width, pSrc, srcImage.rowPitch, srcImage.format))
|
|
return E_FAIL;
|
|
|
|
_ConvertScanline(scanline.get(), width, destImage.format, srcImage.format, filter);
|
|
|
|
if (!_StoreScanlineDither(pDest, destImage.rowPitch, destImage.format, scanline.get(), width, threshold, h, z, nullptr))
|
|
return E_FAIL;
|
|
|
|
pSrc += srcImage.rowPitch;
|
|
pDest += destImage.rowPitch;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No dithering
|
|
for (size_t h = 0; h < srcImage.height; ++h)
|
|
{
|
|
if (!_LoadScanline(scanline.get(), width, pSrc, srcImage.rowPitch, srcImage.format))
|
|
return E_FAIL;
|
|
|
|
_ConvertScanline(scanline.get(), width, destImage.format, srcImage.format, filter);
|
|
|
|
if (!_StoreScanline(pDest, destImage.rowPitch, destImage.format, scanline.get(), width, threshold))
|
|
return E_FAIL;
|
|
|
|
pSrc += srcImage.rowPitch;
|
|
pDest += destImage.rowPitch;
|
|
}
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
DXGI_FORMAT _PlanarToSingle(_In_ DXGI_FORMAT format) noexcept
|
|
{
|
|
switch (format)
|
|
{
|
|
case DXGI_FORMAT_NV12:
|
|
case DXGI_FORMAT_NV11:
|
|
return DXGI_FORMAT_YUY2;
|
|
|
|
case DXGI_FORMAT_P010:
|
|
return DXGI_FORMAT_Y210;
|
|
|
|
case DXGI_FORMAT_P016:
|
|
return DXGI_FORMAT_Y216;
|
|
|
|
// We currently do not support conversion for Xbox One specific 16-bit depth formats
|
|
|
|
// We can't do anything with DXGI_FORMAT_420_OPAQUE because it's an opaque blob of bits
|
|
|
|
// We don't support conversion of JPEG Hardware decode formats
|
|
|
|
default:
|
|
return DXGI_FORMAT_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Convert the image from a planar to non-planar image
|
|
//-------------------------------------------------------------------------------------
|
|
#define CONVERT_420_TO_422( srcType, destType )\
|
|
{\
|
|
size_t rowPitch = srcImage.rowPitch;\
|
|
\
|
|
auto sourceE = reinterpret_cast<const srcType*>(pSrc + srcImage.slicePitch);\
|
|
auto pSrcUV = pSrc + (srcImage.height * rowPitch);\
|
|
\
|
|
for(size_t y = 0; y < srcImage.height; y+= 2)\
|
|
{\
|
|
auto sPtrY0 = reinterpret_cast<const srcType*>(pSrc);\
|
|
auto sPtrY2 = reinterpret_cast<const srcType*>(pSrc + rowPitch);\
|
|
auto sPtrUV = reinterpret_cast<const srcType*>(pSrcUV);\
|
|
\
|
|
destType * __restrict dPtr0 = reinterpret_cast<destType*>(pDest);\
|
|
destType * __restrict dPtr1 = reinterpret_cast<destType*>(pDest + destImage.rowPitch);\
|
|
\
|
|
for(size_t x = 0; x < srcImage.width; x+= 2)\
|
|
{\
|
|
if ((sPtrUV+1) >= sourceE) break;\
|
|
\
|
|
srcType u = *(sPtrUV++);\
|
|
srcType v = *(sPtrUV++);\
|
|
\
|
|
dPtr0->x = *(sPtrY0++);\
|
|
dPtr0->y = u;\
|
|
dPtr0->z = *(sPtrY0++);\
|
|
dPtr0->w = v;\
|
|
++dPtr0;\
|
|
\
|
|
dPtr1->x = *(sPtrY2++);\
|
|
dPtr1->y = u;\
|
|
dPtr1->z = *(sPtrY2++);\
|
|
dPtr1->w = v;\
|
|
++dPtr1;\
|
|
}\
|
|
\
|
|
pSrc += rowPitch * 2;\
|
|
pSrcUV += rowPitch;\
|
|
\
|
|
pDest += destImage.rowPitch * 2;\
|
|
}\
|
|
}
|
|
|
|
HRESULT ConvertToSinglePlane_(_In_ const Image& srcImage, _In_ const Image& destImage) noexcept
|
|
{
|
|
assert(srcImage.width == destImage.width);
|
|
assert(srcImage.height == destImage.height);
|
|
|
|
const uint8_t *pSrc = srcImage.pixels;
|
|
uint8_t *pDest = destImage.pixels;
|
|
if (!pSrc || !pDest)
|
|
return E_POINTER;
|
|
|
|
switch (srcImage.format)
|
|
{
|
|
case DXGI_FORMAT_NV12:
|
|
assert(destImage.format == DXGI_FORMAT_YUY2);
|
|
CONVERT_420_TO_422(uint8_t, XMUBYTEN4)
|
|
return S_OK;
|
|
|
|
case DXGI_FORMAT_P010:
|
|
assert(destImage.format == DXGI_FORMAT_Y210);
|
|
CONVERT_420_TO_422(uint16_t, XMUSHORTN4)
|
|
return S_OK;
|
|
|
|
case DXGI_FORMAT_P016:
|
|
assert(destImage.format == DXGI_FORMAT_Y216);
|
|
CONVERT_420_TO_422(uint16_t, XMUSHORTN4)
|
|
return S_OK;
|
|
|
|
case DXGI_FORMAT_NV11:
|
|
assert(destImage.format == DXGI_FORMAT_YUY2);
|
|
// Convert 4:1:1 to 4:2:2
|
|
{
|
|
size_t rowPitch = srcImage.rowPitch;
|
|
|
|
const uint8_t* sourceE = pSrc + srcImage.slicePitch;
|
|
const uint8_t* pSrcUV = pSrc + (srcImage.height * rowPitch);
|
|
|
|
for (size_t y = 0; y < srcImage.height; ++y)
|
|
{
|
|
const uint8_t* sPtrY = pSrc;
|
|
const uint8_t* sPtrUV = pSrcUV;
|
|
|
|
XMUBYTEN4 * __restrict dPtr = reinterpret_cast<XMUBYTEN4*>(pDest);
|
|
|
|
for (size_t x = 0; x < srcImage.width; x += 4)
|
|
{
|
|
if ((sPtrUV + 1) >= sourceE) break;
|
|
|
|
uint8_t u = *(sPtrUV++);
|
|
uint8_t v = *(sPtrUV++);
|
|
|
|
dPtr->x = *(sPtrY++);
|
|
dPtr->y = u;
|
|
dPtr->z = *(sPtrY++);
|
|
dPtr->w = v;
|
|
++dPtr;
|
|
|
|
dPtr->x = *(sPtrY++);
|
|
dPtr->y = u;
|
|
dPtr->z = *(sPtrY++);
|
|
dPtr->w = v;
|
|
++dPtr;
|
|
}
|
|
|
|
pSrc += rowPitch;
|
|
pSrcUV += (rowPitch >> 1);
|
|
|
|
pDest += destImage.rowPitch;
|
|
}
|
|
}
|
|
return S_OK;
|
|
|
|
default:
|
|
return E_UNEXPECTED;
|
|
}
|
|
}
|
|
|
|
#undef CONVERT_420_TO_422
|
|
}
|
|
|
|
|
|
//=====================================================================================
|
|
// Entry-points
|
|
//=====================================================================================
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Convert image
|
|
//-------------------------------------------------------------------------------------
|
|
_Use_decl_annotations_
|
|
HRESULT DirectX::Convert(
|
|
const Image& srcImage,
|
|
DXGI_FORMAT format,
|
|
TEX_FILTER_FLAGS filter,
|
|
float threshold,
|
|
ScratchImage& image) noexcept
|
|
{
|
|
if ((srcImage.format == format) || !IsValid(format))
|
|
return E_INVALIDARG;
|
|
|
|
if (!srcImage.pixels)
|
|
return E_POINTER;
|
|
|
|
if (IsCompressed(srcImage.format) || IsCompressed(format)
|
|
|| IsPlanar(srcImage.format) || IsPlanar(format)
|
|
|| IsPalettized(srcImage.format) || IsPalettized(format)
|
|
|| IsTypeless(srcImage.format) || IsTypeless(format))
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
|
|
|
if ((srcImage.width > UINT32_MAX) || (srcImage.height > UINT32_MAX))
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr = image.Initialize2D(format, srcImage.width, srcImage.height, 1, 1);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
const Image *rimage = image.GetImage(0, 0, 0);
|
|
if (!rimage)
|
|
{
|
|
image.Release();
|
|
return E_POINTER;
|
|
}
|
|
|
|
#if !defined(_DXTX_NOWIN)
|
|
WICPixelFormatGUID pfGUID, targetGUID;
|
|
if (UseWICConversion(filter, srcImage.format, format, pfGUID, targetGUID))
|
|
{
|
|
hr = ConvertUsingWIC(srcImage, pfGUID, targetGUID, filter, threshold, *rimage);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
hr = ConvertCustom(srcImage, filter, *rimage, threshold, 0);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
image.Release();
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Convert image (complex)
|
|
//-------------------------------------------------------------------------------------
|
|
_Use_decl_annotations_
|
|
HRESULT DirectX::Convert(
|
|
const Image* srcImages,
|
|
size_t nimages,
|
|
const TexMetadata& metadata,
|
|
DXGI_FORMAT format,
|
|
TEX_FILTER_FLAGS filter,
|
|
float threshold,
|
|
ScratchImage& result) noexcept
|
|
{
|
|
if (!srcImages || !nimages || (metadata.format == format) || !IsValid(format))
|
|
return E_INVALIDARG;
|
|
|
|
if (IsCompressed(metadata.format) || IsCompressed(format)
|
|
|| IsPlanar(metadata.format) || IsPlanar(format)
|
|
|| IsPalettized(metadata.format) || IsPalettized(format)
|
|
|| IsTypeless(metadata.format) || IsTypeless(format))
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
|
|
|
if ((metadata.width > UINT32_MAX) || (metadata.height > UINT32_MAX))
|
|
return E_INVALIDARG;
|
|
|
|
TexMetadata mdata2 = metadata;
|
|
mdata2.format = format;
|
|
HRESULT hr = result.Initialize(mdata2);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
if (nimages != result.GetImageCount())
|
|
{
|
|
result.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
const Image* dest = result.GetImages();
|
|
if (!dest)
|
|
{
|
|
result.Release();
|
|
return E_POINTER;
|
|
}
|
|
|
|
bool usewic;
|
|
#if !defined(_DXTX_NOWIN)
|
|
WICPixelFormatGUID pfGUID, targetGUID;
|
|
usewic =!metadata.IsPMAlpha() && UseWICConversion(filter, metadata.format, format, pfGUID, targetGUID);
|
|
#else
|
|
usewic = false;
|
|
#endif
|
|
|
|
|
|
switch (metadata.dimension)
|
|
{
|
|
case TEX_DIMENSION_TEXTURE1D:
|
|
case TEX_DIMENSION_TEXTURE2D:
|
|
for (size_t index = 0; index < nimages; ++index)
|
|
{
|
|
const Image& src = srcImages[index];
|
|
if (src.format != metadata.format)
|
|
{
|
|
result.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
if ((src.width > UINT32_MAX) || (src.height > UINT32_MAX))
|
|
{
|
|
result.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
const Image& dst = dest[index];
|
|
assert(dst.format == format);
|
|
|
|
if (src.width != dst.width || src.height != dst.height)
|
|
{
|
|
result.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
#if !defined(_DXTX_NOWIN)
|
|
if (usewic)
|
|
{
|
|
hr = ConvertUsingWIC(src, pfGUID, targetGUID, filter, threshold, dst);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
hr = ConvertCustom(src, filter, dst, threshold, 0);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
result.Release();
|
|
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)
|
|
{
|
|
result.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
const Image& src = srcImages[index];
|
|
if (src.format != metadata.format)
|
|
{
|
|
result.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
if ((src.width > UINT32_MAX) || (src.height > UINT32_MAX))
|
|
{
|
|
result.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
const Image& dst = dest[index];
|
|
assert(dst.format == format);
|
|
|
|
if (src.width != dst.width || src.height != dst.height)
|
|
{
|
|
result.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
#if !defined(_DXTX_NOWIN)
|
|
if (usewic)
|
|
{
|
|
hr = ConvertUsingWIC(src, pfGUID, targetGUID, filter, threshold, dst);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
hr = ConvertCustom(src, filter, dst, threshold, slice);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
result.Release();
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
if (d > 1)
|
|
d >>= 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
result.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Convert image from planar to single plane (image)
|
|
//-------------------------------------------------------------------------------------
|
|
_Use_decl_annotations_
|
|
HRESULT DirectX::ConvertToSinglePlane(const Image& srcImage, ScratchImage& image) noexcept
|
|
{
|
|
if (!IsPlanar(srcImage.format))
|
|
return E_INVALIDARG;
|
|
|
|
if (!srcImage.pixels)
|
|
return E_POINTER;
|
|
|
|
DXGI_FORMAT format = _PlanarToSingle(srcImage.format);
|
|
if (format == DXGI_FORMAT_UNKNOWN)
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
|
|
|
if ((srcImage.width > UINT32_MAX) || (srcImage.height > UINT32_MAX))
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr = image.Initialize2D(format, srcImage.width, srcImage.height, 1, 1);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
const Image *rimage = image.GetImage(0, 0, 0);
|
|
if (!rimage)
|
|
{
|
|
image.Release();
|
|
return E_POINTER;
|
|
}
|
|
|
|
hr = ConvertToSinglePlane_(srcImage, *rimage);
|
|
if (FAILED(hr))
|
|
{
|
|
image.Release();
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Convert image from planar to single plane (complex)
|
|
//-------------------------------------------------------------------------------------
|
|
_Use_decl_annotations_
|
|
HRESULT DirectX::ConvertToSinglePlane(
|
|
const Image* srcImages,
|
|
size_t nimages,
|
|
const TexMetadata& metadata,
|
|
ScratchImage& result) noexcept
|
|
{
|
|
if (!srcImages || !nimages)
|
|
return E_INVALIDARG;
|
|
|
|
if (metadata.IsVolumemap())
|
|
{
|
|
// Direct3D does not support any planar formats for Texture3D
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
|
}
|
|
|
|
DXGI_FORMAT format = _PlanarToSingle(metadata.format);
|
|
if (format == DXGI_FORMAT_UNKNOWN)
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
|
|
|
if ((metadata.width > UINT32_MAX) || (metadata.height > UINT32_MAX))
|
|
return E_INVALIDARG;
|
|
|
|
TexMetadata mdata2 = metadata;
|
|
mdata2.format = format;
|
|
HRESULT hr = result.Initialize(mdata2);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
if (nimages != result.GetImageCount())
|
|
{
|
|
result.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
const Image* dest = result.GetImages();
|
|
if (!dest)
|
|
{
|
|
result.Release();
|
|
return E_POINTER;
|
|
}
|
|
|
|
for (size_t index = 0; index < nimages; ++index)
|
|
{
|
|
const Image& src = srcImages[index];
|
|
if (src.format != metadata.format)
|
|
{
|
|
result.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
if ((src.width > UINT32_MAX) || (src.height > UINT32_MAX))
|
|
return E_FAIL;
|
|
|
|
const Image& dst = dest[index];
|
|
assert(dst.format == format);
|
|
|
|
if (src.width != dst.width || src.height != dst.height)
|
|
{
|
|
result.Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
hr = ConvertToSinglePlane_(src, dst);
|
|
if (FAILED(hr))
|
|
{
|
|
result.Release();
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
// Returns the data type of a DXGI_FORMAT
|
|
//-------------------------------------------------------------------------------------
|
|
DirectX::FORMAT_TYPE DirectX::FormatDataType(_In_ DXGI_FORMAT fmt) noexcept
|
|
{
|
|
auto cflags = _GetConvertFlags(fmt);
|
|
|
|
switch (cflags & (CONVF_FLOAT | CONVF_UNORM | CONVF_UINT | CONVF_SNORM | CONVF_SINT))
|
|
{
|
|
case CONVF_FLOAT:
|
|
return FORMAT_TYPE_FLOAT;
|
|
|
|
case CONVF_UNORM:
|
|
return FORMAT_TYPE_UNORM;
|
|
|
|
case CONVF_UINT:
|
|
return FORMAT_TYPE_UINT;
|
|
|
|
case CONVF_SNORM:
|
|
return FORMAT_TYPE_SNORM;
|
|
|
|
case CONVF_SINT:
|
|
return FORMAT_TYPE_SINT;
|
|
|
|
default:
|
|
return FORMAT_TYPE_TYPELESS;
|
|
}
|
|
}
|