diff --git a/DDSTextureLoader/DDSTextureLoader12.cpp b/DDSTextureLoader/DDSTextureLoader12.cpp index 56ba6e4..a0fe613 100644 --- a/DDSTextureLoader/DDSTextureLoader12.cpp +++ b/DDSTextureLoader/DDSTextureLoader12.cpp @@ -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(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(res.pData) + res.RowPitch * height; + res.RowPitch = (res.RowPitch >> 1); + res.SlicePitch = res.RowPitch * height; + } + break; + } + } + + //-------------------------------------------------------------------------------------- HRESULT FillInitData(_In_ size_t width, _In_ size_t height, _In_ size_t depth, _In_ size_t mipCount, _In_ size_t arraySize, + _In_ size_t numberOfPlanes, _In_ DXGI_FORMAT format, _In_ size_t maxsize, _In_ size_t bitSize, @@ -832,9 +905,9 @@ namespace _Out_ size_t& theight, _Out_ size_t& tdepth, _Out_ size_t& skipMip, - _Out_writes_(mipCount*arraySize) D3D12_SUBRESOURCE_DATA* initData) + std::vector& initData) { - if (!bitData || !initData) + if (!bitData) { return E_POINTER; } @@ -849,70 +922,78 @@ namespace const uint8_t* pSrcBits = bitData; const uint8_t* pEndBits = bitData + bitSize; - size_t index = 0; - for (size_t j = 0; j < arraySize; j++) - { - size_t w = width; - size_t h = height; - size_t d = depth; - for (size_t i = 0; i < mipCount; i++) - { - GetSurfaceInfo(w, - h, - format, - &NumBytes, - &RowBytes, - nullptr - ); + initData.clear(); - if ((mipCount <= 1) || !maxsize || (w <= maxsize && h <= maxsize && d <= maxsize)) + for (size_t p = 0; p < numberOfPlanes; ++p) + { + for (size_t j = 0; j < arraySize; j++) + { + size_t w = width; + size_t h = height; + size_t d = depth; + for (size_t i = 0; i < mipCount; i++) { - if (!twidth) + GetSurfaceInfo(w, + h, + format, + &NumBytes, + &RowBytes, + nullptr + ); + + if ((mipCount <= 1) || !maxsize || (w <= maxsize && h <= maxsize && d <= maxsize)) { - twidth = w; - theight = h; - tdepth = d; + if (!twidth) + { + twidth = w; + theight = h; + tdepth = d; + } + + D3D12_SUBRESOURCE_DATA res = + { + reinterpret_cast(pSrcBits), + static_cast(RowBytes), + static_cast(NumBytes) + }; + + AdjustPlaneResource(format, h, p, res); + + initData.emplace_back(res); + } + else if (!j) + { + // Count number of skipped mipmaps (first item only) + ++skipMip; } - assert(index < mipCount * arraySize); - _Analysis_assume_(index < mipCount * arraySize); - initData[index].pData = reinterpret_cast(pSrcBits); - initData[index].RowPitch = RowBytes; - initData[index].SlicePitch = NumBytes; - ++index; - } - else if (!j) - { - // Count number of skipped mipmaps (first item only) - ++skipMip; - } + if (pSrcBits + (NumBytes*d) > pEndBits) + { + return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF); + } - if (pSrcBits + (NumBytes*d) > pEndBits) - { - return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF); - } + pSrcBits += NumBytes * d; - pSrcBits += NumBytes * d; - - w = w >> 1; - h = h >> 1; - d = d >> 1; - if (w == 0) - { - w = 1; - } - if (h == 0) - { - h = 1; - } - if (d == 0) - { - d = 1; + w = w >> 1; + h = h >> 1; + d = d >> 1; + if (w == 0) + { + w = 1; + } + if (h == 0) + { + h = 1; + } + if (d == 0) + { + d = 1; + } } } } - 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); } + 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) { *outIsCubeMap = isCubeMap; } // Create the texture - std::vector initData; - initData.resize(mipCount * arraySize); + size_t numberOfResources = (resDim == D3D12_RESOURCE_DIMENSION_TEXTURE3D) + ? 1 : arraySize; + numberOfResources *= mipCount; + numberOfResources *= numberOfPlanes; + + if (numberOfResources > D3D12_REQ_SUBRESOURCES) + return E_INVALIDARG; + + subresources.reserve(numberOfResources); size_t skipMip = 0; size_t twidth = 0; size_t theight = 0; size_t tdepth = 0; - hr = FillInitData(width, height, depth, mipCount, arraySize, format, maxsize, bitSize, bitData, - twidth, theight, tdepth, skipMip, &initData[0]); + hr = FillInitData(width, height, depth, mipCount, arraySize, + numberOfPlanes, format, + maxsize, bitSize, bitData, + twidth, theight, tdepth, skipMip, subresources); if (SUCCEEDED(hr)) { @@ -1179,12 +1279,16 @@ namespace if (FAILED(hr) && !maxsize && (mipCount > 1)) { + subresources.clear(); + maxsize = (resDim == D3D12_RESOURCE_DIMENSION_TEXTURE3D) ? D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION : D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; - hr = FillInitData(width, height, depth, mipCount, arraySize, format, maxsize, bitSize, bitData, - twidth, theight, tdepth, skipMip, &initData[0]); + hr = FillInitData(width, height, depth, mipCount, arraySize, + numberOfPlanes, format, + maxsize, bitSize, bitData, + twidth, theight, tdepth, skipMip, subresources); if (SUCCEEDED(hr)) { 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; diff --git a/DirectXTex/DirectXTex.h b/DirectXTex/DirectXTex.h index b7db2e9..76009fd 100644 --- a/DirectXTex/DirectXTex.h +++ b/DirectXTex/DirectXTex.h @@ -694,7 +694,8 @@ namespace DirectX _In_ D3D12_RESOURCE_FLAGS resFlags, _In_ bool forceSRGB, _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& subresources ); HRESULT __cdecl CaptureTexture( _In_ ID3D12CommandQueue* pCommandQueue, _In_ ID3D12Resource* pSource, _In_ bool isCubeMap, diff --git a/DirectXTex/DirectXTexD3D12.cpp b/DirectXTex/DirectXTexD3D12.cpp index f34d325..6584bc9 100644 --- a/DirectXTex/DirectXTexD3D12.cpp +++ b/DirectXTex/DirectXTexD3D12.cpp @@ -34,6 +34,52 @@ static_assert(TEX_DIMENSION_TEXTURE3D == D3D12_RESOURCE_DIMENSION_TEXTURE3D, "he namespace { + template void AdjustPlaneResource( + _In_ DXGI_FORMAT fmt, + _In_ size_t height, + _In_ size_t slicePlane, + _Inout_ T& res) + { + switch (static_cast(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( _In_ ID3D12GraphicsCommandList* commandList, _In_ ID3D12Resource* resource, @@ -64,6 +110,7 @@ namespace const D3D12_RESOURCE_DESC& desc, ComPtr& pStaging, std::unique_ptr& layoutBuff, + UINT& numberOfPlanes, UINT& numberOfResources, D3D12_RESOURCE_STATES beforeState, D3D12_RESOURCE_STATES afterState) @@ -71,16 +118,27 @@ namespace if (!pCommandQ || !pSource) 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_FLAGS sourceHeapFlags; HRESULT hr = pSource->GetHeapProperties(&sourceHeapProperties, &sourceHeapFlags); if (FAILED(hr)) return hr; - // TODO - planar? numberOfResources = (desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) ? 1 : desc.DepthOrArraySize; numberOfResources *= desc.MipLevels; + numberOfResources *= numberOfPlanes; + if (numberOfResources > D3D12_REQ_SUBRESOURCES) return E_UNEXPECTED; @@ -177,12 +235,15 @@ namespace if (!(formatInfo.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D)) return E_FAIL; - for (UINT item = 0; item < desc.DepthOrArraySize; ++item) + for (UINT plane = 0; plane < numberOfPlanes; ++plane) { - for (UINT level = 0; level < desc.MipLevels; ++level) + for (UINT item = 0; item < desc.DepthOrArraySize; ++item) { - UINT index = D3D12CalcSubresource(level, item, 0, desc.MipLevels, desc.DepthOrArraySize); - commandList->ResolveSubresource(pTemp.Get(), index, pSource, index, fmt); + for (UINT level = 0; level < desc.MipLevels; ++level) + { + UINT index = D3D12CalcSubresource(level, item, plane, desc.MipLevels, desc.DepthOrArraySize); + commandList->ResolveSubresource(pTemp.Get(), index, pSource, index, fmt); + } } } @@ -426,24 +487,36 @@ HRESULT DirectX::CreateTextureEx( _Use_decl_annotations_ HRESULT DirectX::PrepareUpload( + ID3D12Device* pDevice, const Image* srcImages, size_t nimages, const TexMetadata& metadata, std::vector& subresources) { - if (!srcImages || !nimages || !metadata.mipLevels || !metadata.arraySize) + if (!pDevice || !srcImages || !nimages || !metadata.mipLevels || !metadata.arraySize) 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) ? 1 : metadata.arraySize; numberOfResources *= metadata.mipLevels; + numberOfResources *= numberOfPlanes; + if (numberOfResources > D3D12_REQ_SUBRESOURCES) return E_INVALIDARG; + subresources.clear(); subresources.reserve(numberOfResources); - // TODO - Needs special handling for planar formats (planes treated are independant subresources in DX12) - // Fill out subresource array if (metadata.IsVolumemap()) { @@ -458,61 +531,13 @@ HRESULT DirectX::PrepareUpload( // Direct3D 12 doesn't support arrays of 3D textures return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); - size_t depth = metadata.depth; - - for (size_t level = 0; level < metadata.mipLevels; ++level) + for (size_t plane = 0; plane < numberOfPlanes; ++plane) { - size_t index = metadata.ComputeIndex(level, 0, 0); - if (index >= nimages) - return E_FAIL; + size_t depth = metadata.depth; - const Image& img = srcImages[index]; - - if (img.format != metadata.format) - return E_FAIL; - - if (!img.pixels) - return E_POINTER; - - // Verify pixels in image 1 .. (depth-1) are exactly image->slicePitch apart - // For 3D textures, this relies on all slices of the same miplevel being continous in memory - // (this is how ScratchImage lays them out), which is why we just give the 0th slice to Direct3D 11 - const uint8_t* pSlice = img.pixels + img.slicePitch; - for (size_t slice = 1; slice < depth; ++slice) - { - size_t tindex = metadata.ComputeIndex(level, 0, slice); - if (tindex >= nimages) - return E_FAIL; - - const Image& timg = srcImages[tindex]; - - if (!timg.pixels) - return E_POINTER; - - if (timg.pixels != pSlice - || timg.format != metadata.format - || timg.rowPitch != img.rowPitch - || timg.slicePitch != img.slicePitch) - return E_FAIL; - - pSlice = timg.pixels + img.slicePitch; - } - - D3D12_SUBRESOURCE_DATA sr = { img.pixels, static_cast(img.rowPitch), static_cast(img.slicePitch) }; - subresources.emplace_back(sr); - - if (depth > 1) - depth >>= 1; - } - } - else - { - //--- 1D or 2D texture case --------------------------------------------------- - for (size_t item = 0; item < metadata.arraySize; ++item) - { for (size_t level = 0; level < metadata.mipLevels; ++level) { - size_t index = metadata.ComputeIndex(level, item, 0); + size_t index = metadata.ComputeIndex(level, 0, 0); if (index >= nimages) return E_FAIL; @@ -524,13 +549,78 @@ HRESULT DirectX::PrepareUpload( if (!img.pixels) return E_POINTER; - D3D12_SUBRESOURCE_DATA sr = + // Verify pixels in image 1 .. (depth-1) are exactly image->slicePitch apart + // For 3D textures, this relies on all slices of the same miplevel being continous in memory + // (this is how ScratchImage lays them out), which is why we just give the 0th slice to Direct3D 11 + const uint8_t* pSlice = img.pixels + img.slicePitch; + for (size_t slice = 1; slice < depth; ++slice) + { + size_t tindex = metadata.ComputeIndex(level, 0, slice); + if (tindex >= nimages) + return E_FAIL; + + const Image& timg = srcImages[tindex]; + + if (!timg.pixels) + return E_POINTER; + + if (timg.pixels != pSlice + || timg.format != metadata.format + || timg.rowPitch != img.rowPitch + || timg.slicePitch != img.slicePitch) + return E_FAIL; + + pSlice = timg.pixels + img.slicePitch; + } + + D3D12_SUBRESOURCE_DATA res = { img.pixels, static_cast(img.rowPitch), static_cast(img.slicePitch) }; - subresources.emplace_back(sr); + + AdjustPlaneResource(metadata.format, img.height, plane, res); + + subresources.emplace_back(res); + + if (depth > 1) + depth >>= 1; + } + } + } + else + { + //--- 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 level = 0; level < metadata.mipLevels; ++level) + { + size_t index = metadata.ComputeIndex(level, item, 0); + if (index >= nimages) + return E_FAIL; + + const Image& img = srcImages[index]; + + if (img.format != metadata.format) + return E_FAIL; + + if (!img.pixels) + return E_POINTER; + + D3D12_SUBRESOURCE_DATA res = + { + img.pixels, + static_cast(img.rowPitch), + static_cast(img.slicePitch) + }; + + AdjustPlaneResource(metadata.format, img.height, plane, res); + + subresources.emplace_back(res); + } } } } @@ -561,20 +651,21 @@ HRESULT DirectX::CaptureTexture( ComPtr pStaging; std::unique_ptr layoutBuff; - UINT numberOfResources; + UINT numberOfPlanes, numberOfResources; HRESULT hr = Capture(device.Get(), pCommandQueue, pSource, desc, pStaging, layoutBuff, + numberOfPlanes, numberOfResources, beforeState, afterState); if (FAILED(hr)) return hr; - if (!layoutBuff || !numberOfResources) + if (!layoutBuff || !numberOfPlanes || !numberOfResources) return E_UNEXPECTED; auto pLayout = reinterpret_cast(layoutBuff.get()); @@ -663,54 +754,54 @@ HRESULT DirectX::CaptureTexture( depth = 1; } - for (UINT item = 0; item < arraySize; ++item) + for (UINT plane = 0; plane < numberOfPlanes; ++plane) { - UINT height = desc.Height; - - for (UINT level = 0; level < desc.MipLevels; ++level) + for (UINT item = 0; item < arraySize; ++item) { - UINT dindex = D3D12CalcSubresource(level, item, 0 /* TODO planes */, - desc.MipLevels, arraySize); - assert(dindex < numberOfResources); - - const Image* img = result.GetImage(level, item, 0); - if (!img) + for (UINT level = 0; level < desc.MipLevels; ++level) { - pStaging->Unmap(0, nullptr); - result.Release(); - return E_FAIL; + UINT dindex = D3D12CalcSubresource(level, item, plane, desc.MipLevels, arraySize); + assert(dindex < numberOfResources); + + const Image* img = result.GetImage(level, item, 0); + if (!img) + { + pStaging->Unmap(0, nullptr); + result.Release(); + return E_FAIL; + } + + if (!img->pixels) + { + pStaging->Unmap(0, nullptr); + result.Release(); + return E_POINTER; + } + + D3D12_MEMCPY_DEST destData = { img->pixels, img->rowPitch, img->slicePitch }; + + AdjustPlaneResource(img->format, img->height, plane, destData); + + D3D12_SUBRESOURCE_DATA srcData = + { + pData + pLayout[dindex].Offset, + static_cast(pLayout[dindex].Footprint.RowPitch), + static_cast(pLayout[dindex].Footprint.RowPitch * pNumRows[dindex]) + }; + + if (pRowSizesInBytes[dindex] > (SIZE_T)-1) + { + pStaging->Unmap(0, nullptr); + result.Release(); + return E_FAIL; + } + + MemcpySubresource(&destData, &srcData, + (SIZE_T)pRowSizesInBytes[dindex], + pNumRows[dindex], + pLayout[dindex].Footprint.Depth); } - - if (!img->pixels) - { - pStaging->Unmap(0, nullptr); - result.Release(); - return E_POINTER; - } - - D3D12_MEMCPY_DEST destData = { img->pixels, img->rowPitch, img->slicePitch }; - D3D12_SUBRESOURCE_DATA srcData = - { - pData + pLayout[dindex].Offset, - static_cast(pLayout[dindex].Footprint.RowPitch), - static_cast(pLayout[dindex].Footprint.RowPitch * pNumRows[dindex]) - }; - - if (pRowSizesInBytes[dindex] > (SIZE_T)-1) - { - pStaging->Unmap(0, nullptr); - result.Release(); - return E_FAIL; - } - - MemcpySubresource(&destData, &srcData, - (SIZE_T)pRowSizesInBytes[dindex], - pNumRows[dindex], - pLayout[dindex].Footprint.Depth); } - - if (height > 1) - height >>= 1; } pStaging->Unmap(0, nullptr); diff --git a/ScreenGrab/ScreenGrab12.cpp b/ScreenGrab/ScreenGrab12.cpp index 4b5dfef..bd833b5 100644 --- a/ScreenGrab/ScreenGrab12.cpp +++ b/ScreenGrab/ScreenGrab12.cpp @@ -638,6 +638,10 @@ namespace if (desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D) 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_FLAGS sourceHeapFlags; HRESULT hr = pSource->GetHeapProperties(&sourceHeapProperties, &sourceHeapFlags);