DirectX 12 planar resource handling

This commit is contained in:
Chuck Walbourn 2017-01-30 22:29:45 -08:00
parent 7be023e608
commit b9bf00c0ea
4 changed files with 370 additions and 170 deletions

View File

@ -818,12 +818,85 @@ namespace
} }
//--------------------------------------------------------------------------------------
inline bool IsDepthStencil(DXGI_FORMAT fmt)
{
switch (fmt)
{
case DXGI_FORMAT_R32G8X24_TYPELESS:
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
case DXGI_FORMAT_D32_FLOAT:
case DXGI_FORMAT_R24G8_TYPELESS:
case DXGI_FORMAT_D24_UNORM_S8_UINT:
case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
case DXGI_FORMAT_D16_UNORM:
return true;
default:
return false;
}
}
//--------------------------------------------------------------------------------------
inline void AdjustPlaneResource(
_In_ DXGI_FORMAT fmt,
_In_ size_t height,
_In_ size_t slicePlane,
_Inout_ D3D12_SUBRESOURCE_DATA& res)
{
switch (fmt)
{
case DXGI_FORMAT_NV12:
case DXGI_FORMAT_P010:
case DXGI_FORMAT_P016:
#if defined(_XBOX_ONE) && defined(_TITLE)
case DXGI_FORMAT_D16_UNORM_S8_UINT:
case DXGI_FORMAT_R16_UNORM_X8_TYPELESS:
case DXGI_FORMAT_X16_TYPELESS_G8_UINT:
#endif
if (!slicePlane)
{
// Plane 0
res.SlicePitch = res.RowPitch * height;
}
else
{
// Plane 1
res.pData = reinterpret_cast<const uint8_t*>(res.pData) + res.RowPitch * height;
res.SlicePitch = res.RowPitch * ((height + 1) >> 1);
}
break;
case DXGI_FORMAT_NV11:
if (!slicePlane)
{
// Plane 0
res.SlicePitch = res.RowPitch * height;
}
else
{
// Plane 1
res.pData = reinterpret_cast<const uint8_t*>(res.pData) + res.RowPitch * height;
res.RowPitch = (res.RowPitch >> 1);
res.SlicePitch = res.RowPitch * height;
}
break;
}
}
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
HRESULT FillInitData(_In_ size_t width, HRESULT FillInitData(_In_ size_t width,
_In_ size_t height, _In_ size_t height,
_In_ size_t depth, _In_ size_t depth,
_In_ size_t mipCount, _In_ size_t mipCount,
_In_ size_t arraySize, _In_ size_t arraySize,
_In_ size_t numberOfPlanes,
_In_ DXGI_FORMAT format, _In_ DXGI_FORMAT format,
_In_ size_t maxsize, _In_ size_t maxsize,
_In_ size_t bitSize, _In_ size_t bitSize,
@ -832,9 +905,9 @@ namespace
_Out_ size_t& theight, _Out_ size_t& theight,
_Out_ size_t& tdepth, _Out_ size_t& tdepth,
_Out_ size_t& skipMip, _Out_ size_t& skipMip,
_Out_writes_(mipCount*arraySize) D3D12_SUBRESOURCE_DATA* initData) std::vector<D3D12_SUBRESOURCE_DATA>& initData)
{ {
if (!bitData || !initData) if (!bitData)
{ {
return E_POINTER; return E_POINTER;
} }
@ -849,7 +922,10 @@ namespace
const uint8_t* pSrcBits = bitData; const uint8_t* pSrcBits = bitData;
const uint8_t* pEndBits = bitData + bitSize; const uint8_t* pEndBits = bitData + bitSize;
size_t index = 0; initData.clear();
for (size_t p = 0; p < numberOfPlanes; ++p)
{
for (size_t j = 0; j < arraySize; j++) for (size_t j = 0; j < arraySize; j++)
{ {
size_t w = width; size_t w = width;
@ -874,12 +950,16 @@ namespace
tdepth = d; tdepth = d;
} }
assert(index < mipCount * arraySize); D3D12_SUBRESOURCE_DATA res =
_Analysis_assume_(index < mipCount * arraySize); {
initData[index].pData = reinterpret_cast<const void*>(pSrcBits); reinterpret_cast<const void*>(pSrcBits),
initData[index].RowPitch = RowBytes; static_cast<LONG_PTR>(RowBytes),
initData[index].SlicePitch = NumBytes; static_cast<LONG_PTR>(NumBytes)
++index; };
AdjustPlaneResource(format, h, p, res);
initData.emplace_back(res);
} }
else if (!j) else if (!j)
{ {
@ -911,8 +991,9 @@ namespace
} }
} }
} }
}
return (index > 0) ? S_OK : E_FAIL; return initData.empty() ? E_FAIL : S_OK;
} }
@ -1150,21 +1231,40 @@ namespace
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
} }
UINT numberOfPlanes = D3D12GetFormatPlaneCount(d3dDevice, format);
if (!numberOfPlanes)
return E_INVALIDARG;
if ((numberOfPlanes > 1) && IsDepthStencil(format))
{
// DirectX 12 uses planes for stencil, DirectX 11 does not
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
if (outIsCubeMap != nullptr) if (outIsCubeMap != nullptr)
{ {
*outIsCubeMap = isCubeMap; *outIsCubeMap = isCubeMap;
} }
// Create the texture // Create the texture
std::vector<D3D12_SUBRESOURCE_DATA> initData; size_t numberOfResources = (resDim == D3D12_RESOURCE_DIMENSION_TEXTURE3D)
initData.resize(mipCount * arraySize); ? 1 : arraySize;
numberOfResources *= mipCount;
numberOfResources *= numberOfPlanes;
if (numberOfResources > D3D12_REQ_SUBRESOURCES)
return E_INVALIDARG;
subresources.reserve(numberOfResources);
size_t skipMip = 0; size_t skipMip = 0;
size_t twidth = 0; size_t twidth = 0;
size_t theight = 0; size_t theight = 0;
size_t tdepth = 0; size_t tdepth = 0;
hr = FillInitData(width, height, depth, mipCount, arraySize, format, maxsize, bitSize, bitData, hr = FillInitData(width, height, depth, mipCount, arraySize,
twidth, theight, tdepth, skipMip, &initData[0]); numberOfPlanes, format,
maxsize, bitSize, bitData,
twidth, theight, tdepth, skipMip, subresources);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
@ -1179,12 +1279,16 @@ namespace
if (FAILED(hr) && !maxsize && (mipCount > 1)) if (FAILED(hr) && !maxsize && (mipCount > 1))
{ {
subresources.clear();
maxsize = (resDim == D3D12_RESOURCE_DIMENSION_TEXTURE3D) maxsize = (resDim == D3D12_RESOURCE_DIMENSION_TEXTURE3D)
? D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION ? D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION
: D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; : D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
hr = FillInitData(width, height, depth, mipCount, arraySize, format, maxsize, bitSize, bitData, hr = FillInitData(width, height, depth, mipCount, arraySize,
twidth, theight, tdepth, skipMip, &initData[0]); numberOfPlanes, format,
maxsize, bitSize, bitData,
twidth, theight, tdepth, skipMip, subresources);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = CreateTextureResource(d3dDevice, resDim, twidth, theight, tdepth, mipCount - skipMip, arraySize, hr = CreateTextureResource(d3dDevice, resDim, twidth, theight, tdepth, mipCount - skipMip, arraySize,
@ -1193,9 +1297,9 @@ namespace
} }
} }
if (SUCCEEDED(hr)) if (FAILED(hr))
{ {
subresources.insert(subresources.end(), initData.begin(), initData.end()); subresources.clear();
} }
return hr; return hr;

View File

@ -694,7 +694,8 @@ namespace DirectX
_In_ D3D12_RESOURCE_FLAGS resFlags, _In_ bool forceSRGB, _In_ D3D12_RESOURCE_FLAGS resFlags, _In_ bool forceSRGB,
_Outptr_ ID3D12Resource** ppResource ); _Outptr_ ID3D12Resource** ppResource );
HRESULT __cdecl PrepareUpload( _In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata, HRESULT __cdecl PrepareUpload( _In_ ID3D12Device* pDevice,
_In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,
std::vector<D3D12_SUBRESOURCE_DATA>& subresources ); std::vector<D3D12_SUBRESOURCE_DATA>& subresources );
HRESULT __cdecl CaptureTexture( _In_ ID3D12CommandQueue* pCommandQueue, _In_ ID3D12Resource* pSource, _In_ bool isCubeMap, HRESULT __cdecl CaptureTexture( _In_ ID3D12CommandQueue* pCommandQueue, _In_ ID3D12Resource* pSource, _In_ bool isCubeMap,

View File

@ -34,6 +34,52 @@ static_assert(TEX_DIMENSION_TEXTURE3D == D3D12_RESOURCE_DIMENSION_TEXTURE3D, "he
namespace namespace
{ {
template<typename T> void AdjustPlaneResource(
_In_ DXGI_FORMAT fmt,
_In_ size_t height,
_In_ size_t slicePlane,
_Inout_ T& res)
{
switch (static_cast<int>(fmt))
{
case DXGI_FORMAT_NV12:
case DXGI_FORMAT_P010:
case DXGI_FORMAT_P016:
case XBOX_DXGI_FORMAT_D16_UNORM_S8_UINT:
case XBOX_DXGI_FORMAT_R16_UNORM_X8_TYPELESS:
case XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT:
if (!slicePlane)
{
// Plane 0
res.SlicePitch = res.RowPitch * height;
}
else
{
// Plane 1
res.pData = (uint8_t*)(res.pData) + res.RowPitch * height;
res.SlicePitch = res.RowPitch * ((height + 1) >> 1);
}
break;
case DXGI_FORMAT_NV11:
if (!slicePlane)
{
// Plane 0
res.SlicePitch = res.RowPitch * height;
}
else
{
// Plane 1
res.pData = (uint8_t*)(res.pData) + res.RowPitch * height;
res.RowPitch = (res.RowPitch >> 1);
res.SlicePitch = res.RowPitch * height;
}
break;
}
}
//--------------------------------------------------------------------------------------
inline void TransitionResource( inline void TransitionResource(
_In_ ID3D12GraphicsCommandList* commandList, _In_ ID3D12GraphicsCommandList* commandList,
_In_ ID3D12Resource* resource, _In_ ID3D12Resource* resource,
@ -64,6 +110,7 @@ namespace
const D3D12_RESOURCE_DESC& desc, const D3D12_RESOURCE_DESC& desc,
ComPtr<ID3D12Resource>& pStaging, ComPtr<ID3D12Resource>& pStaging,
std::unique_ptr<uint8_t[]>& layoutBuff, std::unique_ptr<uint8_t[]>& layoutBuff,
UINT& numberOfPlanes,
UINT& numberOfResources, UINT& numberOfResources,
D3D12_RESOURCE_STATES beforeState, D3D12_RESOURCE_STATES beforeState,
D3D12_RESOURCE_STATES afterState) D3D12_RESOURCE_STATES afterState)
@ -71,16 +118,27 @@ namespace
if (!pCommandQ || !pSource) if (!pCommandQ || !pSource)
return E_INVALIDARG; return E_INVALIDARG;
numberOfPlanes = D3D12GetFormatPlaneCount(device, desc.Format);
if (!numberOfPlanes)
return E_INVALIDARG;
if ((numberOfPlanes > 1) && IsDepthStencil(desc.Format))
{
// DirectX 12 uses planes for stencil, DirectX 11 does not
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
D3D12_HEAP_PROPERTIES sourceHeapProperties; D3D12_HEAP_PROPERTIES sourceHeapProperties;
D3D12_HEAP_FLAGS sourceHeapFlags; D3D12_HEAP_FLAGS sourceHeapFlags;
HRESULT hr = pSource->GetHeapProperties(&sourceHeapProperties, &sourceHeapFlags); HRESULT hr = pSource->GetHeapProperties(&sourceHeapProperties, &sourceHeapFlags);
if (FAILED(hr)) if (FAILED(hr))
return hr; return hr;
// TODO - planar?
numberOfResources = (desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) numberOfResources = (desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D)
? 1 : desc.DepthOrArraySize; ? 1 : desc.DepthOrArraySize;
numberOfResources *= desc.MipLevels; numberOfResources *= desc.MipLevels;
numberOfResources *= numberOfPlanes;
if (numberOfResources > D3D12_REQ_SUBRESOURCES) if (numberOfResources > D3D12_REQ_SUBRESOURCES)
return E_UNEXPECTED; return E_UNEXPECTED;
@ -177,14 +235,17 @@ namespace
if (!(formatInfo.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D)) if (!(formatInfo.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D))
return E_FAIL; return E_FAIL;
for (UINT plane = 0; plane < numberOfPlanes; ++plane)
{
for (UINT item = 0; item < desc.DepthOrArraySize; ++item) for (UINT item = 0; item < desc.DepthOrArraySize; ++item)
{ {
for (UINT level = 0; level < desc.MipLevels; ++level) for (UINT level = 0; level < desc.MipLevels; ++level)
{ {
UINT index = D3D12CalcSubresource(level, item, 0, desc.MipLevels, desc.DepthOrArraySize); UINT index = D3D12CalcSubresource(level, item, plane, desc.MipLevels, desc.DepthOrArraySize);
commandList->ResolveSubresource(pTemp.Get(), index, pSource, index, fmt); commandList->ResolveSubresource(pTemp.Get(), index, pSource, index, fmt);
} }
} }
}
copySource = pTemp; copySource = pTemp;
} }
@ -426,24 +487,36 @@ HRESULT DirectX::CreateTextureEx(
_Use_decl_annotations_ _Use_decl_annotations_
HRESULT DirectX::PrepareUpload( HRESULT DirectX::PrepareUpload(
ID3D12Device* pDevice,
const Image* srcImages, const Image* srcImages,
size_t nimages, size_t nimages,
const TexMetadata& metadata, const TexMetadata& metadata,
std::vector<D3D12_SUBRESOURCE_DATA>& subresources) std::vector<D3D12_SUBRESOURCE_DATA>& subresources)
{ {
if (!srcImages || !nimages || !metadata.mipLevels || !metadata.arraySize) if (!pDevice || !srcImages || !nimages || !metadata.mipLevels || !metadata.arraySize)
return E_INVALIDARG; return E_INVALIDARG;
UINT numberOfPlanes = D3D12GetFormatPlaneCount(pDevice, metadata.format);
if (!numberOfPlanes)
return E_INVALIDARG;
if ((numberOfPlanes > 1) && IsDepthStencil(metadata.format))
{
// DirectX 12 uses planes for stencil, DirectX 11 does not
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
size_t numberOfResources = (metadata.dimension == TEX_DIMENSION_TEXTURE3D) size_t numberOfResources = (metadata.dimension == TEX_DIMENSION_TEXTURE3D)
? 1 : metadata.arraySize; ? 1 : metadata.arraySize;
numberOfResources *= metadata.mipLevels; numberOfResources *= metadata.mipLevels;
numberOfResources *= numberOfPlanes;
if (numberOfResources > D3D12_REQ_SUBRESOURCES) if (numberOfResources > D3D12_REQ_SUBRESOURCES)
return E_INVALIDARG; return E_INVALIDARG;
subresources.clear();
subresources.reserve(numberOfResources); subresources.reserve(numberOfResources);
// TODO - Needs special handling for planar formats (planes treated are independant subresources in DX12)
// Fill out subresource array // Fill out subresource array
if (metadata.IsVolumemap()) if (metadata.IsVolumemap())
{ {
@ -458,6 +531,8 @@ HRESULT DirectX::PrepareUpload(
// Direct3D 12 doesn't support arrays of 3D textures // Direct3D 12 doesn't support arrays of 3D textures
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
for (size_t plane = 0; plane < numberOfPlanes; ++plane)
{
size_t depth = metadata.depth; size_t depth = metadata.depth;
for (size_t level = 0; level < metadata.mipLevels; ++level) for (size_t level = 0; level < metadata.mipLevels; ++level)
@ -498,16 +573,27 @@ HRESULT DirectX::PrepareUpload(
pSlice = timg.pixels + img.slicePitch; pSlice = timg.pixels + img.slicePitch;
} }
D3D12_SUBRESOURCE_DATA sr = { img.pixels, static_cast<LONG_PTR>(img.rowPitch), static_cast<LONG_PTR>(img.slicePitch) }; D3D12_SUBRESOURCE_DATA res =
subresources.emplace_back(sr); {
img.pixels,
static_cast<LONG_PTR>(img.rowPitch),
static_cast<LONG_PTR>(img.slicePitch)
};
AdjustPlaneResource(metadata.format, img.height, plane, res);
subresources.emplace_back(res);
if (depth > 1) if (depth > 1)
depth >>= 1; depth >>= 1;
} }
} }
}
else else
{ {
//--- 1D or 2D texture case --------------------------------------------------- //--- 1D or 2D texture case ---------------------------------------------------
for (size_t plane = 0; plane < numberOfPlanes; ++plane)
{
for (size_t item = 0; item < metadata.arraySize; ++item) for (size_t item = 0; item < metadata.arraySize; ++item)
{ {
for (size_t level = 0; level < metadata.mipLevels; ++level) for (size_t level = 0; level < metadata.mipLevels; ++level)
@ -524,13 +610,17 @@ HRESULT DirectX::PrepareUpload(
if (!img.pixels) if (!img.pixels)
return E_POINTER; return E_POINTER;
D3D12_SUBRESOURCE_DATA sr = D3D12_SUBRESOURCE_DATA res =
{ {
img.pixels, img.pixels,
static_cast<LONG_PTR>(img.rowPitch), static_cast<LONG_PTR>(img.rowPitch),
static_cast<LONG_PTR>(img.slicePitch) static_cast<LONG_PTR>(img.slicePitch)
}; };
subresources.emplace_back(sr);
AdjustPlaneResource(metadata.format, img.height, plane, res);
subresources.emplace_back(res);
}
} }
} }
} }
@ -561,20 +651,21 @@ HRESULT DirectX::CaptureTexture(
ComPtr<ID3D12Resource> pStaging; ComPtr<ID3D12Resource> pStaging;
std::unique_ptr<uint8_t[]> layoutBuff; std::unique_ptr<uint8_t[]> layoutBuff;
UINT numberOfResources; UINT numberOfPlanes, numberOfResources;
HRESULT hr = Capture(device.Get(), HRESULT hr = Capture(device.Get(),
pCommandQueue, pCommandQueue,
pSource, pSource,
desc, desc,
pStaging, pStaging,
layoutBuff, layoutBuff,
numberOfPlanes,
numberOfResources, numberOfResources,
beforeState, beforeState,
afterState); afterState);
if (FAILED(hr)) if (FAILED(hr))
return hr; return hr;
if (!layoutBuff || !numberOfResources) if (!layoutBuff || !numberOfPlanes || !numberOfResources)
return E_UNEXPECTED; return E_UNEXPECTED;
auto pLayout = reinterpret_cast<const D3D12_PLACED_SUBRESOURCE_FOOTPRINT*>(layoutBuff.get()); auto pLayout = reinterpret_cast<const D3D12_PLACED_SUBRESOURCE_FOOTPRINT*>(layoutBuff.get());
@ -663,14 +754,13 @@ HRESULT DirectX::CaptureTexture(
depth = 1; depth = 1;
} }
for (UINT plane = 0; plane < numberOfPlanes; ++plane)
{
for (UINT item = 0; item < arraySize; ++item) for (UINT item = 0; item < arraySize; ++item)
{ {
UINT height = desc.Height;
for (UINT level = 0; level < desc.MipLevels; ++level) for (UINT level = 0; level < desc.MipLevels; ++level)
{ {
UINT dindex = D3D12CalcSubresource(level, item, 0 /* TODO planes */, UINT dindex = D3D12CalcSubresource(level, item, plane, desc.MipLevels, arraySize);
desc.MipLevels, arraySize);
assert(dindex < numberOfResources); assert(dindex < numberOfResources);
const Image* img = result.GetImage(level, item, 0); const Image* img = result.GetImage(level, item, 0);
@ -689,6 +779,9 @@ HRESULT DirectX::CaptureTexture(
} }
D3D12_MEMCPY_DEST destData = { img->pixels, img->rowPitch, img->slicePitch }; D3D12_MEMCPY_DEST destData = { img->pixels, img->rowPitch, img->slicePitch };
AdjustPlaneResource(img->format, img->height, plane, destData);
D3D12_SUBRESOURCE_DATA srcData = D3D12_SUBRESOURCE_DATA srcData =
{ {
pData + pLayout[dindex].Offset, pData + pLayout[dindex].Offset,
@ -708,9 +801,7 @@ HRESULT DirectX::CaptureTexture(
pNumRows[dindex], pNumRows[dindex],
pLayout[dindex].Footprint.Depth); pLayout[dindex].Footprint.Depth);
} }
}
if (height > 1)
height >>= 1;
} }
pStaging->Unmap(0, nullptr); pStaging->Unmap(0, nullptr);

View File

@ -638,6 +638,10 @@ namespace
if (desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D) if (desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
UINT numberOfPlanes = D3D12GetFormatPlaneCount(device, desc.Format);
if (numberOfPlanes != 1)
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
D3D12_HEAP_PROPERTIES sourceHeapProperties; D3D12_HEAP_PROPERTIES sourceHeapProperties;
D3D12_HEAP_FLAGS sourceHeapFlags; D3D12_HEAP_FLAGS sourceHeapFlags;
HRESULT hr = pSource->GetHeapProperties(&sourceHeapProperties, &sourceHeapFlags); HRESULT hr = pSource->GetHeapProperties(&sourceHeapProperties, &sourceHeapFlags);