diff --git a/.gitmodules b/.gitmodules
index 6565c10..40411be 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -14,11 +14,3 @@
path = thirdparty/Vulkan-Headers
url = https://github.com/KhronosGroup/Vulkan-Headers.git
branch = sdk-1.2.170
-[submodule "thirdparty/libpng"]
- path = thirdparty/libpng
- url = https://github.com/glennrp/libpng.git
- branch = libpng16
-[submodule "thirdparty/zlib-ng"]
- path = thirdparty/zlib-ng
- url = https://github.com/zlib-ng/zlib-ng.git
- branch = stable
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c868510..d8b4ca1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -47,26 +47,13 @@ if(RTXGI_BUILD_SAMPLES)
target_compile_definitions(tinygltf PUBLIC _CRT_SECURE_NO_WARNINGS) # suppress the sprintf CRT warnings
set_target_properties(tinygltf PROPERTIES FOLDER "Thirdparty/")
- # zlib-ng
- option(ZLIB_COMPAT "" ON)
- option(ZLIB_ENABLE_TESTS "" OFF)
- add_subdirectory(thirdparty/zlib-ng)
- set_target_properties(zlib PROPERTIES FOLDER "Thirdparty/")
-
- # libpng
- option(PNG_BUILD_ZLIB "" ON)
- option(PNG_STATIC "" ON)
- option(PNG_SHARED "" OFF)
- option(PNG_EXECUTABLES "" OFF)
- option(PNG_FRAMEWORK "" OFF)
- option(PNG_TESTS "" OFF)
- if(UNIX AND NOT APPLE)
- set(ZLIB_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/zlib-ng" "${CMAKE_BINARY_DIR}/thirdparty/zlib-ng")
- endif()
- set(ZLIB_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/thirdparty/zlib-ng" "${CMAKE_BINARY_DIR}/thirdparty/zlib-ng")
- add_subdirectory(thirdparty/libpng)
- set_target_properties(png_static genfiles PROPERTIES FOLDER "Thirdparty/libpng")
-
# Samples
add_subdirectory(samples)
+
+ # Set the default project. If D3D is an option, set it as default.
+ if(RTXGI_API_D3D12_ENABLE)
+ set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT TestHarness-D3D12)
+ elseif(NOT RTXGI_API_D3D12_ENABLE AND RTXGI_API_VULKAN_ENABLE)
+ set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT TestHarness-VK)
+ endif()
endif()
diff --git a/ChangeLog.md b/ChangeLog.md
index 78b4e50..86f55c5 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,26 @@
# RTXGI SDK Change Log
+## 1.2.12a
+
+### SDK
+- No changes
+
+### Test Harness
+Features and Improvements:
+- Uses stb (stb_image_write) for image saving and screenshot functionality (included with the tinygltf dependency)
+- Removes zlib-ng and libpng dependencies
+- Updates Windows DXC (packman) dependencies to version 1.6.2112 which includes ```dxil.dll```
+- Now using std::filesystem on Windows and Linux
+- CMake
+ - Adds option to select in CMake whether to use the DXC & DXIL binaries from Packman or an installed Win10 SDK (Windows only)
+ - Properly sets the default startup project for RTXGI.sln (it really works now!)
+ - Adds arguments to automatically set the available config ini files for the SmartCmdArgs extension
+ - Removes DirectXTK ```ScreenGrab[.h|.cpp]``` files
+
+Bug Fixes:
+- Fixes VK validation layer error related to the back buffer not being marked as a possible copy source
+- Fixes D3D12 and VK swapchain creation failures (causing a crash) when alt+tabbing or minimizing the application when in fullscreen mode
+
## 1.2.12
### SDK
diff --git a/packman/dependencies.xml b/packman/dependencies.xml
index 95ef49a..1f59b72 100644
--- a/packman/dependencies.xml
+++ b/packman/dependencies.xml
@@ -1,6 +1,7 @@
-
+
+
-
\ No newline at end of file
+
diff --git a/rtxgi-sdk/FindSDKs.cmake b/rtxgi-sdk/FindSDKs.cmake
index 2e5737c..58b2ddc 100644
--- a/rtxgi-sdk/FindSDKs.cmake
+++ b/rtxgi-sdk/FindSDKs.cmake
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
+# Copyright (c) 2019-2022, NVIDIA CORPORATION. All rights reserved.
#
# NVIDIA CORPORATION and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt
index a6658e0..efaa6b9 100644
--- a/samples/CMakeLists.txt
+++ b/samples/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
+# Copyright (c) 2019-2022, NVIDIA CORPORATION. All rights reserved.
#
# NVIDIA CORPORATION and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
diff --git a/samples/test-harness/.args b/samples/test-harness/.args
new file mode 100644
index 0000000..4b738de
--- /dev/null
+++ b/samples/test-harness/.args
@@ -0,0 +1,29 @@
+{
+ "FileVersion": 2,
+ "Items": [
+ {
+ "Command": "Scene Configs",
+ "Items": [
+ {
+ "Command": "../../../samples/test-harness/config/cornell.ini",
+ "DefaultChecked": true
+ },
+ {
+ "Command": "../../../samples/test-harness/config/furnace.ini"
+ },
+ {
+ "Command": "../../../samples/test-harness/config/multi-cornell.ini"
+ },
+ {
+ "Command": "../../../samples/test-harness/config/sponza.ini"
+ },
+ {
+ "Command": "../../../samples/test-harness/config/tunnel.ini"
+ },
+ {
+ "Command": "../../../samples/test-harness/config/two-rooms.ini"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/samples/test-harness/CMakeLists.txt b/samples/test-harness/CMakeLists.txt
index 3b31653..f956094 100644
--- a/samples/test-harness/CMakeLists.txt
+++ b/samples/test-harness/CMakeLists.txt
@@ -191,14 +191,6 @@ file(GLOB THIRD_PARTY_DIRECTXTEX_GPU_COMPRESS_SOURCE
"src/thirdparty/directxtex/BCDirectCompute.cpp"
)
-file(GLOB THIRD_PARTY_DIRECTXTK_INCLUDE
- "include/thirdparty/directxtk/ScreenGrab12.h"
-)
-
-file(GLOB THIRD_PARTY_DIRECTXTK_SOURCE
- "src/thirdparty/directxtk/ScreenGrab12.cpp"
-)
-
file(GLOB THIRD_PARTY_IMGUI_SOURCE
"../../thirdparty/imgui/imgui.cpp"
"../../thirdparty/imgui/imgui_demo.cpp"
@@ -235,6 +227,13 @@ option(RTXGISAMPLES_TEST_HARNESS_DDGI_DEBUG_BORDER_COPY_INDEXING "Enable a borde
# Setup the Test Harness options
function(SetupOptions ARG_TARGET_EXE)
+ if(WIN32)
+ # Setup the dxcompiler and dxil binary options
+ set(RTXGISAMPLES_DXC_BINARIES "Packman" CACHE STRING "The dxcompiler and dxil binaries to use")
+ set(RTXGISAMPLES_DXC_BINARIES "Win10 SDK" CACHE STRING "The dxcompiler and dxil binaries to use")
+ set_property(CACHE RTXGISAMPLES_DXC_BINARIES PROPERTY STRINGS "Packman" "Win10 SDK")
+ endif()
+
# Set GFX object naming
if(RTXGISAMPLES_GFX_NAME_OBJECTS)
target_compile_definitions(${ARG_TARGET_EXE} PRIVATE GFX_NAME_OBJECTS)
@@ -268,7 +267,6 @@ set(GLFW_INCLUDE "${ROOT_DIR}/thirdparty/glfw/include")
set(IMGUI_INCLUDE "${ROOT_DIR}/thirdparty/imgui")
set(IMGUI_BACKENDS_INCLUDE "${ROOT_DIR}/thirdparty/imgui/backends")
set(TINYGLTF_INCLUDE "${ROOT_DIR}/thirdparty/tinygltf")
-set(LIBPNG_INCLUDE "${ROOT_DIR}/thirdparty/libpng" "${CMAKE_BINARY_DIR}/thirdparty/libpng")
# ---- WINDOWS / D3D12 --------------------------------------------------------------------------------------
@@ -293,13 +291,12 @@ if(RTXGI_API_D3D12_ENABLE)
${THIRD_PARTY_DIRECTXTEX_SOURCE}
${THIRD_PARTY_DIRECTXTEX_GPU_COMPRESS_SOURCE}
${THIRD_PARTY_DIRECTXTK_INCLUDE}
- ${THIRD_PARTY_DIRECTXTK_SOURCE}
${THIRD_PARTY_IMGUI_SOURCE}
${THIRD_PARTY_IMGUI_D3D12_SOURCE}
)
# Add dependencies
- add_dependencies(${TARGET_EXE} glfw tinygltf png_static zlib)
+ add_dependencies(${TARGET_EXE} glfw tinygltf)
# Add the include directories
target_include_directories(${TARGET_EXE} PRIVATE
@@ -309,16 +306,16 @@ if(RTXGI_API_D3D12_ENABLE)
"include/thirdparty/directxtex"
"include/thirdparty/directxtk"
"include/thirdparty/dxc"
+ "include/thirdparty/stb"
${DIRECTXMATH_INCLUDE}
${GLFW_INCLUDE}
${IMGUI_INCLUDE}
${IMGUI_BACKENDS_INCLUDE}
${TINYGLTF_INCLUDE}
- ${LIBPNG_INCLUDE}
)
# Add statically linked libs
- target_link_libraries(${TARGET_EXE} RTXGI-D3D12 glfw png_static zlib d3d11 d3d12 dxgi)
+ target_link_libraries(${TARGET_EXE} RTXGI-D3D12 glfw d3d11 d3d12 dxgi)
# Add common compiler definitions for exposed Test Harness options
SetupOptions(${TARGET_EXE})
@@ -371,12 +368,12 @@ if(RTXGI_API_VULKAN_ENABLE)
"include/thirdparty"
"include/thirdparty/directxtex"
"include/thirdparty/dxc"
+ "include/thirdparty/stb"
${DIRECTXMATH_INCLUDE}
${GLFW_INCLUDE}
${IMGUI_INCLUDE}
${IMGUI_BACKENDS_INCLUDE}
${TINYGLTF_INCLUDE}
- ${LIBPNG_INCLUDE}
)
# Add VS filters
@@ -422,17 +419,17 @@ if(RTXGI_API_VULKAN_ENABLE)
"include/thirdparty/directxmath"
"include/thirdparty/directxtex"
"include/thirdparty/dxc"
+ "include/thirdparty/stb"
${GLFW_INCLUDE}
${IMGUI_INCLUDE}
${IMGUI_BACKENDS_INCLUDE}
${TINYGLTF_INCLUDE}
- ${LIBPNG_INCLUDE}
)
endif()
# Add dependencies
- add_dependencies(${TARGET_EXE} glfw tinygltf png_static zlib)
+ add_dependencies(${TARGET_EXE} glfw tinygltf)
# Add compiler definitions
target_compile_definitions(${TARGET_EXE} PUBLIC API_VULKAN)
@@ -446,7 +443,7 @@ if(RTXGI_API_VULKAN_ENABLE)
# Add statically linked libs
if(WIN32)
# Note: Even when targeting Vulkan, Windows uses D3D11 GPU-based texture compression with DirectXTex
- target_link_libraries(${TARGET_EXE} RTXGI-VK ${Vulkan_LIBRARY} glfw png_static zlib d3d11)
+ target_link_libraries(${TARGET_EXE} RTXGI-VK ${Vulkan_LIBRARY} glfw d3d11)
elseif(UNIX AND NOT APPLE)
# Note: UNIX can't use D3D11 GPU-based texture compression with DirectXTex
target_link_libraries(${TARGET_EXE} RTXGI-VK -lglfw -lvulkan -ldl -lpthread -lX11 -lXrandr -lXi -lstdc++fs)
@@ -462,7 +459,7 @@ if(RTXGI_API_VULKAN_ENABLE)
set_target_properties(${TARGET_EXE} PROPERTIES FOLDER "RTXGI Samples")
endif() # VULKAN_ENABLE
-if(WIN32)
+if(WIN32 AND MSVC)
# Add VS filters
source_group("Config" FILES ${TEST_HARNESS_CONFIG})
@@ -477,55 +474,62 @@ if(WIN32)
source_group("Source Files/Thirdparty/DirectXTex" FILES ${THIRD_PARTY_DIRECTXTEX_SOURCE} ${THIRD_PARTY_DIRECTXTEX_GPU_COMPRESS_SOURCE})
source_group("Source Files/Thirdparty/ImGui" FILES ${THIRD_PARTY_IMGUI_SOURCE} ${THIRD_PARTY_IMGUI_D3D12_SOURCE} ${THIRD_PARTY_IMGUI_VULKAN_SOURCE})
- # D3D12 only toolkit files
- if(RTXGI_API_D3D12_ENABLE)
- source_group("Header Files/Thirdparty/DirectXTK" FILES ${THIRD_PARTY_DIRECTXTK_INCLUDE})
- source_group("Source Files/Thirdparty/DirectXTK" FILES ${THIRD_PARTY_DIRECTXTK_SOURCE})
- endif()
+ # Set arguments for Visual Studio Smart Command Line Arguments extension
+ # https://github.com/MBulli/SmartCommandlineArgs
+ configure_file("${ROOT_DIR}/samples/test-harness/.args" "${CMAKE_BINARY_DIR}/samples/test-harness/TestHarness-D3D12.args.json" COPYONLY)
+ configure_file("${ROOT_DIR}/samples/test-harness/.args" "${CMAKE_BINARY_DIR}/samples/test-harness/TestHarness-VK.args.json" COPYONLY)
+endif() # WIN32 and MSVC
- # Set the default project. If D3D is an option, set it as default.
- if(RTXGI_API_D3D12_ENABLE)
- set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT TestHarness-D3D12)
- elseif(NOT RTXGI_API_D3D12_ENABLE AND RTXGI_API_VULKAN_ENABLE)
- set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT TestHarness-VK)
+# Set the dxc binaries location (Windows only)
+if(WIN32)
+ if(${RTXGISAMPLES_DXC_BINARIES} MATCHES "Packman")
+ set(DXC_BINARY ${ROOT_DIR}/dxc/bin/dxcompiler.dll)
+ set(DXIL_BINARY ${ROOT_DIR}/dxc/bin/dxil.dll)
+ elseif(${RTXGISAMPLES_DXC_BINARIES} MATCHES "Win10 SDK")
+ set(DXC_BINARY ${RTXGI_API_D3D12_DXIL_PATH}/dxcompiler.dll)
+ set(DXIL_BINARY ${RTXGI_API_D3D12_DXIL_PATH}/dxil.dll)
endif()
-
-endif() # WIN32
+endif()
if(WIN32 AND RTXGI_API_D3D12_ENABLE)
- # Copy required DLLs and logo images to the working directories
+ # Copy required DLLs next to the executable
+ add_custom_command( TARGET TestHarness-D3D12 POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DXIL_BINARY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/d3d12/$
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DXC_BINARY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/d3d12/$
+ )
+
+ # Copy logo image to the working directories
add_custom_command( TARGET TestHarness-D3D12 POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${RTXGI_API_D3D12_DXIL_PATH}/dxil.dll ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/d3d12/$
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ROOT_DIR}/dxc/bin/dxcompiler.dll ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/d3d12/$
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ROOT_DIR}/docs/nvidia.jpg ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/d3d12/$
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ROOT_DIR}/docs/nvidia.jpg ${CMAKE_BINARY_DIR}/samples/test-harness/
)
endif()
if(WIN32 AND RTXGI_API_VULKAN_ENABLE)
- # Copy required DLLs and logo images to the working directories
+ # Copy required DLLs next to the executable
+ add_custom_command( TARGET TestHarness-VK POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DXC_BINARY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/vulkan/$
+ )
+
+ # Copy logo image to the working directories
add_custom_command( TARGET TestHarness-VK POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ROOT_DIR}/dxc/bin/dxcompiler.dll ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/vulkan/$
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ROOT_DIR}/docs/nvidia.jpg ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/vulkan/$
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ROOT_DIR}/docs/nvidia.jpg ${CMAKE_BINARY_DIR}/samples/test-harness/
)
endif()
if(UNIX AND RTXGI_API_VULKAN_ENABLE)
- # Copy required shared libraries and logo images to the working directories
- if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")
+ if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64")
+ # Copy required shared libraries next to the executable
add_custom_command( TARGET TestHarness-VK POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ROOT_DIR}/dxc/lib/libdxcompiler.so ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/vulkan/$
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ROOT_DIR}/dxc/lib/libdxcompiler.so ${CMAKE_BINARY_DIR}/samples/test-harness
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ROOT_DIR}/docs/nvidia.jpg ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/vulkan/$
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ROOT_DIR}/docs/nvidia.jpg ${CMAKE_BINARY_DIR}/samples/test-harness
)
- elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64")
- add_custom_command( TARGET TestHarness-VK POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ROOT_DIR}/dxc/lib/libdxcompiler.so ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/vulkan/$
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ROOT_DIR}/dxc/lib/libdxcompiler.so ${CMAKE_BINARY_DIR}/samples/test-harness
+
+ # Copy logo image to the working directories
+ add_custom_command( TARGET TestHarness-VK POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ROOT_DIR}/docs/nvidia.jpg ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/vulkan/$
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ROOT_DIR}/docs/nvidia.jpg ${CMAKE_BINARY_DIR}/samples/test-harness
- )
+ )
endif()
endif()
diff --git a/samples/test-harness/include/Direct3D12.h b/samples/test-harness/include/Direct3D12.h
index 71cc58f..490fd15 100644
--- a/samples/test-harness/include/Direct3D12.h
+++ b/samples/test-harness/include/Direct3D12.h
@@ -25,6 +25,7 @@ namespace Graphics
{
static const D3D12_HEAP_PROPERTIES defaultHeapProps = { D3D12_HEAP_TYPE_DEFAULT, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_MEMORY_POOL_UNKNOWN, 0, 0 };
static const D3D12_HEAP_PROPERTIES uploadHeapProps = { D3D12_HEAP_TYPE_UPLOAD, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_MEMORY_POOL_UNKNOWN, 0, 0 };
+ static const D3D12_HEAP_PROPERTIES readbackHeapProps = { D3D12_HEAP_TYPE_READBACK, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_MEMORY_POOL_UNKNOWN, 0, 0 };
bool Check(HRESULT hr, std::string fileName, uint32_t lineNumber);
#define D3DCHECK(hr) if(!Check(hr, __FILE__, __LINE__)) { return false; }
@@ -40,6 +41,7 @@ namespace Graphics
{
DEFAULT = 0,
UPLOAD = 1,
+ READBACK = 2
};
struct BufferDesc
diff --git a/samples/test-harness/include/ImageCapture.h b/samples/test-harness/include/ImageCapture.h
index f36ff4c..a2158c2 100644
--- a/samples/test-harness/include/ImageCapture.h
+++ b/samples/test-harness/include/ImageCapture.h
@@ -12,9 +12,21 @@
#include
#include
+
+#if defined(_WIN32) || defined(WIN32)
+#include
+#include
#include
+#endif
namespace ImageCapture
{
- bool CapturePng(std::string file, uint32_t width, uint32_t height, std::vector& rows);
-}
\ No newline at end of file
+ const static uint32_t NumChannels = 4;
+ bool CapturePng(std::string file, uint32_t width, uint32_t height, const unsigned char* data);
+
+#if defined(_WIN32) || defined(WIN32)
+ IWICImagingFactory2* CreateWICImagingFactory();
+ HRESULT ConvertTextureResource(const D3D12_RESOURCE_DESC desc, UINT64 imageSize, UINT64 dstRowPitch, unsigned char* pMappedMemory, std::vector& converted);
+#endif
+
+}
diff --git a/samples/test-harness/include/thirdparty/directxtk/ScreenGrab12.h b/samples/test-harness/include/thirdparty/directxtk/ScreenGrab12.h
deleted file mode 100644
index c7864cf..0000000
--- a/samples/test-harness/include/thirdparty/directxtk/ScreenGrab12.h
+++ /dev/null
@@ -1,45 +0,0 @@
-//--------------------------------------------------------------------------------------
-// File: ScreenGrab12.h
-//
-// Function for capturing a 2D texture and saving it to a file (aka a 'screenshot'
-// when used on a Direct3D 12 Render Target).
-//
-// Note these functions are useful as a light-weight runtime screen grabber. For
-// full-featured texture capture, DDS writer, and texture processing pipeline,
-// see the 'Texconv' sample and the 'DirectXTex' library.
-//
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-//
-// http://go.microsoft.com/fwlink/?LinkId=248926
-// http://go.microsoft.com/fwlink/?LinkID=615561
-//--------------------------------------------------------------------------------------
-
-#pragma once
-
-#include
-
-#include
-#include
-#include
-
-
-namespace DirectX
-{
- HRESULT __cdecl SaveDDSTextureToFile(
- _In_ ID3D12CommandQueue* pCommandQueue,
- _In_ ID3D12Resource* pSource,
- _In_z_ const wchar_t* fileName,
- D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_RENDER_TARGET,
- D3D12_RESOURCE_STATES afterState = D3D12_RESOURCE_STATE_RENDER_TARGET);
-
- HRESULT __cdecl SaveWICTextureToFile(
- _In_ ID3D12CommandQueue* pCommandQ,
- _In_ ID3D12Resource* pSource,
- REFGUID guidContainerFormat,
- _In_z_ const wchar_t* fileName,
- D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_RENDER_TARGET,
- D3D12_RESOURCE_STATES afterState = D3D12_RESOURCE_STATE_RENDER_TARGET,
- _In_opt_ const GUID* targetFormat = nullptr,
- _In_opt_ std::function setCustomProps = nullptr);
-}
\ No newline at end of file
diff --git a/samples/test-harness/src/Benchmark.cpp b/samples/test-harness/src/Benchmark.cpp
index 9866004..3ddf416 100644
--- a/samples/test-harness/src/Benchmark.cpp
+++ b/samples/test-harness/src/Benchmark.cpp
@@ -11,15 +11,12 @@
#include "Benchmark.h"
#include
+
namespace Benchmark
{
void StartBenchmark(BenchmarkRun& benchmarkRun, Instrumentation::Performance& perf, Configs::Config& config, Graphics::Globals& gfx)
{
- #if defined(_WIN32) || defined(WIN32)
- CreateDirectory(config.scene.screenshotPath.c_str(), NULL);
- #elif __linux__
std::filesystem::create_directories(config.scene.screenshotPath.c_str());
- #endif
benchmarkRun.numFramesBenched = 0;
benchmarkRun.cpuTimingCsv.str("");
diff --git a/samples/test-harness/src/Direct3D12.cpp b/samples/test-harness/src/Direct3D12.cpp
index 0d60c30..a30d172 100644
--- a/samples/test-harness/src/Direct3D12.cpp
+++ b/samples/test-harness/src/Direct3D12.cpp
@@ -12,9 +12,6 @@
#include "UI.h"
#include "ImageCapture.h"
-#include
-#include
-
namespace Graphics
{
using namespace DirectX;
@@ -766,8 +763,8 @@ namespace Graphics
}
/**
- * Create the global (bindless) root signature.
- */
+ * Create the global (bindless) root signature.
+ */
bool CreateGlobalRootSignature(Globals& d3d, Resources& resources)
{
D3D12_DESCRIPTOR_RANGE ranges[9];
@@ -899,8 +896,8 @@ namespace Graphics
}
/**
- * Create the shared render targets.
- */
+ * Create the shared render targets.
+ */
bool CreateRenderTargets(Globals& d3d, Resources& resources)
{
// Create the GBufferA (R8G8B8A8_UNORM) texture resource
@@ -1030,8 +1027,8 @@ namespace Graphics
}
/**
- * Release core D3D12 resources.
- */
+ * Release core D3D12 resources.
+ */
void Cleanup(Globals& d3d)
{
// Leave fullscreen mode if necessary
@@ -1593,39 +1590,18 @@ namespace Graphics
// Debug Functions
//----------------------------------------------------------------------------------------------------------
- IWICImagingFactory2* _GetWIC()
- {
- static INIT_ONCE s_initOnce = INIT_ONCE_STATIC_INIT;
-
- IWICImagingFactory2* factory = nullptr;
- (void)InitOnceExecuteOnce(&s_initOnce,
- [](PINIT_ONCE, PVOID, PVOID* ifactory) -> BOOL
- {
- return SUCCEEDED(CoCreateInstance(
- CLSID_WICImagingFactory2,
- nullptr,
- CLSCTX_INPROC_SERVER,
- __uuidof(IWICImagingFactory2),
- ifactory)) ? TRUE : FALSE;
- }, nullptr, reinterpret_cast(&factory));
-
- return factory;
- }
-
/**
* Write an image to disk from the given D3D12 resource.
*/
bool WriteResourceToDisk(Globals& d3d, std::string file, ID3D12Resource* pResource, D3D12_RESOURCE_STATES state)
{
- CoInitialize(NULL);
- std::wstring filename = std::wstring(file.begin(), file.end());
- //if(FAILED(SaveWICTextureToFile(d3d.cmdQueue, pResource, GUID_ContainerFormatPng, filename.c_str(), state, state))) return false;
-
- // copied from SaveWICTextureToFile() from DirectXTK, but using libpng instead of WIC
+ // Get the resource descriptor
const D3D12_RESOURCE_DESC desc = pResource->GetDesc();
- UINT64 totalResourceSize = 0, fpRowPitch = 0;
+
+ // Get the row count, pitch, and size of the top mip level
+ UINT64 totalResourceSize = 0;
+ UINT64 fpRowPitch = 0;
UINT fpRowCount = 0;
- // Get the rowcount, pitch and size of the top mip
d3d.device->GetCopyableFootprints(
&desc,
0,
@@ -1635,31 +1611,28 @@ namespace Graphics
&fpRowCount,
&fpRowPitch,
&totalResourceSize);
+
// Round up the srcPitch to multiples of 256
UINT64 dstRowPitch = (fpRowPitch + 255) & ~0xFF;
- ID3D12Resource* pStaging = nullptr;
+ // Get the heap properties
D3D12_HEAP_PROPERTIES sourceHeapProperties = {};
D3D12_HEAP_FLAGS sourceHeapFlags = {};
- HRESULT hr = pResource->GetHeapProperties(&sourceHeapProperties, &sourceHeapFlags);
+ D3DCHECK(pResource->GetHeapProperties(&sourceHeapProperties, &sourceHeapFlags));
+
+ // Create a command allocator
ID3D12CommandAllocator* commandAlloc = nullptr;
- hr = d3d.device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAlloc));
+ D3DCHECK(d3d.device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAlloc)));
+
+ // Create a command list
ID3D12GraphicsCommandList* commandList = nullptr;
- hr = d3d.device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAlloc, nullptr, IID_PPV_ARGS(&commandList));
+ D3DCHECK(d3d.device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAlloc, nullptr, IID_PPV_ARGS(&commandList)));
+
+ // Create fence
ID3D12Fence* fence = nullptr;
- hr = d3d.device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
- D3D12_HEAP_PROPERTIES defaultHeapProperties = {}, readBackHeapProperties = {};
- defaultHeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
- defaultHeapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
- defaultHeapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
- defaultHeapProperties.CreationNodeMask = 1;
- defaultHeapProperties.VisibleNodeMask = 1;
- readBackHeapProperties.Type = D3D12_HEAP_TYPE_READBACK;
- readBackHeapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
- readBackHeapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
- readBackHeapProperties.CreationNodeMask = 1;
- readBackHeapProperties.VisibleNodeMask = 1;
- // Readback resources must be buffers
+ D3DCHECK(d3d.device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)));
+
+ // Describe the read-back buffer resource
D3D12_RESOURCE_DESC bufferDesc = {};
bufferDesc.Alignment = desc.Alignment;
bufferDesc.DepthOrArraySize = 1;
@@ -1672,26 +1645,29 @@ namespace Graphics
bufferDesc.MipLevels = 1;
bufferDesc.SampleDesc.Count = 1;
bufferDesc.SampleDesc.Quality = 0;
- // Create a staging texture
- hr = d3d.device->CreateCommittedResource(
- &readBackHeapProperties,
+
+ // Create a staging texture resource
+ ID3D12Resource* pStaging = nullptr;
+ D3DCHECK(d3d.device->CreateCommittedResource(
+ &readbackHeapProps,
D3D12_HEAP_FLAG_NONE,
&bufferDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
- IID_PPV_ARGS(&pStaging));
+ IID_PPV_ARGS(&pStaging)));
{
- D3D12_RESOURCE_BARRIER barrierDesc = {};
- barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
- barrierDesc.Transition.pResource = pResource;
- barrierDesc.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
- barrierDesc.Transition.StateBefore = state;
- barrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
- commandList->ResourceBarrier(1, &barrierDesc);
+ // Transition the staging texture resource to a copy source
+ D3D12_RESOURCE_BARRIER barrier = {};
+ barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+ barrier.Transition.pResource = pResource;
+ barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
+ barrier.Transition.StateBefore = state;
+ barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
+ commandList->ResourceBarrier(1, &barrier);
}
- // Get the copy target location
+ // Describe the copy footprint of the resource
D3D12_PLACED_SUBRESOURCE_FOOTPRINT bufferFootprint = {};
bufferFootprint.Footprint.Width = static_cast(desc.Width);
bufferFootprint.Footprint.Height = desc.Height;
@@ -1699,129 +1675,68 @@ namespace Graphics
bufferFootprint.Footprint.RowPitch = static_cast(dstRowPitch);
bufferFootprint.Footprint.Format = desc.Format;
- D3D12_TEXTURE_COPY_LOCATION copySrc = {}, copyDest = {};
+ // Describe the copy source resource
+ D3D12_TEXTURE_COPY_LOCATION copySrc = {};
copySrc.pResource = pResource;
copySrc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
copySrc.SubresourceIndex = 0;
+
+ // Describe the copy destination resource
+ D3D12_TEXTURE_COPY_LOCATION copyDest = {};
copyDest.pResource = pStaging;
copyDest.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
copyDest.PlacedFootprint = bufferFootprint;
- // Copy the texture
+ // Schedule the texture copy
commandList->CopyTextureRegion(©Dest, 0, 0, 0, ©Src, nullptr);
{
- D3D12_RESOURCE_BARRIER barrierDesc = {};
- barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
- barrierDesc.Transition.pResource = pResource;
- barrierDesc.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
- barrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;
- barrierDesc.Transition.StateAfter = state;
- commandList->ResourceBarrier(1, &barrierDesc);
+ // Transition the staging texture resource to the specified state
+ D3D12_RESOURCE_BARRIER barrier = {};
+ barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+ barrier.Transition.pResource = pResource;
+ barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
+ barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;
+ barrier.Transition.StateAfter = state;
+ commandList->ResourceBarrier(1, &barrier);
}
- hr = commandList->Close();
+ // Close the command list
+ D3DCHECK(commandList->Close());
// Execute the command list
d3d.cmdQueue->ExecuteCommandLists(1, reinterpret_cast(&commandList));
+
// Signal the fence
- hr = d3d.cmdQueue->Signal(fence, 1);
+ D3DCHECK(d3d.cmdQueue->Signal(fence, 1));
+
// Block until the copy is complete
while (fence->GetCompletedValue() < 1)
SwitchToThread();
+ // Map the staging texture resource
+ unsigned char* pData = nullptr;
UINT64 imageSize = dstRowPitch * fpRowCount;
- unsigned char* pMappedMemory = nullptr;
D3D12_RANGE readRange = { 0, static_cast(imageSize) };
- D3D12_RANGE writeRange = { 0, 0 };
- hr = pStaging->Map(0, &readRange, (void**)&pMappedMemory);
+ D3DCHECK(pStaging->Map(0, &readRange, (void**)&pData));
- // convert to RGBA8 UNORM using WIC
- std::vector converted(desc.Width * desc.Height * 4);
- {
- // Determine source format's WIC equivalent
- WICPixelFormatGUID pfGuid;
- bool sRGB = false;
- switch (desc.Format)
- {
- case DXGI_FORMAT_R32G32B32A32_FLOAT: pfGuid = GUID_WICPixelFormat128bppRGBAFloat; break;
- case DXGI_FORMAT_R16G16B16A16_FLOAT: pfGuid = GUID_WICPixelFormat64bppRGBAHalf; break;
- case DXGI_FORMAT_R16G16B16A16_UNORM: pfGuid = GUID_WICPixelFormat64bppRGBA; break;
- case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: pfGuid = GUID_WICPixelFormat32bppRGBA1010102XR; break;
- case DXGI_FORMAT_R10G10B10A2_UNORM: pfGuid = GUID_WICPixelFormat32bppRGBA1010102; break;
- case DXGI_FORMAT_B5G5R5A1_UNORM: pfGuid = GUID_WICPixelFormat16bppBGRA5551; break;
- case DXGI_FORMAT_B5G6R5_UNORM: pfGuid = GUID_WICPixelFormat16bppBGR565; break;
- case DXGI_FORMAT_R32_FLOAT: pfGuid = GUID_WICPixelFormat32bppGrayFloat; break;
- case DXGI_FORMAT_R16_FLOAT: pfGuid = GUID_WICPixelFormat16bppGrayHalf; break;
- case DXGI_FORMAT_R16_UNORM: pfGuid = GUID_WICPixelFormat16bppGray; break;
- case DXGI_FORMAT_R8_UNORM: pfGuid = GUID_WICPixelFormat8bppGray; break;
- case DXGI_FORMAT_A8_UNORM: pfGuid = GUID_WICPixelFormat8bppAlpha; break;
-
- case DXGI_FORMAT_R8G8B8A8_UNORM:
- pfGuid = GUID_WICPixelFormat32bppRGBA;
- break;
+ // Convert the resource to RGBA8 UNORM (using WIC)
+ std::vector converted(desc.Width * desc.Height * ImageCapture::NumChannels);
+ D3DCHECK(ImageCapture::ConvertTextureResource(desc, imageSize, dstRowPitch, pData, converted));
- case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
- pfGuid = GUID_WICPixelFormat32bppRGBA;
- sRGB = true;
- break;
+ // Write the resource to disk as a PNG file (using STB)
+ bool result = ImageCapture::CapturePng(file, static_cast(desc.Width), static_cast(desc.Height), converted.data());
- case DXGI_FORMAT_B8G8R8A8_UNORM:
- pfGuid = GUID_WICPixelFormat32bppBGRA;
- break;
+ // Unmap the staging texture
+ pStaging->Unmap(0, nullptr);
- case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
- pfGuid = GUID_WICPixelFormat32bppBGRA;
- sRGB = true;
- break;
+ // Clean up
+ SAFE_RELEASE(pStaging);
+ SAFE_RELEASE(fence);
+ SAFE_RELEASE(commandList);
+ SAFE_RELEASE(commandAlloc);
- case DXGI_FORMAT_B8G8R8X8_UNORM:
- pfGuid = GUID_WICPixelFormat32bppBGR;
- break;
-
- case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
- pfGuid = GUID_WICPixelFormat32bppBGR;
- sRGB = true;
- break;
-
- default:
- return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
- }
-
- IWICImagingFactory2* pWIC = _GetWIC();
- IWICBitmap* bitmap = nullptr;
- hr = pWIC->CreateBitmapFromMemory(static_cast(desc.Width), desc.Height, pfGuid,
- static_cast(dstRowPitch), static_cast(imageSize),
- static_cast(pMappedMemory), &bitmap);
-
- IWICFormatConverter* converter = nullptr;
- hr = pWIC->CreateFormatConverter(&converter);
- hr = converter->Initialize(bitmap, GUID_WICPixelFormat32bppRGBA, WICBitmapDitherTypeNone, nullptr, 0, WICBitmapPaletteTypeMedianCut);
-
- WICRect rect = { 0, 0, static_cast(desc.Width), static_cast(desc.Height) };
- converter->CopyPixels(&rect, static_cast(desc.Width * 4), static_cast(converted.size()), converted.data());
-
- converter->Release();
- bitmap->Release();
- }
-
- {
- // libpng wants pointers to each row
- std::vector rows(desc.Height, nullptr);
- for (uint32_t i = 0; i < desc.Height; i++)
- {
- rows[i] = &converted[desc.Width * 4 * i];
- }
- ImageCapture::CapturePng(file, static_cast(desc.Width), static_cast(desc.Height), rows);
- }
- pStaging->Unmap(0, &writeRange);
-
- pStaging->Release();
- fence->Release();
- commandList->Release();
- commandAlloc->Release();
-
- return true;
+ return result;
}
//----------------------------------------------------------------------------------------------------------
@@ -1881,8 +1796,8 @@ namespace Graphics
}
/**
- * Create a D3D12 root signature.
- */
+ * Create a D3D12 root signature.
+ */
ID3D12RootSignature* CreateRootSignature(Globals& d3d, const D3D12_ROOT_SIGNATURE_DESC& desc)
{
ID3DBlob* sig = nullptr;
@@ -1907,8 +1822,8 @@ namespace Graphics
}
/**
- * Create a buffer resource.
- */
+ * Create a buffer resource.
+ */
bool CreateBuffer(Globals& d3d, const BufferDesc& info, ID3D12Resource** ppResource)
{
// Describe the upload buffer resource
@@ -1942,8 +1857,8 @@ namespace Graphics
}
/**
- * Create a texture resource on the default heap.
- */
+ * Create a texture resource on the default heap.
+ */
bool CreateTexture(Globals& d3d, const TextureDesc& info, ID3D12Resource** resource)
{
// Describe the texture resource
@@ -2232,8 +2147,8 @@ namespace Graphics
}
/*
- * Initialize D3D12.
- */
+ * Initialize D3D12.
+ */
bool Initialize(const Configs::Config& config, Scenes::Scene& scene, Globals& d3d, Resources& resources, std::ofstream& log)
{
// Set config variables
@@ -2417,8 +2332,8 @@ namespace Graphics
}
/**
- * Reset the command list.
- */
+ * Reset the command list.
+ */
bool ResetCmdList(Globals& d3d)
{
// Reset the command allocator for the current frame
@@ -2431,8 +2346,8 @@ namespace Graphics
}
/**
- * Submit the command list.
- */
+ * Submit the command list.
+ */
bool SubmitCmdList(Globals& d3d)
{
// Close the command list
@@ -2446,8 +2361,8 @@ namespace Graphics
}
/**
- * Swap the back buffers.
- */
+ * Swap the back buffers.
+ */
bool Present(Globals& d3d)
{
HRESULT hr;
@@ -2458,8 +2373,8 @@ namespace Graphics
}
/*
- * Wait for pending GPU work to complete.
- */
+ * Wait for pending GPU work to complete.
+ */
bool WaitForGPU(Globals& d3d)
{
// Increment the fence value
@@ -2480,8 +2395,8 @@ namespace Graphics
}
/**
- * Prepare to render the next frame.
- */
+ * Prepare to render the next frame.
+ */
bool MoveToNextFrame(Globals& d3d)
{
// Set the frame index for the next frame
@@ -2537,8 +2452,8 @@ namespace Graphics
#endif
/**
- * Release D3D12 resources.
- */
+ * Release D3D12 resources.
+ */
void Cleanup(Globals& d3d, GlobalResources& resources)
{
Cleanup(resources);
@@ -2550,9 +2465,7 @@ namespace Graphics
*/
bool WriteBackBufferToDisk(Globals& d3d, std::string directory)
{
- CoInitialize(NULL);
- bool success = WriteResourceToDisk(d3d, directory + "/backbuffer.png", d3d.backBuffer[d3d.frameIndex], D3D12_RESOURCE_STATE_PRESENT);
- return success;
+ return WriteResourceToDisk(d3d, directory + "/backbuffer.png", d3d.backBuffer[d3d.frameIndex], D3D12_RESOURCE_STATE_PRESENT);
}
}
diff --git a/samples/test-harness/src/ImageCapture.cpp b/samples/test-harness/src/ImageCapture.cpp
index 4d20058..3cb5bbb 100644
--- a/samples/test-harness/src/ImageCapture.cpp
+++ b/samples/test-harness/src/ImageCapture.cpp
@@ -9,65 +9,133 @@
*/
#include "ImageCapture.h"
-#include
-#include
+#include "Common.h"
+
+#if defined(_WIN32) || defined(WIN32)
+#define STBI_MSC_SECURE_CRT
+#endif
+
+#define STB_IMAGE_WRITE_IMPLEMENTATION
+#include
namespace ImageCapture
{
+
/**
* Write image data to a PNG format file.
*/
- bool CapturePng(std::string file, uint32_t width, uint32_t height, std::vector& rows)
+ bool CapturePng(std::string file, uint32_t width, uint32_t height, const unsigned char* data)
+ {
+ int result = stbi_write_png(file.c_str(), width, height, NumChannels, data, width * NumChannels);
+ return result != 0;
+ }
+
+#if defined(_WIN32) || defined(WIN32)
+ /**
+ * Create a Windows Image Component (WIC) imaging factory.
+ */
+ IWICImagingFactory2* CreateWICImagingFactory()
+ {
+ static INIT_ONCE s_initOnce = INIT_ONCE_STATIC_INIT;
+
+ IWICImagingFactory2* factory = nullptr;
+ (void)InitOnceExecuteOnce(&s_initOnce,
+ [](PINIT_ONCE, PVOID, PVOID* ifactory) -> BOOL
+ {
+ return SUCCEEDED(CoCreateInstance(
+ CLSID_WICImagingFactory2,
+ nullptr,
+ CLSCTX_INPROC_SERVER,
+ __uuidof(IWICImagingFactory2),
+ ifactory)) ? TRUE : FALSE;
+ }, nullptr, reinterpret_cast(&factory));
+
+ return factory;
+ }
+
+ /**
+ * Convert the data format of a D3D resource using Windows Imaging Component (WIC).
+ */
+ HRESULT ConvertTextureResource(
+ const D3D12_RESOURCE_DESC desc,
+ UINT64 imageSize,
+ UINT64 dstRowPitch,
+ unsigned char* pMappedMemory,
+ std::vector& converted)
{
- #if (defined(_WIN32) || defined(WIN32))
- FILE* fp = nullptr;
- errno_t ferror = fopen_s(&fp, file.c_str(), "wb");
- if (ferror != 0) return false;
- #elif __linux__
- FILE* fp = fopen(file.c_str(), "wb");
- if (ferror != nullptr) return false;
- #endif
-
- png_structp pngWrite = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (!pngWrite) return false;
-
- png_infop pngInfo = png_create_info_struct(pngWrite);
- if (!pngInfo)
+ bool sRGB = false;
+ WICPixelFormatGUID pfGuid;
+
+ // Determine source format's WIC equivalent
+ switch (desc.Format)
{
- png_destroy_write_struct(&pngWrite, (png_infopp)nullptr);
- return false;
+ case DXGI_FORMAT_R32G32B32A32_FLOAT: pfGuid = GUID_WICPixelFormat128bppRGBAFloat; break;
+ case DXGI_FORMAT_R16G16B16A16_FLOAT: pfGuid = GUID_WICPixelFormat64bppRGBAHalf; break;
+ case DXGI_FORMAT_R16G16B16A16_UNORM: pfGuid = GUID_WICPixelFormat64bppRGBA; break;
+ case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: pfGuid = GUID_WICPixelFormat32bppRGBA1010102XR; break;
+ case DXGI_FORMAT_R10G10B10A2_UNORM: pfGuid = GUID_WICPixelFormat32bppRGBA1010102; break;
+ case DXGI_FORMAT_B5G5R5A1_UNORM: pfGuid = GUID_WICPixelFormat16bppBGRA5551; break;
+ case DXGI_FORMAT_B5G6R5_UNORM: pfGuid = GUID_WICPixelFormat16bppBGR565; break;
+ case DXGI_FORMAT_R32_FLOAT: pfGuid = GUID_WICPixelFormat32bppGrayFloat; break;
+ case DXGI_FORMAT_R16_FLOAT: pfGuid = GUID_WICPixelFormat16bppGrayHalf; break;
+ case DXGI_FORMAT_R16_UNORM: pfGuid = GUID_WICPixelFormat16bppGray; break;
+ case DXGI_FORMAT_R8_UNORM: pfGuid = GUID_WICPixelFormat8bppGray; break;
+ case DXGI_FORMAT_A8_UNORM: pfGuid = GUID_WICPixelFormat8bppAlpha; break;
+ case DXGI_FORMAT_R8G8B8A8_UNORM: pfGuid = GUID_WICPixelFormat32bppRGBA; break;
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: pfGuid = GUID_WICPixelFormat32bppRGBA; sRGB = true; break;
+ case DXGI_FORMAT_B8G8R8A8_UNORM: pfGuid = GUID_WICPixelFormat32bppBGRA; break;
+ case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: pfGuid = GUID_WICPixelFormat32bppBGRA; sRGB = true; break;
+ case DXGI_FORMAT_B8G8R8X8_UNORM: pfGuid = GUID_WICPixelFormat32bppBGR; break;
+ case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: pfGuid = GUID_WICPixelFormat32bppBGR; sRGB = true; break;
+ default:
+ return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
- if (setjmp(png_jmpbuf(pngWrite)))
+ // Create an imaging factory
+ IWICImagingFactory2* pWIC = CreateWICImagingFactory();
+
+ // Create a WIC bitmap from the D3D resource
+ IWICBitmap* bitmap = nullptr;
+ HRESULT hr = pWIC->CreateBitmapFromMemory(
+ static_cast(desc.Width),
+ static_cast(desc.Height),
+ pfGuid,
+ static_cast(dstRowPitch),
+ static_cast(imageSize),
+ static_cast(pMappedMemory),
+ &bitmap);
+
+ if(FAILED(hr)) return hr;
+
+ // Create the WIC converter
+ IWICFormatConverter* converter = nullptr;
+ hr = pWIC->CreateFormatConverter(&converter);
+ if(FAILED(hr))
{
- png_destroy_write_struct(&pngWrite, &pngInfo);
- fclose(fp);
- return false;
+ SAFE_RELEASE(bitmap);
+ return hr;
}
- png_init_io(pngWrite, fp);
- png_set_IHDR(
- pngWrite,
- pngInfo,
- width,
- height,
- 8,
- PNG_COLOR_TYPE_RGB,
- PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_DEFAULT,
- PNG_FILTER_TYPE_DEFAULT
- );
- png_write_info(pngWrite, pngInfo);
-
- // Removing the alpha channel for captured images
- // too bad if there's useful data there...
- png_set_filler(pngWrite, 0, PNG_FILLER_AFTER);
- png_write_image(pngWrite, rows.data());
- png_write_end(pngWrite, NULL);
- fclose(fp);
-
- png_destroy_write_struct(&pngWrite, &pngInfo);
-
- return true;
+ // Initialize the WIC converter
+ hr = converter->Initialize(bitmap, GUID_WICPixelFormat32bppRGBA, WICBitmapDitherTypeNone, nullptr, 0, WICBitmapPaletteTypeMedianCut);
+ if(FAILED(hr))
+ {
+ SAFE_RELEASE(converter);
+ SAFE_RELEASE(bitmap);
+ return hr;
+ }
+
+ // Convert the texels
+ WICRect rect = { 0, 0, static_cast(desc.Width), static_cast(desc.Height) };
+ hr = converter->CopyPixels(&rect, static_cast(desc.Width * 4), static_cast(converted.size()), converted.data());
+
+ // Clean up
+ SAFE_RELEASE(converter);
+ SAFE_RELEASE(bitmap);
+
+ return hr;
}
-}
\ No newline at end of file
+
+#endif
+
+}
diff --git a/samples/test-harness/src/Vulkan.cpp b/samples/test-harness/src/Vulkan.cpp
index 838a4f9..8d538a7 100644
--- a/samples/test-harness/src/Vulkan.cpp
+++ b/samples/test-harness/src/Vulkan.cpp
@@ -420,8 +420,8 @@ namespace Graphics
}
/**
- * Create the fences.
- */
+ * Create the fences.
+ */
bool CreateFences(Globals& vk)
{
VkFenceCreateInfo fenceCreateInfo = {};
@@ -476,7 +476,7 @@ namespace Graphics
surfaceCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : surfaceCapabilities.currentTransform;
// Get the swap chain's format and color space
- // TODO: Get rid of this and use B8G8R8A8Unorm and SrgbNonlinear?
+ // TODO: use B8G8R8A8Unorm and SrgbNonlinear?
if (!GetSwapChainFormatAndColorSpace(vk.physicalDevice, vk.surface, &vk.swapChainFormat, &vk.swapChainColorSpace)) return false;
// Describe the swap chain
@@ -500,9 +500,16 @@ namespace Graphics
if (surfaceCapabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
{
+ // Allow the back buffer to be a copy destination
swapchainCreateInfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
+ if (surfaceCapabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
+ {
+ // Allow the back buffer to be a copy source
+ swapchainCreateInfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+ }
+
// Create the swap chain
VKCHECK(vkCreateSwapchainKHR(vk.device, &swapchainCreateInfo, nullptr, &vk.swapChain));
#ifdef GFX_NAME_OBJECTS
@@ -558,8 +565,8 @@ namespace Graphics
}
/**
- * Create the render pass.
- */
+ * Create the render pass.
+ */
bool CreateRenderPass(Globals& vk)
{
// Describe the render pass
@@ -599,8 +606,8 @@ namespace Graphics
}
/**
- * Create the frame buffers.
- */
+ * Create the frame buffers.
+ */
bool CreateFrameBuffers(Globals& vk)
{
for (uint32_t bufferIndex = 0; bufferIndex < 2; bufferIndex++)
@@ -626,8 +633,8 @@ namespace Graphics
}
/**
- * Create the command pool.
- */
+ * Create the command pool.
+ */
bool CreateCommandPool(Globals& vk)
{
// Describe the command pool
@@ -645,8 +652,8 @@ namespace Graphics
}
/**
- * Create the command buffers.
- */
+ * Create the command buffers.
+ */
bool CreateCommandBuffers(Globals& vk)
{
uint32_t numCommandBuffers = 2;
@@ -780,8 +787,8 @@ namespace Graphics
}
/**
- * Create the samplers.
- */
+ * Create the samplers.
+ */
bool CreateSamplers(Globals& vk, Resources& resources)
{
// Describe a bilinear sampler
@@ -1360,8 +1367,8 @@ namespace Graphics
}
/**
- * Create the shared render targets.
- */
+ * Create the shared render targets.
+ */
bool CreateRenderTargets(Globals& vk, Resources& resources)
{
// Create the GBufferA (R8G8B8A8_UNORM) texture resource
@@ -1436,8 +1443,8 @@ namespace Graphics
}
/**
- * Release Vulkan resources.
- */
+ * Release Vulkan resources.
+ */
void Cleanup(VkDevice& device, Resources& resources)
{
// Buffers
@@ -1541,8 +1548,8 @@ namespace Graphics
}
/**
- * Release core Vulkan resources.
- */
+ * Release core Vulkan resources.
+ */
void Cleanup(Globals& vk)
{
uint32_t resourceIndex;
@@ -1930,8 +1937,8 @@ namespace Graphics
}
/**
- * Create the scene textures.
- */
+ * Create the scene textures.
+ */
bool CreateSceneTextures(Globals& vk, Resources &resources, const Scenes::Scene &scene, std::ofstream& log)
{
// Early out if there are no scene textures
@@ -1997,47 +2004,51 @@ namespace Graphics
*/
bool WriteResourceToDisk(Globals& vk, std::string file, VkImage image, uint32_t width, uint32_t height, VkFormat imageFormat, VkImageLayout originalLayout)
{
- VkCommandPool pool;
- VkCommandBuffer cmd;
+ bool result = false;
+ VkCommandPool commandPool = nullptr;
+ VkCommandBuffer commandBuffer = nullptr;
+ VkImage linearScreenshotImage = nullptr;
+ VkImage optimalScreenshotImage = nullptr;
+ VkDeviceMemory linearScreenshotImageMemory;
+ VkDeviceMemory optimalScreenshotImageMemory;
- // create custom command pool
+ // Create a command pool
{
VkCommandPoolCreateInfo commandPoolCreateInfo = {};
commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
commandPoolCreateInfo.queueFamilyIndex = vk.queueFamilyIndex;
commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
- VKCHECK(vkCreateCommandPool(vk.device, &commandPoolCreateInfo, nullptr, &pool));
-#ifdef GFX_NAME_OBJECTS
- SetObjectName(vk.device, reinterpret_cast(pool), "Image capture Command Pool", VK_OBJECT_TYPE_COMMAND_POOL);
-#endif
+ VKCHECK(vkCreateCommandPool(vk.device, &commandPoolCreateInfo, nullptr, &commandPool));
+ #ifdef GFX_NAME_OBJECTS
+ SetObjectName(vk.device, reinterpret_cast(commandPool), "Image Capture Command Pool", VK_OBJECT_TYPE_COMMAND_POOL);
+ #endif
}
- // create custom command buffer
+ // Create and begin the command buffer
{
uint32_t numCommandBuffers = 1;
VkCommandBufferAllocateInfo commandBufferAllocateInfo = {};
commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
commandBufferAllocateInfo.commandBufferCount = numCommandBuffers;
- commandBufferAllocateInfo.commandPool = pool;
+ commandBufferAllocateInfo.commandPool = commandPool;
commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- VKCHECK(vkAllocateCommandBuffers(vk.device, &commandBufferAllocateInfo, &cmd));
+ VKCHECK(vkAllocateCommandBuffers(vk.device, &commandBufferAllocateInfo, &commandBuffer));
+ #ifdef GFX_NAME_OBJECTS
+ SetObjectName(vk.device, reinterpret_cast(commandBuffer), "Image capture Command Buffer", VK_OBJECT_TYPE_COMMAND_BUFFER);
+ #endif
-#ifdef GFX_NAME_OBJECTS
- SetObjectName(vk.device, reinterpret_cast(cmd), "Image capture Command Buffer", VK_OBJECT_TYPE_COMMAND_BUFFER);
-#endif
+ // Begin the command buffer
VkCommandBufferBeginInfo commandBufferBeginInfo = {};
commandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- VKCHECK(vkBeginCommandBuffer(cmd, &commandBufferBeginInfo));
+ VKCHECK(vkBeginCommandBuffer(commandBuffer, &commandBufferBeginInfo));
}
- // using vr_sli_vk demo for reference
- VkImage linearScreenshotImage, optimalScreenshotImage;
- VkDeviceMemory linearScreenshotImageMemory, optimalScreenshotImageMemory;
+ // Create intermediate texture resources
{
- // same as CreateTexture() but don't create a view
+ // Describe the image
VkImageCreateInfo imageCreateInfo = {};
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
@@ -2053,26 +2064,35 @@ namespace Graphics
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ // Create the image (linear layout)
VKCHECK(vkCreateImage(vk.device, &imageCreateInfo, nullptr, &linearScreenshotImage));
+
+ // Create the image (optimal tiling)
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VKCHECK(vkCreateImage(vk.device, &imageCreateInfo, nullptr, &optimalScreenshotImage));
+ // Get the memory requirements for the linear image
AllocateMemoryDesc desc = {};
vkGetImageMemoryRequirements(vk.device, linearScreenshotImage, &desc.requirements);
desc.properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
desc.flags = 0;
+ // Allocate and bind the memory for the linear image
if (!AllocateMemory(vk, desc, &linearScreenshotImageMemory)) return false;
VKCHECK(vkBindImageMemory(vk.device, linearScreenshotImage, linearScreenshotImageMemory, 0));
+ // Get the memory requirements for the optimal tiled image
vkGetImageMemoryRequirements(vk.device, optimalScreenshotImage, &desc.requirements);
desc.properties = 0;
desc.flags = 0;
+
+ // Allocate and bind the memory for the optimal tiled image
if (!AllocateMemory(vk, desc, &optimalScreenshotImageMemory)) return false;
VKCHECK(vkBindImageMemory(vk.device, optimalScreenshotImage, optimalScreenshotImageMemory, 0));
}
+ // Barriers
{
ImageBarrierDesc barrier =
{
@@ -2082,15 +2102,19 @@ namespace Graphics
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
};
- SetImageMemoryBarrier(cmd, linearScreenshotImage, barrier);
- SetImageMemoryBarrier(cmd, optimalScreenshotImage, barrier);
+
+ // Transition the intermediate images to copy destinations
+ SetImageMemoryBarrier(commandBuffer, linearScreenshotImage, barrier);
+ SetImageMemoryBarrier(commandBuffer, optimalScreenshotImage, barrier);
+
+ // Transition the source image to a copy source
barrier.oldLayout = originalLayout;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
- SetImageMemoryBarrier(cmd, image, barrier);
+ SetImageMemoryBarrier(commandBuffer, image, barrier);
}
+ // Copy the source image to the optimal tiled image
{
- // blit image (format conversion if necessary)
VkImageBlit region = {};
VkImageSubresourceLayers subres = {};
subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@@ -2103,9 +2127,17 @@ namespace Graphics
region.srcOffsets[1] = { (int32_t) width, (int32_t) height, 1 };
region.dstOffsets[0] = {};
region.dstOffsets[1] = { (int32_t) width, (int32_t) height, 1 };
- vkCmdBlitImage(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, optimalScreenshotImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion, VK_FILTER_NEAREST);
+
+ vkCmdBlitImage(
+ commandBuffer,
+ image,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ optimalScreenshotImage,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ 1, ®ion, VK_FILTER_NEAREST);
}
+ // Barriers
{
ImageBarrierDesc barrier =
{
@@ -2115,19 +2147,24 @@ namespace Graphics
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
};
- SetImageMemoryBarrier(cmd, optimalScreenshotImage, barrier);
+
+ // Transition the optimal tiled image to a copy source
+ SetImageMemoryBarrier(commandBuffer, optimalScreenshotImage, barrier);
+
+ // Transition the source image to a copy source
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.newLayout = originalLayout;
- SetImageMemoryBarrier(cmd, image, barrier);
+ SetImageMemoryBarrier(commandBuffer, image, barrier);
}
+ // Copy optimal tiled image to linear image (for CPU copy)
{
- // copy to linear tiling image for CPU copy
VkImageSubresourceLayers subResource = {};
subResource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subResource.baseArrayLayer = 0;
subResource.mipLevel = 0;
subResource.layerCount = 1;
+
VkImageCopy region = {};
region.srcSubresource = subResource;
region.dstSubresource = subResource;
@@ -2136,16 +2173,17 @@ namespace Graphics
region.extent.width = width;
region.extent.height = height;
region.extent.depth = 1;
+
vkCmdCopyImage(
- cmd,
+ commandBuffer,
optimalScreenshotImage,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
linearScreenshotImage,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- 1, ®ion
- );
+ 1, ®ion);
}
+ // Transition the linear image to general read
{
ImageBarrierDesc barrier =
{
@@ -2155,17 +2193,17 @@ namespace Graphics
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
};
- SetImageMemoryBarrier(cmd, linearScreenshotImage, barrier);
+ SetImageMemoryBarrier(commandBuffer, linearScreenshotImage, barrier);
}
+ // Execute GPU work
{
- // Execute GPU work to finish initialization
- VKCHECK(vkEndCommandBuffer(cmd));
+ VKCHECK(vkEndCommandBuffer(commandBuffer));
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &cmd;
+ submitInfo.pCommandBuffers = &commandBuffer;
VKCHECK(vkQueueSubmit(vk.queue, 1, &submitInfo, VK_NULL_HANDLE));
VKCHECK(vkQueueWaitIdle(vk.queue));
@@ -2173,45 +2211,39 @@ namespace Graphics
WaitForGPU(vk);
}
- // copy screenshot image to cpu-side memory
+ // Copy the linear image to CPU memory
{
- unsigned char* rawData = nullptr;
-
VkImageSubresource subResource{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 };
VkSubresourceLayout subResourceLayout;
vkGetImageSubresourceLayout(vk.device, linearScreenshotImage, &subResource, &subResourceLayout);
- VkResult result = vkMapMemory(vk.device, linearScreenshotImageMemory, 0, VK_WHOLE_SIZE, 0, (void**)&rawData);
- if (result != VK_SUCCESS)
- {
- return false;
- }
+ // Map the linear image memory
+ unsigned char* pData = nullptr;
+ VKCHECK(vkMapMemory(vk.device, linearScreenshotImageMemory, 0, VK_WHOLE_SIZE, 0, (void**)&pData));
- // libpng wants pointers to each row
- std::vector rows(height, nullptr);
- for (uint32_t i = 0; i < height; i++)
- {
- rows[i] = rawData + i * subResourceLayout.rowPitch;
- }
+ // Copy linear image to CPU memory
+ std::vector converted(width * height * ImageCapture::NumChannels);
+ memcpy(converted.data(), pData, converted.size());
- // output the image file to disk
- ImageCapture::CapturePng(file, width, height, rows);
+ // Write the resource to disk as a PNG file (using STB)
+ result = ImageCapture::CapturePng(file, width, height, converted.data());
+ // Unmap the linear image memory
vkUnmapMemory(vk.device, linearScreenshotImageMemory);
}
+ // Clean up
{
- // tear-down screenshot images
vkFreeMemory(vk.device, linearScreenshotImageMemory, nullptr);
vkDestroyImage(vk.device, linearScreenshotImage, nullptr);
vkFreeMemory(vk.device, optimalScreenshotImageMemory, nullptr);
vkDestroyImage(vk.device, optimalScreenshotImage, nullptr);
- // tear-down temporary command list and pool
- vkFreeCommandBuffers(vk.device, pool, 1, &cmd);
- vkDestroyCommandPool(vk.device, pool, nullptr);
+
+ vkFreeCommandBuffers(vk.device, commandPool, 1, &commandBuffer);
+ vkDestroyCommandPool(vk.device, commandPool, nullptr);
}
- return true;
+ return result;
}
#ifdef GFX_NAME_OBJECTS
@@ -2844,7 +2876,7 @@ namespace Graphics
vkCmdBeginRenderPass(vk.cmdBuffer[vk.frameIndex], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
}
- /*
+ /**
* Initialize Vulkan.
*/
bool Initialize(const Configs::Config& config, Scenes::Scene& scene, Globals& vk, Resources& resources, std::ofstream& log)
@@ -3007,6 +3039,9 @@ namespace Graphics
vk.scissor.extent.width = vk.width;
vk.scissor.extent.height = vk.height;
+ // Wait for the GPU to finish up any work
+ VKCHECK(vkDeviceWaitIdle(vk.device));
+
// Release the swapchain and associated resources
CleanupSwapchain(vk);
@@ -3081,8 +3116,8 @@ namespace Graphics
}
/**
- * Reset the command list.
- */
+ * Reset the command list.
+ */
bool ResetCmdList(Globals& vk)
{
// Start the command buffer for the next frame
@@ -3093,8 +3128,8 @@ namespace Graphics
}
/**
- * Submit the command list.
- */
+ * Submit the command list.
+ */
bool SubmitCmdList(Globals& vk)
{
// Close the command buffer
@@ -3119,8 +3154,8 @@ namespace Graphics
}
/**
- * Swap the back buffers.
- */
+ * Swap the back buffers.
+ */
bool Present(Globals& vk)
{
// Present
@@ -3143,16 +3178,16 @@ namespace Graphics
}
/*
- * Wait for pending GPU work to complete.
- */
+ * Wait for pending GPU work to complete.
+ */
bool WaitForGPU(Globals& vk)
{
return (vkDeviceWaitIdle(vk.device) == VK_SUCCESS);
}
/**
- * Prepare to render the next frame.
- */
+ * Prepare to render the next frame.
+ */
bool MoveToNextFrame(Globals& vk)
{
if (vk.vsyncChanged)
@@ -3261,9 +3296,6 @@ namespace Graphics
*/
bool WriteBackBufferToDisk(Globals& vk, std::string directory)
{
- #if (defined(_WIN32) || defined(WIN32))
- CoInitialize(NULL);
- #endif
return WriteResourceToDisk(vk, directory + "/backbuffer.png", vk.swapChainImage[vk.frameIndex], vk.width, vk.height, vk.swapChainFormat, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
}
diff --git a/samples/test-harness/src/main.cpp b/samples/test-harness/src/main.cpp
index 5ceddb1..0b28d22 100644
--- a/samples/test-harness/src/main.cpp
+++ b/samples/test-harness/src/main.cpp
@@ -35,11 +35,7 @@ void WriteImages(
Graphics::RTAO::Resources& rtao,
Graphics::DDGI::Resources& ddgi)
{
-#if defined(_WIN32) || defined(WIN32)
- CreateDirectory(config.scene.screenshotPath.c_str(), NULL);
-#elif __linux__
std::filesystem::create_directories(config.scene.screenshotPath.c_str());
-#endif
Graphics::WriteBackBufferToDisk(gfx, config.scene.screenshotPath);
Graphics::GBuffer::WriteGBufferToDisk(gfx, gfxResources, config.scene.screenshotPath);
@@ -210,6 +206,13 @@ int Run(const std::vector& arguments)
int width, height;
glfwGetFramebufferSize(gfx.window, &width, &height);
+ // Wait for the window to have valid dimensions
+ while(width == 0 || height == 0)
+ {
+ glfwGetFramebufferSize(gfx.window, &width, &height);
+ glfwWaitEvents();
+ }
+
// Resize all screen-space buffers
if (!Graphics::Resize(gfx, gfxResources, width, height, log)) break; // Back buffers and GBuffer textures
if (!Graphics::PathTracing::Resize(gfx, gfxResources, pt, log)) break; // PT Output and Accumulation
diff --git a/samples/test-harness/src/thirdparty/directxtk/ScreenGrab12.cpp b/samples/test-harness/src/thirdparty/directxtk/ScreenGrab12.cpp
deleted file mode 100644
index 4faffd2..0000000
--- a/samples/test-harness/src/thirdparty/directxtk/ScreenGrab12.cpp
+++ /dev/null
@@ -1,1356 +0,0 @@
-//--------------------------------------------------------------------------------------
-// File: ScreenGrab12.cpp
-//
-// Function for capturing a 2D texture and saving it to a file (aka a 'screenshot'
-// when used on a Direct3D 12 Render Target).
-//
-// Note these functions are useful as a light-weight runtime screen grabber. For
-// full-featured texture capture, DDS writer, and texture processing pipeline,
-// see the 'Texconv' sample and the 'DirectXTex' library.
-//
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-//
-// http://go.microsoft.com/fwlink/?LinkId=248926
-// http://go.microsoft.com/fwlink/?LinkID=615561
-//--------------------------------------------------------------------------------------
-
-// Does not capture 1D textures or 3D textures (volume maps)
-
-// Does not capture mipmap chains, only the top-most texture level is saved
-
-// For 2D array textures and cubemaps, it captures only the first image in the array
-
-#include "ScreenGrab12.h"
-
-#include
-#include
-#include
-
-#include
-
-#include
-
-#include "d3dx12.h"
-
-using Microsoft::WRL::ComPtr;
-
-//--------------------------------------------------------------------------------------
-// Macros
-//--------------------------------------------------------------------------------------
-#ifndef MAKEFOURCC
-#define MAKEFOURCC(ch0, ch1, ch2, ch3) \
- ((uint32_t)(uint8_t)(ch0) | ((uint32_t)(uint8_t)(ch1) << 8) | \
- ((uint32_t)(uint8_t)(ch2) << 16) | ((uint32_t)(uint8_t)(ch3) << 24 ))
-#endif /* defined(MAKEFOURCC) */
-
-//--------------------------------------------------------------------------------------
-// DDS file structure definitions
-//
-// See DDS.h in the 'Texconv' sample and the 'DirectXTex' library
-//--------------------------------------------------------------------------------------
-namespace
-{
- #pragma pack(push,1)
-
- #define DDS_MAGIC 0x20534444 // "DDS "
-
- struct DDS_PIXELFORMAT
- {
- uint32_t size;
- uint32_t flags;
- uint32_t fourCC;
- uint32_t RGBBitCount;
- uint32_t RBitMask;
- uint32_t GBitMask;
- uint32_t BBitMask;
- uint32_t ABitMask;
- };
-
- #define DDS_FOURCC 0x00000004 // DDPF_FOURCC
- #define DDS_RGB 0x00000040 // DDPF_RGB
- #define DDS_RGBA 0x00000041 // DDPF_RGB | DDPF_ALPHAPIXELS
- #define DDS_LUMINANCE 0x00020000 // DDPF_LUMINANCE
- #define DDS_LUMINANCEA 0x00020001 // DDPF_LUMINANCE | DDPF_ALPHAPIXELS
- #define DDS_ALPHA 0x00000002 // DDPF_ALPHA
- #define DDS_BUMPDUDV 0x00080000 // DDPF_BUMPDUDV
-
- #define DDS_HEADER_FLAGS_TEXTURE 0x00001007 // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT
- #define DDS_HEADER_FLAGS_MIPMAP 0x00020000 // DDSD_MIPMAPCOUNT
- #define DDS_HEADER_FLAGS_PITCH 0x00000008 // DDSD_PITCH
- #define DDS_HEADER_FLAGS_LINEARSIZE 0x00080000 // DDSD_LINEARSIZE
-
- #define DDS_HEIGHT 0x00000002 // DDSD_HEIGHT
- #define DDS_WIDTH 0x00000004 // DDSD_WIDTH
-
- #define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE
-
- typedef struct
- {
- uint32_t size;
- uint32_t flags;
- uint32_t height;
- uint32_t width;
- uint32_t pitchOrLinearSize;
- uint32_t depth; // only if DDS_HEADER_FLAGS_VOLUME is set in flags
- uint32_t mipMapCount;
- uint32_t reserved1[11];
- DDS_PIXELFORMAT ddspf;
- uint32_t caps;
- uint32_t caps2;
- uint32_t caps3;
- uint32_t caps4;
- uint32_t reserved2;
- } DDS_HEADER;
-
- typedef struct
- {
- DXGI_FORMAT dxgiFormat;
- uint32_t resourceDimension;
- uint32_t miscFlag; // see D3D11_RESOURCE_MISC_FLAG
- uint32_t arraySize;
- uint32_t reserved;
- } DDS_HEADER_DXT10;
-
- #pragma pack(pop)
-
- const DDS_PIXELFORMAT DDSPF_DXT1 =
- { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 };
-
- const DDS_PIXELFORMAT DDSPF_DXT3 =
- { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','3'), 0, 0, 0, 0, 0 };
-
- const DDS_PIXELFORMAT DDSPF_DXT5 =
- { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0 };
-
- const DDS_PIXELFORMAT DDSPF_BC4_UNORM =
- { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','4','U'), 0, 0, 0, 0, 0 };
-
- const DDS_PIXELFORMAT DDSPF_BC4_SNORM =
- { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','4','S'), 0, 0, 0, 0, 0 };
-
- const DDS_PIXELFORMAT DDSPF_BC5_UNORM =
- { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','5','U'), 0, 0, 0, 0, 0 };
-
- const DDS_PIXELFORMAT DDSPF_BC5_SNORM =
- { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','5','S'), 0, 0, 0, 0, 0 };
-
- const DDS_PIXELFORMAT DDSPF_R8G8_B8G8 =
- { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('R','G','B','G'), 0, 0, 0, 0, 0 };
-
- const DDS_PIXELFORMAT DDSPF_G8R8_G8B8 =
- { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('G','R','G','B'), 0, 0, 0, 0, 0 };
-
- const DDS_PIXELFORMAT DDSPF_YUY2 =
- { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('Y','U','Y','2'), 0, 0, 0, 0, 0 };
-
- const DDS_PIXELFORMAT DDSPF_A8R8G8B8 =
- { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 };
-
- const DDS_PIXELFORMAT DDSPF_X8R8G8B8 =
- { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 };
-
- const DDS_PIXELFORMAT DDSPF_A8B8G8R8 =
- { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };
-
- const DDS_PIXELFORMAT DDSPF_G16R16 =
- { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 };
-
- const DDS_PIXELFORMAT DDSPF_R5G6B5 =
- { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000 };
-
- const DDS_PIXELFORMAT DDSPF_A1R5G5B5 =
- { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000 };
-
- const DDS_PIXELFORMAT DDSPF_A4R4G4B4 =
- { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000 };
-
- const DDS_PIXELFORMAT DDSPF_L8 =
- { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 8, 0xff, 0x00, 0x00, 0x00 };
-
- const DDS_PIXELFORMAT DDSPF_L16 =
- { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 16, 0xffff, 0x0000, 0x0000, 0x0000 };
-
- const DDS_PIXELFORMAT DDSPF_A8L8 =
- { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 16, 0x00ff, 0x0000, 0x0000, 0xff00 };
-
- const DDS_PIXELFORMAT DDSPF_A8 =
- { sizeof(DDS_PIXELFORMAT), DDS_ALPHA, 0, 8, 0x00, 0x00, 0x00, 0xff };
-
- const DDS_PIXELFORMAT DDSPF_V8U8 =
- { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 16, 0x00ff, 0xff00, 0x0000, 0x0000 };
-
- const DDS_PIXELFORMAT DDSPF_Q8W8V8U8 =
- { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };
-
- const DDS_PIXELFORMAT DDSPF_V16U16 =
- { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 };
-
- // DXGI_FORMAT_R10G10B10A2_UNORM should be written using DX10 extension to avoid D3DX 10:10:10:2 reversal issue
-
- // This indicates the DDS_HEADER_DXT10 extension is present (the format is in dxgiFormat)
- const DDS_PIXELFORMAT DDSPF_DX10 =
- { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 };
-
- //-----------------------------------------------------------------------------
- struct handle_closer { void operator()(HANDLE h) { if (h) CloseHandle(h); } };
-
- typedef std::unique_ptr ScopedHandle;
-
- inline HANDLE safe_handle( HANDLE h ) { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
-
- class auto_delete_file
- {
- public:
- auto_delete_file(HANDLE hFile) : m_handle(hFile) {}
- ~auto_delete_file()
- {
- if (m_handle)
- {
- FILE_DISPOSITION_INFO info = {};
- info.DeleteFile = TRUE;
- (void)SetFileInformationByHandle(m_handle, FileDispositionInfo, &info, sizeof(info));
- }
- }
-
- void clear() { m_handle = 0; }
-
- private:
- HANDLE m_handle;
-
- auto_delete_file(const auto_delete_file&) = delete;
- auto_delete_file& operator=(const auto_delete_file&) = delete;
- };
-
- class auto_delete_file_wic
- {
- public:
- auto_delete_file_wic(ComPtr& hFile, LPCWSTR szFile) : m_handle(hFile), m_filename(szFile) {}
- ~auto_delete_file_wic()
- {
- if (m_filename)
- {
- m_handle.Reset();
- DeleteFileW(m_filename);
- }
- }
-
- void clear() { m_filename = 0; }
-
- private:
- LPCWSTR m_filename;
- ComPtr& m_handle;
-
- auto_delete_file_wic(const auto_delete_file_wic&) = delete;
- auto_delete_file_wic& operator=(const auto_delete_file_wic&) = delete;
- };
-
- //--------------------------------------------------------------------------------------
- // Return the BPP for a particular format
- //--------------------------------------------------------------------------------------
- size_t BitsPerPixel( _In_ DXGI_FORMAT fmt )
- {
- switch( fmt )
- {
- case DXGI_FORMAT_R32G32B32A32_TYPELESS:
- case DXGI_FORMAT_R32G32B32A32_FLOAT:
- case DXGI_FORMAT_R32G32B32A32_UINT:
- case DXGI_FORMAT_R32G32B32A32_SINT:
- return 128;
-
- case DXGI_FORMAT_R32G32B32_TYPELESS:
- case DXGI_FORMAT_R32G32B32_FLOAT:
- case DXGI_FORMAT_R32G32B32_UINT:
- case DXGI_FORMAT_R32G32B32_SINT:
- return 96;
-
- case DXGI_FORMAT_R16G16B16A16_TYPELESS:
- case DXGI_FORMAT_R16G16B16A16_FLOAT:
- case DXGI_FORMAT_R16G16B16A16_UNORM:
- case DXGI_FORMAT_R16G16B16A16_UINT:
- case DXGI_FORMAT_R16G16B16A16_SNORM:
- case DXGI_FORMAT_R16G16B16A16_SINT:
- case DXGI_FORMAT_R32G32_TYPELESS:
- case DXGI_FORMAT_R32G32_FLOAT:
- case DXGI_FORMAT_R32G32_UINT:
- case DXGI_FORMAT_R32G32_SINT:
- 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_Y416:
- case DXGI_FORMAT_Y210:
- case DXGI_FORMAT_Y216:
- return 64;
-
- case DXGI_FORMAT_R10G10B10A2_TYPELESS:
- case DXGI_FORMAT_R10G10B10A2_UNORM:
- case DXGI_FORMAT_R10G10B10A2_UINT:
- case DXGI_FORMAT_R11G11B10_FLOAT:
- case DXGI_FORMAT_R8G8B8A8_TYPELESS:
- case DXGI_FORMAT_R8G8B8A8_UNORM:
- case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
- case DXGI_FORMAT_R8G8B8A8_UINT:
- case DXGI_FORMAT_R8G8B8A8_SNORM:
- case DXGI_FORMAT_R8G8B8A8_SINT:
- case DXGI_FORMAT_R16G16_TYPELESS:
- case DXGI_FORMAT_R16G16_FLOAT:
- case DXGI_FORMAT_R16G16_UNORM:
- case DXGI_FORMAT_R16G16_UINT:
- case DXGI_FORMAT_R16G16_SNORM:
- case DXGI_FORMAT_R16G16_SINT:
- case DXGI_FORMAT_R32_TYPELESS:
- case DXGI_FORMAT_D32_FLOAT:
- case DXGI_FORMAT_R32_FLOAT:
- case DXGI_FORMAT_R32_UINT:
- case DXGI_FORMAT_R32_SINT:
- 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_R9G9B9E5_SHAREDEXP:
- case DXGI_FORMAT_R8G8_B8G8_UNORM:
- case DXGI_FORMAT_G8R8_G8B8_UNORM:
- case DXGI_FORMAT_B8G8R8A8_UNORM:
- case DXGI_FORMAT_B8G8R8X8_UNORM:
- case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
- case DXGI_FORMAT_B8G8R8A8_TYPELESS:
- case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
- case DXGI_FORMAT_B8G8R8X8_TYPELESS:
- case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
- case DXGI_FORMAT_AYUV:
- case DXGI_FORMAT_Y410:
- case DXGI_FORMAT_YUY2:
- return 32;
-
- case DXGI_FORMAT_P010:
- case DXGI_FORMAT_P016:
- case DXGI_FORMAT_V408:
- return 24;
-
- case DXGI_FORMAT_R8G8_TYPELESS:
- case DXGI_FORMAT_R8G8_UNORM:
- case DXGI_FORMAT_R8G8_UINT:
- case DXGI_FORMAT_R8G8_SNORM:
- case DXGI_FORMAT_R8G8_SINT:
- case DXGI_FORMAT_R16_TYPELESS:
- case DXGI_FORMAT_R16_FLOAT:
- case DXGI_FORMAT_D16_UNORM:
- case DXGI_FORMAT_R16_UNORM:
- case DXGI_FORMAT_R16_UINT:
- case DXGI_FORMAT_R16_SNORM:
- case DXGI_FORMAT_R16_SINT:
- case DXGI_FORMAT_B5G6R5_UNORM:
- case DXGI_FORMAT_B5G5R5A1_UNORM:
- case DXGI_FORMAT_A8P8:
- case DXGI_FORMAT_B4G4R4A4_UNORM:
- case DXGI_FORMAT_P208:
- case DXGI_FORMAT_V208:
- return 16;
-
- case DXGI_FORMAT_NV12:
- case DXGI_FORMAT_420_OPAQUE:
- case DXGI_FORMAT_NV11:
- return 12;
-
- case DXGI_FORMAT_R8_TYPELESS:
- case DXGI_FORMAT_R8_UNORM:
- case DXGI_FORMAT_R8_UINT:
- case DXGI_FORMAT_R8_SNORM:
- case DXGI_FORMAT_R8_SINT:
- case DXGI_FORMAT_A8_UNORM:
- case DXGI_FORMAT_AI44:
- case DXGI_FORMAT_IA44:
- case DXGI_FORMAT_P8:
- return 8;
-
- case DXGI_FORMAT_R1_UNORM:
- return 1;
-
- case DXGI_FORMAT_BC1_TYPELESS:
- case DXGI_FORMAT_BC1_UNORM:
- case DXGI_FORMAT_BC1_UNORM_SRGB:
- case DXGI_FORMAT_BC4_TYPELESS:
- case DXGI_FORMAT_BC4_UNORM:
- case DXGI_FORMAT_BC4_SNORM:
- return 4;
-
- case DXGI_FORMAT_BC2_TYPELESS:
- case DXGI_FORMAT_BC2_UNORM:
- case DXGI_FORMAT_BC2_UNORM_SRGB:
- case DXGI_FORMAT_BC3_TYPELESS:
- case DXGI_FORMAT_BC3_UNORM:
- case DXGI_FORMAT_BC3_UNORM_SRGB:
- case DXGI_FORMAT_BC5_TYPELESS:
- case DXGI_FORMAT_BC5_UNORM:
- case DXGI_FORMAT_BC5_SNORM:
- case DXGI_FORMAT_BC6H_TYPELESS:
- case DXGI_FORMAT_BC6H_UF16:
- case DXGI_FORMAT_BC6H_SF16:
- case DXGI_FORMAT_BC7_TYPELESS:
- case DXGI_FORMAT_BC7_UNORM:
- case DXGI_FORMAT_BC7_UNORM_SRGB:
- return 8;
-
- default:
- return 0;
- }
- }
-
-
- //--------------------------------------------------------------------------------------
- // Determines if the format is block compressed
- //--------------------------------------------------------------------------------------
- bool IsCompressed( _In_ DXGI_FORMAT fmt )
- {
- switch ( fmt )
- {
- case DXGI_FORMAT_BC1_TYPELESS:
- case DXGI_FORMAT_BC1_UNORM:
- case DXGI_FORMAT_BC1_UNORM_SRGB:
- case DXGI_FORMAT_BC2_TYPELESS:
- case DXGI_FORMAT_BC2_UNORM:
- case DXGI_FORMAT_BC2_UNORM_SRGB:
- case DXGI_FORMAT_BC3_TYPELESS:
- case DXGI_FORMAT_BC3_UNORM:
- case DXGI_FORMAT_BC3_UNORM_SRGB:
- case DXGI_FORMAT_BC4_TYPELESS:
- case DXGI_FORMAT_BC4_UNORM:
- case DXGI_FORMAT_BC4_SNORM:
- case DXGI_FORMAT_BC5_TYPELESS:
- case DXGI_FORMAT_BC5_UNORM:
- case DXGI_FORMAT_BC5_SNORM:
- case DXGI_FORMAT_BC6H_TYPELESS:
- case DXGI_FORMAT_BC6H_UF16:
- case DXGI_FORMAT_BC6H_SF16:
- case DXGI_FORMAT_BC7_TYPELESS:
- case DXGI_FORMAT_BC7_UNORM:
- case DXGI_FORMAT_BC7_UNORM_SRGB:
- return true;
-
- default:
- return false;
- }
- }
-
-
- //--------------------------------------------------------------------------------------
- // Get surface information for a particular format
- //--------------------------------------------------------------------------------------
- HRESULT GetSurfaceInfo(
- _In_ size_t width,
- _In_ size_t height,
- _In_ DXGI_FORMAT fmt,
- _Out_opt_ size_t* outNumBytes,
- _Out_opt_ size_t* outRowBytes,
- _Out_opt_ size_t* outNumRows)
- {
- uint64_t numBytes = 0;
- uint64_t rowBytes = 0;
- uint64_t numRows = 0;
-
- bool bc = false;
- bool packed = false;
- bool planar = false;
- size_t bpe = 0;
- switch (fmt)
- {
- case DXGI_FORMAT_BC1_TYPELESS:
- case DXGI_FORMAT_BC1_UNORM:
- case DXGI_FORMAT_BC1_UNORM_SRGB:
- case DXGI_FORMAT_BC4_TYPELESS:
- case DXGI_FORMAT_BC4_UNORM:
- case DXGI_FORMAT_BC4_SNORM:
- bc = true;
- bpe = 8;
- break;
-
- case DXGI_FORMAT_BC2_TYPELESS:
- case DXGI_FORMAT_BC2_UNORM:
- case DXGI_FORMAT_BC2_UNORM_SRGB:
- case DXGI_FORMAT_BC3_TYPELESS:
- case DXGI_FORMAT_BC3_UNORM:
- case DXGI_FORMAT_BC3_UNORM_SRGB:
- case DXGI_FORMAT_BC5_TYPELESS:
- case DXGI_FORMAT_BC5_UNORM:
- case DXGI_FORMAT_BC5_SNORM:
- case DXGI_FORMAT_BC6H_TYPELESS:
- case DXGI_FORMAT_BC6H_UF16:
- case DXGI_FORMAT_BC6H_SF16:
- case DXGI_FORMAT_BC7_TYPELESS:
- case DXGI_FORMAT_BC7_UNORM:
- case DXGI_FORMAT_BC7_UNORM_SRGB:
- bc = true;
- bpe = 16;
- break;
-
- case DXGI_FORMAT_R8G8_B8G8_UNORM:
- case DXGI_FORMAT_G8R8_G8B8_UNORM:
- case DXGI_FORMAT_YUY2:
- packed = true;
- bpe = 4;
- break;
-
- case DXGI_FORMAT_Y210:
- case DXGI_FORMAT_Y216:
- packed = true;
- bpe = 8;
- break;
-
- case DXGI_FORMAT_NV12:
- case DXGI_FORMAT_420_OPAQUE:
- case DXGI_FORMAT_P208:
- planar = true;
- bpe = 2;
- break;
-
- case DXGI_FORMAT_P010:
- case DXGI_FORMAT_P016:
- planar = true;
- bpe = 4;
- break;
-
- default:
- break;
- }
-
- if (bc)
- {
- uint64_t numBlocksWide = 0;
- if (width > 0)
- {
- numBlocksWide = std::max(1u, (uint64_t(width) + 3u) / 4u);
- }
- uint64_t numBlocksHigh = 0;
- if (height > 0)
- {
- numBlocksHigh = std::max(1u, (uint64_t(height) + 3u) / 4u);
- }
- rowBytes = numBlocksWide * bpe;
- numRows = numBlocksHigh;
- numBytes = rowBytes * numBlocksHigh;
- }
- else if (packed)
- {
- rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;
- numRows = uint64_t(height);
- numBytes = rowBytes * height;
- }
- else if (fmt == DXGI_FORMAT_NV11)
- {
- rowBytes = ((uint64_t(width) + 3u) >> 2) * 4u;
- numRows = uint64_t(height) * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data
- numBytes = rowBytes * numRows;
- }
- else if (planar)
- {
- rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;
- numBytes = (rowBytes * uint64_t(height)) + ((rowBytes * uint64_t(height) + 1u) >> 1);
- numRows = height + ((uint64_t(height) + 1u) >> 1);
- }
- else
- {
- size_t bpp = BitsPerPixel(fmt);
- if (!bpp)
- return E_INVALIDARG;
-
- rowBytes = (uint64_t(width) * bpp + 7u) / 8u; // round up to nearest byte
- numRows = uint64_t(height);
- numBytes = rowBytes * height;
- }
-
-#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64)
- static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!");
- if (numBytes > UINT32_MAX || rowBytes > UINT32_MAX || numRows > UINT32_MAX)
- return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
-#else
- static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!");
-#endif
-
- if (outNumBytes)
- {
- *outNumBytes = static_cast(numBytes);
- }
- if (outRowBytes)
- {
- *outRowBytes = static_cast(rowBytes);
- }
- if (outNumRows)
- {
- *outNumRows = static_cast(numRows);
- }
-
- return S_OK;
- }
-
-
- //--------------------------------------------------------------------------------------
- DXGI_FORMAT EnsureNotTypeless( DXGI_FORMAT fmt )
- {
- // Assumes UNORM or FLOAT; doesn't use UINT or SINT
- switch( fmt )
- {
- case DXGI_FORMAT_R32G32B32A32_TYPELESS: return DXGI_FORMAT_R32G32B32A32_FLOAT;
- case DXGI_FORMAT_R32G32B32_TYPELESS: return DXGI_FORMAT_R32G32B32_FLOAT;
- case DXGI_FORMAT_R16G16B16A16_TYPELESS: return DXGI_FORMAT_R16G16B16A16_UNORM;
- case DXGI_FORMAT_R32G32_TYPELESS: return DXGI_FORMAT_R32G32_FLOAT;
- case DXGI_FORMAT_R10G10B10A2_TYPELESS: return DXGI_FORMAT_R10G10B10A2_UNORM;
- case DXGI_FORMAT_R8G8B8A8_TYPELESS: return DXGI_FORMAT_R8G8B8A8_UNORM;
- case DXGI_FORMAT_R16G16_TYPELESS: return DXGI_FORMAT_R16G16_UNORM;
- case DXGI_FORMAT_R32_TYPELESS: return DXGI_FORMAT_R32_FLOAT;
- case DXGI_FORMAT_R8G8_TYPELESS: return DXGI_FORMAT_R8G8_UNORM;
- case DXGI_FORMAT_R16_TYPELESS: return DXGI_FORMAT_R16_UNORM;
- case DXGI_FORMAT_R8_TYPELESS: return DXGI_FORMAT_R8_UNORM;
- case DXGI_FORMAT_BC1_TYPELESS: return DXGI_FORMAT_BC1_UNORM;
- case DXGI_FORMAT_BC2_TYPELESS: return DXGI_FORMAT_BC2_UNORM;
- case DXGI_FORMAT_BC3_TYPELESS: return DXGI_FORMAT_BC3_UNORM;
- case DXGI_FORMAT_BC4_TYPELESS: return DXGI_FORMAT_BC4_UNORM;
- case DXGI_FORMAT_BC5_TYPELESS: return DXGI_FORMAT_BC5_UNORM;
- case DXGI_FORMAT_B8G8R8A8_TYPELESS: return DXGI_FORMAT_B8G8R8A8_UNORM;
- case DXGI_FORMAT_B8G8R8X8_TYPELESS: return DXGI_FORMAT_B8G8R8X8_UNORM;
- case DXGI_FORMAT_BC7_TYPELESS: return DXGI_FORMAT_BC7_UNORM;
- default: return fmt;
- }
- }
-
-
- //--------------------------------------------------------------------------------------
- inline void TransitionResource(
- _In_ ID3D12GraphicsCommandList* commandList,
- _In_ ID3D12Resource* resource,
- _In_ D3D12_RESOURCE_STATES stateBefore,
- _In_ D3D12_RESOURCE_STATES stateAfter)
- {
- assert(commandList != nullptr);
- assert(resource != nullptr);
-
- if (stateBefore == stateAfter)
- return;
-
- D3D12_RESOURCE_BARRIER desc = {};
- desc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
- desc.Transition.pResource = resource;
- desc.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
- desc.Transition.StateBefore = stateBefore;
- desc.Transition.StateAfter = stateAfter;
-
- commandList->ResourceBarrier(1, &desc);
- }
-
-
- //--------------------------------------------------------------------------------------
- HRESULT CaptureTexture(_In_ ID3D12Device* device,
- _In_ ID3D12CommandQueue* pCommandQ,
- _In_ ID3D12Resource* pSource,
- UINT64 srcPitch,
- const D3D12_RESOURCE_DESC& desc,
- ComPtr& pStaging,
- D3D12_RESOURCE_STATES beforeState,
- D3D12_RESOURCE_STATES afterState)
- {
- if (!pCommandQ || !pSource)
- return E_INVALIDARG;
-
- if (desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)
- return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
-
- if (srcPitch > UINT32_MAX)
- return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
-
- 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);
- if (FAILED(hr))
- return hr;
-
- if (sourceHeapProperties.Type == D3D12_HEAP_TYPE_READBACK)
- {
- // Handle case where the source is already a staging texture we can use directly
- pStaging = pSource;
- return S_OK;
- }
-
- // Create a command allocator
- ComPtr commandAlloc;
- hr = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(commandAlloc.GetAddressOf()));
- if (FAILED(hr))
- return hr;
-
- // Spin up a new command list
- ComPtr commandList;
- hr = device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAlloc.Get(), nullptr, IID_PPV_ARGS(commandList.GetAddressOf()));
- if (FAILED(hr))
- return hr;
-
- // Create a fence
- ComPtr fence;
- hr = device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(fence.GetAddressOf()));
- if (FAILED(hr))
- return hr;
-
- assert((srcPitch & 0xFF) == 0);
-
- CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT);
- CD3DX12_HEAP_PROPERTIES readBackHeapProperties(D3D12_HEAP_TYPE_READBACK);
-
- // Readback resources must be buffers
- D3D12_RESOURCE_DESC bufferDesc = {};
- bufferDesc.Alignment = desc.Alignment;
- bufferDesc.DepthOrArraySize = 1;
- bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
- bufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
- bufferDesc.Format = DXGI_FORMAT_UNKNOWN;
- bufferDesc.Height = 1;
- bufferDesc.Width = srcPitch * desc.Height;
- bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
- bufferDesc.MipLevels = 1;
- bufferDesc.SampleDesc.Count = 1;
- bufferDesc.SampleDesc.Quality = 0;
-
- ComPtr copySource(pSource);
- if (desc.SampleDesc.Count > 1)
- {
- // MSAA content must be resolved before being copied to a staging texture
- auto descCopy = desc;
- descCopy.SampleDesc.Count = 1;
- descCopy.SampleDesc.Quality = 0;
-
- ComPtr pTemp;
- hr = device->CreateCommittedResource(
- &defaultHeapProperties,
- D3D12_HEAP_FLAG_NONE,
- &descCopy,
- D3D12_RESOURCE_STATE_COPY_DEST,
- nullptr,
- IID_PPV_ARGS(pTemp.GetAddressOf()));
- if (FAILED(hr))
- return hr;
-
- assert(pTemp);
-
- DXGI_FORMAT fmt = EnsureNotTypeless(desc.Format);
-
- D3D12_FEATURE_DATA_FORMAT_SUPPORT formatInfo = { fmt, D3D12_FORMAT_SUPPORT1_NONE, D3D12_FORMAT_SUPPORT2_NONE };
- hr = device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &formatInfo, sizeof(formatInfo));
- if (FAILED(hr))
- return hr;
-
- if (!(formatInfo.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D))
- return E_FAIL;
-
- for (UINT item = 0; item < desc.DepthOrArraySize; ++item)
- {
- for (UINT level = 0; level < desc.MipLevels; ++level)
- {
- UINT index = D3D12CalcSubresource(level, item, 0, desc.MipLevels, desc.DepthOrArraySize);
- commandList->ResolveSubresource(pTemp.Get(), index, pSource, index, fmt);
- }
- }
-
- copySource = pTemp;
- }
-
- // Create a staging texture
- hr = device->CreateCommittedResource(
- &readBackHeapProperties,
- D3D12_HEAP_FLAG_NONE,
- &bufferDesc,
- D3D12_RESOURCE_STATE_COPY_DEST,
- nullptr,
- IID_PPV_ARGS(pStaging.ReleaseAndGetAddressOf()));
- if (FAILED(hr))
- return hr;
-
- assert(pStaging);
-
- // Transition the resource if necessary
- TransitionResource(commandList.Get(), pSource, beforeState, D3D12_RESOURCE_STATE_COPY_SOURCE);
-
- // Get the copy target location
- D3D12_PLACED_SUBRESOURCE_FOOTPRINT bufferFootprint = {};
- bufferFootprint.Footprint.Width = static_cast(desc.Width);
- bufferFootprint.Footprint.Height = desc.Height;
- bufferFootprint.Footprint.Depth = 1;
- bufferFootprint.Footprint.RowPitch = static_cast(srcPitch);
- bufferFootprint.Footprint.Format = desc.Format;
-
- CD3DX12_TEXTURE_COPY_LOCATION copyDest(pStaging.Get(), bufferFootprint);
- CD3DX12_TEXTURE_COPY_LOCATION copySrc(copySource.Get(), 0);
-
- // Copy the texture
- commandList->CopyTextureRegion(©Dest, 0, 0, 0, ©Src, nullptr);
-
- // Transition the resource to the next state
- TransitionResource(commandList.Get(), pSource, D3D12_RESOURCE_STATE_COPY_SOURCE, afterState);
-
- hr = commandList->Close();
- if (FAILED(hr))
- return hr;
-
- // Execute the command list
- pCommandQ->ExecuteCommandLists(1, CommandListCast(commandList.GetAddressOf()));
-
- // Signal the fence
- hr = pCommandQ->Signal(fence.Get(), 1);
- if (FAILED(hr))
- return hr;
-
- // Block until the copy is complete
- while (fence->GetCompletedValue() < 1)
- SwitchToThread();
-
- return S_OK;
- }
-
- IWICImagingFactory2* _GetWIC()
- {
- static INIT_ONCE s_initOnce = INIT_ONCE_STATIC_INIT;
-
- IWICImagingFactory2* factory = nullptr;
- (void)InitOnceExecuteOnce(&s_initOnce,
- [](PINIT_ONCE, PVOID, PVOID *ifactory) -> BOOL
- {
- return SUCCEEDED( CoCreateInstance(
- CLSID_WICImagingFactory2,
- nullptr,
- CLSCTX_INPROC_SERVER,
- __uuidof(IWICImagingFactory2),
- ifactory) ) ? TRUE : FALSE;
- }, nullptr, reinterpret_cast(&factory));
-
- return factory;
- }
-} // anonymous namespace
-
-
-//--------------------------------------------------------------------------------------
-_Use_decl_annotations_
-HRESULT DirectX::SaveDDSTextureToFile(
- ID3D12CommandQueue* pCommandQ,
- ID3D12Resource* pSource,
- const wchar_t* fileName,
- D3D12_RESOURCE_STATES beforeState,
- D3D12_RESOURCE_STATES afterState)
-{
- if ( !fileName )
- return E_INVALIDARG;
-
- ComPtr device;
- pCommandQ->GetDevice(IID_PPV_ARGS(device.GetAddressOf()));
-
- // Get the size of the image
- const auto desc = pSource->GetDesc();
-
- if (desc.Width > UINT32_MAX)
- return E_INVALIDARG;
-
- UINT64 totalResourceSize = 0;
- UINT64 fpRowPitch = 0;
- UINT fpRowCount = 0;
- // Get the rowcount, pitch and size of the top mip
- device->GetCopyableFootprints(
- &desc,
- 0,
- 1,
- 0,
- nullptr,
- &fpRowCount,
- &fpRowPitch,
- &totalResourceSize);
-
- // Round up the srcPitch to multiples of 256
- UINT64 dstRowPitch = (fpRowPitch + 255) & ~0xFF;
-
- if (dstRowPitch > UINT32_MAX)
- return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
-
- ComPtr pStaging;
- HRESULT hr = CaptureTexture( device.Get(), pCommandQ, pSource, dstRowPitch, desc, pStaging, beforeState, afterState );
- if ( FAILED(hr) )
- return hr;
-
- // Create file
- ScopedHandle hFile( safe_handle( CreateFile2( fileName, GENERIC_WRITE, 0, CREATE_ALWAYS, nullptr ) ) );
- if ( !hFile )
- return HRESULT_FROM_WIN32( GetLastError() );
-
- auto_delete_file delonfail(hFile.get());
-
- // Setup header
- const size_t MAX_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10);
- uint8_t fileHeader[ MAX_HEADER_SIZE ];
-
- *reinterpret_cast(&fileHeader[0]) = DDS_MAGIC;
-
- auto header = reinterpret_cast( &fileHeader[0] + sizeof(uint32_t) );
- size_t headerSize = sizeof(uint32_t) + sizeof(DDS_HEADER);
- memset( header, 0, sizeof(DDS_HEADER) );
- header->size = sizeof( DDS_HEADER );
- header->flags = DDS_HEADER_FLAGS_TEXTURE | DDS_HEADER_FLAGS_MIPMAP;
- header->height = desc.Height;
- header->width = static_cast(desc.Width);
- header->mipMapCount = 1;
- header->caps = DDS_SURFACE_FLAGS_TEXTURE;
-
- // Try to use a legacy .DDS pixel format for better tools support, otherwise fallback to 'DX10' header extension
- DDS_HEADER_DXT10* extHeader = nullptr;
- switch( desc.Format )
- {
- case DXGI_FORMAT_R8G8B8A8_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_A8B8G8R8, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_R16G16_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_G16R16, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_R8G8_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_A8L8, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_R16_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_L16, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_R8_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_L8, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_A8_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_A8, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_R8G8_B8G8_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_R8G8_B8G8, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_G8R8_G8B8_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_G8R8_G8B8, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_BC1_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_DXT1, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_BC2_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_DXT3, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_BC3_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_DXT5, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_BC4_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_BC4_UNORM, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_BC4_SNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_BC4_SNORM, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_BC5_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_BC5_UNORM, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_BC5_SNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_BC5_SNORM, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_B5G6R5_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_R5G6B5, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_B5G5R5A1_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_A1R5G5B5, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_R8G8_SNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_V8U8, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_R8G8B8A8_SNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_Q8W8V8U8, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_R16G16_SNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_V16U16, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_B8G8R8A8_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_A8R8G8B8, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_B8G8R8X8_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_X8R8G8B8, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_YUY2: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_YUY2, sizeof(DDS_PIXELFORMAT) ); break;
- case DXGI_FORMAT_B4G4R4A4_UNORM: memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_A4R4G4B4, sizeof(DDS_PIXELFORMAT) ); break;
-
- // Legacy D3DX formats using D3DFMT enum value as FourCC
- case DXGI_FORMAT_R32G32B32A32_FLOAT: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 116; break; // D3DFMT_A32B32G32R32F
- case DXGI_FORMAT_R16G16B16A16_FLOAT: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 113; break; // D3DFMT_A16B16G16R16F
- case DXGI_FORMAT_R16G16B16A16_UNORM: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 36; break; // D3DFMT_A16B16G16R16
- case DXGI_FORMAT_R16G16B16A16_SNORM: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 110; break; // D3DFMT_Q16W16V16U16
- case DXGI_FORMAT_R32G32_FLOAT: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 115; break; // D3DFMT_G32R32F
- case DXGI_FORMAT_R16G16_FLOAT: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 112; break; // D3DFMT_G16R16F
- case DXGI_FORMAT_R32_FLOAT: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 114; break; // D3DFMT_R32F
- case DXGI_FORMAT_R16_FLOAT: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 111; break; // D3DFMT_R16F
-
- case DXGI_FORMAT_AI44:
- case DXGI_FORMAT_IA44:
- case DXGI_FORMAT_P8:
- case DXGI_FORMAT_A8P8:
- return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
-
- default:
- memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_DX10, sizeof(DDS_PIXELFORMAT) );
-
- headerSize += sizeof(DDS_HEADER_DXT10);
- extHeader = reinterpret_cast(fileHeader + sizeof(uint32_t) + sizeof(DDS_HEADER) );
- memset( extHeader, 0, sizeof(DDS_HEADER_DXT10) );
- extHeader->dxgiFormat = desc.Format;
- extHeader->resourceDimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
- extHeader->arraySize = 1;
- break;
- }
-
- size_t rowPitch, slicePitch, rowCount;
- hr = GetSurfaceInfo(static_cast(desc.Width), desc.Height, desc.Format, &slicePitch, &rowPitch, &rowCount);
- if (FAILED(hr))
- return hr;
-
- if (rowPitch > UINT32_MAX || slicePitch > UINT32_MAX)
- return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
-
- if ( IsCompressed( desc.Format ) )
- {
- header->flags |= DDS_HEADER_FLAGS_LINEARSIZE;
- header->pitchOrLinearSize = static_cast( slicePitch );
- }
- else
- {
- header->flags |= DDS_HEADER_FLAGS_PITCH;
- header->pitchOrLinearSize = static_cast( rowPitch );
- }
-
- // Setup pixels
- std::unique_ptr pixels( new (std::nothrow) uint8_t[ slicePitch ] );
- if (!pixels)
- return E_OUTOFMEMORY;
-
- assert(fpRowCount == rowCount);
- assert(fpRowPitch == rowPitch);
-
- UINT64 imageSize = dstRowPitch * UINT64(rowCount);
- if (imageSize > UINT32_MAX)
- return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
-
- void* pMappedMemory = nullptr;
- D3D12_RANGE readRange = { 0, static_cast(imageSize) };
- D3D12_RANGE writeRange = { 0, 0 };
- hr = pStaging->Map(0, &readRange, &pMappedMemory );
- if ( FAILED(hr) )
- return hr;
-
- auto sptr = static_cast(pMappedMemory);
- if ( !sptr )
- {
- pStaging->Unmap(0, &writeRange);
- return E_POINTER;
- }
-
- uint8_t* dptr = pixels.get();
-
- size_t msize = std::min( rowPitch, rowPitch );
- for( size_t h = 0; h < rowCount; ++h )
- {
- memcpy_s( dptr, rowPitch, sptr, msize );
- sptr += dstRowPitch;
- dptr += rowPitch;
- }
-
- pStaging->Unmap( 0, &writeRange );
-
- // Write header & pixels
- DWORD bytesWritten;
- if ( !WriteFile( hFile.get(), fileHeader, static_cast( headerSize ), &bytesWritten, nullptr ) )
- return HRESULT_FROM_WIN32( GetLastError() );
-
- if ( bytesWritten != headerSize )
- return E_FAIL;
-
- if ( !WriteFile( hFile.get(), pixels.get(), static_cast( slicePitch ), &bytesWritten, nullptr ) )
- return HRESULT_FROM_WIN32( GetLastError() );
-
- if ( bytesWritten != slicePitch )
- return E_FAIL;
-
- delonfail.clear();
-
- return S_OK;
-}
-
-//--------------------------------------------------------------------------------------
-_Use_decl_annotations_
-HRESULT DirectX::SaveWICTextureToFile(
- ID3D12CommandQueue* pCommandQ,
- ID3D12Resource* pSource,
- REFGUID guidContainerFormat,
- const wchar_t* fileName,
- D3D12_RESOURCE_STATES beforeState,
- D3D12_RESOURCE_STATES afterState,
- const GUID* targetFormat,
- std::function setCustomProps )
-{
- if ( !fileName )
- return E_INVALIDARG;
-
- ComPtr device;
- pCommandQ->GetDevice(IID_PPV_ARGS(device.GetAddressOf()));
-
- // Get the size of the image
- const auto desc = pSource->GetDesc();
-
- if (desc.Width > UINT32_MAX)
- return E_INVALIDARG;
-
- UINT64 totalResourceSize = 0;
- UINT64 fpRowPitch = 0;
- UINT fpRowCount = 0;
- // Get the rowcount, pitch and size of the top mip
- device->GetCopyableFootprints(
- &desc,
- 0,
- 1,
- 0,
- nullptr,
- &fpRowCount,
- &fpRowPitch,
- &totalResourceSize);
-
- // Round up the srcPitch to multiples of 256
- UINT64 dstRowPitch = (fpRowPitch + 255) & ~0xFF;
-
- if (dstRowPitch > UINT32_MAX)
- return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
-
- ComPtr pStaging;
- HRESULT hr = CaptureTexture(device.Get(), pCommandQ, pSource, dstRowPitch, desc, pStaging, beforeState, afterState);
- if (FAILED(hr))
- return hr;
-
- // Determine source format's WIC equivalent
- WICPixelFormatGUID pfGuid;
- bool sRGB = false;
- switch ( desc.Format )
- {
- case DXGI_FORMAT_R32G32B32A32_FLOAT: pfGuid = GUID_WICPixelFormat128bppRGBAFloat; break;
- case DXGI_FORMAT_R16G16B16A16_FLOAT: pfGuid = GUID_WICPixelFormat64bppRGBAHalf; break;
- case DXGI_FORMAT_R16G16B16A16_UNORM: pfGuid = GUID_WICPixelFormat64bppRGBA; break;
- case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: pfGuid = GUID_WICPixelFormat32bppRGBA1010102XR; break;
- case DXGI_FORMAT_R10G10B10A2_UNORM: pfGuid = GUID_WICPixelFormat32bppRGBA1010102; break;
- case DXGI_FORMAT_B5G5R5A1_UNORM: pfGuid = GUID_WICPixelFormat16bppBGRA5551; break;
- case DXGI_FORMAT_B5G6R5_UNORM: pfGuid = GUID_WICPixelFormat16bppBGR565; break;
- case DXGI_FORMAT_R32_FLOAT: pfGuid = GUID_WICPixelFormat32bppGrayFloat; break;
- case DXGI_FORMAT_R16_FLOAT: pfGuid = GUID_WICPixelFormat16bppGrayHalf; break;
- case DXGI_FORMAT_R16_UNORM: pfGuid = GUID_WICPixelFormat16bppGray; break;
- case DXGI_FORMAT_R8_UNORM: pfGuid = GUID_WICPixelFormat8bppGray; break;
- case DXGI_FORMAT_A8_UNORM: pfGuid = GUID_WICPixelFormat8bppAlpha; break;
-
- case DXGI_FORMAT_R8G8B8A8_UNORM:
- pfGuid = GUID_WICPixelFormat32bppRGBA;
- break;
-
- case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
- pfGuid = GUID_WICPixelFormat32bppRGBA;
- sRGB = true;
- break;
-
- case DXGI_FORMAT_B8G8R8A8_UNORM:
- pfGuid = GUID_WICPixelFormat32bppBGRA;
- break;
-
- case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
- pfGuid = GUID_WICPixelFormat32bppBGRA;
- sRGB = true;
- break;
-
- case DXGI_FORMAT_B8G8R8X8_UNORM:
- pfGuid = GUID_WICPixelFormat32bppBGR;
- break;
-
- case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
- pfGuid = GUID_WICPixelFormat32bppBGR;
- sRGB = true;
- break;
-
- default:
- return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
- }
-
- auto pWIC = _GetWIC();
- if ( !pWIC )
- return E_NOINTERFACE;
-
- ComPtr stream;
- hr = pWIC->CreateStream( stream.GetAddressOf() );
- if ( FAILED(hr) )
- return hr;
-
- hr = stream->InitializeFromFilename( fileName, GENERIC_WRITE );
- if ( FAILED(hr) )
- return hr;
-
- auto_delete_file_wic delonfail(stream, fileName);
-
- ComPtr encoder;
- hr = pWIC->CreateEncoder( guidContainerFormat, nullptr, encoder.GetAddressOf() );
- if ( FAILED(hr) )
- return hr;
-
- hr = encoder->Initialize( stream.Get(), WICBitmapEncoderNoCache );
- if ( FAILED(hr) )
- return hr;
-
- ComPtr frame;
- ComPtr props;
- hr = encoder->CreateNewFrame( frame.GetAddressOf(), props.GetAddressOf() );
- if ( FAILED(hr) )
- return hr;
-
- if ( targetFormat && memcmp( &guidContainerFormat, &GUID_ContainerFormatBmp, sizeof(WICPixelFormatGUID) ) == 0 )
- {
- // Opt-in to the WIC2 support for writing 32-bit Windows BMP files with an alpha channel
- PROPBAG2 option = {};
- option.pstrName = const_cast(L"EnableV5Header32bppBGRA");
-
- VARIANT varValue;
- varValue.vt = VT_BOOL;
- varValue.boolVal = VARIANT_TRUE;
- (void)props->Write( 1, &option, &varValue );
- }
-
- if ( setCustomProps )
- {
- setCustomProps( props.Get() );
- }
-
- hr = frame->Initialize( props.Get() );
- if ( FAILED(hr) )
- return hr;
-
- hr = frame->SetSize(static_cast(desc.Width), desc.Height );
- if ( FAILED(hr) )
- return hr;
-
- hr = frame->SetResolution( 72, 72 );
- if ( FAILED(hr) )
- return hr;
-
- // Pick a target format
- WICPixelFormatGUID targetGuid;
- if ( targetFormat )
- {
- targetGuid = *targetFormat;
- }
- else
- {
- // Screenshots don't typically include the alpha channel of the render target
- switch ( desc.Format )
- {
- case DXGI_FORMAT_R32G32B32A32_FLOAT:
- case DXGI_FORMAT_R16G16B16A16_FLOAT:
- targetGuid = GUID_WICPixelFormat96bppRGBFloat; // WIC 2
- break;
-
- case DXGI_FORMAT_R16G16B16A16_UNORM: targetGuid = GUID_WICPixelFormat48bppBGR; break;
- case DXGI_FORMAT_B5G5R5A1_UNORM: targetGuid = GUID_WICPixelFormat16bppBGR555; break;
- case DXGI_FORMAT_B5G6R5_UNORM: targetGuid = GUID_WICPixelFormat16bppBGR565; break;
-
- case DXGI_FORMAT_R32_FLOAT:
- case DXGI_FORMAT_R16_FLOAT:
- case DXGI_FORMAT_R16_UNORM:
- case DXGI_FORMAT_R8_UNORM:
- case DXGI_FORMAT_A8_UNORM:
- targetGuid = GUID_WICPixelFormat8bppGray;
- break;
-
- default:
- targetGuid = GUID_WICPixelFormat24bppBGR;
- break;
- }
- }
-
- hr = frame->SetPixelFormat( &targetGuid );
- if ( FAILED(hr) )
- return hr;
-
- if ( targetFormat && memcmp( targetFormat, &targetGuid, sizeof(WICPixelFormatGUID) ) != 0 )
- {
- // Requested output pixel format is not supported by the WIC codec
- return E_FAIL;
- }
-
- // Encode WIC metadata
- ComPtr metawriter;
- if ( SUCCEEDED( frame->GetMetadataQueryWriter( metawriter.GetAddressOf() ) ) )
- {
- PROPVARIANT value;
- PropVariantInit( &value );
-
- value.vt = VT_LPSTR;
- value.pszVal = const_cast("DirectXTK");
-
- if ( memcmp( &guidContainerFormat, &GUID_ContainerFormatPng, sizeof(GUID) ) == 0 )
- {
- // Set Software name
- (void)metawriter->SetMetadataByName( L"/tEXt/{str=Software}", &value );
-
- // Set sRGB chunk
- if (sRGB)
- {
- value.vt = VT_UI1;
- value.bVal = 0;
- (void)metawriter->SetMetadataByName(L"/sRGB/RenderingIntent", &value);
- }
- else
- {
- // add gAMA chunk with gamma 1.0
- value.vt = VT_UI4;
- value.uintVal = 100000; // gama value * 100,000 -- i.e. gamma 1.0
- (void)metawriter->SetMetadataByName(L"/gAMA/ImageGamma", &value);
-
- // remove sRGB chunk which is added by default.
- (void)metawriter->RemoveMetadataByName(L"/sRGB/RenderingIntent");
- }
- }
- else
- {
- // Set Software name
- (void)metawriter->SetMetadataByName( L"System.ApplicationName", &value );
-
- if ( sRGB )
- {
- // Set EXIF Colorspace of sRGB
- value.vt = VT_UI2;
- value.uiVal = 1;
- (void)metawriter->SetMetadataByName( L"System.Image.ColorSpace", &value );
- }
- }
- }
-
- UINT64 imageSize = dstRowPitch * UINT64(desc.Height);
- if (imageSize > UINT32_MAX)
- return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
-
- void* pMappedMemory = nullptr;
- D3D12_RANGE readRange = {0, static_cast(imageSize)};
- D3D12_RANGE writeRange = {0, 0};
- hr = pStaging->Map(0, &readRange, &pMappedMemory);
- if (FAILED(hr))
- return hr;
-
- if ( memcmp( &targetGuid, &pfGuid, sizeof(WICPixelFormatGUID) ) != 0 )
- {
- // Conversion required to write
- ComPtr source;
- hr = pWIC->CreateBitmapFromMemory(static_cast(desc.Width), desc.Height, pfGuid,
- static_cast(dstRowPitch), static_cast(imageSize),
- static_cast(pMappedMemory), source.GetAddressOf() );
- if ( FAILED(hr) )
- {
- pStaging->Unmap( 0, &writeRange );
- return hr;
- }
-
- ComPtr FC;
- hr = pWIC->CreateFormatConverter( FC.GetAddressOf() );
- if ( FAILED(hr) )
- {
- pStaging->Unmap(0, &writeRange);
- return hr;
- }
-
- BOOL canConvert = FALSE;
- hr = FC->CanConvert( pfGuid, targetGuid, &canConvert );
- if ( FAILED(hr) || !canConvert )
- {
- return E_UNEXPECTED;
- }
-
- hr = FC->Initialize( source.Get(), targetGuid, WICBitmapDitherTypeNone, nullptr, 0, WICBitmapPaletteTypeMedianCut );
- if ( FAILED(hr) )
- {
- pStaging->Unmap(0, &writeRange);
- return hr;
- }
-
- WICRect rect = { 0, 0, static_cast( desc.Width ), static_cast( desc.Height ) };
- hr = frame->WriteSource( FC.Get(), &rect );
- if ( FAILED(hr) )
- {
- pStaging->Unmap(0, &writeRange);
- return hr;
- }
- }
- else
- {
- // No conversion required
- hr = frame->WritePixels( desc.Height, static_cast(dstRowPitch), static_cast(imageSize), static_cast( pMappedMemory ) );
- if ( FAILED(hr) )
- return hr;
- }
-
- pStaging->Unmap(0, &writeRange);
-
- hr = frame->Commit();
- if ( FAILED(hr) )
- return hr;
-
- hr = encoder->Commit();
- if ( FAILED(hr) )
- return hr;
-
- delonfail.clear();
-
- return S_OK;
-}
diff --git a/thirdparty/libpng b/thirdparty/libpng
deleted file mode 160000
index a37d483..0000000
--- a/thirdparty/libpng
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit a37d4836519517bdce6cb9d956092321eca3e73b
diff --git a/thirdparty/zlib-ng b/thirdparty/zlib-ng
deleted file mode 160000
index b56a2fd..0000000
--- a/thirdparty/zlib-ng
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit b56a2fd0b126cfe5f13e68ab9090cd4f6a773286