Fix DX12 Capture transition state handling for MSAA (#532)
Some checks failed
MSBuild / build (Debug, x86, 2022) (push) Has been cancelled
CTest (BVTs) / build (amd64, x64-Release, windows-2022) (push) Has been cancelled
CTest (BVTs) / build (amd64, x64-Release, windows-2019) (push) Has been cancelled
MSBuild / build (Debug, x86, 2019) (push) Has been cancelled
CodeQL / Analyze (C/C++) (push) Has been cancelled
CMake (Windows) / build (amd64, x64-Debug, windows-2019) (push) Has been cancelled
CMake (Windows) / build (amd64, x64-Debug, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64, x64-Debug-Clang, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64, x64-Release, windows-2019) (push) Has been cancelled
CMake (Windows) / build (amd64, x64-Release, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64, x64-Release-Clang, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64_arm64, arm64-Debug, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64_arm64, arm64-Release, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64_arm64, arm64ec-Debug, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64_arm64, arm64ec-Release, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64_x86, x86-Debug, windows-2019) (push) Has been cancelled
CMake (Windows) / build (amd64_x86, x86-Debug, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64_x86, x86-Debug-Clang, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64_x86, x86-Release, windows-2019) (push) Has been cancelled
CMake (Windows) / build (amd64_x86, x86-Release, windows-2022) (push) Has been cancelled
CMake (Windows) / build (amd64_x86, x86-Release-Clang, windows-2022) (push) Has been cancelled
MSBuild / build (Debug, ARM64, 2019) (push) Has been cancelled
MSBuild / build (Debug, ARM64, 2022) (push) Has been cancelled
MSBuild / build (Debug, x64, 2019) (push) Has been cancelled
MSBuild / build (Debug, x64, 2022) (push) Has been cancelled
MSBuild / build (Release, ARM64, 2019) (push) Has been cancelled
MSBuild / build (Release, ARM64, 2022) (push) Has been cancelled
MSBuild / build (Release, x64, 2019) (push) Has been cancelled
MSBuild / build (Release, x64, 2022) (push) Has been cancelled
MSBuild / build (Release, x86, 2019) (push) Has been cancelled
MSBuild / build (Release, x86, 2022) (push) Has been cancelled
Microsoft C++ Code Analysis / Analyze (push) Has been cancelled
CTest (Windows) / build (amd64, x64-Debug, windows-2019) (push) Has been cancelled
CTest (Windows) / build (amd64, x64-Debug, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64, x64-Debug-Clang, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64, x64-Release, windows-2019) (push) Has been cancelled
CTest (Windows) / build (amd64, x64-Release, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64, x64-Release-Clang, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64_arm64, arm64-Debug, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64_arm64, arm64-Release, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64_arm64, arm64ec-Debug, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64_arm64, arm64ec-Release, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64_x86, x86-Debug, windows-2019) (push) Has been cancelled
CTest (Windows) / build (amd64_x86, x86-Debug, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64_x86, x86-Debug-Clang, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64_x86, x86-Release, windows-2019) (push) Has been cancelled
CTest (Windows) / build (amd64_x86, x86-Release, windows-2022) (push) Has been cancelled
CTest (Windows) / build (amd64_x86, x86-Release-Clang, windows-2022) (push) Has been cancelled
CMake (Windows using VCPKG) / build (amd64, x64-Debug-Clang-VCPKG, windows-2022) (push) Has been cancelled
CMake (Windows using VCPKG) / build (amd64, x64-Debug-VCPKG, windows-2019) (push) Has been cancelled
CMake (Windows using VCPKG) / build (amd64, x64-Debug-VCPKG, windows-2022) (push) Has been cancelled
CMake (Windows using VCPKG) / build (amd64_arm64, arm64-Debug-VCPKG, windows-2022) (push) Has been cancelled
CMake (Windows using VCPKG) / build (amd64_x86, x86-Debug-VCPKG, windows-2022) (push) Has been cancelled
CMake (WSL) / build (x64-Debug-Linux, 10) (push) Has been cancelled
CMake (WSL) / build (x64-Debug-Linux, 11) (push) Has been cancelled
CMake (WSL) / build (x64-Debug-Linux, 12) (push) Has been cancelled
CMake (WSL) / build (x64-Release-Linux, 10) (push) Has been cancelled
CMake (WSL) / build (x64-Release-Linux, 11) (push) Has been cancelled
CMake (WSL) / build (x64-Release-Linux, 12) (push) Has been cancelled

This commit is contained in:
Chuck Walbourn 2024-10-14 15:49:44 -07:00 committed by GitHub
parent 1262c4b293
commit 09affb78aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 356 additions and 298 deletions

View File

@ -18,6 +18,7 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cstdint>
#include <memory> #include <memory>
#include <new> #include <new>
@ -53,6 +54,8 @@ using namespace DirectX;
// //
// See DDS.h in the 'Texconv' sample and the 'DirectXTex' library // See DDS.h in the 'Texconv' sample and the 'DirectXTex' library
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
namespace
{
#pragma pack(push,1) #pragma pack(push,1)
constexpr uint32_t DDS_MAGIC = 0x20534444; // "DDS " constexpr uint32_t DDS_MAGIC = 0x20534444; // "DDS "
@ -126,9 +129,15 @@ struct DDS_HEADER_DXT10
#pragma pack(pop) #pragma pack(pop)
static_assert(sizeof(DDS_PIXELFORMAT) == 32, "DDS pixel format size mismatch");
static_assert(sizeof(DDS_HEADER) == 124, "DDS Header size mismatch");
static_assert(sizeof(DDS_HEADER_DXT10) == 20, "DDS DX10 Extended Header size mismatch");
constexpr size_t DDS_MIN_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER);
constexpr size_t DDS_DX10_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10);
static_assert(DDS_DX10_HEADER_SIZE > DDS_MIN_HEADER_SIZE, "DDS DX10 Header should be larger than standard header");
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
namespace
{
struct handle_closer { void operator()(HANDLE h) noexcept { if (h) CloseHandle(h); } }; struct handle_closer { void operator()(HANDLE h) noexcept { if (h) CloseHandle(h); } };
using ScopedHandle = std::unique_ptr<void, handle_closer>; using ScopedHandle = std::unique_ptr<void, handle_closer>;
@ -168,7 +177,7 @@ namespace
return E_FAIL; return E_FAIL;
} }
if (ddsDataSize < (sizeof(uint32_t) + sizeof(DDS_HEADER))) if (ddsDataSize < DDS_MIN_HEADER_SIZE)
{ {
return E_FAIL; return E_FAIL;
} }
@ -195,7 +204,7 @@ namespace
(MAKEFOURCC('D', 'X', '1', '0') == hdr->ddspf.fourCC)) (MAKEFOURCC('D', 'X', '1', '0') == hdr->ddspf.fourCC))
{ {
// Must be long enough for both headers and magic value // Must be long enough for both headers and magic value
if (ddsDataSize < (sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10))) if (ddsDataSize < DDS_DX10_HEADER_SIZE)
{ {
return E_FAIL; return E_FAIL;
} }
@ -205,8 +214,7 @@ namespace
// setup the pointers in the process request // setup the pointers in the process request
*header = hdr; *header = hdr;
auto offset = sizeof(uint32_t) auto offset = DDS_MIN_HEADER_SIZE
+ sizeof(DDS_HEADER)
+ (bDXT10Header ? sizeof(DDS_HEADER_DXT10) : 0u); + (bDXT10Header ? sizeof(DDS_HEADER_DXT10) : 0u);
*bitData = ddsData + offset; *bitData = ddsData + offset;
*bitSize = ddsDataSize - offset; *bitSize = ddsDataSize - offset;
@ -264,7 +272,7 @@ namespace
} }
// Need at least enough data to fill the header and magic number to be a valid DDS // Need at least enough data to fill the header and magic number to be a valid DDS
if (fileInfo.EndOfFile.LowPart < (sizeof(uint32_t) + sizeof(DDS_HEADER))) if (fileInfo.EndOfFile.LowPart < DDS_MIN_HEADER_SIZE)
{ {
return E_FAIL; return E_FAIL;
} }
@ -319,7 +327,7 @@ namespace
(MAKEFOURCC('D', 'X', '1', '0') == hdr->ddspf.fourCC)) (MAKEFOURCC('D', 'X', '1', '0') == hdr->ddspf.fourCC))
{ {
// Must be long enough for both headers and magic value // Must be long enough for both headers and magic value
if (fileInfo.EndOfFile.LowPart < (sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10))) if (fileInfo.EndOfFile.LowPart < DDS_DX10_HEADER_SIZE)
{ {
ddsData.reset(); ddsData.reset();
return E_FAIL; return E_FAIL;
@ -330,7 +338,7 @@ namespace
// setup the pointers in the process request // setup the pointers in the process request
*header = hdr; *header = hdr;
auto offset = sizeof(uint32_t) + sizeof(DDS_HEADER) auto offset = DDS_MIN_HEADER_SIZE
+ (bDXT10Header ? sizeof(DDS_HEADER_DXT10) : 0u); + (bDXT10Header ? sizeof(DDS_HEADER_DXT10) : 0u);
*bitData = ddsData.get() + offset; *bitData = ddsData.get() + offset;
*bitSize = fileInfo.EndOfFile.LowPart - offset; *bitSize = fileInfo.EndOfFile.LowPart - offset;

View File

@ -18,6 +18,7 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cstdint>
#include <memory> #include <memory>
#include <new> #include <new>
@ -81,6 +82,8 @@ using namespace DirectX;
// //
// See DDS.h in the 'Texconv' sample and the 'DirectXTex' library // See DDS.h in the 'Texconv' sample and the 'DirectXTex' library
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
namespace
{
#pragma pack(push,1) #pragma pack(push,1)
constexpr uint32_t DDS_MAGIC = 0x20534444; // "DDS " constexpr uint32_t DDS_MAGIC = 0x20534444; // "DDS "
@ -154,9 +157,15 @@ struct DDS_HEADER_DXT10
#pragma pack(pop) #pragma pack(pop)
static_assert(sizeof(DDS_PIXELFORMAT) == 32, "DDS pixel format size mismatch");
static_assert(sizeof(DDS_HEADER) == 124, "DDS Header size mismatch");
static_assert(sizeof(DDS_HEADER_DXT10) == 20, "DDS DX10 Extended Header size mismatch");
constexpr size_t DDS_MIN_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER);
constexpr size_t DDS_DX10_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10);
static_assert(DDS_DX10_HEADER_SIZE > DDS_MIN_HEADER_SIZE, "DDS DX10 Header should be larger than standard header");
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
namespace
{
#ifdef _WIN32 #ifdef _WIN32
struct handle_closer { void operator()(HANDLE h) noexcept { if (h) CloseHandle(h); } }; struct handle_closer { void operator()(HANDLE h) noexcept { if (h) CloseHandle(h); } };
@ -214,7 +223,7 @@ namespace
return E_FAIL; return E_FAIL;
} }
if (ddsDataSize < (sizeof(uint32_t) + sizeof(DDS_HEADER))) if (ddsDataSize < DDS_MIN_HEADER_SIZE)
{ {
return E_FAIL; return E_FAIL;
} }
@ -241,7 +250,7 @@ namespace
(MAKEFOURCC('D', 'X', '1', '0') == hdr->ddspf.fourCC)) (MAKEFOURCC('D', 'X', '1', '0') == hdr->ddspf.fourCC))
{ {
// Must be long enough for both headers and magic value // Must be long enough for both headers and magic value
if (ddsDataSize < (sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10))) if (ddsDataSize < DDS_DX10_HEADER_SIZE)
{ {
return E_FAIL; return E_FAIL;
} }
@ -251,8 +260,7 @@ namespace
// setup the pointers in the process request // setup the pointers in the process request
*header = hdr; *header = hdr;
auto offset = sizeof(uint32_t) auto offset = DDS_MIN_HEADER_SIZE
+ sizeof(DDS_HEADER)
+ (bDXT10Header ? sizeof(DDS_HEADER_DXT10) : 0u); + (bDXT10Header ? sizeof(DDS_HEADER_DXT10) : 0u);
*bitData = ddsData + offset; *bitData = ddsData + offset;
*bitSize = ddsDataSize - offset; *bitSize = ddsDataSize - offset;
@ -302,7 +310,7 @@ namespace
} }
// Need at least enough data to fill the header and magic number to be a valid DDS // Need at least enough data to fill the header and magic number to be a valid DDS
if (fileInfo.EndOfFile.LowPart < (sizeof(uint32_t) + sizeof(DDS_HEADER))) if (fileInfo.EndOfFile.LowPart < DDS_MIN_HEADER_SIZE)
{ {
return E_FAIL; return E_FAIL;
} }
@ -345,7 +353,7 @@ namespace
return E_FAIL; return E_FAIL;
// Need at least enough data to fill the header and magic number to be a valid DDS // Need at least enough data to fill the header and magic number to be a valid DDS
if (fileLen < (sizeof(uint32_t) + sizeof(DDS_HEADER))) if (fileLen < DDS_MIN_HEADER_SIZE)
return E_FAIL; return E_FAIL;
ddsData.reset(new (std::nothrow) uint8_t[size_t(fileLen)]); ddsData.reset(new (std::nothrow) uint8_t[size_t(fileLen)]);
@ -395,7 +403,7 @@ namespace
(MAKEFOURCC('D', 'X', '1', '0') == hdr->ddspf.fourCC)) (MAKEFOURCC('D', 'X', '1', '0') == hdr->ddspf.fourCC))
{ {
// Must be long enough for both headers and magic value // Must be long enough for both headers and magic value
if (len < (sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10))) if (len < DDS_DX10_HEADER_SIZE)
{ {
ddsData.reset(); ddsData.reset();
return E_FAIL; return E_FAIL;
@ -406,7 +414,7 @@ namespace
// setup the pointers in the process request // setup the pointers in the process request
*header = hdr; *header = hdr;
auto offset = sizeof(uint32_t) + sizeof(DDS_HEADER) auto offset = DDS_MIN_HEADER_SIZE
+ (bDXT10Header ? sizeof(DDS_HEADER_DXT10) : 0u); + (bDXT10Header ? sizeof(DDS_HEADER_DXT10) : 0u);
*bitData = ddsData.get() + offset; *bitData = ddsData.get() + offset;
*bitSize = len - offset; *bitSize = len - offset;

View File

@ -20,6 +20,7 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cstdint>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <new> #include <new>
@ -57,6 +58,8 @@ using Microsoft::WRL::ComPtr;
// //
// See DDS.h in the 'Texconv' sample and the 'DirectXTex' library // See DDS.h in the 'Texconv' sample and the 'DirectXTex' library
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
namespace
{
#pragma pack(push,1) #pragma pack(push,1)
constexpr uint32_t DDS_MAGIC = 0x20534444; // "DDS " constexpr uint32_t DDS_MAGIC = 0x20534444; // "DDS "
@ -115,9 +118,12 @@ struct DDS_HEADER
#pragma pack(pop) #pragma pack(pop)
static_assert(sizeof(DDS_PIXELFORMAT) == 32, "DDS pixel format size mismatch");
static_assert(sizeof(DDS_HEADER) == 124, "DDS Header size mismatch");
constexpr size_t DDS_DX9_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER);
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
namespace
{
struct handle_closer { void operator()(HANDLE h) noexcept { if (h) CloseHandle(h); } }; struct handle_closer { void operator()(HANDLE h) noexcept { if (h) CloseHandle(h); } };
using ScopedHandle = std::unique_ptr<void, handle_closer>; using ScopedHandle = std::unique_ptr<void, handle_closer>;
@ -144,7 +150,7 @@ namespace
return E_FAIL; return E_FAIL;
} }
if (ddsDataSize < (sizeof(uint32_t) + sizeof(DDS_HEADER))) if (ddsDataSize < DDS_DX9_HEADER_SIZE)
{ {
return E_FAIL; return E_FAIL;
} }
@ -175,9 +181,8 @@ namespace
// setup the pointers in the process request // setup the pointers in the process request
*header = hdr; *header = hdr;
auto offset = sizeof(uint32_t) + sizeof(DDS_HEADER); *bitData = ddsData + DDS_DX9_HEADER_SIZE;
*bitData = ddsData + offset; *bitSize = ddsDataSize - DDS_DX9_HEADER_SIZE;
*bitSize = ddsDataSize - offset;
return S_OK; return S_OK;
} }
@ -234,7 +239,7 @@ namespace
} }
// Need at least enough data to fill the header and magic number to be a valid DDS // Need at least enough data to fill the header and magic number to be a valid DDS
if (fileInfo.EndOfFile.LowPart < (sizeof(uint32_t) + sizeof(DDS_HEADER))) if (fileInfo.EndOfFile.LowPart < DDS_DX9_HEADER_SIZE)
{ {
return E_FAIL; return E_FAIL;
} }
@ -294,9 +299,8 @@ namespace
// setup the pointers in the process request // setup the pointers in the process request
*header = hdr; *header = hdr;
auto offset = sizeof(uint32_t) + sizeof(DDS_HEADER); *bitData = ddsData.get() + DDS_DX9_HEADER_SIZE;
*bitData = ddsData.get() + offset; *bitSize = fileInfo.EndOfFile.LowPart - DDS_DX9_HEADER_SIZE;
*bitSize = fileInfo.EndOfFile.LowPart - offset;
return S_OK; return S_OK;
} }

