in Src/XboxDDSTextureLoader.cpp [416:582]
HRESULT CreateTextureFromDDS(_In_ ID3D11DeviceX* d3dDevice,
_In_ const DDS_HEADER* header,
_In_reads_bytes_(bitSize) const uint8_t* bitData,
_In_ size_t bitSize,
_In_ bool forceSRGB,
_Outptr_opt_ ID3D11Resource** texture,
_Outptr_opt_ ID3D11ShaderResourceView** textureView,
_Outptr_ void** grfxMemory) 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));
#ifndef NDEBUG
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 D3D11_RESOURCE_DIMENSION_TEXTURE1D:
if ((header->flags & DDS_HEIGHT) && height != 1)
{
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
height = depth = 1;
break;
case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
if (xboxext->miscFlag & D3D11_RESOURCE_MISC_TEXTURECUBE)
{
arraySize *= 6;
isCubeMap = true;
}
depth = 1;
break;
case D3D11_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);
}
// Bound sizes
if (mipCount > D3D11_REQ_MIP_LEVELS)
{
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
switch (xboxext->resourceDimension)
{
case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
if ((arraySize > D3D11_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION) ||
(width > D3D11_REQ_TEXTURE1D_U_DIMENSION))
{
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
break;
case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
if (isCubeMap)
{
// This is the right bound because we set arraySize to (NumCubes*6) above
if ((arraySize > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) ||
(width > D3D11_REQ_TEXTURECUBE_DIMENSION) ||
(height > D3D11_REQ_TEXTURECUBE_DIMENSION))
{
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
}
else if ((arraySize > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) ||
(width > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION) ||
(height > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION))
{
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
break;
case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
if ((arraySize > 1) ||
(width > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ||
(height > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ||
(depth > D3D11_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, isCubeMap, *grfxMemory,
texture, textureView);
if (FAILED(hr))
{
XMemFree(grfxMemory, c_XMemAllocAttributes);
*grfxMemory = nullptr;
}
return hr;
}