Merge Xbox extensions into mainline as Auxiliary (#417)

This commit is contained in:
Chuck Walbourn
2023-11-29 11:00:59 -08:00
committed by GitHub
parent 14f26b27d2
commit e8dd6c7559
28 changed files with 6216 additions and 12 deletions

172
Auxiliary/DirectXTexXbox.h Normal file
View File

@@ -0,0 +1,172 @@
//--------------------------------------------------------------------------------------
// File: DirectXTexXbox.h
//
// DirectXTex Auxillary functions for Xbox texture processing
//
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//--------------------------------------------------------------------------------------
#pragma once
#ifndef _M_X64
#error This tool is only supported for x64 native
#endif
#include "DirectXTex.h"
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnonportable-system-include-path"
#pragma clang diagnostic ignored "-Wold-style-cast"
#endif
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
#include <xg_xs.h>
#else
#include <xg.h>
#endif
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#ifdef _GAMING_XBOX_SCARLETT
#include <d3d12_xs.h>
#elif defined(_GAMING_XBOX)
#include <d3d12_x.h>
#elif defined(_XBOX_ONE) && defined(_TITLE)
#include <d3d11_x.h>
#else
#include <d3d11_1.h>
#endif
#define DIRECTX_TEX_XBOX_VERSION 150
namespace Xbox
{
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
using XboxTileMode = XG_SWIZZLE_MODE;
constexpr XboxTileMode c_XboxTileModeInvalid = XG_SWIZZLE_MODE_INVALID;
constexpr XboxTileMode c_XboxTileModeLinear = XG_SWIZZLE_MODE_LINEAR;
#else
using XboxTileMode = XG_TILE_MODE;
constexpr XboxTileMode c_XboxTileModeInvalid = XG_TILE_MODE_INVALID;
constexpr XboxTileMode c_XboxTileModeLinear = XG_TILE_MODE_LINEAR;
#endif
class XboxImage
{
public:
XboxImage() noexcept
: dataSize(0), baseAlignment(0), tilemode(c_XboxTileModeInvalid), metadata{}, memory(nullptr) {}
XboxImage(XboxImage&& moveFrom) noexcept
: dataSize(0), baseAlignment(0), tilemode(c_XboxTileModeInvalid), metadata{}, memory(nullptr) { *this = std::move(moveFrom); }
~XboxImage() { Release(); }
XboxImage& __cdecl operator= (XboxImage&& moveFrom) noexcept;
XboxImage(const XboxImage&) = delete;
XboxImage& operator=(const XboxImage&) = delete;
HRESULT Initialize(_In_ const XG_TEXTURE1D_DESC& desc, _In_ const XG_RESOURCE_LAYOUT& layout, _In_ uint32_t miscFlags2 = 0);
HRESULT Initialize(_In_ const XG_TEXTURE2D_DESC& desc, _In_ const XG_RESOURCE_LAYOUT& layout, _In_ uint32_t miscFlags2 = 0);
HRESULT Initialize(_In_ const XG_TEXTURE3D_DESC& desc, _In_ const XG_RESOURCE_LAYOUT& layout, _In_ uint32_t miscFlags2 = 0);
HRESULT Initialize(_In_ const DirectX::TexMetadata& mdata, _In_ XboxTileMode tm, _In_ uint32_t size, _In_ uint32_t alignment);
void Release();
const DirectX::TexMetadata& GetMetadata() const { return metadata; }
XboxTileMode GetTileMode() const { return tilemode; }
uint32_t GetSize() const { return dataSize; }
uint32_t GetAlignment() const { return baseAlignment; }
uint8_t* GetPointer() const { return memory; }
private:
uint32_t dataSize;
uint32_t baseAlignment;
XboxTileMode tilemode;
DirectX::TexMetadata metadata;
uint8_t* memory;
};
//---------------------------------------------------------------------------------
// Image I/O
HRESULT GetMetadataFromDDSMemory(
_In_reads_bytes_(size) const void* pSource, _In_ size_t size,
_Out_ DirectX::TexMetadata& metadata, _Out_ bool& isXbox);
HRESULT GetMetadataFromDDSFile(
_In_z_ const wchar_t* szFile, _Out_ DirectX::TexMetadata& metadata, _Out_ bool& isXbox);
HRESULT GetMetadataFromDDSMemoryEx(
_In_reads_bytes_(size) const void* pSource, _In_ size_t size,
_Out_ DirectX::TexMetadata& metadata, _Out_ bool& isXbox,
_Out_opt_ DirectX::DDSMetaData* ddPixelFormat);
HRESULT GetMetadataFromDDSFileEx(
_In_z_ const wchar_t* szFile, _Out_ DirectX::TexMetadata& metadata, _Out_ bool& isXbox,
_Out_opt_ DirectX::DDSMetaData* ddPixelFormat);
HRESULT LoadFromDDSMemory(
_In_reads_bytes_(size) const void* pSource, _In_ size_t size,
_Out_opt_ DirectX::TexMetadata* metadata, _Out_ XboxImage& image);
HRESULT LoadFromDDSFile(
_In_z_ const wchar_t* szFile,
_Out_opt_ DirectX::TexMetadata* metadata, _Out_ XboxImage& image);
HRESULT LoadFromDDSMemoryEx(
_In_reads_bytes_(size) const void* pSource, _In_ size_t size,
_Out_opt_ DirectX::TexMetadata* metadata,
_Out_opt_ DirectX::DDSMetaData* ddPixelFormat,
_Out_ XboxImage& image);
HRESULT LoadFromDDSFileEx(
_In_z_ const wchar_t* szFile,
_Out_opt_ DirectX::TexMetadata* metadata,
_Out_opt_ DirectX::DDSMetaData* ddPixelFormat,
_Out_ XboxImage& image);
HRESULT SaveToDDSMemory(_In_ const XboxImage& xbox, _Out_ DirectX::Blob& blob);
HRESULT SaveToDDSFile(_In_ const XboxImage& xbox, _In_z_ const wchar_t* szFile);
//---------------------------------------------------------------------------------
// Xbox Texture Tiling / Detiling (requires XG DLL to be present at runtime)
HRESULT Tile(_In_ const DirectX::Image& srcImage, _Out_ XboxImage& xbox, _In_ XboxTileMode mode = c_XboxTileModeInvalid);
HRESULT Tile(
_In_ const DirectX::Image* srcImages, _In_ size_t nimages, _In_ const DirectX::TexMetadata& metadata,
_Out_ XboxImage& xbox, _In_ XboxTileMode mode = c_XboxTileModeInvalid);
HRESULT Detile(_In_ const XboxImage& xbox, _Out_ DirectX::ScratchImage& image);
//---------------------------------------------------------------------------------
// Direct3D 11.X functions
#if defined(_XBOX_ONE) && defined(_TITLE) && defined(__d3d11_x_h__)
HRESULT CreateTexture(
_In_ ID3D11DeviceX* d3dDevice,
_In_ const XboxImage& xbox, _Outptr_opt_ ID3D11Resource** ppResource, _Outptr_ void** grfxMemory);
HRESULT CreateShaderResourceView(
_In_ ID3D11DeviceX* d3dDevice,
_In_ const XboxImage& xbox, _Outptr_opt_ ID3D11ShaderResourceView** ppSRV, _Outptr_ void** grfxMemory);
void FreeTextureMemory(_In_ ID3D11DeviceX* d3dDevice, _In_opt_ void* grfxMemory);
#endif
//---------------------------------------------------------------------------------
// Direct3D 12.X functions
#if ((defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)) && (defined(__d3d12_x_h__) || defined(__XBOX_D3D12_X__))
HRESULT CreateTexture(
_In_ ID3D12Device* d3dDevice,
_In_ const XboxImage& xbox, _Outptr_opt_ ID3D12Resource** ppResource, _Outptr_ void** grfxMemory);
void FreeTextureMemory(_In_ ID3D12Device* d3dDevice, _In_opt_ void* grfxMemory);
#endif
} // namespace

View File

@@ -0,0 +1,258 @@
//-------------------------------------------------------------------------------------
// DirectXTexD3D11X.cpp
//
// DirectXTex Auxillary functions for creating resouces from XboxImage containers
// via the CreatePlacement APIs
//
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//-------------------------------------------------------------------------------------
#include "DirectXTexP.h"
#include "DirectXTexXbox.h"
#ifdef _GAMING_XBOX
#error This module is not supported for GDK
#elif !defined(_XBOX_ONE) || !defined(_TITLE)
#error This module only supports Xbox One exclusive apps
#endif
using namespace Xbox;
using Microsoft::WRL::ComPtr;
namespace
{
//--------------------------------------------------------------------------------------
// Default XMemAlloc attributes for texture loading
//--------------------------------------------------------------------------------------
const uint64_t c_XMemAllocAttributes = MAKE_XALLOC_ATTRIBUTES(
eXALLOCAllocatorId_MiddlewareReservedMin,
0,
XALLOC_MEMTYPE_GRAPHICS_WRITECOMBINE_GPU_READONLY,
XALLOC_PAGESIZE_64KB,
XALLOC_ALIGNMENT_64K);
}
//=====================================================================================
// Entry-points
//=====================================================================================
//-------------------------------------------------------------------------------------
// Create a texture resource
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
HRESULT Xbox::CreateTexture(
ID3D11DeviceX* d3dDevice,
const XboxImage& xbox,
ID3D11Resource** ppResource,
void** grfxMemory)
{
if (!d3dDevice || !ppResource || !grfxMemory)
return E_INVALIDARG;
*grfxMemory = nullptr;
*ppResource = nullptr;
if (!xbox.GetPointer() || !xbox.GetAlignment() || !xbox.GetSize() || xbox.GetTileMode() == c_XboxTileModeInvalid)
return E_INVALIDARG;
// Allocate graphics memory
*grfxMemory = XMemAlloc(xbox.GetSize(), c_XMemAllocAttributes);
if (!*grfxMemory)
return E_OUTOFMEMORY;
// Copy tiled data into graphics memory
memcpy(*grfxMemory, xbox.GetPointer(), xbox.GetSize());
// Create texture resource
auto& metadata = xbox.GetMetadata();
HRESULT hr = E_FAIL;
switch (metadata.dimension)
{
case DirectX::TEX_DIMENSION_TEXTURE1D:
{
D3D11_TEXTURE1D_DESC desc = {};
desc.Width = static_cast<UINT>(metadata.width);
desc.MipLevels = static_cast<UINT>(metadata.mipLevels);
desc.ArraySize = static_cast<UINT>(metadata.arraySize);
desc.Format = metadata.format;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
ID3D11Texture1D* tex = nullptr;
hr = d3dDevice->CreatePlacementTexture1D(&desc, xbox.GetTileMode(), 0, *grfxMemory, &tex);
if (SUCCEEDED(hr) && tex)
{
*ppResource = tex;
}
}
break;
case DirectX::TEX_DIMENSION_TEXTURE2D:
{
D3D11_TEXTURE2D_DESC desc = {};
desc.Width = static_cast<UINT>(metadata.width);
desc.Height = static_cast<UINT>(metadata.height);
desc.MipLevels = static_cast<UINT>(metadata.mipLevels);
desc.ArraySize = static_cast<UINT>(metadata.arraySize);
desc.Format = metadata.format;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.MiscFlags = (metadata.miscFlags & DirectX::TEX_MISC_TEXTURECUBE) ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0;
ID3D11Texture2D* tex = nullptr;
hr = d3dDevice->CreatePlacementTexture2D(&desc, xbox.GetTileMode(), 0, *grfxMemory, &tex);
if (SUCCEEDED(hr) && tex)
{
*ppResource = tex;
}
}
break;
case DirectX::TEX_DIMENSION_TEXTURE3D:
{
D3D11_TEXTURE3D_DESC desc = {};
desc.Width = static_cast<UINT>(metadata.width);
desc.Height = static_cast<UINT>(metadata.height);
desc.Depth = static_cast<UINT>(metadata.depth);
desc.MipLevels = static_cast<UINT>(metadata.mipLevels);
desc.Format = metadata.format;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
ID3D11Texture3D* tex = nullptr;
hr = d3dDevice->CreatePlacementTexture3D(&desc, xbox.GetTileMode(), 0, *grfxMemory, &tex);
if (SUCCEEDED(hr) && tex)
{
*ppResource = tex;
}
}
break;
default:
hr = E_FAIL;
break;
}
if (FAILED(hr))
{
XMemFree(grfxMemory, c_XMemAllocAttributes);
*grfxMemory = nullptr;
}
return hr;
}
//-------------------------------------------------------------------------------------
// Create a shader resource view and associated texture
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
HRESULT Xbox::CreateShaderResourceView(
ID3D11DeviceX* d3dDevice,
const XboxImage& xbox,
ID3D11ShaderResourceView** ppSRV,
void** grfxMemory)
{
if (!ppSRV)
return E_INVALIDARG;
*ppSRV = nullptr;
ComPtr<ID3D11Resource> resource;
HRESULT hr = CreateTexture(d3dDevice, xbox, resource.GetAddressOf(), grfxMemory);
if (FAILED(hr))
return hr;
assert(resource);
auto& metadata = xbox.GetMetadata();
D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc = {};
SRVDesc.Format = metadata.format;
switch (metadata.dimension)
{
case DirectX::TEX_DIMENSION_TEXTURE1D:
if (metadata.arraySize > 1)
{
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
SRVDesc.Texture1DArray.MipLevels = static_cast<UINT>(metadata.mipLevels);
SRVDesc.Texture1DArray.ArraySize = static_cast<UINT>(metadata.arraySize);
}
else
{
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
SRVDesc.Texture1D.MipLevels = static_cast<UINT>(metadata.mipLevels);
}
break;
case DirectX::TEX_DIMENSION_TEXTURE2D:
if (metadata.IsCubemap())
{
if (metadata.arraySize > 6)
{
assert((metadata.arraySize % 6) == 0);
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY;
SRVDesc.TextureCubeArray.MipLevels = static_cast<UINT>(metadata.mipLevels);
SRVDesc.TextureCubeArray.NumCubes = static_cast<UINT>(metadata.arraySize / 6);
}
else
{
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
SRVDesc.TextureCube.MipLevels = static_cast<UINT>(metadata.mipLevels);
}
}
else if (metadata.arraySize > 1)
{
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
SRVDesc.Texture2DArray.MipLevels = static_cast<UINT>(metadata.mipLevels);
SRVDesc.Texture2DArray.ArraySize = static_cast<UINT>(metadata.arraySize);
}
else
{
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
SRVDesc.Texture2D.MipLevels = static_cast<UINT>(metadata.mipLevels);
}
break;
case DirectX::TEX_DIMENSION_TEXTURE3D:
assert(metadata.arraySize == 1);
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
SRVDesc.Texture3D.MipLevels = static_cast<UINT>(metadata.mipLevels);
break;
default:
assert(grfxMemory != nullptr);
XMemFree(grfxMemory, c_XMemAllocAttributes);
*grfxMemory = nullptr;
return E_FAIL;
}
hr = d3dDevice->CreateShaderResourceView(resource.Get(), &SRVDesc, ppSRV);
if (FAILED(hr))
{
XMemFree(grfxMemory, c_XMemAllocAttributes);
*grfxMemory = nullptr;
}
return hr;
}
//-------------------------------------------------------------------------------------
// Free allocated graphics memory
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
void Xbox::FreeTextureMemory(ID3D11DeviceX* d3dDevice, void* grfxMemory)
{
UNREFERENCED_PARAMETER(d3dDevice); // used only for overload resolution
if (grfxMemory)
{
XMemFree(grfxMemory, c_XMemAllocAttributes);
}
}

View File

@@ -0,0 +1,117 @@
//-------------------------------------------------------------------------------------
// DirectXTexD3D12X.cpp
//
// DirectXTex Auxillary functions for creating resouces from XboxImage containers
// via the CreatePlacedResourceX API
//
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//-------------------------------------------------------------------------------------
#include "DirectXTexP.h"
#include "DirectXTexXbox.h"
#if !(defined(_XBOX_ONE) && defined(_TITLE)) && !defined(_GAMING_XBOX)
#error This module only supports Xbox exclusive apps
#endif
#ifdef _GAMING_XBOX
#include <xmem.h>
#endif
using namespace Xbox;
using Microsoft::WRL::ComPtr;
namespace
{
//--------------------------------------------------------------------------------------
// Default XMemAlloc attributes for texture loading
//--------------------------------------------------------------------------------------
const uint64_t c_XMemAllocAttributes = MAKE_XALLOC_ATTRIBUTES(
eXALLOCAllocatorId_MiddlewareReservedMin,
0,
XALLOC_MEMTYPE_GRAPHICS_WRITECOMBINE_GPU_READONLY,
XALLOC_PAGESIZE_64KB,
XALLOC_ALIGNMENT_64K
#ifdef _GAMING_XBOX
, 0
#endif
);
}
//=====================================================================================
// Entry-points
//=====================================================================================
//-------------------------------------------------------------------------------------
// Create a texture resource
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
HRESULT Xbox::CreateTexture(
ID3D12Device* d3dDevice,
const XboxImage& xbox,
ID3D12Resource** ppResource,
void** grfxMemory)
{
if (!d3dDevice || !ppResource || !grfxMemory)
return E_INVALIDARG;
*grfxMemory = nullptr;
*ppResource = nullptr;
if (!xbox.GetPointer() || !xbox.GetAlignment() || !xbox.GetSize() || xbox.GetTileMode() == c_XboxTileModeInvalid)
return E_INVALIDARG;
// Allocate graphics memory
*grfxMemory = XMemAlloc(xbox.GetSize(), c_XMemAllocAttributes);
if (!*grfxMemory)
return E_OUTOFMEMORY;
// Copy tiled data into graphics memory
memcpy(*grfxMemory, xbox.GetPointer(), xbox.GetSize());
// Create texture resource
auto& metadata = xbox.GetMetadata();
D3D12_RESOURCE_DESC desc = {};
desc.Width = static_cast<UINT>(metadata.width);
desc.Height = static_cast<UINT>(metadata.height);
desc.MipLevels = static_cast<UINT16>(metadata.mipLevels);
desc.DepthOrArraySize = (metadata.dimension == DirectX::TEX_DIMENSION_TEXTURE3D) ? static_cast<UINT16>(metadata.depth) : static_cast<UINT16>(metadata.arraySize);
desc.Format = metadata.format;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Dimension = static_cast<D3D12_RESOURCE_DIMENSION>(metadata.dimension);
desc.Layout = static_cast<D3D12_TEXTURE_LAYOUT>(0x100 | xbox.GetTileMode());
HRESULT hr = d3dDevice->CreatePlacedResourceX(
reinterpret_cast<D3D12_GPU_VIRTUAL_ADDRESS>(*grfxMemory),
&desc,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
nullptr,
IID_GRAPHICS_PPV_ARGS(ppResource));
if (FAILED(hr))
{
XMemFree(*grfxMemory, c_XMemAllocAttributes);
*grfxMemory = nullptr;
}
return hr;
}
//-------------------------------------------------------------------------------------
// Free allocated graphics memory
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
void Xbox::FreeTextureMemory(ID3D12Device* d3dDevice, void* grfxMemory)
{
UNREFERENCED_PARAMETER(d3dDevice); // used only for overload resolution
if (grfxMemory)
{
XMemFree(grfxMemory, c_XMemAllocAttributes);
}
}

View File

@@ -0,0 +1,869 @@
//--------------------------------------------------------------------------------------
// File: DirectXTexXboxDDS.cpp
//
// DirectXTex Auxillary functions for saving "XBOX" Xbox variants of DDS files
//
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//--------------------------------------------------------------------------------------
#include "DirectXTexP.h"
#include "DirectXTexXbox.h"
#include "DDS.h"
#if defined(_GAMING_XBOX) || defined(_USE_GXDK)
#include "gxdk.h"
#else
#include "xdk.h"
#endif
using namespace DirectX;
using namespace Xbox;
namespace
{
const DDS_PIXELFORMAT DDSPF_XBOX =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('X','B','O','X'), 0, 0, 0, 0, 0 };
#pragma pack(push,1)
struct DDS_HEADER_XBOX
// Must match structure in XboxDDSTextureLoader module
{
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 / XG_SWIZZLE_MODE
uint32_t baseAlignment;
uint32_t dataSize;
uint32_t xdkVer; // matching _XDK_VER / _GXDK_VER
};
#pragma pack(pop)
constexpr uint32_t XBOX_TILEMODE_SCARLETT = 0x1000000;
static_assert(sizeof(DDS_HEADER_XBOX) == 36, "DDS XBOX Header size mismatch");
static_assert(sizeof(DDS_HEADER_XBOX) >= sizeof(DDS_HEADER_DXT10), "DDS XBOX Header should be larger than DX10 header");
constexpr size_t XBOX_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_XBOX);
//-------------------------------------------------------------------------------------
// Decodes DDS header using XBOX extended header (variant of DX10 header)
//-------------------------------------------------------------------------------------
HRESULT DecodeDDSHeader(
_In_reads_bytes_(size) const void* pSource,
size_t size,
DirectX::TexMetadata& metadata,
_Out_opt_ DDSMetaData* ddPixelFormat,
_Out_opt_ XboxTileMode* tmode,
_Out_opt_ uint32_t* dataSize,
_Out_opt_ uint32_t* baseAlignment)
{
if (!pSource)
return E_INVALIDARG;
if (tmode)
{
*tmode = c_XboxTileModeInvalid;
}
if (dataSize)
{
*dataSize = 0;
}
if (baseAlignment)
{
*baseAlignment = 0;
}
metadata = {};
if (ddPixelFormat)
{
*ddPixelFormat = {};
}
if (size < (sizeof(DDS_HEADER) + sizeof(uint32_t)))
{
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
// DDS files always start with the same magic number ("DDS ")
auto const dwMagicNumber = *reinterpret_cast<const uint32_t*>(pSource);
if (dwMagicNumber != DDS_MAGIC)
{
return E_FAIL;
}
auto pHeader = reinterpret_cast<const DDS_HEADER*>(reinterpret_cast<const uint8_t*>(pSource) + sizeof(uint32_t));
// Verify header to validate DDS file
if (pHeader->size != sizeof(DDS_HEADER)
|| pHeader->ddspf.size != sizeof(DDS_PIXELFORMAT))
{
return E_FAIL;
}
metadata.mipLevels = pHeader->mipMapCount;
if (metadata.mipLevels == 0)
metadata.mipLevels = 1;
// Check for XBOX extension
if (!(pHeader->ddspf.flags & DDS_FOURCC)
|| (MAKEFOURCC('X', 'B', 'O', 'X') != pHeader->ddspf.fourCC))
{
// We know it's a DDS file, but it's not an XBOX extension
return S_FALSE;
}
// Buffer must be big enough for both headers and magic value
if (size < XBOX_HEADER_SIZE)
{
return E_FAIL;
}
auto xboxext = reinterpret_cast<const DDS_HEADER_XBOX*>(
reinterpret_cast<const uint8_t*>(pSource) + sizeof(uint32_t) + sizeof(DDS_HEADER));
#ifdef _GXDK_VER
if (xboxext->xdkVer < _GXDK_VER)
{
OutputDebugStringA("WARNING: DDS XBOX file may be outdated and need regeneration\n");
}
#elif defined(_XDK_VER)
if (xboxext->xdkVer < _XDK_VER)
{
OutputDebugStringA("WARNING: DDS XBOX file may be outdated and need regeneration\n");
}
#endif
metadata.arraySize = xboxext->arraySize;
if (metadata.arraySize == 0)
{
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
metadata.format = xboxext->dxgiFormat;
if (!IsValid(metadata.format))
{
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
static_assert(static_cast<int>(TEX_MISC_TEXTURECUBE) == static_cast<int>(DDS_RESOURCE_MISC_TEXTURECUBE), "DDS header mismatch");
metadata.miscFlags = xboxext->miscFlag & ~static_cast<uint32_t>(TEX_MISC_TEXTURECUBE);
switch (xboxext->resourceDimension)
{
case DDS_DIMENSION_TEXTURE1D:
if ((pHeader->flags & DDS_HEIGHT) && pHeader->height != 1)
{
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
metadata.width = pHeader->width;
metadata.height = 1;
metadata.depth = 1;
metadata.dimension = TEX_DIMENSION_TEXTURE1D;
break;
case DDS_DIMENSION_TEXTURE2D:
if (xboxext->miscFlag & DDS_RESOURCE_MISC_TEXTURECUBE)
{
metadata.miscFlags |= TEX_MISC_TEXTURECUBE;
metadata.arraySize *= 6;
}
metadata.width = pHeader->width;
metadata.height = pHeader->height;
metadata.depth = 1;
metadata.dimension = TEX_DIMENSION_TEXTURE2D;
break;
case DDS_DIMENSION_TEXTURE3D:
if (!(pHeader->flags & DDS_HEADER_FLAGS_VOLUME))
{
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
if (metadata.arraySize > 1)
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
metadata.width = pHeader->width;
metadata.height = pHeader->height;
metadata.depth = pHeader->depth;
metadata.dimension = TEX_DIMENSION_TEXTURE3D;
break;
default:
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
if (static_cast<XboxTileMode>(xboxext->tileMode) == c_XboxTileModeInvalid)
{
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
else if (!(xboxext->tileMode & XBOX_TILEMODE_SCARLETT))
{
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
#else
else if (xboxext->tileMode & XBOX_TILEMODE_SCARLETT)
{
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
#endif
static_assert(static_cast<int>(TEX_MISC2_ALPHA_MODE_MASK) == static_cast<int>(DDS_MISC_FLAGS2_ALPHA_MODE_MASK), "DDS header mismatch");
static_assert(static_cast<int>(TEX_ALPHA_MODE_UNKNOWN) == static_cast<int>(DDS_ALPHA_MODE_UNKNOWN), "DDS header mismatch");
static_assert(static_cast<int>(TEX_ALPHA_MODE_STRAIGHT) == static_cast<int>(DDS_ALPHA_MODE_STRAIGHT), "DDS header mismatch");
static_assert(static_cast<int>(TEX_ALPHA_MODE_PREMULTIPLIED) == static_cast<int>(DDS_ALPHA_MODE_PREMULTIPLIED), "DDS header mismatch");
static_assert(static_cast<int>(TEX_ALPHA_MODE_OPAQUE) == static_cast<int>(DDS_ALPHA_MODE_OPAQUE), "DDS header mismatch");
static_assert(static_cast<int>(TEX_ALPHA_MODE_CUSTOM) == static_cast<int>(DDS_ALPHA_MODE_CUSTOM), "DDS header mismatch");
metadata.miscFlags2 = xboxext->miscFlags2;
if (tmode)
{
*tmode = static_cast<XboxTileMode>(xboxext->tileMode & ~XBOX_TILEMODE_SCARLETT);
}
if (baseAlignment)
*baseAlignment = xboxext->baseAlignment;
if (dataSize)
*dataSize = xboxext->dataSize;
// Handle DDS-specific metadata
if (ddPixelFormat)
{
ddPixelFormat->size = pHeader->ddspf.size;
ddPixelFormat->flags = pHeader->ddspf.flags;
ddPixelFormat->fourCC = pHeader->ddspf.fourCC;
ddPixelFormat->RGBBitCount = pHeader->ddspf.RGBBitCount;
ddPixelFormat->RBitMask = pHeader->ddspf.RBitMask;
ddPixelFormat->GBitMask = pHeader->ddspf.GBitMask;
ddPixelFormat->BBitMask = pHeader->ddspf.BBitMask;
ddPixelFormat->ABitMask = pHeader->ddspf.ABitMask;
}
return S_OK;
}
//-------------------------------------------------------------------------------------
// Encodes DDS file header (magic value, header, XBOX extended header)
//-------------------------------------------------------------------------------------
HRESULT EncodeDDSHeader(
const XboxImage& xbox,
_Out_writes_(maxsize) void* pDestination,
size_t maxsize)
{
if (!pDestination)
return E_POINTER;
if (maxsize < XBOX_HEADER_SIZE)
return E_NOT_SUFFICIENT_BUFFER;
*reinterpret_cast<uint32_t*>(pDestination) = DDS_MAGIC;
auto header = reinterpret_cast<DDS_HEADER*>(reinterpret_cast<uint8_t*>(pDestination) + sizeof(uint32_t));
memset(header, 0, sizeof(DDS_HEADER));
header->size = sizeof(DDS_HEADER);
header->flags = DDS_HEADER_FLAGS_TEXTURE;
header->caps = DDS_SURFACE_FLAGS_TEXTURE;
auto& metadata = xbox.GetMetadata();
if (metadata.mipLevels > 0)
{
header->flags |= DDS_HEADER_FLAGS_MIPMAP;
if (metadata.mipLevels > UINT32_MAX)
return E_INVALIDARG;
header->mipMapCount = static_cast<uint32_t>(metadata.mipLevels);
if (header->mipMapCount > 1)
header->caps |= DDS_SURFACE_FLAGS_MIPMAP;
}
switch (metadata.dimension)
{
case TEX_DIMENSION_TEXTURE1D:
if (metadata.width > UINT32_MAX)
return E_INVALIDARG;
header->width = static_cast<uint32_t>(metadata.width);
header->height = header->depth = 1;
break;
case TEX_DIMENSION_TEXTURE2D:
if (metadata.height > UINT32_MAX
|| metadata.width > UINT32_MAX)
return E_INVALIDARG;
header->height = static_cast<uint32_t>(metadata.height);
header->width = static_cast<uint32_t>(metadata.width);
header->depth = 1;
if (metadata.IsCubemap())
{
header->caps |= DDS_SURFACE_FLAGS_CUBEMAP;
header->caps2 |= DDS_CUBEMAP_ALLFACES;
}
break;
case TEX_DIMENSION_TEXTURE3D:
if (metadata.height > UINT32_MAX
|| metadata.width > UINT32_MAX
|| metadata.depth > UINT32_MAX)
return E_INVALIDARG;
header->flags |= DDS_HEADER_FLAGS_VOLUME;
header->caps2 |= DDS_FLAGS_VOLUME;
header->height = static_cast<uint32_t>(metadata.height);
header->width = static_cast<uint32_t>(metadata.width);
header->depth = static_cast<uint32_t>(metadata.depth);
break;
default:
return E_FAIL;
}
size_t rowPitch, slicePitch;
ComputePitch(metadata.format, metadata.width, metadata.height, rowPitch, slicePitch, CP_FLAGS_NONE);
if (slicePitch > UINT32_MAX
|| rowPitch > UINT32_MAX)
return E_FAIL;
if (IsCompressed(metadata.format))
{
header->flags |= DDS_HEADER_FLAGS_LINEARSIZE;
header->pitchOrLinearSize = static_cast<uint32_t>(slicePitch);
}
else
{
header->flags |= DDS_HEADER_FLAGS_PITCH;
header->pitchOrLinearSize = static_cast<uint32_t>(rowPitch);
}
memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_XBOX, sizeof(DDS_PIXELFORMAT));
// Setup XBOX extended header
auto xboxext = reinterpret_cast<DDS_HEADER_XBOX*>(reinterpret_cast<uint8_t*>(header) + sizeof(DDS_HEADER));
memset(xboxext, 0, sizeof(DDS_HEADER_XBOX));
xboxext->dxgiFormat = metadata.format;
xboxext->resourceDimension = metadata.dimension;
if (metadata.arraySize > UINT32_MAX)
return E_INVALIDARG;
static_assert(static_cast<int>(TEX_MISC_TEXTURECUBE) == static_cast<int>(DDS_RESOURCE_MISC_TEXTURECUBE), "DDS header mismatch");
xboxext->miscFlag = metadata.miscFlags & ~static_cast<uint32_t>(TEX_MISC_TEXTURECUBE);
if (metadata.miscFlags & TEX_MISC_TEXTURECUBE)
{
xboxext->miscFlag |= TEX_MISC_TEXTURECUBE;
assert((metadata.arraySize % 6) == 0);
xboxext->arraySize = static_cast<UINT>(metadata.arraySize / 6);
}
else
{
xboxext->arraySize = static_cast<UINT>(metadata.arraySize);
}
static_assert(static_cast<int>(TEX_MISC2_ALPHA_MODE_MASK) == static_cast<int>(DDS_MISC_FLAGS2_ALPHA_MODE_MASK), "DDS header mismatch");
static_assert(static_cast<int>(TEX_ALPHA_MODE_UNKNOWN) == static_cast<int>(DDS_ALPHA_MODE_UNKNOWN), "DDS header mismatch");
static_assert(static_cast<int>(TEX_ALPHA_MODE_STRAIGHT) == static_cast<int>(DDS_ALPHA_MODE_STRAIGHT), "DDS header mismatch");
static_assert(static_cast<int>(TEX_ALPHA_MODE_PREMULTIPLIED) == static_cast<int>(DDS_ALPHA_MODE_PREMULTIPLIED), "DDS header mismatch");
static_assert(static_cast<int>(TEX_ALPHA_MODE_OPAQUE) == static_cast<int>(DDS_ALPHA_MODE_OPAQUE), "DDS header mismatch");
static_assert(static_cast<int>(TEX_ALPHA_MODE_CUSTOM) == static_cast<int>(DDS_ALPHA_MODE_CUSTOM), "DDS header mismatch");
xboxext->miscFlags2 = metadata.miscFlags2;
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
xboxext->tileMode = static_cast<uint32_t>(xbox.GetTileMode()) | XBOX_TILEMODE_SCARLETT;
#else
xboxext->tileMode = static_cast<uint32_t>(xbox.GetTileMode());
#endif
xboxext->baseAlignment = xbox.GetAlignment();
xboxext->dataSize = xbox.GetSize();
#ifdef _GXDK_VER
xboxext->xdkVer = _GXDK_VER;
#elif defined(_XDK_VER)
xboxext->xdkVer = _XDK_VER;
#endif
return S_OK;
}
}
//=====================================================================================
// Entry-points
//=====================================================================================
//-------------------------------------------------------------------------------------
// Obtain metadata from DDS file in memory/on disk
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
HRESULT Xbox::GetMetadataFromDDSMemory(
const void* pSource,
size_t size,
TexMetadata& metadata,
bool& isXbox)
{
return Xbox::GetMetadataFromDDSMemoryEx(pSource, size, metadata, isXbox, nullptr);
}
_Use_decl_annotations_
HRESULT Xbox::GetMetadataFromDDSMemoryEx(
const void* pSource,
size_t size,
TexMetadata& metadata,
bool& isXbox,
DDSMetaData* ddPixelFormat)
{
if (!pSource || !size)
return E_INVALIDARG;
isXbox = false;
HRESULT hr = DecodeDDSHeader(pSource, size, metadata, ddPixelFormat, nullptr, nullptr, nullptr);
if (hr == S_FALSE)
{
hr = DirectX::GetMetadataFromDDSMemoryEx(pSource, size, DirectX::DDS_FLAGS_NONE, metadata, ddPixelFormat);
}
else if (SUCCEEDED(hr))
{
isXbox = true;
}
return hr;
}
_Use_decl_annotations_
HRESULT Xbox::GetMetadataFromDDSFile(
const wchar_t* szFile,
TexMetadata& metadata,
bool& isXbox)
{
return Xbox::GetMetadataFromDDSFileEx(szFile, metadata, isXbox, nullptr);
}
_Use_decl_annotations_
HRESULT Xbox::GetMetadataFromDDSFileEx(
const wchar_t* szFile,
TexMetadata& metadata,
bool& isXbox,
DDSMetaData* ddPixelFormat)
{
if (!szFile)
return E_INVALIDARG;
isXbox = false;
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
ScopedHandle hFile(safe_handle(CreateFile2(szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr)));
#else
ScopedHandle hFile(safe_handle(CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN, nullptr)));
#endif
if (!hFile)
{
return HRESULT_FROM_WIN32(GetLastError());
}
// Get the file size
FILE_STANDARD_INFO fileInfo;
if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))
{
return HRESULT_FROM_WIN32(GetLastError());
}
// File is too big for 32-bit allocation, so reject read (4 GB should be plenty large enough for a valid DDS file)
if (fileInfo.EndOfFile.HighPart > 0)
{
return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE);
}
// Need at least enough data to fill the standard header and magic number to be a valid DDS
if (fileInfo.EndOfFile.LowPart < (sizeof(DDS_HEADER) + sizeof(uint32_t)))
{
return E_FAIL;
}
// Read the header in (including extended header if present)
uint8_t header[XBOX_HEADER_SIZE] = {};
DWORD bytesRead = 0;
if (!ReadFile(hFile.get(), header, XBOX_HEADER_SIZE, &bytesRead, nullptr))
{
return HRESULT_FROM_WIN32(GetLastError());
}
HRESULT hr = DecodeDDSHeader(header, bytesRead, metadata, ddPixelFormat, nullptr, nullptr, nullptr);
if (hr == S_FALSE)
{
hr = DirectX::GetMetadataFromDDSMemoryEx(header, bytesRead, DirectX::DDS_FLAGS_NONE, metadata, ddPixelFormat);
}
else if (SUCCEEDED(hr))
{
isXbox = true;
}
return hr;
}
//-------------------------------------------------------------------------------------
// Load a DDS file in memory
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
HRESULT Xbox::LoadFromDDSMemory(
const void* pSource,
size_t size,
TexMetadata* metadata,
XboxImage& xbox)
{
return Xbox::LoadFromDDSMemoryEx(pSource, size, metadata, nullptr, xbox);
}
_Use_decl_annotations_
HRESULT Xbox::LoadFromDDSMemoryEx(
const void* pSource,
size_t size,
TexMetadata* metadata,
DDSMetaData* ddPixelFormat,
XboxImage& xbox)
{
if (!pSource || !size)
return E_INVALIDARG;
xbox.Release();
TexMetadata mdata;
uint32_t dataSize;
uint32_t baseAlignment;
XboxTileMode tmode;
HRESULT hr = DecodeDDSHeader(pSource, size, mdata, ddPixelFormat, &tmode, &dataSize, &baseAlignment);
if (hr == S_FALSE)
{
// It's a DDS, but not an XBOX variant
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
if (FAILED(hr))
{
return hr;
}
if (!dataSize || !baseAlignment)
{
return E_FAIL;
}
if (size <= XBOX_HEADER_SIZE)
{
return E_FAIL;
}
// Copy tiled data
const size_t remaining = size - XBOX_HEADER_SIZE;
if (remaining < dataSize)
{
return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
}
hr = xbox.Initialize(mdata, tmode, dataSize, baseAlignment);
if (FAILED(hr))
return hr;
assert(xbox.GetPointer() != nullptr);
memcpy(xbox.GetPointer(), reinterpret_cast<const uint8_t*>(pSource) + XBOX_HEADER_SIZE, dataSize);
if (metadata)
memcpy(metadata, &mdata, sizeof(TexMetadata));
return S_OK;
}
//-------------------------------------------------------------------------------------
// Load a DDS file from disk
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
HRESULT Xbox::LoadFromDDSFile(
const wchar_t* szFile,
TexMetadata* metadata,
XboxImage& xbox)
{
return Xbox::LoadFromDDSFileEx(szFile, metadata, nullptr, xbox);
}
_Use_decl_annotations_
HRESULT Xbox::LoadFromDDSFileEx(
const wchar_t* szFile,
TexMetadata* metadata,
DDSMetaData* ddPixelFormat,
XboxImage& xbox)
{
if (!szFile)
return E_INVALIDARG;
xbox.Release();
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
ScopedHandle hFile(safe_handle(CreateFile2(szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr)));
#else
ScopedHandle hFile(safe_handle(CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN, nullptr)));
#endif
if (!hFile)
{
return HRESULT_FROM_WIN32(GetLastError());
}
// Get the file size
FILE_STANDARD_INFO fileInfo;
if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))
{
return HRESULT_FROM_WIN32(GetLastError());
}
// File is too big for 32-bit allocation, so reject read (4 GB should be plenty large enough for a valid DDS file)
if (fileInfo.EndOfFile.HighPart > 0)
{
return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE);
}
// Need at least enough data to fill the standard header and magic number to be a valid DDS
if (fileInfo.EndOfFile.LowPart < (sizeof(DDS_HEADER) + sizeof(uint32_t)))
{
return E_FAIL;
}
// Read the header in (including extended header if present)
uint8_t header[XBOX_HEADER_SIZE] = {};
DWORD bytesRead = 0;
if (!ReadFile(hFile.get(), header, XBOX_HEADER_SIZE, &bytesRead, nullptr))
{
return HRESULT_FROM_WIN32(GetLastError());
}
TexMetadata mdata;
XboxTileMode tmode;
uint32_t dataSize;
uint32_t baseAlignment;
HRESULT hr = DecodeDDSHeader(header, bytesRead, mdata, ddPixelFormat, &tmode, &dataSize, &baseAlignment);
if (hr == S_FALSE)
{
// It's a DDS, but not an XBOX variant
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
if (FAILED(hr))
return hr;
if (!dataSize || !baseAlignment)
{
return E_FAIL;
}
// Read tiled data
const DWORD remaining = fileInfo.EndOfFile.LowPart - XBOX_HEADER_SIZE;
if (remaining == 0)
return E_FAIL;
if (remaining < dataSize)
{
return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
}
hr = xbox.Initialize(mdata, tmode, dataSize, baseAlignment);
if (FAILED(hr))
return hr;
assert(xbox.GetPointer() != nullptr);
if (!ReadFile(hFile.get(), xbox.GetPointer(), dataSize, &bytesRead, nullptr))
{
xbox.Release();
return HRESULT_FROM_WIN32(GetLastError());
}
if (metadata)
memcpy(metadata, &mdata, sizeof(TexMetadata));
return S_OK;
}
//-------------------------------------------------------------------------------------
// Save a DDS file to memory
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
HRESULT Xbox::SaveToDDSMemory(const XboxImage& xbox, Blob& blob)
{
if (!xbox.GetPointer() || !xbox.GetSize() || !xbox.GetAlignment())
return E_INVALIDARG;
blob.Release();
HRESULT hr = blob.Initialize(XBOX_HEADER_SIZE + xbox.GetSize());
if (FAILED(hr))
return hr;
// Copy header
auto pDestination = reinterpret_cast<uint8_t*>(blob.GetBufferPointer());
assert(pDestination);
hr = EncodeDDSHeader(xbox, pDestination, XBOX_HEADER_SIZE);
if (FAILED(hr))
{
blob.Release();
return hr;
}
// Copy tiled data
const size_t remaining = blob.GetBufferSize() - XBOX_HEADER_SIZE;
pDestination += XBOX_HEADER_SIZE;
if (!remaining)
{
blob.Release();
return E_FAIL;
}
if (remaining < xbox.GetSize())
{
blob.Release();
return E_UNEXPECTED;
}
memcpy(pDestination, xbox.GetPointer(), xbox.GetSize());
return S_OK;
}
//-------------------------------------------------------------------------------------
// Save a DDS file to disk
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
HRESULT Xbox::SaveToDDSFile(const XboxImage& xbox, const wchar_t* szFile)
{
if (!szFile || !xbox.GetPointer() || !xbox.GetSize() || !xbox.GetAlignment())
return E_INVALIDARG;
// Create DDS Header
uint8_t header[XBOX_HEADER_SIZE] = {};
HRESULT hr = EncodeDDSHeader(xbox, header, XBOX_HEADER_SIZE);
if (FAILED(hr))
return hr;
// Create file and write header
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
ScopedHandle hFile(safe_handle(CreateFile2(szFile,
GENERIC_WRITE, 0, CREATE_ALWAYS, nullptr)));
#else
ScopedHandle hFile(safe_handle(CreateFileW(szFile,
GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr)));
#endif
if (!hFile)
{
return HRESULT_FROM_WIN32(GetLastError());
}
DWORD bytesWritten;
if (!WriteFile(hFile.get(), header, static_cast<DWORD>(XBOX_HEADER_SIZE), &bytesWritten, nullptr))
{
return HRESULT_FROM_WIN32(GetLastError());
}
if (bytesWritten != XBOX_HEADER_SIZE)
{
return E_FAIL;
}
// Write tiled data
if (!WriteFile(hFile.get(), xbox.GetPointer(), static_cast<DWORD>(xbox.GetSize()), &bytesWritten, nullptr))
{
return HRESULT_FROM_WIN32(GetLastError());
}
if (bytesWritten != xbox.GetSize())
{
return E_FAIL;
}
return S_OK;
}
//--------------------------------------------------------------------------------------
// Adapters for /Zc:wchar_t- clients
#if defined(_MSC_VER) && !defined(_NATIVE_WCHAR_T_DEFINED)
namespace Xbox
{
HRESULT __cdecl GetMetadataFromDDSFile(
_In_z_ const __wchar_t* szFile,
_Out_ DirectX::TexMetadata& metadata,
_Out_ bool& isXbox)
{
return GetMetadataFromDDSFile(reinterpret_cast<const unsigned short*>(szFile), metadata, isXbox);
}
HRESULT __cdecl GetMetadataFromDDSFileEx(
_In_z_ const __wchar_t* szFile,
_Out_ DirectX::TexMetadata& metadata,
_Out_ bool& isXbox,
_Out_opt_ DirectX::DDSMetaData* ddPixelFormat)
{
return GetMetadataFromDDSFileEx(reinterpret_cast<const unsigned short*>(szFile), metadata, isXbox, ddPixelFormat);
}
HRESULT __cdecl LoadFromDDSFile(
_In_z_ const __wchar_t* szFile,
_Out_opt_ DirectX::TexMetadata* metadata,
_Out_ XboxImage& image)
{
return LoadFromDDSFile(reinterpret_cast<const unsigned short*>(szFile), metadata, image);
}
HRESULT __cdecl LoadFromDDSFileEx(
_In_z_ const __wchar_t* szFile,
_Out_opt_ DirectX::TexMetadata* metadata,
_Out_opt_ DirectX::DDSMetaData* ddPixelFormat,
_Out_ XboxImage& image)
{
return LoadFromDDSFileEx(reinterpret_cast<const unsigned short*>(szFile), metadata, ddPixelFormat, image);
}
HRESULT __cdecl SaveToDDSFile(_In_ const XboxImage& xbox, _In_z_ const __wchar_t* szFile)
{
return SaveToDDSFile(xbox, reinterpret_cast<const unsigned short*>(szFile));
}
}
#endif // !_NATIVE_WCHAR_T_DEFINED

View File

@@ -0,0 +1,877 @@
//--------------------------------------------------------------------------------------
// File: DirectXTexXboxDetile.cpp
//
// DirectXTex Auxillary functions for converting from Xbox tiled to linear
//
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//--------------------------------------------------------------------------------------
#include "DirectXTexP.h"
#include "DirectXTexXbox.h"
using Microsoft::WRL::ComPtr;
using namespace DirectX;
using namespace DirectX::Internal;
using namespace Xbox;
namespace
{
//----------------------------------------------------------------------------------
inline HRESULT DetileByElement1D(
const XboxImage& xbox,
uint32_t level,
_In_ XGTextureAddressComputer* computer,
const XG_RESOURCE_LAYOUT& layout,
_In_reads_(nimages) const Image* const * result,
size_t nimages,
size_t bpp,
size_t w,
bool packed)
{
const uint8_t* sptr = xbox.GetPointer();
const uint8_t* endPtr = sptr + layout.SizeBytes;
for (uint32_t item = 0; item < nimages; ++item)
{
const Image* img = result[item];
if (!img || !img->pixels)
return E_POINTER;
assert(img->width == result[0]->width);
assert(img->height == result[0]->height);
assert(img->rowPitch == result[0]->rowPitch);
assert(img->format == result[0]->format);
uint8_t* dptr = img->pixels;
for (size_t x = 0; x < w; ++x)
{
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
const UINT64 element = (packed) ? (x >> 1) : x;
const size_t offset = computer->GetTexelElementOffsetBytes(0, level, element, 0, item, 0, nullptr);
#else
const size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, 0, item, 0);
#endif
if (offset == size_t(-1))
return E_FAIL;
const uint8_t* src = sptr + offset;
if ((src + bpp) > endPtr)
return E_FAIL;
memcpy(dptr, src, bpp);
dptr += bpp;
if (packed)
++x;
}
}
return S_OK;
}
//----------------------------------------------------------------------------------
inline HRESULT DetileByElement2D(
const XboxImage& xbox,
uint32_t level,
_In_ XGTextureAddressComputer* computer,
const XG_RESOURCE_LAYOUT& layout,
_In_reads_(nimages) const Image* const * result,
size_t nimages,
size_t bpp,
size_t w,
size_t h,
bool packed)
{
const uint8_t* sptr = xbox.GetPointer();
const uint8_t* endPtr = sptr + layout.SizeBytes;
for (uint32_t item = 0; item < nimages; ++item)
{
const Image* img = result[item];
if (!img || !img->pixels)
return E_POINTER;
assert(img->width == result[0]->width);
assert(img->height == result[0]->height);
assert(img->rowPitch == result[0]->rowPitch);
assert(img->format == result[0]->format);
uint8_t* dptr = img->pixels;
for (uint32_t y = 0; y < h; ++y)
{
uint8_t* tptr = dptr;
for (size_t x = 0; x < w; ++x)
{
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
const UINT64 element = (packed) ? (x >> 1) : x;
const size_t offset = computer->GetTexelElementOffsetBytes(0, level, element, y, item, 0, nullptr);
#else
const size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, item, 0);
#endif
if (offset == size_t(-1))
return E_FAIL;
const uint8_t* src = sptr + offset;
if ((src + bpp) > endPtr)
return E_FAIL;
memcpy(tptr, src, bpp);
tptr += bpp;
if (packed)
++x;
}
dptr += img->rowPitch;
}
}
return S_OK;
}
//----------------------------------------------------------------------------------
inline HRESULT DetileByElement3D(
const XboxImage& xbox,
uint32_t level,
uint32_t slices,
_In_ XGTextureAddressComputer* computer,
const XG_RESOURCE_LAYOUT& layout,
const Image& result,
size_t bpp,
size_t w,
size_t h,
bool packed)
{
const uint8_t* sptr = xbox.GetPointer();
const uint8_t* endPtr = sptr + layout.SizeBytes;
uint8_t* dptr = result.pixels;
for (uint32_t z = 0; z < slices; ++z)
{
uint8_t* rptr = dptr;
for (uint32_t y = 0; y < h; ++y)
{
uint8_t* tptr = rptr;
for (size_t x = 0; x < w; ++x)
{
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
const UINT64 element = (packed) ? (x >> 1) : x;
const size_t offset = computer->GetTexelElementOffsetBytes(0, level, element, y, z, 0, nullptr);
#else
const size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, z, 0);
#endif
if (offset == size_t(-1))
return E_FAIL;
const uint8_t* src = sptr + offset;
if ((src + bpp) > endPtr)
return E_FAIL;
memcpy(tptr, src, bpp);
tptr += bpp;
if (packed)
++x;
}
rptr += result.rowPitch;
}
dptr += result.slicePitch;
}
return S_OK;
}
//-------------------------------------------------------------------------------------
// 1D Tiling
//-------------------------------------------------------------------------------------
HRESULT Detile1D(
const XboxImage& xbox,
uint32_t level,
_In_ XGTextureAddressComputer* computer,
const XG_RESOURCE_LAYOUT& layout,
_In_reads_(nimages) const Image** result,
size_t nimages)
{
if (!nimages)
return E_INVALIDARG;
if (!xbox.GetPointer() || !computer || !result || !result[0])
return E_POINTER;
assert(layout.Planes == 1);
const DXGI_FORMAT format = result[0]->format;
assert(format == xbox.GetMetadata().format);
assert(!IsCompressed(format));
bool byelement = IsTypeless(format);
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
if (nimages > 1)
byelement = true;
#endif
if (IsPacked(format))
{
const size_t bpp = (BitsPerPixel(format) + 7) / 8;
// XG (XboxOne) incorrectly returns 2 instead of 4 here for layout.Plane[0].BytesPerElement
const size_t w = result[0]->width;
assert(((w + 1) / 2) == layout.Plane[0].MipLayout[level].WidthElements);
return DetileByElement1D(xbox, level, computer, layout, result, nimages, bpp, w, true);
}
else if (byelement)
{
//--- Typeless is done with per-element copy ----------------------------------
const size_t bpp = (BitsPerPixel(format) + 7) / 8;
assert(bpp == layout.Plane[0].BytesPerElement);
const size_t w = result[0]->width;
assert(w == layout.Plane[0].MipLayout[level].WidthElements);
return DetileByElement1D(xbox, level, computer, layout, result, nimages, bpp, w, false);
}
else
{
//--- Standard format handling ------------------------------------------------
auto& mip = layout.Plane[0].MipLayout[level];
const UINT32 tiledPixels = mip.PitchPixels * mip.PaddedDepthOrArraySize;
auto scanline = make_AlignedArrayXMVECTOR(tiledPixels + result[0]->width);
XMVECTOR* target = scanline.get();
XMVECTOR* tiled = target + result[0]->width;
#ifdef _DEBUG
memset(target, 0xCD, sizeof(XMVECTOR) * result[0]->width);
memset(tiled, 0xDD, sizeof(XMVECTOR) * tiledPixels);
#endif
// Load tiled texture
if ((xbox.GetSize() - mip.OffsetBytes) < mip.SizeBytes)
return E_FAIL;
if (!LoadScanline(tiled, tiledPixels, xbox.GetPointer() + mip.OffsetBytes, mip.SizeBytes, xbox.GetMetadata().format))
return E_FAIL;
// Perform detiling
for (uint32_t item = 0; item < nimages; ++item)
{
const Image* img = result[item];
if (!img || !img->pixels)
return E_POINTER;
assert(img->width == result[0]->width);
assert(img->height == result[0]->height);
assert(img->rowPitch == result[0]->rowPitch);
assert(img->format == result[0]->format);
for (size_t x = 0; x < img->width; ++x)
{
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, 0, item, 0, nullptr);
#else
size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, 0, item, 0);
#endif
if (offset == size_t(-1))
return E_FAIL;
assert(offset >= mip.OffsetBytes);
assert(offset < mip.OffsetBytes + mip.SizeBytes);
offset = (offset - mip.OffsetBytes) / layout.Plane[0].BytesPerElement;
assert(offset < tiledPixels);
target[x] = tiled[offset];
}
if (!StoreScanline(img->pixels, img->rowPitch, img->format, target, img->width))
return E_FAIL;
}
}
return S_OK;
}
//-------------------------------------------------------------------------------------
// 2D Tiling
//-------------------------------------------------------------------------------------
HRESULT Detile2D(
const XboxImage& xbox,
uint32_t level,
_In_ XGTextureAddressComputer* computer,
const XG_RESOURCE_LAYOUT& layout,
_In_reads_(nimages) const Image** result,
size_t nimages)
{
if (!nimages)
return E_INVALIDARG;
if (!xbox.GetPointer() || !computer || !result || !result[0])
return E_POINTER;
assert(xbox.GetMetadata().format == result[0]->format);
assert(layout.Planes == 1);
const DXGI_FORMAT format = result[0]->format;
assert(format == xbox.GetMetadata().format);
bool byelement = IsTypeless(format);
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
if (nimages > 1)
byelement = true;
#endif
if (IsCompressed(format))
{
//--- BC formats use per-block copy -------------------------------------------
const size_t nbw = std::max<size_t>(1, (result[0]->width + 3) / 4);
const size_t nbh = std::max<size_t>(1, (result[0]->height + 3) / 4);
const size_t bpb = (format == DXGI_FORMAT_BC1_TYPELESS
|| format == DXGI_FORMAT_BC1_UNORM
|| format == DXGI_FORMAT_BC1_UNORM_SRGB
|| format == DXGI_FORMAT_BC4_TYPELESS
|| format == DXGI_FORMAT_BC4_UNORM
|| format == DXGI_FORMAT_BC4_SNORM) ? 8 : 16;
assert(nbw == layout.Plane[0].MipLayout[level].WidthElements);
assert(nbh == layout.Plane[0].MipLayout[level].HeightElements);
assert(bpb == layout.Plane[0].BytesPerElement);
return DetileByElement2D(xbox, level, computer, layout, result, nimages, bpb, nbw, nbh, false);
}
else if (IsPacked(format))
{
const size_t bpp = (BitsPerPixel(format) + 7) / 8;
// XG (XboxOne) incorrectly returns 2 instead of 4 here for layout.Plane[0].BytesPerElement
const size_t w = result[0]->width;
const size_t h = result[0]->height;
assert(((w + 1) / 2) == layout.Plane[0].MipLayout[level].WidthElements);
assert(h == layout.Plane[0].MipLayout[level].HeightElements);
return DetileByElement2D(xbox, level, computer, layout, result, nimages, bpp, w, h, true);
}
else if (byelement)
{
//--- Typeless is done with per-element copy ----------------------------------
const size_t bpp = (BitsPerPixel(format) + 7) / 8;
assert(bpp == layout.Plane[0].BytesPerElement);
const size_t w = result[0]->width;
const size_t h = result[0]->height;
assert(w == layout.Plane[0].MipLayout[level].WidthElements);
assert(h == layout.Plane[0].MipLayout[level].HeightElements);
return DetileByElement2D(xbox, level, computer, layout, result, nimages, bpp, w, h, false);
}
else
{
//--- Standard format handling ------------------------------------------------
auto& mip = layout.Plane[0].MipLayout[level];
const UINT32 tiledPixels = mip.PaddedWidthElements * mip.PaddedHeightElements * mip.PaddedDepthOrArraySize;
auto scanline = make_AlignedArrayXMVECTOR(tiledPixels + result[0]->width);
XMVECTOR* target = scanline.get();
XMVECTOR* tiled = target + result[0]->width;
#ifdef _DEBUG
memset(target, 0xCD, sizeof(XMVECTOR) * result[0]->width);
memset(tiled, 0xDD, sizeof(XMVECTOR) * tiledPixels);
#endif
// Load tiled texture
if ((xbox.GetSize() - mip.OffsetBytes) < mip.SizeBytes)
return E_FAIL;
if (!LoadScanline(tiled, tiledPixels, xbox.GetPointer() + mip.OffsetBytes, mip.SizeBytes, xbox.GetMetadata().format))
return E_FAIL;
// Perform detiling
for (uint32_t item = 0; item < nimages; ++item)
{
const Image* img = result[item];
if (!img || !img->pixels)
return E_POINTER;
assert(img->width == result[0]->width);
assert(img->height == result[0]->height);
assert(img->rowPitch == result[0]->rowPitch);
assert(img->format == result[0]->format);
auto dptr = reinterpret_cast<uint8_t * __restrict>(img->pixels);
for (uint32_t y = 0; y < img->height; ++y)
{
for (size_t x = 0; x < img->width; ++x)
{
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, item, 0, nullptr);
#else
size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, item, 0);
#endif
if (offset == size_t(-1))
return E_FAIL;
assert(offset >= mip.OffsetBytes);
assert(offset < mip.OffsetBytes + mip.SizeBytes);
offset = (offset - mip.OffsetBytes) / layout.Plane[0].BytesPerElement;
assert(offset < tiledPixels);
target[x] = tiled[offset];
}
if (!StoreScanline(dptr, img->rowPitch, img->format, target, img->width))
return E_FAIL;
dptr += img->rowPitch;
}
}
}
return S_OK;
}
//-------------------------------------------------------------------------------------
// 3D Tiling
//-------------------------------------------------------------------------------------
HRESULT Detile3D(
const XboxImage& xbox,
uint32_t level,
uint32_t slices,
_In_ XGTextureAddressComputer* computer,
const XG_RESOURCE_LAYOUT& layout,
const Image& result)
{
if (!computer || !xbox.GetPointer() || !result.pixels)
return E_POINTER;
assert(xbox.GetMetadata().format == result.format);
assert(layout.Planes == 1);
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
const bool byelement = true;
#else
const bool byelement = IsTypeless(result.format);
#endif
if (IsCompressed(result.format))
{
//--- BC formats use per-block copy -------------------------------------------
const size_t nbw = std::max<size_t>(1, (result.width + 3) / 4);
const size_t nbh = std::max<size_t>(1, (result.height + 3) / 4);
const size_t bpb = (result.format == DXGI_FORMAT_BC1_TYPELESS
|| result.format == DXGI_FORMAT_BC1_UNORM
|| result.format == DXGI_FORMAT_BC1_UNORM_SRGB
|| result.format == DXGI_FORMAT_BC4_TYPELESS
|| result.format == DXGI_FORMAT_BC4_UNORM
|| result.format == DXGI_FORMAT_BC4_SNORM) ? 8 : 16;
assert(nbw == layout.Plane[0].MipLayout[level].WidthElements);
assert(nbh == layout.Plane[0].MipLayout[level].HeightElements);
assert(bpb == layout.Plane[0].BytesPerElement);
return DetileByElement3D(xbox, level, slices, computer, layout, result, bpb, nbw, nbh, false);
}
else if (IsPacked(result.format))
{
const size_t bpp = (BitsPerPixel(result.format) + 7) / 8;
// XG (XboxOne) incorrectly returns 2 instead of 4 here for layout.Plane[0].BytesPerElement
assert(((result.width + 1) / 2) == layout.Plane[0].MipLayout[level].WidthElements);
assert(result.height == layout.Plane[0].MipLayout[level].HeightElements);
return DetileByElement3D(xbox, level, slices, computer, layout, result, bpp, result.width, result.height, true);
}
else if (byelement)
{
//--- Typeless is done with per-element copy ----------------------------------
const size_t bpp = (BitsPerPixel(result.format) + 7) / 8;
assert(bpp == layout.Plane[0].BytesPerElement);
assert(result.width == layout.Plane[0].MipLayout[level].WidthElements);
assert(result.height == layout.Plane[0].MipLayout[level].HeightElements);
return DetileByElement3D(xbox, level, slices, computer, layout, result, bpp, result.width, result.height, false);
}
else
{
//--- Standard format handling ------------------------------------------------
auto& mip = layout.Plane[0].MipLayout[level];
const UINT32 tiledPixels = mip.PaddedWidthElements * mip.PaddedHeightElements * mip.PaddedDepthOrArraySize;
assert(tiledPixels >= (result.width * result.height * slices));
auto scanline = make_AlignedArrayXMVECTOR(tiledPixels + result.width);
XMVECTOR* target = scanline.get();
XMVECTOR* tiled = target + result.width;
#ifdef _DEBUG
memset(target, 0xCD, sizeof(XMVECTOR) * result.width);
memset(tiled, 0xDD, sizeof(XMVECTOR) * tiledPixels);
#endif
// Load tiled texture
if ((xbox.GetSize() - mip.OffsetBytes) < mip.SizeBytes)
return E_FAIL;
const uint8_t* sptr = xbox.GetPointer() + mip.OffsetBytes;
const uint8_t* endPtr = sptr + mip.SizeBytes;
XMVECTOR* tptr = tiled;
for (uint32_t z = 0; z < mip.PaddedDepthOrArraySize; ++z)
{
const uint8_t* rptr = sptr;
XMVECTOR* uptr = tptr;
for (uint32_t y = 0; y < mip.PaddedHeightElements; ++y)
{
if ((rptr + mip.PitchBytes) > endPtr)
return E_FAIL;
if (!LoadScanline(uptr, mip.PitchPixels, rptr, mip.PitchBytes, xbox.GetMetadata().format))
return E_FAIL;
rptr += mip.PitchBytes;
uptr += mip.PaddedWidthElements;
}
sptr += mip.Slice2DSizeBytes;
tptr += size_t(mip.PaddedHeightElements) * size_t(mip.PaddedWidthElements);
}
// Perform detiling
uint8_t* dptr = reinterpret_cast<uint8_t*>(result.pixels);
for (uint32_t z = 0; z < slices; ++z)
{
uint8_t* rptr = dptr;
for (uint32_t y = 0; y < result.height; ++y)
{
for (size_t x = 0; x < result.width; ++x)
{
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, z, 0, nullptr);
#else
size_t offset = computer->GetTexelElementOffsetBytes(0, level, x, y, z, 0);
#endif
if (offset == size_t(-1))
return E_FAIL;
assert(offset >= mip.OffsetBytes);
assert(offset < mip.OffsetBytes + mip.SizeBytes);
offset = (offset - mip.OffsetBytes) / layout.Plane[0].BytesPerElement;
assert(offset < tiledPixels);
target[x] = tiled[offset];
}
if (!StoreScanline(rptr, result.rowPitch, result.format, target, result.width))
return E_FAIL;
rptr += result.rowPitch;
}
dptr += result.slicePitch;
}
}
return S_OK;
}
}
//=====================================================================================
// Entry-points
//=====================================================================================
//-------------------------------------------------------------------------------------
// Detile image
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
HRESULT Xbox::Detile(
const XboxImage& xbox,
DirectX::ScratchImage& image)
{
if (!xbox.GetSize() || !xbox.GetPointer() || xbox.GetTileMode() == c_XboxTileModeInvalid)
return E_INVALIDARG;
image.Release();
auto& metadata = xbox.GetMetadata();
if (metadata.format == DXGI_FORMAT_R1_UNORM
|| IsVideo(metadata.format))
{
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
switch (metadata.format)
{
case DXGI_FORMAT_R32G32B32_TYPELESS:
case DXGI_FORMAT_R32G32B32_FLOAT:
case DXGI_FORMAT_R32G32B32_UINT:
case DXGI_FORMAT_R32G32B32_SINT:
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
default:
break;
}
XG_RESOURCE_LAYOUT layout = {};
switch (metadata.dimension)
{
case TEX_DIMENSION_TEXTURE1D:
{
XG_TEXTURE1D_DESC desc = {};
desc.Width = static_cast<UINT>(metadata.width);
desc.MipLevels = static_cast<UINT>(metadata.mipLevels);
desc.ArraySize = static_cast<UINT>(metadata.arraySize);
desc.Format = static_cast<XG_FORMAT>(metadata.format);
desc.Usage = XG_USAGE_DEFAULT;
desc.BindFlags = XG_BIND_SHADER_RESOURCE;
desc.MiscFlags = (metadata.IsCubemap()) ? XG_RESOURCE_MISC_TEXTURECUBE : 0;
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
desc.SwizzleMode = xbox.GetTileMode();
#else
desc.TileMode = xbox.GetTileMode();
#endif
ComPtr<XGTextureAddressComputer> computer;
HRESULT hr = XGCreateTexture1DComputer(&desc, computer.GetAddressOf());
if (FAILED(hr))
return hr;
hr = computer->GetResourceLayout(&layout);
if (FAILED(hr))
return hr;
if (layout.Planes != 1)
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
if (layout.SizeBytes != xbox.GetSize()
|| layout.BaseAlignmentBytes != xbox.GetAlignment())
return E_UNEXPECTED;
hr = image.Initialize(metadata);
if (FAILED(hr))
return hr;
for (uint32_t level = 0; level < metadata.mipLevels; ++level)
{
if (metadata.arraySize > 1)
{
std::vector<const Image*> images;
images.reserve(metadata.arraySize);
for (uint32_t item = 0; item < metadata.arraySize; ++item)
{
const Image* img = image.GetImage(level, item, 0);
if (!img)
{
image.Release();
return E_FAIL;
}
images.push_back(img);
}
hr = Detile1D(xbox, level, computer.Get(), layout, &images[0], images.size());
}
else
{
const Image* img = image.GetImage(level, 0, 0);
if (!img)
{
image.Release();
return E_FAIL;
}
hr = Detile1D(xbox, level, computer.Get(), layout, &img, 1);
}
if (FAILED(hr))
{
image.Release();
return hr;
}
}
}
break;
case TEX_DIMENSION_TEXTURE2D:
{
XG_TEXTURE2D_DESC desc = {};
desc.Width = static_cast<UINT>(metadata.width);
desc.Height = static_cast<UINT>(metadata.height);
desc.MipLevels = static_cast<UINT>(metadata.mipLevels);
desc.ArraySize = static_cast<UINT>(metadata.arraySize);
desc.Format = static_cast<XG_FORMAT>(metadata.format);
desc.SampleDesc.Count = 1;
desc.Usage = XG_USAGE_DEFAULT;
desc.BindFlags = XG_BIND_SHADER_RESOURCE;
desc.MiscFlags = (metadata.miscFlags & TEX_MISC_TEXTURECUBE) ? XG_RESOURCE_MISC_TEXTURECUBE : 0;
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
desc.SwizzleMode = xbox.GetTileMode();
#else
desc.TileMode = xbox.GetTileMode();
#endif
ComPtr<XGTextureAddressComputer> computer;
HRESULT hr = XGCreateTexture2DComputer(&desc, computer.GetAddressOf());
if (FAILED(hr))
return hr;
hr = computer->GetResourceLayout(&layout);
if (FAILED(hr))
return hr;
if (layout.Planes != 1)
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
if (layout.SizeBytes != xbox.GetSize()
|| layout.BaseAlignmentBytes != xbox.GetAlignment())
return E_UNEXPECTED;
hr = image.Initialize(metadata);
if (FAILED(hr))
return hr;
for (uint32_t level = 0; level < metadata.mipLevels; ++level)
{
if (metadata.arraySize > 1)
{
std::vector<const Image*> images;
images.reserve(metadata.arraySize);
for (uint32_t item = 0; item < metadata.arraySize; ++item)
{
const Image* img = image.GetImage(level, item, 0);
if (!img)
{
image.Release();
return E_FAIL;
}
images.push_back(img);
}
hr = Detile2D(xbox, level, computer.Get(), layout, &images[0], images.size());
}
else
{
const Image* img = image.GetImage(level, 0, 0);
if (!img)
{
image.Release();
return E_FAIL;
}
hr = Detile2D(xbox, level, computer.Get(), layout, &img, 1);
}
if (FAILED(hr))
{
image.Release();
return hr;
}
}
}
break;
case TEX_DIMENSION_TEXTURE3D:
{
XG_TEXTURE3D_DESC desc = {};
desc.Width = static_cast<UINT>(metadata.width);
desc.Height = static_cast<UINT>(metadata.height);
desc.Depth = static_cast<UINT>(metadata.depth);
desc.MipLevels = static_cast<UINT>(metadata.mipLevels);
desc.Format = static_cast<XG_FORMAT>(metadata.format);
desc.Usage = XG_USAGE_DEFAULT;
desc.BindFlags = XG_BIND_SHADER_RESOURCE;
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
desc.SwizzleMode = xbox.GetTileMode();
#else
desc.TileMode = xbox.GetTileMode();
#endif
ComPtr<XGTextureAddressComputer> computer;
HRESULT hr = XGCreateTexture3DComputer(&desc, computer.GetAddressOf());
if (FAILED(hr))
return hr;
hr = computer->GetResourceLayout(&layout);
if (FAILED(hr))
return hr;
if (layout.Planes != 1)
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
if (layout.SizeBytes != xbox.GetSize()
|| layout.BaseAlignmentBytes != xbox.GetAlignment())
return E_UNEXPECTED;
hr = image.Initialize(metadata);
if (FAILED(hr))
return hr;
uint32_t d = static_cast<uint32_t>(metadata.depth);
size_t index = 0;
for (uint32_t level = 0; level < metadata.mipLevels; ++level)
{
if ((index + d) > image.GetImageCount())
{
image.Release();
return E_FAIL;
}
// Relies on the fact that slices are contiguous
hr = Detile3D(xbox, level, d, computer.Get(), layout, image.GetImages()[index]);
if (FAILED(hr))
{
image.Release();
return hr;
}
index += d;
if (d > 1)
d >>= 1;
}
}
break;
default:
return E_FAIL;
}
return S_OK;
}

View File

@@ -0,0 +1,319 @@
//--------------------------------------------------------------------------------------
// File: DirectXTexXboxImage.cpp
//
// DirectXTex Auxillary functions for Xbox texture blob
//
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//--------------------------------------------------------------------------------------
#include "DirectXTexP.h"
#include "DirectXTexXbox.h"
using namespace DirectX;
using namespace Xbox;
// Sanity check XG library values against DirectXTex's values
static_assert(static_cast<int>(XG_FORMAT_UNKNOWN) == static_cast<int>(DXGI_FORMAT_UNKNOWN), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32G32B32A32_TYPELESS) == static_cast<int>(DXGI_FORMAT_R32G32B32A32_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32G32B32A32_FLOAT) == static_cast<int>(DXGI_FORMAT_R32G32B32A32_FLOAT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32G32B32A32_UINT) == static_cast<int>(DXGI_FORMAT_R32G32B32A32_UINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32G32B32A32_SINT) == static_cast<int>(DXGI_FORMAT_R32G32B32A32_SINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32G32B32_TYPELESS) == static_cast<int>(DXGI_FORMAT_R32G32B32_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32G32B32_FLOAT) == static_cast<int>(DXGI_FORMAT_R32G32B32_FLOAT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32G32B32_UINT) == static_cast<int>(DXGI_FORMAT_R32G32B32_UINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32G32B32_SINT) == static_cast<int>(DXGI_FORMAT_R32G32B32_SINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16G16B16A16_TYPELESS) == static_cast<int>(DXGI_FORMAT_R16G16B16A16_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16G16B16A16_FLOAT) == static_cast<int>(DXGI_FORMAT_R16G16B16A16_FLOAT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16G16B16A16_UNORM) == static_cast<int>(DXGI_FORMAT_R16G16B16A16_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16G16B16A16_UINT) == static_cast<int>(DXGI_FORMAT_R16G16B16A16_UINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16G16B16A16_SNORM) == static_cast<int>(DXGI_FORMAT_R16G16B16A16_SNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16G16B16A16_SINT) == static_cast<int>(DXGI_FORMAT_R16G16B16A16_SINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32G32_TYPELESS) == static_cast<int>(DXGI_FORMAT_R32G32_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32G32_FLOAT) == static_cast<int>(DXGI_FORMAT_R32G32_FLOAT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32G32_UINT) == static_cast<int>(DXGI_FORMAT_R32G32_UINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32G32_SINT) == static_cast<int>(DXGI_FORMAT_R32G32_SINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32G8X24_TYPELESS) == static_cast<int>(DXGI_FORMAT_R32G8X24_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_D32_FLOAT_S8X24_UINT) == static_cast<int>(DXGI_FORMAT_D32_FLOAT_S8X24_UINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32_FLOAT_X8X24_TYPELESS) == static_cast<int>(DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_X32_TYPELESS_G8X24_UINT) == static_cast<int>(DXGI_FORMAT_X32_TYPELESS_G8X24_UINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R10G10B10A2_TYPELESS) == static_cast<int>(DXGI_FORMAT_R10G10B10A2_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R10G10B10A2_UNORM) == static_cast<int>(DXGI_FORMAT_R10G10B10A2_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R10G10B10A2_UINT) == static_cast<int>(DXGI_FORMAT_R10G10B10A2_UINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R11G11B10_FLOAT) == static_cast<int>(DXGI_FORMAT_R11G11B10_FLOAT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8G8B8A8_TYPELESS) == static_cast<int>(DXGI_FORMAT_R8G8B8A8_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8G8B8A8_UNORM) == static_cast<int>(DXGI_FORMAT_R8G8B8A8_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8G8B8A8_UNORM_SRGB) == static_cast<int>(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8G8B8A8_UINT) == static_cast<int>(DXGI_FORMAT_R8G8B8A8_UINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8G8B8A8_SNORM) == static_cast<int>(DXGI_FORMAT_R8G8B8A8_SNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8G8B8A8_SINT) == static_cast<int>(DXGI_FORMAT_R8G8B8A8_SINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16G16_TYPELESS) == static_cast<int>(DXGI_FORMAT_R16G16_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16G16_FLOAT) == static_cast<int>(DXGI_FORMAT_R16G16_FLOAT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16G16_UNORM) == static_cast<int>(DXGI_FORMAT_R16G16_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16G16_UINT) == static_cast<int>(DXGI_FORMAT_R16G16_UINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16G16_SNORM) == static_cast<int>(DXGI_FORMAT_R16G16_SNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16G16_SINT) == static_cast<int>(DXGI_FORMAT_R16G16_SINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32_TYPELESS) == static_cast<int>(DXGI_FORMAT_R32_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_D32_FLOAT) == static_cast<int>(DXGI_FORMAT_D32_FLOAT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32_FLOAT) == static_cast<int>(DXGI_FORMAT_R32_FLOAT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32_UINT) == static_cast<int>(DXGI_FORMAT_R32_UINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R32_SINT) == static_cast<int>(DXGI_FORMAT_R32_SINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R24G8_TYPELESS) == static_cast<int>(DXGI_FORMAT_R24G8_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_D24_UNORM_S8_UINT) == static_cast<int>(DXGI_FORMAT_D24_UNORM_S8_UINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R24_UNORM_X8_TYPELESS) == static_cast<int>(DXGI_FORMAT_R24_UNORM_X8_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_X24_TYPELESS_G8_UINT) == static_cast<int>(DXGI_FORMAT_X24_TYPELESS_G8_UINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8G8_TYPELESS) == static_cast<int>(DXGI_FORMAT_R8G8_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8G8_UNORM) == static_cast<int>(DXGI_FORMAT_R8G8_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8G8_UINT) == static_cast<int>(DXGI_FORMAT_R8G8_UINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8G8_SNORM) == static_cast<int>(DXGI_FORMAT_R8G8_SNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8G8_SINT) == static_cast<int>(DXGI_FORMAT_R8G8_SINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16_TYPELESS) == static_cast<int>(DXGI_FORMAT_R16_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16_FLOAT) == static_cast<int>(DXGI_FORMAT_R16_FLOAT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_D16_UNORM) == static_cast<int>(DXGI_FORMAT_D16_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16_UNORM) == static_cast<int>(DXGI_FORMAT_R16_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16_UINT) == static_cast<int>(DXGI_FORMAT_R16_UINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16_SNORM) == static_cast<int>(DXGI_FORMAT_R16_SNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R16_SINT) == static_cast<int>(DXGI_FORMAT_R16_SINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8_TYPELESS) == static_cast<int>(DXGI_FORMAT_R8_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8_UNORM) == static_cast<int>(DXGI_FORMAT_R8_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8_UINT) == static_cast<int>(DXGI_FORMAT_R8_UINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8_SNORM) == static_cast<int>(DXGI_FORMAT_R8_SNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8_SINT) == static_cast<int>(DXGI_FORMAT_R8_SINT), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_A8_UNORM) == static_cast<int>(DXGI_FORMAT_A8_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R1_UNORM) == static_cast<int>(DXGI_FORMAT_R1_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R9G9B9E5_SHAREDEXP) == static_cast<int>(DXGI_FORMAT_R9G9B9E5_SHAREDEXP), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R8G8_B8G8_UNORM) == static_cast<int>(DXGI_FORMAT_R8G8_B8G8_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_G8R8_G8B8_UNORM) == static_cast<int>(DXGI_FORMAT_G8R8_G8B8_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC1_TYPELESS) == static_cast<int>(DXGI_FORMAT_BC1_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC1_UNORM) == static_cast<int>(DXGI_FORMAT_BC1_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC1_UNORM_SRGB) == static_cast<int>(DXGI_FORMAT_BC1_UNORM_SRGB), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC2_TYPELESS) == static_cast<int>(DXGI_FORMAT_BC2_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC2_UNORM) == static_cast<int>(DXGI_FORMAT_BC2_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC2_UNORM_SRGB) == static_cast<int>(DXGI_FORMAT_BC2_UNORM_SRGB), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC3_TYPELESS) == static_cast<int>(DXGI_FORMAT_BC3_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC3_UNORM) == static_cast<int>(DXGI_FORMAT_BC3_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC3_UNORM_SRGB) == static_cast<int>(DXGI_FORMAT_BC3_UNORM_SRGB), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC4_TYPELESS) == static_cast<int>(DXGI_FORMAT_BC4_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC4_UNORM) == static_cast<int>(DXGI_FORMAT_BC4_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC4_SNORM) == static_cast<int>(DXGI_FORMAT_BC4_SNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC5_TYPELESS) == static_cast<int>(DXGI_FORMAT_BC5_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC5_UNORM) == static_cast<int>(DXGI_FORMAT_BC5_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC5_SNORM) == static_cast<int>(DXGI_FORMAT_BC5_SNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_B5G6R5_UNORM) == static_cast<int>(DXGI_FORMAT_B5G6R5_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_B5G5R5A1_UNORM) == static_cast<int>(DXGI_FORMAT_B5G5R5A1_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_B8G8R8A8_UNORM) == static_cast<int>(DXGI_FORMAT_B8G8R8A8_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_B8G8R8X8_UNORM) == static_cast<int>(DXGI_FORMAT_B8G8R8X8_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_R10G10B10_XR_BIAS_A2_UNORM) == static_cast<int>(DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_B8G8R8A8_TYPELESS) == static_cast<int>(DXGI_FORMAT_B8G8R8A8_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_B8G8R8A8_UNORM_SRGB) == static_cast<int>(DXGI_FORMAT_B8G8R8A8_UNORM_SRGB), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_B8G8R8X8_TYPELESS) == static_cast<int>(DXGI_FORMAT_B8G8R8X8_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_B8G8R8X8_UNORM_SRGB) == static_cast<int>(DXGI_FORMAT_B8G8R8X8_UNORM_SRGB), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC6H_TYPELESS) == static_cast<int>(DXGI_FORMAT_BC6H_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC6H_UF16) == static_cast<int>(DXGI_FORMAT_BC6H_UF16), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC6H_SF16) == static_cast<int>(DXGI_FORMAT_BC6H_SF16), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC7_TYPELESS) == static_cast<int>(DXGI_FORMAT_BC7_TYPELESS), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC7_UNORM) == static_cast<int>(DXGI_FORMAT_BC7_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_BC7_UNORM_SRGB) == static_cast<int>(DXGI_FORMAT_BC7_UNORM_SRGB), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_AYUV) == static_cast<int>(DXGI_FORMAT_AYUV), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_Y410) == static_cast<int>(DXGI_FORMAT_Y410), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_Y416) == static_cast<int>(DXGI_FORMAT_Y416), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_NV12) == static_cast<int>(DXGI_FORMAT_NV12), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_P010) == static_cast<int>(DXGI_FORMAT_P010), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_P016) == static_cast<int>(DXGI_FORMAT_P016), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_420_OPAQUE) == static_cast<int>(DXGI_FORMAT_420_OPAQUE), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_YUY2) == static_cast<int>(DXGI_FORMAT_YUY2), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_Y210) == static_cast<int>(DXGI_FORMAT_Y210), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_Y216) == static_cast<int>(DXGI_FORMAT_Y216), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_NV11) == static_cast<int>(DXGI_FORMAT_NV11), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_AI44) == static_cast<int>(DXGI_FORMAT_AI44), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_IA44) == static_cast<int>(DXGI_FORMAT_IA44), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_P8) == static_cast<int>(DXGI_FORMAT_P8), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_A8P8) == static_cast<int>(DXGI_FORMAT_A8P8), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_FORMAT_B4G4R4A4_UNORM) == static_cast<int>(DXGI_FORMAT_B4G4R4A4_UNORM), "XG vs. DXGI mismatch");
static_assert(static_cast<int>(XG_RESOURCE_DIMENSION_TEXTURE1D) == static_cast<int>(TEX_DIMENSION_TEXTURE1D), "XG vs. Direct3D 11 mismatch");
static_assert(static_cast<int>(XG_RESOURCE_DIMENSION_TEXTURE2D) == static_cast<int>(TEX_DIMENSION_TEXTURE2D), "XG vs. Direct3D 11 mismatch");
static_assert(static_cast<int>(XG_RESOURCE_DIMENSION_TEXTURE3D) == static_cast<int>(TEX_DIMENSION_TEXTURE3D), "XG vs. Direct3D 11 mismatch");
static_assert(static_cast<int>(XG_RESOURCE_MISC_TEXTURECUBE) == static_cast<int>(TEX_MISC_TEXTURECUBE), "XG vs. Direct3D 11 mismatch");
//--------------------------------------------------------------------------------------
// Initialize memory
//--------------------------------------------------------------------------------------
XboxImage& XboxImage::operator= (XboxImage&& moveFrom) noexcept
{
if (this != &moveFrom)
{
Release();
dataSize = moveFrom.dataSize;
baseAlignment = moveFrom.baseAlignment;
tilemode = moveFrom.tilemode;
metadata = moveFrom.metadata;
memory = moveFrom.memory;
moveFrom.dataSize = 0;
moveFrom.baseAlignment = 0;
moveFrom.tilemode = c_XboxTileModeInvalid;
moveFrom.memory = nullptr;
}
return *this;
}
_Use_decl_annotations_
HRESULT XboxImage::Initialize(const XG_TEXTURE1D_DESC& desc, const XG_RESOURCE_LAYOUT& layout, uint32_t miscFlags2)
{
if (!layout.SizeBytes || !layout.BaseAlignmentBytes)
return E_INVALIDARG;
Release();
if (layout.SizeBytes > UINT32_MAX
|| layout.BaseAlignmentBytes > UINT32_MAX)
return E_FAIL;
memory = reinterpret_cast<uint8_t*>(_aligned_malloc(layout.SizeBytes, 16));
if (!memory)
return E_OUTOFMEMORY;
memset(memory, 0, layout.SizeBytes);
memset(&metadata, 0, sizeof(metadata));
metadata.width = desc.Width;
metadata.height = 1;
metadata.depth = 1;
metadata.arraySize = desc.ArraySize;
metadata.mipLevels = layout.MipLevels;
metadata.format = static_cast<DXGI_FORMAT>(desc.Format);
metadata.dimension = TEX_DIMENSION_TEXTURE1D;
metadata.miscFlags2 = miscFlags2;
dataSize = static_cast<uint32_t>(layout.SizeBytes);
baseAlignment = static_cast<uint32_t>(layout.BaseAlignmentBytes);
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
tilemode = desc.SwizzleMode;
#else
tilemode = desc.TileMode;
#endif
return S_OK;
}
_Use_decl_annotations_
HRESULT XboxImage::Initialize(const XG_TEXTURE2D_DESC& desc, const XG_RESOURCE_LAYOUT& layout, uint32_t miscFlags2)
{
if (!layout.SizeBytes || !layout.BaseAlignmentBytes)
return E_INVALIDARG;
Release();
if (layout.SizeBytes > UINT32_MAX
|| layout.BaseAlignmentBytes > UINT32_MAX)
return E_FAIL;
memory = reinterpret_cast<uint8_t*>(_aligned_malloc(layout.SizeBytes, 16));
if (!memory)
return E_OUTOFMEMORY;
memset(memory, 0, layout.SizeBytes);
memset(&metadata, 0, sizeof(metadata));
metadata.width = desc.Width;
metadata.height = desc.Height;
metadata.depth = 1;
metadata.arraySize = desc.ArraySize;
metadata.mipLevels = layout.MipLevels;
metadata.miscFlags = (desc.MiscFlags & XG_RESOURCE_MISC_TEXTURECUBE) ? TEX_MISC_TEXTURECUBE : 0;
metadata.format = static_cast<DXGI_FORMAT>(desc.Format);
metadata.dimension = TEX_DIMENSION_TEXTURE2D;
metadata.miscFlags2 = miscFlags2;
dataSize = static_cast<uint32_t>(layout.SizeBytes);
baseAlignment = static_cast<uint32_t>(layout.BaseAlignmentBytes);
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
tilemode = desc.SwizzleMode;
#else
tilemode = desc.TileMode;
#endif
return S_OK;
}
_Use_decl_annotations_
HRESULT XboxImage::Initialize(const XG_TEXTURE3D_DESC& desc, const XG_RESOURCE_LAYOUT& layout, uint32_t miscFlags2)
{
if (!layout.SizeBytes || !layout.BaseAlignmentBytes)
return E_INVALIDARG;
Release();
if (layout.SizeBytes > UINT32_MAX
|| layout.BaseAlignmentBytes > UINT32_MAX)
return E_FAIL;
memory = reinterpret_cast<uint8_t*>(_aligned_malloc(layout.SizeBytes, 16));
if (!memory)
return E_OUTOFMEMORY;
memset(memory, 0, layout.SizeBytes);
memset(&metadata, 0, sizeof(metadata));
metadata.width = desc.Width;
metadata.height = desc.Height;
metadata.depth = desc.Depth;
metadata.arraySize = 1;
metadata.mipLevels = layout.MipLevels;
metadata.format = static_cast<DXGI_FORMAT>(desc.Format);
metadata.dimension = TEX_DIMENSION_TEXTURE3D;
metadata.miscFlags2 = miscFlags2;
dataSize = static_cast<uint32_t>(layout.SizeBytes);
baseAlignment = static_cast<uint32_t>(layout.BaseAlignmentBytes);
#if defined(_GAMING_XBOX_SCARLETT) || defined(_USE_SCARLETT)
tilemode = desc.SwizzleMode;
#else
tilemode = desc.TileMode;
#endif
return S_OK;
}
_Use_decl_annotations_
HRESULT XboxImage::Initialize(const DirectX::TexMetadata& mdata, XboxTileMode tm, uint32_t size, uint32_t alignment)
{
if (!size || !alignment || tm == c_XboxTileModeInvalid)
return E_INVALIDARG;
Release();
memory = reinterpret_cast<uint8_t*>(_aligned_malloc(size, 16));
if (!memory)
return E_OUTOFMEMORY;
memset(memory, 0, size);
metadata = mdata;
dataSize = size;
baseAlignment = alignment;
tilemode = tm;
return S_OK;
}
//--------------------------------------------------------------------------------------
// Release memory
//--------------------------------------------------------------------------------------
void XboxImage::Release()
{
if (memory)
{
_aligned_free(memory);
memory = nullptr;
}
}

File diff suppressed because it is too large Load Diff