in Src/XboxDDSTextureLoader.cpp [263:452]
HRESULT CreateTextureFromDDS(_In_ ID3D12Device* d3dDevice,
_In_ const DDS_HEADER* header,
_In_reads_bytes_(bitSize) const uint8_t* bitData,
_In_ size_t bitSize,
_In_ bool forceSRGB,
_Outptr_ ID3D12Resource** texture,
_Outptr_ void** grfxMemory,
_Out_opt_ bool* outIsCubeMap) noexcept
{
HRESULT hr = S_OK;
uint32_t width = header->width;
uint32_t height = header->height;
uint32_t depth = header->depth;
uint32_t mipCount = header->mipMapCount;
if (0 == mipCount)
{
mipCount = 1;
}
if (!(header->ddspf.flags & DDS_FOURCC)
|| (MAKEFOURCC('X', 'B', 'O', 'X') != header->ddspf.fourCC))
{
// Use standard DDSTextureLoader instead
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
auto xboxext = reinterpret_cast<const DDS_HEADER_XBOX*>(reinterpret_cast<const uint8_t*>(header) + sizeof(DDS_HEADER));
#if !defined(NDEBUG) && defined(_GXDK_VER)
if (xboxext->xdkVer < _GXDK_VER)
{
OutputDebugStringA("WARNING: DDS XBOX file may be outdated and need regeneration\n");
}
#elif !defined(NDEBUG) && defined(_XDK_VER)
if (xboxext->xdkVer < _XDK_VER)
{
OutputDebugStringA("WARNING: DDS XBOX file may be outdated and need regeneration\n");
}
#endif
uint32_t arraySize = xboxext->arraySize;
if (arraySize == 0)
{
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
bool isCubeMap = false;
switch (xboxext->resourceDimension)
{
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
if ((header->flags & DDS_HEIGHT) && height != 1)
{
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
height = depth = 1;
break;
case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
if (xboxext->miscFlag & 0x4 /* RESOURCE_MISC_TEXTURECUBE */)
{
arraySize *= 6;
isCubeMap = true;
}
depth = 1;
break;
case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
if (!(header->flags & DDS_HEADER_FLAGS_VOLUME))
{
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
if (arraySize > 1)
{
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
break;
default:
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
if (xboxext->tileMode == uint32_t(-1))
{
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
#if defined(_GAMING_XBOX_SCARLETT)
else if (!(xboxext->tileMode & XBOX_TILEMODE_SCARLETT))
{
DebugTrace("ERROR: XboxDDSTextureLoader for Scarlett cannot load textures tiled for Xbox One");
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
#else
else if (xboxext->tileMode & XBOX_TILEMODE_SCARLETT)
{
DebugTrace("ERROR: XboxDDSTextureLoader for Xbox One cannot load textures tiled for Scarlett");
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
#endif
// Bound sizes
if (mipCount > D3D11_REQ_MIP_LEVELS)
{
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
switch (xboxext->resourceDimension)
{
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
if ((arraySize > D3D12_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION) ||
(width > D3D12_REQ_TEXTURE1D_U_DIMENSION))
{
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
break;
case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
if (isCubeMap)
{
// This is the right bound because we set arraySize to (NumCubes*6) above
if ((arraySize > D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) ||
(width > D3D12_REQ_TEXTURECUBE_DIMENSION) ||
(height > D3D12_REQ_TEXTURECUBE_DIMENSION))
{
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
}
else if ((arraySize > D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) ||
(width > D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION) ||
(height > D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION))
{
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
break;
case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
if ((arraySize > 1) ||
(width > D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ||
(height > D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ||
(depth > D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION))
{
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
break;
}
if (xboxext->dxgiFormat == DXGI_FORMAT_UNKNOWN)
{
return E_FAIL;
}
if (!xboxext->dataSize || !xboxext->baseAlignment)
{
return E_FAIL;
}
if (xboxext->dataSize > bitSize)
{
return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
}
// Allocate graphics memory. Depending on the data size it uses 4MB or 64K pages.
*grfxMemory = XMemAlloc(xboxext->dataSize, c_XMemAllocAttributes);
if (!*grfxMemory)
return E_OUTOFMEMORY;
// Copy tiled data into graphics memory
memcpy(*grfxMemory, bitData, xboxext->dataSize);
// Create the texture
hr = CreateD3DResources(d3dDevice, xboxext,
width, height, depth, mipCount, arraySize,
forceSRGB, *grfxMemory,
texture);
if (FAILED(hr))
{
XMemFree(*grfxMemory, c_XMemAllocAttributes);
*grfxMemory = nullptr;
}
if (outIsCubeMap)
{
*outIsCubeMap = isCubeMap;
}
return hr;
}