View File

@ -217,8 +217,11 @@ namespace
bufferDesc.SampleDesc.Count = 1; bufferDesc.SampleDesc.Count = 1;
ComPtr<ID3D12Resource> copySource(pSource); ComPtr<ID3D12Resource> copySource(pSource);
D3D12_RESOURCE_STATES beforeStateSource = beforeState;
if (desc.SampleDesc.Count > 1) if (desc.SampleDesc.Count > 1)
{ {
TransitionResource(commandList.Get(), pSource, beforeState, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
// MSAA content must be resolved before being copied to a staging texture // MSAA content must be resolved before being copied to a staging texture
auto descCopy = desc; auto descCopy = desc;
descCopy.SampleDesc.Count = 1; descCopy.SampleDesc.Count = 1;
@ -230,7 +233,7 @@ namespace
&defaultHeapProperties, &defaultHeapProperties,
D3D12_HEAP_FLAG_NONE, D3D12_HEAP_FLAG_NONE,
&descCopy, &descCopy,
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_RESOLVE_DEST,
nullptr, nullptr,
IID_GRAPHICS_PPV_ARGS(pTemp.GetAddressOf())); IID_GRAPHICS_PPV_ARGS(pTemp.GetAddressOf()));
if (FAILED(hr)) if (FAILED(hr))
@ -267,6 +270,11 @@ namespace
} }
copySource = pTemp; copySource = pTemp;
beforeState = D3D12_RESOURCE_STATE_RESOLVE_DEST;
}
else
{
beforeStateSource = D3D12_RESOURCE_STATE_COPY_SOURCE;
} }
// Create a staging texture // Create a staging texture
@ -283,7 +291,7 @@ namespace
assert(*pStaging); assert(*pStaging);
// Transition the resource if necessary // Transition the resource if necessary
TransitionResource(commandList.Get(), pSource, beforeState, D3D12_RESOURCE_STATE_COPY_SOURCE); TransitionResource(commandList.Get(), copySource.Get(), beforeState, D3D12_RESOURCE_STATE_COPY_SOURCE);
// Get the copy target location // Get the copy target location
for (UINT j = 0; j < numberOfResources; ++j) for (UINT j = 0; j < numberOfResources; ++j)
@ -293,8 +301,8 @@ namespace
commandList->CopyTextureRegion(&copyDest, 0, 0, 0, &copySrc, nullptr); commandList->CopyTextureRegion(&copyDest, 0, 0, 0, &copySrc, nullptr);
} }
// Transition the resource to the next state // Transition the source resource to the next state
TransitionResource(commandList.Get(), pSource, D3D12_RESOURCE_STATE_COPY_SOURCE, afterState); TransitionResource(commandList.Get(), pSource, beforeStateSource, afterState);
hr = commandList->Close(); hr = commandList->Close();
if (FAILED(hr)) if (FAILED(hr))

