template project, first version
This commit is contained in:
787
DirectXTK/Src/XboxDDSTextureLoader.cpp
Normal file
787
DirectXTK/Src/XboxDDSTextureLoader.cpp
Normal file
@@ -0,0 +1,787 @@
|
||||
//--------------------------------------------------------------------------------------
|
||||
// File: XboxDDSTextureLoader.cpp
|
||||
//
|
||||
// Functions for loading a DDS texture using the XBOX extended header and creating a
|
||||
// Direct3D11.X runtime resource for it via the CreatePlacement APIs
|
||||
//
|
||||
// Note these functions will not load standard DDS files. Use the DDSTextureLoader
|
||||
// module in the DirectXTex package or as part of the DirectXTK library to load
|
||||
// these files which use standard Direct3D resource creation APIs.
|
||||
//
|
||||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||||
// PARTICULAR PURPOSE.
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// http://go.microsoft.com/fwlink/?LinkId=248926
|
||||
// http://go.microsoft.com/fwlink/?LinkId=248929
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include "XboxDDSTextureLoader.h"
|
||||
|
||||
#include "dds.h"
|
||||
#include "DirectXHelpers.h"
|
||||
#include "PlatformHelpers.h"
|
||||
|
||||
#include <xdk.h>
|
||||
|
||||
using namespace DirectX;
|
||||
using namespace Xbox;
|
||||
|
||||
namespace
|
||||
{
|
||||
//--------------------------------------------------------------------------------------
|
||||
// DDS file structure definitions
|
||||
//
|
||||
// See DDS.h in the 'Texconv' sample and the 'DirectXTex' library
|
||||
//--------------------------------------------------------------------------------------
|
||||
#pragma pack(push,1)
|
||||
|
||||
struct DDS_HEADER_XBOX
|
||||
// Must match structure defined in xtexconv tool
|
||||
{
|
||||
DXGI_FORMAT dxgiFormat;
|
||||
uint32_t resourceDimension;
|
||||
uint32_t miscFlag; // see DDS_RESOURCE_MISC_FLAG
|
||||
uint32_t arraySize;
|
||||
uint32_t miscFlags2; // see DDS_MISC_FLAGS2
|
||||
uint32_t tileMode; // see XG_TILE_MODE
|
||||
uint32_t baseAlignment;
|
||||
uint32_t dataSize;
|
||||
uint32_t xdkVer; // matching _XDK_VER
|
||||
};
|
||||
|
||||
static_assert(sizeof(DDS_HEADER_XBOX) == 36, "DDS XBOX Header size mismatch");
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
HRESULT LoadTextureDataFromFile(_In_z_ const wchar_t* fileName,
|
||||
std::unique_ptr<uint8_t[]>& ddsData,
|
||||
DDS_HEADER** header,
|
||||
uint8_t** bitData,
|
||||
size_t* bitSize
|
||||
)
|
||||
{
|
||||
if (!header || !bitData || !bitSize)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
// open the file
|
||||
ScopedHandle hFile(safe_handle(CreateFile2(fileName,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
OPEN_EXISTING,
|
||||
nullptr)));
|
||||
|
||||
if (!hFile)
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
// Get the file size
|
||||
LARGE_INTEGER FileSize = { 0 };
|
||||
|
||||
FILE_STANDARD_INFO fileInfo;
|
||||
if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
FileSize = fileInfo.EndOfFile;
|
||||
|
||||
// File is too big for 32-bit allocation, so reject read
|
||||
if (FileSize.HighPart > 0)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Need at least enough data to fill the header and magic number to be a valid DDS
|
||||
if (FileSize.LowPart < (sizeof(DDS_HEADER) + sizeof(uint32_t)))
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// create enough space for the file data
|
||||
ddsData.reset(new (std::nothrow) uint8_t[FileSize.LowPart]);
|
||||
if (!ddsData)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
// read the data in
|
||||
DWORD BytesRead = 0;
|
||||
if (!ReadFile(hFile.get(),
|
||||
ddsData.get(),
|
||||
FileSize.LowPart,
|
||||
&BytesRead,
|
||||
nullptr
|
||||
))
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
if (BytesRead < FileSize.LowPart)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// DDS files always start with the same magic number ("DDS ")
|
||||
uint32_t dwMagicNumber = *(const uint32_t*)(ddsData.get());
|
||||
if (dwMagicNumber != DDS_MAGIC)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
auto hdr = reinterpret_cast<DDS_HEADER*>(ddsData.get() + sizeof(uint32_t));
|
||||
|
||||
// Verify header to validate DDS file
|
||||
if (hdr->size != sizeof(DDS_HEADER) ||
|
||||
hdr->ddspf.size != sizeof(DDS_PIXELFORMAT))
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Check for XBOX extension
|
||||
if (!(hdr->ddspf.flags & DDS_FOURCC)
|
||||
|| (MAKEFOURCC('X', 'B', 'O', 'X') != hdr->ddspf.fourCC))
|
||||
{
|
||||
// Use standard DDSTextureLoader instead
|
||||
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
// Must be long enough for both headers and magic value
|
||||
if (FileSize.LowPart < (sizeof(DDS_HEADER) + sizeof(uint32_t) + sizeof(DDS_HEADER_XBOX)))
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// setup the pointers in the process request
|
||||
*header = hdr;
|
||||
ptrdiff_t offset = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_XBOX);
|
||||
*bitData = ddsData.get() + offset;
|
||||
*bitSize = FileSize.LowPart - offset;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
DXGI_FORMAT MakeSRGB(_In_ DXGI_FORMAT format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
|
||||
|
||||
case DXGI_FORMAT_BC1_UNORM:
|
||||
return DXGI_FORMAT_BC1_UNORM_SRGB;
|
||||
|
||||
case DXGI_FORMAT_BC2_UNORM:
|
||||
return DXGI_FORMAT_BC2_UNORM_SRGB;
|
||||
|
||||
case DXGI_FORMAT_BC3_UNORM:
|
||||
return DXGI_FORMAT_BC3_UNORM_SRGB;
|
||||
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
||||
return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
|
||||
|
||||
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
||||
return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB;
|
||||
|
||||
case DXGI_FORMAT_BC7_UNORM:
|
||||
return DXGI_FORMAT_BC7_UNORM_SRGB;
|
||||
|
||||
default:
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
HRESULT CreateD3DResources(_In_ ID3D11DeviceX* d3dDevice,
|
||||
_In_ const DDS_HEADER_XBOX* xboxext,
|
||||
_In_ uint32_t width,
|
||||
_In_ uint32_t height,
|
||||
_In_ uint32_t depth,
|
||||
_In_ uint32_t mipCount,
|
||||
_In_ uint32_t arraySize,
|
||||
_In_ bool forceSRGB,
|
||||
_In_ bool isCubeMap,
|
||||
_In_ void* grfxMemory,
|
||||
_Outptr_opt_ ID3D11Resource** texture,
|
||||
_Outptr_opt_ ID3D11ShaderResourceView** textureView)
|
||||
{
|
||||
if (!d3dDevice || !grfxMemory)
|
||||
return E_POINTER;
|
||||
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
DXGI_FORMAT format = xboxext->dxgiFormat;
|
||||
if (forceSRGB)
|
||||
{
|
||||
format = MakeSRGB(format);
|
||||
}
|
||||
|
||||
switch (xboxext->resourceDimension)
|
||||
{
|
||||
case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
|
||||
{
|
||||
D3D11_TEXTURE1D_DESC desc;
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
desc.Width = static_cast<UINT>(width);
|
||||
desc.MipLevels = static_cast<UINT>(mipCount);
|
||||
desc.ArraySize = static_cast<UINT>(arraySize);
|
||||
desc.Format = format;
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
|
||||
ID3D11Texture1D* tex = nullptr;
|
||||
hr = d3dDevice->CreatePlacementTexture1D(&desc, xboxext->tileMode, 0, grfxMemory, &tex);
|
||||
if (SUCCEEDED(hr) && tex != 0)
|
||||
{
|
||||
if (textureView != 0)
|
||||
{
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
|
||||
memset(&SRVDesc, 0, sizeof(SRVDesc));
|
||||
SRVDesc.Format = format;
|
||||
|
||||
if (arraySize > 1)
|
||||
{
|
||||
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
|
||||
SRVDesc.Texture1DArray.MipLevels = desc.MipLevels;
|
||||
SRVDesc.Texture1DArray.ArraySize = static_cast<UINT>(arraySize);
|
||||
}
|
||||
else
|
||||
{
|
||||
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
|
||||
SRVDesc.Texture1D.MipLevels = desc.MipLevels;
|
||||
}
|
||||
|
||||
hr = d3dDevice->CreateShaderResourceView(tex,
|
||||
&SRVDesc,
|
||||
textureView
|
||||
);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
tex->Release();
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
if (texture != 0)
|
||||
{
|
||||
*texture = tex;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDebugObjectName(tex, "XboxDDSTextureLoader");
|
||||
tex->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
desc.Width = static_cast<UINT>(width);
|
||||
desc.Height = static_cast<UINT>(height);
|
||||
desc.MipLevels = static_cast<UINT>(mipCount);
|
||||
desc.ArraySize = static_cast<UINT>(arraySize);
|
||||
desc.Format = format;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
desc.MiscFlags = (isCubeMap) ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0;
|
||||
|
||||
ID3D11Texture2D* tex = nullptr;
|
||||
hr = d3dDevice->CreatePlacementTexture2D(&desc, xboxext->tileMode, 0, grfxMemory, &tex);
|
||||
if (SUCCEEDED(hr) && tex != 0)
|
||||
{
|
||||
if (textureView != 0)
|
||||
{
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
|
||||
memset(&SRVDesc, 0, sizeof(SRVDesc));
|
||||
SRVDesc.Format = format;
|
||||
|
||||
if (isCubeMap)
|
||||
{
|
||||
if (arraySize > 6)
|
||||
{
|
||||
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY;
|
||||
SRVDesc.TextureCubeArray.MipLevels = desc.MipLevels;
|
||||
|
||||
// Earlier we set arraySize to (NumCubes * 6)
|
||||
SRVDesc.TextureCubeArray.NumCubes = static_cast<UINT>(arraySize / 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
|
||||
SRVDesc.TextureCube.MipLevels = desc.MipLevels;
|
||||
}
|
||||
}
|
||||
else if (arraySize > 1)
|
||||
{
|
||||
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
|
||||
SRVDesc.Texture2DArray.MipLevels = desc.MipLevels;
|
||||
SRVDesc.Texture2DArray.ArraySize = static_cast<UINT>(arraySize);
|
||||
}
|
||||
else
|
||||
{
|
||||
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
SRVDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||
}
|
||||
|
||||
hr = d3dDevice->CreateShaderResourceView(tex,
|
||||
&SRVDesc,
|
||||
textureView
|
||||
);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
tex->Release();
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
if (texture != 0)
|
||||
{
|
||||
*texture = tex;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDebugObjectName(tex, "XboxDDSTextureLoader");
|
||||
tex->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
|
||||
{
|
||||
D3D11_TEXTURE3D_DESC desc;
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
desc.Width = static_cast<UINT>(width);
|
||||
desc.Height = static_cast<UINT>(height);
|
||||
desc.Depth = static_cast<UINT>(depth);
|
||||
desc.MipLevels = static_cast<UINT>(mipCount);
|
||||
desc.Format = format;
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
|
||||
ID3D11Texture3D* tex = nullptr;
|
||||
hr = d3dDevice->CreatePlacementTexture3D(&desc, xboxext->tileMode, 0, grfxMemory, &tex);
|
||||
if (SUCCEEDED(hr) && tex != 0)
|
||||
{
|
||||
if (textureView != 0)
|
||||
{
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
|
||||
memset(&SRVDesc, 0, sizeof(SRVDesc));
|
||||
SRVDesc.Format = format;
|
||||
|
||||
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
|
||||
SRVDesc.Texture3D.MipLevels = desc.MipLevels;
|
||||
|
||||
hr = d3dDevice->CreateShaderResourceView(tex,
|
||||
&SRVDesc,
|
||||
textureView
|
||||
);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
tex->Release();
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
if (texture != 0)
|
||||
{
|
||||
*texture = tex;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDebugObjectName(tex, "XboxDDSTextureLoader");
|
||||
tex->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
// 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
|
||||
size_t sizeBytes = (size_t(xboxext->dataSize) + 0xFFF) & ~0xFFF; // 4K boundary
|
||||
size_t alignmentBytes = std::max<size_t>(xboxext->baseAlignment, 4096);
|
||||
|
||||
hr = D3DAllocateGraphicsMemory(sizeBytes, alignmentBytes, 0, D3D11_GRAPHICS_MEMORY_ACCESS_CPU_CACHE_COHERENT, grfxMemory);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
assert(*grfxMemory != 0);
|
||||
|
||||
// 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))
|
||||
{
|
||||
(void)D3DFreeGraphicsMemory(*grfxMemory);
|
||||
*grfxMemory = nullptr;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
DDS_ALPHA_MODE GetAlphaMode(_In_ const DDS_HEADER* header)
|
||||
{
|
||||
if (header->ddspf.flags & DDS_FOURCC)
|
||||
{
|
||||
if (MAKEFOURCC('X', 'B', 'O', 'X') == header->ddspf.fourCC)
|
||||
{
|
||||
auto xboxext = reinterpret_cast<const DDS_HEADER_XBOX*>(reinterpret_cast<const uint8_t*>(header) + sizeof(DDS_HEADER));
|
||||
auto mode = static_cast<DDS_ALPHA_MODE>(xboxext->miscFlags2 & DDS_MISC_FLAGS2_ALPHA_MODE_MASK);
|
||||
switch (mode)
|
||||
{
|
||||
case DDS_ALPHA_MODE_STRAIGHT:
|
||||
case DDS_ALPHA_MODE_PREMULTIPLIED:
|
||||
case DDS_ALPHA_MODE_OPAQUE:
|
||||
case DDS_ALPHA_MODE_CUSTOM:
|
||||
return mode;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DDS_ALPHA_MODE_UNKNOWN;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
_Use_decl_annotations_
|
||||
HRESULT Xbox::CreateDDSTextureFromMemory( ID3D11DeviceX* d3dDevice,
|
||||
const uint8_t* ddsData,
|
||||
size_t ddsDataSize,
|
||||
ID3D11Resource** texture,
|
||||
ID3D11ShaderResourceView** textureView,
|
||||
void** grfxMemory,
|
||||
DDS_ALPHA_MODE* alphaMode,
|
||||
bool forceSRGB )
|
||||
{
|
||||
if ( texture )
|
||||
{
|
||||
*texture = nullptr;
|
||||
}
|
||||
if ( textureView )
|
||||
{
|
||||
*textureView = nullptr;
|
||||
}
|
||||
if ( grfxMemory )
|
||||
{
|
||||
*grfxMemory = nullptr;
|
||||
}
|
||||
if ( alphaMode )
|
||||
{
|
||||
*alphaMode = DDS_ALPHA_MODE_UNKNOWN;
|
||||
}
|
||||
|
||||
if ( !d3dDevice || !ddsData || (!texture && !textureView) || !grfxMemory )
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
// Validate DDS file in memory
|
||||
if (ddsDataSize < (sizeof(uint32_t) + sizeof(DDS_HEADER)))
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
uint32_t dwMagicNumber = *( const uint32_t* )( ddsData );
|
||||
if (dwMagicNumber != DDS_MAGIC)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
auto header = reinterpret_cast<const DDS_HEADER*>( ddsData + sizeof( uint32_t ) );
|
||||
|
||||
// Verify header to validate DDS file
|
||||
if (header->size != sizeof(DDS_HEADER) ||
|
||||
header->ddspf.size != sizeof(DDS_PIXELFORMAT))
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Check for XBOX extension
|
||||
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 );
|
||||
}
|
||||
|
||||
// Must be long enough for both headers and magic value
|
||||
if (ddsDataSize < (sizeof(DDS_HEADER) + sizeof(uint32_t) + sizeof(DDS_HEADER_XBOX)))
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
ptrdiff_t offset = sizeof( uint32_t ) + sizeof( DDS_HEADER ) + sizeof( DDS_HEADER_XBOX );
|
||||
|
||||
HRESULT hr = CreateTextureFromDDS( d3dDevice, header,
|
||||
ddsData + offset, ddsDataSize - offset, forceSRGB,
|
||||
texture, textureView,
|
||||
grfxMemory );
|
||||
if ( SUCCEEDED(hr) )
|
||||
{
|
||||
if (texture != 0 && *texture != 0)
|
||||
{
|
||||
SetDebugObjectName(*texture, "XboxDDSTextureLoader");
|
||||
}
|
||||
|
||||
if (textureView != 0 && *textureView != 0)
|
||||
{
|
||||
SetDebugObjectName(*textureView, "XboxDDSTextureLoader");
|
||||
}
|
||||
|
||||
if ( alphaMode )
|
||||
*alphaMode = GetAlphaMode( header );
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
_Use_decl_annotations_
|
||||
HRESULT Xbox::CreateDDSTextureFromFile( ID3D11DeviceX* d3dDevice,
|
||||
const wchar_t* fileName,
|
||||
ID3D11Resource** texture,
|
||||
ID3D11ShaderResourceView** textureView,
|
||||
void** grfxMemory,
|
||||
DDS_ALPHA_MODE* alphaMode,
|
||||
bool forceSRGB )
|
||||
{
|
||||
if ( texture )
|
||||
{
|
||||
*texture = nullptr;
|
||||
}
|
||||
if ( textureView )
|
||||
{
|
||||
*textureView = nullptr;
|
||||
}
|
||||
if ( grfxMemory )
|
||||
{
|
||||
*grfxMemory = nullptr;
|
||||
}
|
||||
if ( alphaMode )
|
||||
{
|
||||
*alphaMode = DDS_ALPHA_MODE_UNKNOWN;
|
||||
}
|
||||
|
||||
if ( !d3dDevice || !fileName || (!texture && !textureView) || !grfxMemory )
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
DDS_HEADER* header = nullptr;
|
||||
uint8_t* bitData = nullptr;
|
||||
size_t bitSize = 0;
|
||||
|
||||
std::unique_ptr<uint8_t[]> ddsData;
|
||||
HRESULT hr = LoadTextureDataFromFile( fileName,
|
||||
ddsData,
|
||||
&header,
|
||||
&bitData,
|
||||
&bitSize
|
||||
);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = CreateTextureFromDDS( d3dDevice, header,
|
||||
bitData, bitSize, forceSRGB,
|
||||
texture, textureView,
|
||||
grfxMemory );
|
||||
|
||||
if ( SUCCEEDED(hr) )
|
||||
{
|
||||
#if !defined(NO_D3D11_DEBUG_NAME) && ( defined(_DEBUG) || defined(PROFILE) )
|
||||
if (texture != 0 && *texture != 0)
|
||||
{
|
||||
(*texture)->SetName( fileName );
|
||||
}
|
||||
if (textureView != 0 && *textureView != 0 )
|
||||
{
|
||||
(*textureView)->SetName( fileName );
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( alphaMode )
|
||||
*alphaMode = GetAlphaMode( header );
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
_Use_decl_annotations_
|
||||
void Xbox::FreeDDSTextureMemory(void* grfxMemory)
|
||||
{
|
||||
if (grfxMemory)
|
||||
{
|
||||
(void)D3DFreeGraphicsMemory(grfxMemory);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user