View File

@ -26,6 +26,7 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <cstdint>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <new> #include <new>
@ -71,7 +72,7 @@ namespace
{ {
#pragma pack(push,1) #pragma pack(push,1)
#define DDS_MAGIC 0x20534444 // "DDS " constexpr uint32_t DDS_MAGIC = 0x20534444; // "DDS "
struct DDS_PIXELFORMAT struct DDS_PIXELFORMAT
{ {
@ -129,6 +130,14 @@ namespace
#pragma pack(pop) #pragma pack(pop)
static_assert(sizeof(DDS_PIXELFORMAT) == 32, "DDS pixel format size mismatch");
static_assert(sizeof(DDS_HEADER) == 124, "DDS Header size mismatch");
static_assert(sizeof(DDS_HEADER_DXT10) == 20, "DDS DX10 Extended Header size mismatch");
constexpr size_t DDS_MIN_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER);
constexpr size_t DDS_DX10_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10);
static_assert(DDS_DX10_HEADER_SIZE > DDS_MIN_HEADER_SIZE, "DDS DX10 Header should be larger than standard header");
const DDS_PIXELFORMAT DDSPF_DXT1 = const DDS_PIXELFORMAT DDSPF_DXT1 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 }; { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 };
@ -816,13 +825,12 @@ HRESULT DirectX::SaveDDSTextureToFile(
auto_delete_file delonfail(hFile.get()); auto_delete_file delonfail(hFile.get());
// Setup header // Setup header
constexpr size_t MAX_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10); uint8_t fileHeader[DDS_DX10_HEADER_SIZE] = {};
uint8_t fileHeader[MAX_HEADER_SIZE] = {};
*reinterpret_cast<uint32_t*>(&fileHeader[0]) = DDS_MAGIC; *reinterpret_cast<uint32_t*>(&fileHeader[0]) = DDS_MAGIC;
auto header = reinterpret_cast<DDS_HEADER*>(&fileHeader[0] + sizeof(uint32_t)); auto header = reinterpret_cast<DDS_HEADER*>(&fileHeader[0] + sizeof(uint32_t));
size_t headerSize = sizeof(uint32_t) + sizeof(DDS_HEADER); size_t headerSize = DDS_MIN_HEADER_SIZE;
header->size = sizeof(DDS_HEADER); header->size = sizeof(DDS_HEADER);
header->flags = DDS_HEADER_FLAGS_TEXTURE | DDS_HEADER_FLAGS_MIPMAP; header->flags = DDS_HEADER_FLAGS_TEXTURE | DDS_HEADER_FLAGS_MIPMAP;
header->height = desc.Height; header->height = desc.Height;
@ -879,7 +887,7 @@ HRESULT DirectX::SaveDDSTextureToFile(
memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_DX10, sizeof(DDS_PIXELFORMAT)); memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_DX10, sizeof(DDS_PIXELFORMAT));
headerSize += sizeof(DDS_HEADER_DXT10); headerSize += sizeof(DDS_HEADER_DXT10);
extHeader = reinterpret_cast<DDS_HEADER_DXT10*>(fileHeader + sizeof(uint32_t) + sizeof(DDS_HEADER)); extHeader = reinterpret_cast<DDS_HEADER_DXT10*>(fileHeader + DDS_MIN_HEADER_SIZE);
extHeader->dxgiFormat = desc.Format; extHeader->dxgiFormat = desc.Format;
extHeader->resourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE2D; extHeader->resourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE2D;
extHeader->arraySize = 1; extHeader->arraySize = 1;

View File

@ -26,6 +26,7 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <cstdint>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <new> #include <new>
@ -93,7 +94,7 @@ namespace
{ {
#pragma pack(push,1) #pragma pack(push,1)
#define DDS_MAGIC 0x20534444 // "DDS " constexpr uint32_t DDS_MAGIC = 0x20534444; // "DDS "
struct DDS_PIXELFORMAT struct DDS_PIXELFORMAT
{ {
@ -149,8 +150,16 @@ namespace
uint32_t reserved; uint32_t reserved;
}; };
static_assert(sizeof(DDS_PIXELFORMAT) == 32, "DDS pixel format size mismatch");
static_assert(sizeof(DDS_HEADER) == 124, "DDS Header size mismatch");
static_assert(sizeof(DDS_HEADER_DXT10) == 20, "DDS DX10 Extended Header size mismatch");
#pragma pack(pop) #pragma pack(pop)
constexpr size_t DDS_MIN_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER);
constexpr size_t DDS_DX10_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10);
static_assert(DDS_DX10_HEADER_SIZE > DDS_MIN_HEADER_SIZE, "DDS DX10 Header should be larger than standard header");
const DDS_PIXELFORMAT DDSPF_DXT1 = const DDS_PIXELFORMAT DDSPF_DXT1 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 }; { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 };
@ -755,8 +764,11 @@ namespace
bufferDesc.SampleDesc.Count = 1; bufferDesc.SampleDesc.Count = 1;
ComPtr<ID3D12Resource> copySource(pSource); ComPtr<ID3D12Resource> copySource(pSource);
D3D12_RESOURCE_STATES beforeStateSource = beforeState;
if (desc.SampleDesc.Count > 1) if (desc.SampleDesc.Count > 1)
{ {
TransitionResource(commandList.Get(), pSource, beforeState, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
// MSAA content must be resolved before being copied to a staging texture // MSAA content must be resolved before being copied to a staging texture
auto descCopy = desc; auto descCopy = desc;
descCopy.SampleDesc.Count = 1; descCopy.SampleDesc.Count = 1;
@ -768,7 +780,7 @@ namespace
&defaultHeapProperties, &defaultHeapProperties,
D3D12_HEAP_FLAG_NONE, D3D12_HEAP_FLAG_NONE,
&descCopy, &descCopy,
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_RESOLVE_DEST,
nullptr, nullptr,
IID_ID3D12Resource, IID_ID3D12Resource,
reinterpret_cast<void**>(pTemp.GetAddressOf())); reinterpret_cast<void**>(pTemp.GetAddressOf()));
@ -797,6 +809,11 @@ namespace
} }
copySource = pTemp; copySource = pTemp;
beforeState = D3D12_RESOURCE_STATE_RESOLVE_DEST;
}
else
{
beforeStateSource = D3D12_RESOURCE_STATE_COPY_SOURCE;
} }
// Create a staging texture // Create a staging texture
@ -815,7 +832,7 @@ namespace
assert(*pStaging); assert(*pStaging);
// Transition the resource if necessary // Transition the resource if necessary
TransitionResource(commandList.Get(), pSource, beforeState, D3D12_RESOURCE_STATE_COPY_SOURCE); TransitionResource(commandList.Get(), copySource.Get(), beforeState, D3D12_RESOURCE_STATE_COPY_SOURCE);
// Get the copy target location // Get the copy target location
D3D12_PLACED_SUBRESOURCE_FOOTPRINT bufferFootprint = {}; D3D12_PLACED_SUBRESOURCE_FOOTPRINT bufferFootprint = {};
@ -831,8 +848,8 @@ namespace
// Copy the texture // Copy the texture
commandList->CopyTextureRegion(&copyDest, 0, 0, 0, &copySrc, nullptr); commandList->CopyTextureRegion(&copyDest, 0, 0, 0, &copySrc, nullptr);
// Transition the resource to the next state // Transition the source resource to the next state
TransitionResource(commandList.Get(), pSource, D3D12_RESOURCE_STATE_COPY_SOURCE, afterState); TransitionResource(commandList.Get(), pSource, beforeStateSource, afterState);
hr = commandList->Close(); hr = commandList->Close();
if (FAILED(hr)) if (FAILED(hr))
@ -954,13 +971,12 @@ HRESULT DirectX::SaveDDSTextureToFile(
#endif #endif
// Setup header // Setup header
constexpr size_t MAX_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10); uint8_t fileHeader[DDS_DX10_HEADER_SIZE] = {};
uint8_t fileHeader[MAX_HEADER_SIZE] = {};
*reinterpret_cast<uint32_t*>(&fileHeader[0]) = DDS_MAGIC; *reinterpret_cast<uint32_t*>(&fileHeader[0]) = DDS_MAGIC;
auto header = reinterpret_cast<DDS_HEADER*>(&fileHeader[0] + sizeof(uint32_t)); auto header = reinterpret_cast<DDS_HEADER*>(&fileHeader[0] + sizeof(uint32_t));
size_t headerSize = sizeof(uint32_t) + sizeof(DDS_HEADER); size_t headerSize = DDS_MIN_HEADER_SIZE;
header->size = sizeof(DDS_HEADER); header->size = sizeof(DDS_HEADER);
header->flags = DDS_HEADER_FLAGS_TEXTURE | DDS_HEADER_FLAGS_MIPMAP; header->flags = DDS_HEADER_FLAGS_TEXTURE | DDS_HEADER_FLAGS_MIPMAP;
header->height = desc.Height; header->height = desc.Height;
@ -1017,7 +1033,7 @@ HRESULT DirectX::SaveDDSTextureToFile(
memcpy(&header->ddspf, &DDSPF_DX10, sizeof(DDS_PIXELFORMAT)); memcpy(&header->ddspf, &DDSPF_DX10, sizeof(DDS_PIXELFORMAT));
headerSize += sizeof(DDS_HEADER_DXT10); headerSize += sizeof(DDS_HEADER_DXT10);
extHeader = reinterpret_cast<DDS_HEADER_DXT10*>(fileHeader + sizeof(uint32_t) + sizeof(DDS_HEADER)); extHeader = reinterpret_cast<DDS_HEADER_DXT10*>(fileHeader + DDS_MIN_HEADER_SIZE);
extHeader->dxgiFormat = desc.Format; extHeader->dxgiFormat = desc.Format;
extHeader->resourceDimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; extHeader->resourceDimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
extHeader->arraySize = 1; extHeader->arraySize = 1;
@ -1422,7 +1438,9 @@ HRESULT DirectX::SaveWICTextureToFile(
else else
{ {
// No conversion required // No conversion required
hr = frame->WritePixels(desc.Height, static_cast<UINT>(dstRowPitch), static_cast<UINT>(imageSize), static_cast<BYTE*>(pMappedMemory)); hr = frame->WritePixels(desc.Height,
static_cast<UINT>(dstRowPitch), static_cast<UINT>(imageSize),
static_cast<BYTE*>(pMappedMemory));
} }
pStaging->Unmap(0, &writeRange); pStaging->Unmap(0, &writeRange);

View File

@ -20,6 +20,7 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <cstdint>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <new> #include <new>
@ -65,7 +66,7 @@ namespace
{ {
#pragma pack(push,1) #pragma pack(push,1)
#define DDS_MAGIC 0x20534444 // "DDS " constexpr uint32_t DDS_MAGIC = 0x20534444; // "DDS "
struct DDS_PIXELFORMAT struct DDS_PIXELFORMAT
{ {
@ -116,6 +117,11 @@ namespace
#pragma pack(pop) #pragma pack(pop)
static_assert(sizeof(DDS_PIXELFORMAT) == 32, "DDS pixel format size mismatch");
static_assert(sizeof(DDS_HEADER) == 124, "DDS Header size mismatch");
constexpr size_t DDS_DX9_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER);
const DDS_PIXELFORMAT DDSPF_DXT1 = const DDS_PIXELFORMAT DDSPF_DXT1 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 }; { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 };
@ -606,13 +612,11 @@ HRESULT DirectX::SaveDDSTextureToFile(
auto_delete_file delonfail(hFile.get()); auto_delete_file delonfail(hFile.get());
// Setup header // Setup header
constexpr size_t MAX_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER); uint8_t fileHeader[DDS_DX9_HEADER_SIZE] = {};
uint8_t fileHeader[MAX_HEADER_SIZE] = {};
*reinterpret_cast<uint32_t*>(&fileHeader[0]) = DDS_MAGIC; *reinterpret_cast<uint32_t*>(&fileHeader[0]) = DDS_MAGIC;
auto header = reinterpret_cast<DDS_HEADER*>(&fileHeader[0] + sizeof(uint32_t)); auto header = reinterpret_cast<DDS_HEADER*>(&fileHeader[0] + sizeof(uint32_t));
constexpr size_t headerSize = sizeof(uint32_t) + sizeof(DDS_HEADER);
header->size = sizeof(DDS_HEADER); header->size = sizeof(DDS_HEADER);
header->flags = DDS_HEADER_FLAGS_TEXTURE | DDS_HEADER_FLAGS_MIPMAP; header->flags = DDS_HEADER_FLAGS_TEXTURE | DDS_HEADER_FLAGS_MIPMAP;
header->height = desc.Height; header->height = desc.Height;
@ -726,10 +730,10 @@ HRESULT DirectX::SaveDDSTextureToFile(
// Write header & pixels // Write header & pixels
DWORD bytesWritten; DWORD bytesWritten;
if (!WriteFile(hFile.get(), fileHeader, static_cast<DWORD>(headerSize), &bytesWritten, nullptr)) if (!WriteFile(hFile.get(), fileHeader, static_cast<DWORD>(DDS_DX9_HEADER_SIZE), &bytesWritten, nullptr))
return HRESULT_FROM_WIN32(GetLastError()); return HRESULT_FROM_WIN32(GetLastError());
if (bytesWritten != headerSize) if (bytesWritten != DDS_DX9_HEADER_SIZE)
return E_FAIL; return E_FAIL;
if (!WriteFile(hFile.get(), pixels.get(), static_cast<DWORD>(slicePitch), &bytesWritten, nullptr)) if (!WriteFile(hFile.get(), pixels.get(), static_cast<DWORD>(slicePitch), &bytesWritten, nullptr))