diff --git a/.gitmodules b/.gitmodules
index 40411be..ec54d46 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -14,3 +14,11 @@
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"]
+ path = thirdparty/zlib
+ url = https://github.com/madler/zlib.git
+ branch = master
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1b63b15..c1013d1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,7 +19,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin")
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
-# Add Vulkan headers on ARM since there is no official Vulkan SDK
+# Add Vulkan headers on ARM since there is no official ARM Vulkan SDK
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")
add_subdirectory(thirdparty/Vulkan-Headers)
set(RTXGI_API_VULKAN_SDK "1")
@@ -47,6 +47,26 @@ 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
+ set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "" FORCE)
+ set(CMAKE_DEBUG_POSTFIX "" CACHE STRING "override debug postfix")
+ option(ASM686 "" OFF)
+ option(AMD64 "" OFF)
+ add_subdirectory(thirdparty/zlib)
+ target_compile_options(zlib BEFORE PUBLIC /wd4267) # suppress the implicit conversion warning
+ set_target_properties(zlib zlibstatic example minigzip PROPERTIES FOLDER "Thirdparty/zlib" DEBUG_POSTFIX "")
+
+ # 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)
+ set(ZLIB_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/thirdparty/zlib" "${CMAKE_BINARY_DIR}/thirdparty/zlib")
+ add_subdirectory(thirdparty/libpng)
+ set_target_properties(png_static genfiles PROPERTIES FOLDER "Thirdparty/libpng" DEBUG_POSTFIX "")
+
# Samples
add_subdirectory(samples)
endif()
diff --git a/ChangeLog.md b/ChangeLog.md
index 50f40e4..2b224bf 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,34 @@
# RTXGI SDK Change Log
+## 1.2.07
+
+### SDK
+
+Features and Improvements:
+- Shader improvements for probe data reads/writes
+ - The probe data texture now uses the same layout as the irradiance and distance textures
+ - This change makes probe data visualizations easier to understand
+- Adds a RWTexture2D variant of ```DDGILoadProbeState()```
+- Uses the ```DDGILoadProbeState()``` convenience function where appropriate
+- Moved the ```data``` member of the ```DDGIVolumeDescGPU``` struct inside the ```GetPackedData()``` function so the struct size is the same on the CPU and GPU
+- Updated stale code comments (non-functional)
+- Bumped SDK revision number and version string
+
+Bug Fixes:
+- ```DDGIGetVolumeBlendWeight```: fixed regression related to volume edge fade not respecting rotations
+
+### Test Harness
+
+Features and Improvements:
+- ```ProbeTraceRGS.hlsl```: no longer performs lighting for fixed rays when probe relocation is enabled (performance optimization)
+- Adds a performance benchmark mode that collects CPU and GPU performance data and outputs the results to ```*.csv``` files
+ - Press the ```F2``` key to run a benchmark
+- Adds the ability to store intermediate textures (back buffer, GBuffer, RTAO, and DDGIVolume textures) to disk
+ - Uses the zlib and libpng libraries for cross-platform compatibility
+ - Press the ```F1``` key to save the current image data to disk
+- ```VolumeTexturesCS.hlsl```: minor updates to the layout order of visualized textures
+- Config file and documentation updates
+
## 1.2.04
### SDK
diff --git a/docs/DDGIVolume.md b/docs/DDGIVolume.md
index e137e3e..0ab3e72 100644
--- a/docs/DDGIVolume.md
+++ b/docs/DDGIVolume.md
@@ -369,11 +369,11 @@ This texture stores world-space offsets and classification states for all probes
- ```ProbeDataCommon.hlsl``` contains helper functions for reading and writing world-space offset data.
- Probe classification state is stored in the W channel.
-The texture's layout is the same as the irradiance and distance texture altases, except each probe uses just *one texel*. Below is a visualization of the probe data texture's world-space offsets (top) and probe states (bottom).
+The texture's layout is the same as the irradiance and distance texture altases, except here each probe is represented by just *one texel*. Below is a visualization of the probe data texture's world-space offsets (top) and probe states (bottom).
diff --git a/docs/ShaderAPI.md b/docs/ShaderAPI.md
index 9ad2008..1042bc1 100644
--- a/docs/ShaderAPI.md
+++ b/docs/ShaderAPI.md
@@ -52,9 +52,14 @@ The Test Harness sample application provides [an example ray generation shader](
Computes the 3D grid-space coordinates for the probe at a given probe index in the range [0, numProbes]. Provide these coordinates to ```DDGIGetProbeWorldPosition()``` and ```DDGIGetScrollingProbeIndex()```.
-#### ```DDGIGetProbeState(...)```
+#### ```DDGILoadProbeState(...)```
- float DDGIGetProbeState(
+ float DDGILoadProbeState(
+ int probeIndex,
+ RWTexture2D probeData,
+ DDGIVolumeDescGPU volume)
+
+ float DDGILoadProbeState(
int probeIndex,
Texture2D probeData,
DDGIVolumeDescGPU volume)
diff --git a/docs/images/ddgivolume-textures-probedata.jpg b/docs/images/ddgivolume-textures-probedata.jpg
index 7b067eb..af31fee 100644
Binary files a/docs/images/ddgivolume-textures-probedata.jpg and b/docs/images/ddgivolume-textures-probedata.jpg differ
diff --git a/rtxgi-sdk/.gitignore b/rtxgi-sdk/.gitignore
deleted file mode 100644
index a007fea..0000000
--- a/rtxgi-sdk/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-build/*
diff --git a/rtxgi-sdk/include/rtxgi/Common.h b/rtxgi-sdk/include/rtxgi/Common.h
index 7167b65..b0e5cdb 100644
--- a/rtxgi-sdk/include/rtxgi/Common.h
+++ b/rtxgi-sdk/include/rtxgi/Common.h
@@ -20,11 +20,11 @@ namespace rtxgi
{
static const int major = 1;
static const int minor = 2;
- static const int revision = 4;
+ static const int revision = 7;
inline static const char* getVersionString()
{
- return "1.2.04";
+ return "1.2.07";
}
};
diff --git a/rtxgi-sdk/include/rtxgi/ddgi/DDGIVolumeDescGPU.h b/rtxgi-sdk/include/rtxgi/ddgi/DDGIVolumeDescGPU.h
index 1f9474a..94158bf 100644
--- a/rtxgi-sdk/include/rtxgi/ddgi/DDGIVolumeDescGPU.h
+++ b/rtxgi-sdk/include/rtxgi/ddgi/DDGIVolumeDescGPU.h
@@ -95,9 +95,9 @@ struct DDGIVolumeDescGPU
bool probeScrollClear[3]; // whether probes of a plane need to be cleared due to scrolling movement
#ifndef HLSL
- rtxgi::DDGIVolumeDescGPUPacked data;
rtxgi::DDGIVolumeDescGPUPacked GetPackedData()
{
+ rtxgi::DDGIVolumeDescGPUPacked data;
data.origin = origin;
data.probeHysteresis = probeHysteresis;
data.rotation = rotation;
diff --git a/rtxgi-sdk/include/rtxgi/ddgi/gfx/DDGIVolume_D3D12.h b/rtxgi-sdk/include/rtxgi/ddgi/gfx/DDGIVolume_D3D12.h
index 760edeb..136e70c 100644
--- a/rtxgi-sdk/include/rtxgi/ddgi/gfx/DDGIVolume_D3D12.h
+++ b/rtxgi-sdk/include/rtxgi/ddgi/gfx/DDGIVolume_D3D12.h
@@ -128,7 +128,7 @@ namespace rtxgi
ID3D12Resource* constantsBuffer = nullptr; // Constants structured buffer resource pointer (device)
- // Provide these resources if you use DDGIVolume::Upload() to transfer constants to the GPU
+ // Provide these resources if you use UploadDDGIVolumeConstants() to transfer constants to the GPU
ID3D12Resource* constantsBufferUpload = nullptr; // [Optional] Constants structured buffer resource pointer (upload)
UINT64 constantsBufferSizeInBytes = 0; // [Optional] Size (in bytes) of the constants structured buffer
};
@@ -261,7 +261,7 @@ namespace rtxgi
ID3D12Device* m_device = nullptr; // D3D12 device pointer
#endif
- // Constants (if you use the DDGIVolume::Upload() to transfer constants to the GPU)
+ // Constants (if you use UploadDDGIVolumeConstants() to transfer constants to the GPU)
ID3D12Resource* m_constantsBuffer = nullptr; // Structured buffer that stores the volume's constants (device)
ID3D12Resource* m_constantsBufferUpload = nullptr; // Structured buffer that stores the volume's constants (upload)
UINT64 m_constantsBufferSizeInBytes = 0; // Size (in bytes) of the structured buffer that stores *all* volumes constants
diff --git a/rtxgi-sdk/include/rtxgi/ddgi/gfx/DDGIVolume_VK.h b/rtxgi-sdk/include/rtxgi/ddgi/gfx/DDGIVolume_VK.h
index 79a2226..951b379 100644
--- a/rtxgi-sdk/include/rtxgi/ddgi/gfx/DDGIVolume_VK.h
+++ b/rtxgi-sdk/include/rtxgi/ddgi/gfx/DDGIVolume_VK.h
@@ -142,7 +142,7 @@ namespace rtxgi
VkBuffer constantsBuffer = nullptr; // Constants structured buffer (device)
- // Provide these resources if you use DDGIVolume::Upload() to transfer constants to the GPU
+ // Provide these resources if you use UploadDDGIVolumeConstants() to transfer constants to the GPU
VkBuffer constantsBufferUpload = nullptr; // [Optional] Constants structured buffer (upload)
VkDeviceMemory constantsBufferUploadMemory = nullptr; // [Optional] Constants structured buffer memory (upload)
uint64_t constantsBufferSizeInBytes = 0; // [Optional] Size (in bytes) of the constants structured buffer
@@ -307,7 +307,7 @@ namespace rtxgi
VkDescriptorPool m_descriptorPool = nullptr; // Vulkan descriptor pool handle
#endif
- // Constants (if you use the DDGIVolume::Upload() to transfer constants to the GPU)
+ // Constants (if you use UploadDDGIVolumeConstants() to transfer constants to the GPU)
VkBuffer m_constantsBuffer = nullptr; // Structured buffer that stores the volume's constants (device)
VkBuffer m_constantsBufferUpload = nullptr; // Structured buffer that stores the volume's constants (upload)
VkDeviceMemory m_constantsBufferUploadMemory = nullptr; // Memory for the volume's constants upload structured buffer
diff --git a/rtxgi-sdk/shaders/ddgi/Irradiance.hlsl b/rtxgi-sdk/shaders/ddgi/Irradiance.hlsl
index 78521a9..05364be 100644
--- a/rtxgi-sdk/shaders/ddgi/Irradiance.hlsl
+++ b/rtxgi-sdk/shaders/ddgi/Irradiance.hlsl
@@ -38,12 +38,14 @@ float3 DDGIGetSurfaceBias(float3 surfaceNormal, float3 cameraDirection, DDGIVolu
*/
float DDGIGetVolumeBlendWeight(float3 worldPosition, DDGIVolumeDescGPU volume)
{
- // Get the volume's origin
+ // Get the volume's origin and extent
float3 origin = volume.origin + (volume.probeScrollOffsets * volume.probeSpacing);
-
- // Get spatial delta between the world position and the volume
float3 extent = (volume.probeSpacing * (volume.probeCounts - 1)) * 0.5f;
- float3 position = abs(worldPosition - origin);
+
+ // Get the delta between the (rotated volume) and the world-space position
+ float3 position = (worldPosition - origin);
+ position = abs(RTXGIQuaternionRotate(position, RTXGIQuaternionConjugate(volume.rotation)));
+
float3 delta = position - extent;
if(all(delta < 0)) return 1.f;
@@ -99,13 +101,8 @@ float3 DDGIGetVolumeIrradiance(
int adjacentProbeIndex = DDGIGetScrollingProbeIndex(adjacentProbeCoords, volume);
// Early Out: don't allow inactive probes to contribute to irradiance
- if (volume.probeClassificationEnabled)
- {
- // Get the probe state
- int2 probeDataCoords = DDGIGetProbeDataTexelCoords(adjacentProbeIndex, volume);
- int probeState = resources.probeData[probeDataCoords].w;
- if (probeState == RTXGI_DDGI_PROBE_STATE_INACTIVE) continue;
- }
+ int probeState = DDGILoadProbeState(adjacentProbeIndex, resources.probeData, volume);
+ if (probeState == RTXGI_DDGI_PROBE_STATE_INACTIVE) continue;
// Get the adjacent probe's world position
float3 adjacentProbeWorldPosition = DDGIGetProbeWorldPosition(adjacentProbeCoords, volume, resources.probeData);
diff --git a/rtxgi-sdk/shaders/ddgi/ProbeBlendingCS.hlsl b/rtxgi-sdk/shaders/ddgi/ProbeBlendingCS.hlsl
index ccff9da..0b82f0a 100644
--- a/rtxgi-sdk/shaders/ddgi/ProbeBlendingCS.hlsl
+++ b/rtxgi-sdk/shaders/ddgi/ProbeBlendingCS.hlsl
@@ -406,13 +406,8 @@ void DDGIProbeBlendingCS(uint3 DispatchThreadID : SV_DispatchThreadID, uint Grou
}
// Early Out: don't blend rays for probes that are inactive
- if(volume.probeClassificationEnabled)
- {
- // Get the probe state
- int2 probeDataCoords = DDGIGetProbeDataTexelCoords(probeIndex, volume);
- int probeState = ProbeData[probeDataCoords].w;
- if (probeState == RTXGI_DDGI_PROBE_STATE_INACTIVE) return;
- }
+ int probeState = DDGILoadProbeState(probeIndex, ProbeData, volume);
+ if (probeState == RTXGI_DDGI_PROBE_STATE_INACTIVE) return;
// Visualize the probe index
#if RTXGI_DDGI_BLEND_RADIANCE && RTXGI_DDGI_DEBUG_PROBE_INDEXING
diff --git a/rtxgi-sdk/shaders/ddgi/ProbeClassificationCS.hlsl b/rtxgi-sdk/shaders/ddgi/ProbeClassificationCS.hlsl
index a55d453..c71c43b 100644
--- a/rtxgi-sdk/shaders/ddgi/ProbeClassificationCS.hlsl
+++ b/rtxgi-sdk/shaders/ddgi/ProbeClassificationCS.hlsl
@@ -288,7 +288,7 @@ void DDGIProbeClassificationCS(uint3 DispatchThreadID : SV_DispatchThreadID)
}
// Get the probe's texel coordinates in the Probe Data texture
- uint2 probeDataCoords = DDGIGetProbeDataTexelCoords(probeIndex, volume);
+ uint2 probeDataCoords = DDGIGetProbeTexelCoords(probeIndex, volume);
// Early out: number of backface hits has been exceeded. The probe is probably inside geometry.
if(((float)backfaceCount / (float)RTXGI_DDGI_NUM_FIXED_RAYS) > volume.probeBackfaceThreshold)
@@ -369,7 +369,7 @@ void DDGIProbeClassificationResetCS(uint3 DispatchThreadID : SV_DispatchThreadID
#endif
// Get the probe's texel coordinates in the Probe Data texture
- uint2 probeDataCoords = DDGIGetProbeDataTexelCoords(DispatchThreadID.x, volume);
+ uint2 probeDataCoords = DDGIGetProbeTexelCoords(DispatchThreadID.x, volume);
ProbeData[probeDataCoords].w = RTXGI_DDGI_PROBE_STATE_ACTIVE;
}
diff --git a/rtxgi-sdk/shaders/ddgi/ProbeRelocationCS.hlsl b/rtxgi-sdk/shaders/ddgi/ProbeRelocationCS.hlsl
index ba26c9b..b6c4224 100644
--- a/rtxgi-sdk/shaders/ddgi/ProbeRelocationCS.hlsl
+++ b/rtxgi-sdk/shaders/ddgi/ProbeRelocationCS.hlsl
@@ -268,7 +268,7 @@ void DDGIProbeRelocationCS(uint3 DispatchThreadID : SV_DispatchThreadID)
#endif
// Get the probe's texel coordinates in the Probe Data texture
- uint2 coords = DDGIGetProbeDataTexelCoords(probeIndex, volume);
+ uint2 coords = DDGIGetProbeTexelCoords(probeIndex, volume);
// Read the current world position offset
float3 offset = DDGILoadProbeDataOffset(ProbeData, coords, volume);
@@ -387,7 +387,7 @@ void DDGIProbeRelocationResetCS(uint3 DispatchThreadID : SV_DispatchThreadID)
#endif
// Get the probe's texel coordinates in the Probe Data texture
- uint2 probeDataCoords = DDGIGetProbeDataTexelCoords(DispatchThreadID.x, volume);
+ uint2 probeDataCoords = DDGIGetProbeTexelCoords(DispatchThreadID.x, volume);
// Write the probe offset
ProbeData[probeDataCoords].xyz = float3(0.f, 0.f, 0.f);
diff --git a/rtxgi-sdk/shaders/ddgi/include/ProbeCommon.hlsl b/rtxgi-sdk/shaders/ddgi/include/ProbeCommon.hlsl
index a08e345..8856cfe 100644
--- a/rtxgi-sdk/shaders/ddgi/include/ProbeCommon.hlsl
+++ b/rtxgi-sdk/shaders/ddgi/include/ProbeCommon.hlsl
@@ -62,7 +62,7 @@ float3 DDGIGetProbeWorldPosition(int3 probeCoords, DDGIVolumeDescGPU volume, Tex
int probeIndex = DDGIGetScrollingProbeIndex(probeCoords, volume);
// Find the texture coordinates of the probe in the Probe Data texture
- uint2 coords = DDGIGetProbeDataTexelCoords(probeIndex, volume);
+ uint2 coords = DDGIGetProbeTexelCoords(probeIndex, volume);
// Load the probe's world-space position offset and add it to the current world position
probeWorldPosition += DDGILoadProbeDataOffset(probeData, coords, volume);
@@ -88,7 +88,7 @@ float3 DDGIGetProbeWorldPosition(int3 probeCoords, DDGIVolumeDescGPU volume, RWT
int probeIndex = DDGIGetScrollingProbeIndex(probeCoords, volume);
// Find the texture coordinates of the probe in the Probe Data texture
- uint2 coords = DDGIGetProbeDataTexelCoords(probeIndex, volume);
+ uint2 coords = DDGIGetProbeTexelCoords(probeIndex, volume);
// Load the probe's world-space position offset and add it to the current world position
probeWorldPosition += DDGILoadProbeDataOffset(probeData, coords, volume);
diff --git a/rtxgi-sdk/shaders/ddgi/include/ProbeIndexing.hlsl b/rtxgi-sdk/shaders/ddgi/include/ProbeIndexing.hlsl
index 70b1894..660ae5e 100644
--- a/rtxgi-sdk/shaders/ddgi/include/ProbeIndexing.hlsl
+++ b/rtxgi-sdk/shaders/ddgi/include/ProbeIndexing.hlsl
@@ -172,22 +172,17 @@ int3 DDGIGetBaseProbeGridCoords(float3 worldPosition, DDGIVolumeDescGPU volume)
//------------------------------------------------------------------------
/**
- * Computes the normalized texture UVs for the Probe Irradiance and Probe Distance textures
- * used in blending given the probe index and 2D normalized octant coordinates [-1, 1].
- *
+ * Computes the 2D texture coordinates of the probe at the given probe index.
+ *
* When infinite scrolling is enbled, probeIndex is expected to be the scroll adjusted probe index.
* Obtain the adjusted index with DDGIGetScrollingProbeIndex().
*/
-float2 DDGIGetProbeUV(int probeIndex, float2 octantCoordinates, int numTexels, DDGIVolumeDescGPU volume)
+uint2 DDGIGetProbeTexelCoords(int probeIndex, DDGIVolumeDescGPU volume)
{
// Find the probe's plane index
int probesPerPlane = DDGIGetProbesPerPlane(volume.probeCounts);
int planeIndex = int(probeIndex / probesPerPlane);
- // Account for the border texels
- float probeInteriorTexels = float(numTexels);
- float probeTexels = (probeInteriorTexels + 2.f);
-
#if RTXGI_COORDINATE_SYSTEM == RTXGI_COORDINATE_SYSTEM_LEFT || RTXGI_COORDINATE_SYSTEM == RTXGI_COORDINATE_SYSTEM_RIGHT
int gridSpaceX = (probeIndex % volume.probeCounts.x);
int gridSpaceY = (probeIndex / volume.probeCounts.x);
@@ -208,6 +203,25 @@ float2 DDGIGetProbeUV(int probeIndex, float2 octantCoordinates, int numTexels, D
int y = gridSpaceY % volume.probeCounts.y;
#endif
+ return uint2(x, y);
+}
+
+/**
+ * Computes the normalized texture UVs for the Probe Irradiance and Probe Distance textures
+ * (used in blending) given the probe index and 2D normalized octant coordinates [-1, 1].
+ *
+ * When infinite scrolling is enbled, probeIndex is expected to be the scroll adjusted probe index.
+ * Obtain the adjusted index with DDGIGetScrollingProbeIndex().
+ */
+float2 DDGIGetProbeUV(int probeIndex, float2 octantCoordinates, int numTexels, DDGIVolumeDescGPU volume)
+{
+ // Get the probe's texel coordinates, assuming one texel per probe
+ uint2 coords = DDGIGetProbeTexelCoords(probeIndex, volume);
+
+ // Adjust for the number of interior and border texels
+ float probeInteriorTexels = float(numTexels);
+ float probeTexels = (probeInteriorTexels + 2.f);
+
#if RTXGI_COORDINATE_SYSTEM == RTXGI_COORDINATE_SYSTEM_LEFT || RTXGI_COORDINATE_SYSTEM == RTXGI_COORDINATE_SYSTEM_RIGHT
float textureWidth = probeTexels * (volume.probeCounts.x * volume.probeCounts.y);
float textureHeight = probeTexels * volume.probeCounts.z;
@@ -219,34 +233,33 @@ float2 DDGIGetProbeUV(int probeIndex, float2 octantCoordinates, int numTexels, D
float textureHeight = probeTexels * volume.probeCounts.y;
#endif
- float2 uv = float2(x * probeTexels, y * probeTexels) + (probeTexels * 0.5f);
+ float2 uv = float2(coords.x * probeTexels, coords.y * probeTexels) + (probeTexels * 0.5f);
uv += octantCoordinates.xy * (probeInteriorTexels * 0.5f);
uv /= float2(textureWidth, textureHeight);
return uv;
}
+//------------------------------------------------------------------------
+// Probe Classification
+//------------------------------------------------------------------------
+
/**
- * Computes the 2D texture coordinates of the probe at the given probe index
- * for the Probe Data texture used in relocation and classification.
- *
- * When infinite scrolling is enbled, probeIndex is expected to be the scroll adjusted probe index.
- * Obtain the adjusted index with DDGIGetScrollingProbeIndex().
+ * Loads and returns the probe's classification state (from a RWTexture2D).
*/
-uint2 DDGIGetProbeDataTexelCoords(int probeIndex, DDGIVolumeDescGPU volume)
+float DDGILoadProbeState(int probeIndex, RWTexture2D probeData, DDGIVolumeDescGPU volume)
{
- // Compute the probe texel coordinates for this probe
-#if RTXGI_COORDINATE_SYSTEM == RTXGI_COORDINATE_SYSTEM_LEFT || RTXGI_COORDINATE_SYSTEM == RTXGI_COORDINATE_SYSTEM_RIGHT
- return uint2(probeIndex % (volume.probeCounts.x * volume.probeCounts.y), probeIndex / (volume.probeCounts.x * volume.probeCounts.y));
-#elif RTXGI_COORDINATE_SYSTEM == RTXGI_COORDINATE_SYSTEM_LEFT_Z_UP
- return uint2(probeIndex % (volume.probeCounts.y * volume.probeCounts.z), probeIndex / (volume.probeCounts.y * volume.probeCounts.z));
-#elif RTXGI_COORDINATE_SYSTEM == RTXGI_COORDINATE_SYSTEM_RIGHT_Z_UP
- return uint2(probeIndex % (volume.probeCounts.x * volume.probeCounts.z), probeIndex / (volume.probeCounts.x * volume.probeCounts.z));
-#endif
-}
+ float state = RTXGI_DDGI_PROBE_STATE_ACTIVE;
+ if (volume.probeClassificationEnabled)
+ {
+ // Get the probe's texel coordinates in the Probe Data texture
+ int2 probeDataCoords = DDGIGetProbeTexelCoords(probeIndex, volume);
-//------------------------------------------------------------------------
-// Probe Classification
-//------------------------------------------------------------------------
+ // Get the probe's classification state
+ state = probeData[probeDataCoords].w;
+ }
+
+ return state;
+}
/**
* Loads and returns the probe's classification state (from a Texture2D).
@@ -257,7 +270,7 @@ float DDGILoadProbeState(int probeIndex, Texture2D probeData, DDGIVolume
if (volume.probeClassificationEnabled)
{
// Get the probe's texel coordinates in the Probe Data texture
- int2 probeDataCoords = DDGIGetProbeDataTexelCoords(probeIndex, volume);
+ int2 probeDataCoords = DDGIGetProbeTexelCoords(probeIndex, volume);
// Get the probe's classification state
state = probeData.Load(int3(probeDataCoords, 0)).w;
diff --git a/samples/test-harness/CMakeLists.txt b/samples/test-harness/CMakeLists.txt
index a49e52e..b6e0374 100644
--- a/samples/test-harness/CMakeLists.txt
+++ b/samples/test-harness/CMakeLists.txt
@@ -35,21 +35,25 @@ file(GLOB TEST_HARNESS_CONFIG
)
file(GLOB TEST_HARNESS_SOURCE
+ "include/Benchmark.h"
"include/Caches.h"
"include/Common.h"
"include/Configs.h"
"include/Geometry.h"
"include/Graphics.h"
+ "include/ImageCapture.h"
"include/Inputs.h"
"include/Instrumentation.h"
"include/Scenes.h"
"include/Shaders.h"
"include/Textures.h"
"include/Window.h"
+ "src/Benchmark.cpp"
"src/Caches.cpp"
"src/Configs.cpp"
"src/Geometry.cpp"
"src/Inputs.cpp"
+ "src/ImageCapture.cpp"
"src/Instrumentation.cpp"
"src/main.cpp"
"src/Scenes.cpp"
@@ -264,6 +268,7 @@ 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 --------------------------------------------------------------------------------------
@@ -294,7 +299,7 @@ if(RTXGI_API_D3D12_ENABLE)
)
# Add dependencies
- add_dependencies(${TARGET_EXE} glfw tinygltf)
+ add_dependencies(${TARGET_EXE} glfw tinygltf png_static zlibstatic)
# Add the include directories
target_include_directories(${TARGET_EXE} PRIVATE
@@ -309,6 +314,7 @@ if(RTXGI_API_D3D12_ENABLE)
${IMGUI_INCLUDE}
${IMGUI_BACKENDS_INCLUDE}
${TINYGLTF_INCLUDE}
+ ${LIBPNG_INCLUDE}
)
# Add statically linked libs
@@ -318,6 +324,8 @@ if(RTXGI_API_D3D12_ENABLE)
d3d11
d3d12
dxgi
+ ../../thirdparty/libpng/$/libpng16_static
+ ../../thirdparty/zlib/$/zlibstatic
)
# Add common compiler definitions for exposed Test Harness options
@@ -330,7 +338,7 @@ if(RTXGI_API_D3D12_ENABLE)
set_target_properties(${TARGET_EXE} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ../bin/d3d12/$)
# Set the default scene config
- set_target_properties(${TARGET_EXE} PROPERTIES VS_DEBUGGER_COMMAND_ARGUMENTS ../../../samples/test-harness/config/cornell.ini)
+ set_target_properties(${TARGET_EXE} PROPERTIES VS_DEBUGGER_COMMAND_ARGUMENTS ${CMAKE_SOURCE_DIR}/samples/test-harness/config/cornell.ini)
# Add to the samples folder
set_target_properties(${TARGET_EXE} PROPERTIES FOLDER "RTXGI Samples")
@@ -376,6 +384,7 @@ if(RTXGI_API_VULKAN_ENABLE)
${IMGUI_INCLUDE}
${IMGUI_BACKENDS_INCLUDE}
${TINYGLTF_INCLUDE}
+ ${LIBPNG_INCLUDE}
)
# Add VS filters
@@ -425,12 +434,13 @@ if(RTXGI_API_VULKAN_ENABLE)
${IMGUI_INCLUDE}
${IMGUI_BACKENDS_INCLUDE}
${TINYGLTF_INCLUDE}
+ ${LIBPNG_INCLUDE}
)
endif()
# Add dependencies
- add_dependencies(${TARGET_EXE} glfw tinygltf)
+ add_dependencies(${TARGET_EXE} glfw tinygltf png_static zlibstatic)
# Add compiler definitions
target_compile_definitions(${TARGET_EXE} PUBLIC API_VULKAN)
@@ -444,17 +454,17 @@ 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} ../../thirdparty/glfw/src/$/glfw3 d3d11)
+ target_link_libraries(${TARGET_EXE} RTXGI-VK ${Vulkan_LIBRARY} ../../thirdparty/glfw/src/$/glfw3 d3d11 ../../thirdparty/libpng/$/libpng16_static ../../thirdparty/zlib/$/zlibstatic)
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)
+ target_link_libraries(${TARGET_EXE} RTXGI-VK -llibpng16_static -lz -lglfw -lvulkan -ldl -lpthread -lX11 -lXrandr -lXi -lstdc++fs)
endif()
# Set the binary output directory
set_target_properties(${TARGET_EXE} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ../bin/vulkan/$)
# Set the default scene config
- set_target_properties(${TARGET_EXE} PROPERTIES VS_DEBUGGER_COMMAND_ARGUMENTS ../../../samples/test-harness/config/cornell.ini)
+ set_target_properties(${TARGET_EXE} PROPERTIES VS_DEBUGGER_COMMAND_ARGUMENTS ${CMAKE_SOURCE_DIR}/samples/test-harness/config/cornell.ini)
# Add to the samples folder
set_target_properties(${TARGET_EXE} PROPERTIES FOLDER "RTXGI Samples")
@@ -514,14 +524,14 @@ if(UNIX AND RTXGI_API_VULKAN_ENABLE)
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")
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_SOURCE_DIR}/build/samples/test-harness
+ 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_SOURCE_DIR}/build/samples/test-harness
+ 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
)
diff --git a/samples/test-harness/config/cornell.ini b/samples/test-harness/config/cornell.ini
index ec736bf..5b4ec11 100644
--- a/samples/test-harness/config/cornell.ini
+++ b/samples/test-harness/config/cornell.ini
@@ -27,14 +27,14 @@ scene.lights.0.radius=4.0
scene.lights.1.name=Sun
scene.lights.1.type=0
-scene.lights.1.direction=0.6 -0.435, -0.816 # right hand, y-up
+scene.lights.1.direction=0.6 -0.435 -0.816 # right hand, y-up
scene.lights.1.color=1.0 1.0 1.0
scene.lights.1.power=1.0
scene.lights.2.name=Spot Light 1
scene.lights.2.type=1
scene.lights.2.position=0.0 1.0 0.5
-scene.lights.2.direction=0.6 -0.435, -0.816 # right hand, y-up
+scene.lights.2.direction=0.6 -0.435 -0.816 # right hand, y-up
scene.lights.2.color=1.0 1.0 1.0
scene.lights.2.power=0.0
scene.lights.2.radius=4.0
@@ -96,8 +96,8 @@ ddgi.volume.0.vis.showProbes=1
ddgi.volume.0.vis.texture.rayDataScale=0.75
ddgi.volume.0.vis.texture.irradianceScale=2.1
ddgi.volume.0.vis.texture.distanceScale=1.05
-ddgi.volume.0.vis.texture.relocationOffsetScale=5.9
-ddgi.volume.0.vis.texture.classificationStateScale=5.9
+ddgi.volume.0.vis.texture.relocationOffsetScale=16.8
+ddgi.volume.0.vis.texture.classificationStateScale=16.8
# ray traced ambient occlusion
rtao.enable=1
diff --git a/samples/test-harness/config/furnace.ini b/samples/test-harness/config/furnace.ini
index 118238b..91d8fe2 100644
--- a/samples/test-harness/config/furnace.ini
+++ b/samples/test-harness/config/furnace.ini
@@ -53,8 +53,8 @@ ddgi.volume.0.textures.rayData.format=0
ddgi.volume.0.textures.irradiance.format=0
ddgi.volume.0.textures.distance.format=0
ddgi.volume.0.textures.data.format=0
-ddgi.volume.0.origin=0.0, 0.5, 0.0 # left and right hand, y-up
-ddgi.volume.0.probeCounts=8, 3, 8
+ddgi.volume.0.origin=0.0 0.5 0.0 # left and right hand, y-up
+ddgi.volume.0.probeCounts=8 3 8
ddgi.volume.0.probeSpacing=2 1 2
ddgi.volume.0.probeNumRays=288
ddgi.volume.0.probeNumIrradianceTexels=6
@@ -68,9 +68,9 @@ ddgi.volume.0.probeBrightnessThreshold=1.0
ddgi.volume.0.vis.probeRadius=0.2
ddgi.volume.0.vis.probeDistanceDivisor=30
ddgi.volume.0.vis.showProbes=1
-ddgi.volume.0.vis.texture.rayDataScale=0.25
+ddgi.volume.0.vis.texture.rayDataScale=1.0
ddgi.volume.0.vis.texture.irradianceScale=1.0
-ddgi.volume.0.vis.texture.distanceScale=1.3
+ddgi.volume.0.vis.texture.distanceScale=1.0
ddgi.volume.0.vis.texture.relocationOffsetScale=7.0
ddgi.volume.0.vis.texture.classificationStateScale=7.0
diff --git a/samples/test-harness/config/multi-cornell.ini b/samples/test-harness/config/multi-cornell.ini
index 124360c..a4ffe0f 100644
--- a/samples/test-harness/config/multi-cornell.ini
+++ b/samples/test-harness/config/multi-cornell.ini
@@ -72,8 +72,8 @@ ddgi.volume.0.vis.showProbes=1
ddgi.volume.0.vis.texture.rayDataScale=0.75
ddgi.volume.0.vis.texture.irradianceScale=2.1
ddgi.volume.0.vis.texture.distanceScale=1.05
-ddgi.volume.0.vis.texture.relocationOffsetScale=5.9
-ddgi.volume.0.vis.texture.classificationStateScale=5.9
+ddgi.volume.0.vis.texture.relocationOffsetScale=16.81
+ddgi.volume.0.vis.texture.classificationStateScale=16.81
ddgi.volume.1.name=Cornell Box 2 Volume
ddgi.volume.1.probeRelocation.enabled=1
@@ -103,8 +103,8 @@ ddgi.volume.1.vis.showProbes=1
ddgi.volume.1.vis.texture.rayDataScale=0.75
ddgi.volume.1.vis.texture.irradianceScale=2.1
ddgi.volume.1.vis.texture.distanceScale=1.05
-ddgi.volume.1.vis.texture.relocationOffsetScale=5.9
-ddgi.volume.1.vis.texture.classificationStateScale=5.9
+ddgi.volume.1.vis.texture.relocationOffsetScale=16.81
+ddgi.volume.1.vis.texture.classificationStateScale=16.81
ddgi.volume.2.name=Cornell Box 3 Volume
ddgi.volume.2.probeRelocation.enabled=1
@@ -134,8 +134,8 @@ ddgi.volume.2.vis.showProbes=1
ddgi.volume.2.vis.texture.rayDataScale=0.75
ddgi.volume.2.vis.texture.irradianceScale=2.1
ddgi.volume.2.vis.texture.distanceScale=1.05
-ddgi.volume.2.vis.texture.relocationOffsetScale=5.9
-ddgi.volume.2.vis.texture.classificationStateScale=5.9
+ddgi.volume.2.vis.texture.relocationOffsetScale=16.81
+ddgi.volume.2.vis.texture.classificationStateScale=16.81
ddgi.volume.3.name=Cornell Box 4 Volume
ddgi.volume.3.probeRelocation.enabled=1
@@ -165,8 +165,8 @@ ddgi.volume.3.vis.showProbes=1
ddgi.volume.3.vis.texture.rayDataScale=0.75
ddgi.volume.3.vis.texture.irradianceScale=2.1
ddgi.volume.3.vis.texture.distanceScale=1.05
-ddgi.volume.3.vis.texture.relocationOffsetScale=5.9
-ddgi.volume.3.vis.texture.classificationStateScale=5.9
+ddgi.volume.3.vis.texture.relocationOffsetScale=16.81
+ddgi.volume.3.vis.texture.classificationStateScale=16.81
ddgi.volume.4.name=Cornell Box 5 Volume
ddgi.volume.4.probeRelocation.enabled=1
@@ -196,8 +196,8 @@ ddgi.volume.4.vis.showProbes=1
ddgi.volume.4.vis.texture.rayDataScale=0.75
ddgi.volume.4.vis.texture.irradianceScale=2.1
ddgi.volume.4.vis.texture.distanceScale=1.05
-ddgi.volume.4.vis.texture.relocationOffsetScale=5.9
-ddgi.volume.4.vis.texture.classificationStateScale=5.9
+ddgi.volume.4.vis.texture.relocationOffsetScale=16.81
+ddgi.volume.4.vis.texture.classificationStateScale=16.81
ddgi.volume.5.name=Cornell Box 6 Volume
ddgi.volume.5.probeRelocation.enabled=1
@@ -227,8 +227,8 @@ ddgi.volume.5.vis.showProbes=1
ddgi.volume.5.vis.texture.rayDataScale=0.75
ddgi.volume.5.vis.texture.irradianceScale=2.1
ddgi.volume.5.vis.texture.distanceScale=1.05
-ddgi.volume.5.vis.texture.relocationOffsetScale=5.9
-ddgi.volume.5.vis.texture.classificationStateScale=5.9
+ddgi.volume.5.vis.texture.relocationOffsetScale=16.81
+ddgi.volume.5.vis.texture.classificationStateScale=16.81
# ray traced ambient occlusion
rtao.enable=1
diff --git a/samples/test-harness/config/sponza.ini b/samples/test-harness/config/sponza.ini
index 4d3fd4b..6f815a8 100644
--- a/samples/test-harness/config/sponza.ini
+++ b/samples/test-harness/config/sponza.ini
@@ -77,7 +77,7 @@ ddgi.volume.0.vis.probeRadius=0.1
ddgi.volume.0.vis.probeAlpha=0.9
ddgi.volume.0.vis.probeDistanceDivisor=200
ddgi.volume.0.vis.showProbes=1
-ddgi.volume.0.vis.texture.rayDataScale=0.067
+ddgi.volume.0.vis.texture.rayDataScale=0.4
ddgi.volume.0.vis.texture.irradianceScale=0.395
ddgi.volume.0.vis.texture.distanceScale=0.24
ddgi.volume.0.vis.texture.relocationOffsetScale=3.9
diff --git a/samples/test-harness/config/tunnel.ini b/samples/test-harness/config/tunnel.ini
index 1b4f64d..176bbc3 100644
--- a/samples/test-harness/config/tunnel.ini
+++ b/samples/test-harness/config/tunnel.ini
@@ -20,7 +20,7 @@ scene.skyIntensity=1.0
# scene lights
scene.lights.0.name=Sun
scene.lights.0.type=0
-scene.lights.0.direction=1.0 -1.0, -0.7 # right hand, y-up
+scene.lights.0.direction=1.0 -1.0 -0.7 # right hand, y-up
scene.lights.0.color=1.0 1.0 1.0
scene.lights.0.power=2.2
@@ -70,10 +70,10 @@ ddgi.volume.0.vis.probeRadius=1.0
ddgi.volume.0.vis.probeDistanceDivisor=3
ddgi.volume.0.vis.showProbes=1
ddgi.volume.0.vis.texture.rayDataScale=0.3
-ddgi.volume.0.vis.texture.irradianceScale=0.805
-ddgi.volume.0.vis.texture.distanceScale=0.403
-ddgi.volume.0.vis.texture.relocationOffsetScale=4.5
-ddgi.volume.0.vis.texture.classificationStateScale=4.5
+ddgi.volume.0.vis.texture.irradianceScale=0.8
+ddgi.volume.0.vis.texture.distanceScale=0.4
+ddgi.volume.0.vis.texture.relocationOffsetScale=6.4
+ddgi.volume.0.vis.texture.classificationStateScale=6.4
# ray traced ambient occlusion
rtao.enable=1
diff --git a/samples/test-harness/config/two-rooms.ini b/samples/test-harness/config/two-rooms.ini
index 400cc29..1b125de 100644
--- a/samples/test-harness/config/two-rooms.ini
+++ b/samples/test-harness/config/two-rooms.ini
@@ -95,11 +95,11 @@ ddgi.volume.0.probeBrightnessThreshold=2.0
ddgi.volume.0.vis.probeRadius=2.0
ddgi.volume.0.vis.probeDistanceDivisor=30
ddgi.volume.0.vis.showProbes=1
-ddgi.volume.0.vis.texture.rayDataScale=0.25
-ddgi.volume.0.vis.texture.irradianceScale=1.2
-ddgi.volume.0.vis.texture.distanceScale=0.6
-ddgi.volume.0.vis.texture.relocationOffsetScale=4.0
-ddgi.volume.0.vis.texture.classificationStateScale=4.0
+ddgi.volume.0.vis.texture.rayDataScale=0.15
+ddgi.volume.0.vis.texture.irradianceScale=0.7
+ddgi.volume.0.vis.texture.distanceScale=0.35
+ddgi.volume.0.vis.texture.relocationOffsetScale=5.6
+ddgi.volume.0.vis.texture.classificationStateScale=5.6
# ray traced ambient occlusion
rtao.enable=1
diff --git a/samples/test-harness/include/Benchmark.h b/samples/test-harness/include/Benchmark.h
new file mode 100644
index 0000000..c44cd15
--- /dev/null
+++ b/samples/test-harness/include/Benchmark.h
@@ -0,0 +1,30 @@
+/*
+* 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
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#pragma once
+
+#include "Instrumentation.h"
+#include "Configs.h"
+#include "Graphics.h"
+
+#include
+
+namespace Benchmark
+{
+ const static uint32_t NumBenchmarkFrames = 1024;
+
+ struct BenchmarkRun
+ {
+ std::stringstream cpuTimingCsv;
+ std::stringstream gpuTimingCsv;
+ };
+ void StartBenchmark(BenchmarkRun& benchmarkRun, Instrumentation::Performance& perf, Configs::Config& config, Graphics::Globals& gfx);
+ bool UpdateBenchmark(BenchmarkRun& benchmarkRun, Instrumentation::Performance& perf, Configs::Config& config, Graphics::Globals& gfx, std::ofstream& log);
+}
\ No newline at end of file
diff --git a/samples/test-harness/include/Configs.h b/samples/test-harness/include/Configs.h
index 9826d2f..d41cc6c 100644
--- a/samples/test-harness/include/Configs.h
+++ b/samples/test-harness/include/Configs.h
@@ -33,6 +33,7 @@ namespace Configs
{
std::string name = "";
uint32_t index = 0;
+ uint32_t rngSeed = 0;
bool insertPerfMarkers = false;
bool showProbes = false;
diff --git a/samples/test-harness/include/Graphics.h b/samples/test-harness/include/Graphics.h
index 7a8e19c..6580f44 100644
--- a/samples/test-harness/include/Graphics.h
+++ b/samples/test-harness/include/Graphics.h
@@ -62,7 +62,7 @@ namespace Graphics
bool UpdateTimestamps(Globals& gfx, GlobalResources& gfxResources, Instrumentation::Performance& performance);
#endif
- bool WriteGBufferToDisk(Globals& gfx, GlobalResources& gfxResources, std::string directory);
+ bool WriteBackBufferToDisk(Globals& gfx, std::string directory);
namespace BindlessResourceOffsets
{
diff --git a/samples/test-harness/include/ImageCapture.h b/samples/test-harness/include/ImageCapture.h
new file mode 100644
index 0000000..f36ff4c
--- /dev/null
+++ b/samples/test-harness/include/ImageCapture.h
@@ -0,0 +1,20 @@
+/*
+* 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
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#pragma once
+
+#include
+#include
+#include
+
+namespace ImageCapture
+{
+ bool CapturePng(std::string file, uint32_t width, uint32_t height, std::vector& rows);
+}
\ No newline at end of file
diff --git a/samples/test-harness/include/Inputs.h b/samples/test-harness/include/Inputs.h
index f7262e3..af4e7f0 100644
--- a/samples/test-harness/include/Inputs.h
+++ b/samples/test-harness/include/Inputs.h
@@ -24,6 +24,7 @@ namespace Inputs
SAVE_IMAGE,
CAMERA_MOVEMENT,
FULLSCREEN_CHANGE,
+ RUN_BENCHMARK,
COUNT
};
@@ -34,7 +35,7 @@ namespace Inputs
DirectX::XMINT2 prevMousePos = { INT_MAX, INT_MAX };
bool mouseLeftBtnDown = false;
bool mouseRightBtnDown = false;
- bool saveImages = false;
+ bool runBenchmark = false;
};
bool Initialize(GLFWwindow* window, Input& input, Configs::Config& config, Scenes::Scene& scene);
diff --git a/samples/test-harness/include/Instrumentation.h b/samples/test-harness/include/Instrumentation.h
index 28885e7..91dddf5 100644
--- a/samples/test-harness/include/Instrumentation.h
+++ b/samples/test-harness/include/Instrumentation.h
@@ -14,6 +14,7 @@
#include
#include
+#include
namespace Instrumentation
{
@@ -42,12 +43,14 @@ namespace Instrumentation
this->sampleSize = sampleSize;
}
+ const static uint32_t FallbackSampleSize = 10;
+
std::string name = "";
EStatType type;
uint32_t index = 0;
uint64_t timestamp = 0;
- uint32_t sampleSize = 10;
+ uint32_t sampleSize = FallbackSampleSize;
double elapsed = 0; // milliseconds
double average = 0;
double total = 0;
@@ -56,6 +59,15 @@ namespace Instrumentation
uint32_t GetQueryBeginIndex() { return (index * 2); }
uint32_t GetQueryEndIndex() { return (index * 2) + 1; }
+ void Reset(uint32_t sampleSize = FallbackSampleSize)
+ {
+ elapsed = 0;
+ average = 0;
+ total = 0;
+ samples = {};
+ this->sampleSize = sampleSize;
+ }
+
};
struct Performance
@@ -63,27 +75,42 @@ namespace Instrumentation
std::vector gpuTimes;
std::vector cpuTimes;
+ const static uint32_t DefaultSampleSize = 50;
+
uint32_t GetNumGPUQueries() { return static_cast(gpuTimes.size() * 2); };
- Stat*& AddCPUStat(std::string name, uint32_t sampleSize = 50)
+ Stat*& AddCPUStat(std::string name, uint32_t sampleSize = DefaultSampleSize)
{
cpuTimes.emplace_back(new Stat(EStatType::CPU, name, sampleSize));
return cpuTimes.back();
}
- Stat*& AddGPUStat(std::string name, uint32_t sampleSize = 50)
+ Stat*& AddGPUStat(std::string name, uint32_t sampleSize = DefaultSampleSize)
{
uint32_t index = static_cast(gpuTimes.size());
gpuTimes.emplace_back(new Stat(EStatType::GPU, index, name, sampleSize));
return gpuTimes.back();
}
- void AddStat(std::string name, Stat*& cpu, Stat*& gpu, uint32_t sampleSize = 50)
+ void AddStat(std::string name, Stat*& cpu, Stat*& gpu, uint32_t sampleSize = DefaultSampleSize)
{
cpu = AddCPUStat(name, sampleSize);
gpu = AddGPUStat(name, sampleSize);
}
+ void Reset(uint32_t sampleSize = DefaultSampleSize)
+ {
+ for (Stat* stat : cpuTimes)
+ {
+ stat->Reset(sampleSize);
+ }
+
+ for (Stat* stat : gpuTimes)
+ {
+ stat->Reset(sampleSize);
+ }
+ }
+
void Cleanup()
{
size_t index;
@@ -102,6 +129,7 @@ namespace Instrumentation
cpuTimes.clear();
gpuTimes.clear();
}
+
};
void Begin(Stat* s);
@@ -109,6 +137,9 @@ namespace Instrumentation
void Resolve(Stat* s);
void EndAndResolve(Stat* s);
+ std::ostream& operator<<(std::ostream& os, const Stat& stat);
+ std::ostream& operator<<(std::ostream& os, std::vector& stats);
+
}
#define CPU_TIMESTAMP_BEGIN(x) Begin(x)
diff --git a/samples/test-harness/include/Vulkan.h b/samples/test-harness/include/Vulkan.h
index 0d48dc7..1408a79 100644
--- a/samples/test-harness/include/Vulkan.h
+++ b/samples/test-harness/include/Vulkan.h
@@ -397,8 +397,7 @@ namespace Graphics
void BeginRenderPass(Globals& vk);
- /*bool WriteResourceImageToDisk(Globals& gfx, ID3D12Resource* pResource, std::string folder, std::string filename, D3D12_RESOURCE_STATES state);
- bool WriteResourceImagesToDisk(Globals& gfx, Resources& resources, std::string folder);*/
+ bool WriteResourceToDisk(Globals& vk, std::string file, VkImage image, uint32_t width, uint32_t height, VkFormat imageFormat, VkImageLayout originalLayout);
#ifdef GFX_NAME_OBJECTS
void SetObjectName(VkDevice device, uint64_t handle, const char* name, VkObjectType type);
diff --git a/samples/test-harness/include/graphics/DDGI.h b/samples/test-harness/include/graphics/DDGI.h
index 3ede156..f7a5fab 100644
--- a/samples/test-harness/include/graphics/DDGI.h
+++ b/samples/test-harness/include/graphics/DDGI.h
@@ -36,5 +36,7 @@ namespace Graphics
void AddCommonShaderDefines(Shaders::ShaderProgram& shader, const DDGIVolumeDesc& volumeDesc, bool spirv);
bool CompileDDGIVolumeShaders(Globals& vk, const DDGIVolumeDesc& volumeDesc, std::vector& volumeShaders, bool spirv, std::ofstream& log);
+
+ bool WriteVolumesToDisk(Globals& globals, GlobalResources& gfxResources, Resources& resources, std::string directory);
}
}
diff --git a/samples/test-harness/include/graphics/RTAO.h b/samples/test-harness/include/graphics/RTAO.h
index e7bdf4f..f883ea1 100644
--- a/samples/test-harness/include/graphics/RTAO.h
+++ b/samples/test-harness/include/graphics/RTAO.h
@@ -32,5 +32,6 @@ namespace Graphics
void Update(Globals& globals, GlobalResources& gfxResources, Resources& resources, const Configs::Config& config);
void Execute(Globals& globals, GlobalResources& gfxResources, Resources& resources);
void Cleanup(Globals& globals, Resources& resources);
+ bool WriteRTAOBuffersToDisk(Globals& globals, GlobalResources& gfxResources, Resources& resources, std::string directory);
}
}
diff --git a/samples/test-harness/shaders/ddgi/ProbeTraceRGS.hlsl b/samples/test-harness/shaders/ddgi/ProbeTraceRGS.hlsl
index 12e2271..576e372 100644
--- a/samples/test-harness/shaders/ddgi/ProbeTraceRGS.hlsl
+++ b/samples/test-harness/shaders/ddgi/ProbeTraceRGS.hlsl
@@ -107,7 +107,7 @@ void RayGen()
// Early out: a "fixed" ray hit a front facing surface. Fixed rays are not blended since their direction
// is not random and they would bias the irradiance estimate. Don't perform lighting for these rays.
- if(volume.probeClassificationEnabled && rayIndex < RTXGI_DDGI_NUM_FIXED_RAYS)
+ if((volume.probeRelocationEnabled || volume.probeClassificationEnabled) && rayIndex < RTXGI_DDGI_NUM_FIXED_RAYS)
{
// Store the ray front face hit distance (only)
DDGIStoreProbeRayFrontfaceHit(RayData, texCoords, volume, payload.hitT);
diff --git a/samples/test-harness/shaders/ddgi/visualizations/ProbesRGS.hlsl b/samples/test-harness/shaders/ddgi/visualizations/ProbesRGS.hlsl
index fd19678..d71cb02 100644
--- a/samples/test-harness/shaders/ddgi/visualizations/ProbesRGS.hlsl
+++ b/samples/test-harness/shaders/ddgi/visualizations/ProbesRGS.hlsl
@@ -164,7 +164,7 @@ void RayGen()
// Get the probe's location in the probe data texture
Texture2D ProbeData = GetDDGIVolumeProbeDataSRV(volumeIndex);
- uint2 probeStateTexCoords = DDGIGetProbeDataTexelCoords(probeIndex, volume);
+ uint2 probeStateTexCoords = DDGIGetProbeTexelCoords(probeIndex, volume);
// Get the probe's state
float probeState = ProbeData[probeStateTexCoords].w;
@@ -257,7 +257,7 @@ void RayGenHideInactive()
// Get the probe's state
Texture2D ProbeData = GetDDGIVolumeProbeDataSRV(volumeIndex);
- uint2 probeStateTexCoords = DDGIGetProbeDataTexelCoords(probeIndex, volume);
+ uint2 probeStateTexCoords = DDGIGetProbeTexelCoords(probeIndex, volume);
float probeState = ProbeData[probeStateTexCoords].w;
if(probeState == RTXGI_DDGI_PROBE_STATE_INACTIVE) continue;
diff --git a/samples/test-harness/shaders/ddgi/visualizations/VolumeTexturesCS.hlsl b/samples/test-harness/shaders/ddgi/visualizations/VolumeTexturesCS.hlsl
index f33220f..2464bea 100644
--- a/samples/test-harness/shaders/ddgi/visualizations/VolumeTexturesCS.hlsl
+++ b/samples/test-harness/shaders/ddgi/visualizations/VolumeTexturesCS.hlsl
@@ -114,36 +114,9 @@ void CS(uint3 DispatchThreadID : SV_DispatchThreadID)
return;
}
- // Ray Data
- float2 radianceRect = float2(DDGIVolume.probeNumRays, DDGIVolume.probeCounts.x * DDGIVolume.probeCounts.y * DDGIVolume.probeCounts.z) *GetGlobalConst(ddgivis, rayDataTextureScale);
- xmax = radianceRect.x;
- ymin += distanceRect.y + 5;
- ymax = (ymin + radianceRect.y);
- if (DispatchThreadID.x <= xmax && DispatchThreadID.y > ymin && DispatchThreadID.y <= ymax)
- {
- Texture2D RayData = GetDDGIVolumeRayDataSRV(volumeIndex);
-
- // Sample the ray data texture
- coords = float2(DispatchThreadID.x, (DispatchThreadID.y - ymin)) / radianceRect.xy;
-
- if(DDGIVolume.probeRayDataFormat == RTXGI_DDGI_FORMAT_PROBE_RAY_DATA_R32G32B32A32_FLOAT)
- {
- color = RayData.SampleLevel(PointClampSampler, coords, 0).rgb;
- }
- else if(DDGIVolume.probeRayDataFormat == RTXGI_DDGI_FORMAT_PROBE_RAY_DATA_R32G32_FLOAT)
- {
- color = RTXGIUintToFloat3(asuint(RayData.SampleLevel(PointClampSampler, coords, 0).r));
- }
-
- // Overwrite GBufferA's albedo and mark the pixel to not be lit
- GBufferA[DispatchThreadID.xy] = float4(color, 0.f);
-
- return;
- }
-
// Relocation offsets
float2 offsetRect = 0;
- ymin += radianceRect.y + 5;
+ ymin += distanceRect.y + 5;
if (DDGIVolume.probeRelocationEnabled)
{
offsetRect = numProbes.xy * GetGlobalConst(ddgivis, relocationOffsetTextureScale);
@@ -204,4 +177,31 @@ void CS(uint3 DispatchThreadID : SV_DispatchThreadID)
}
}
+ // Ray Data
+ float2 radianceRect = float2(DDGIVolume.probeNumRays, DDGIVolume.probeCounts.x * DDGIVolume.probeCounts.y * DDGIVolume.probeCounts.z) *GetGlobalConst(ddgivis, rayDataTextureScale);
+ xmax = radianceRect.x;
+ ymin = ymax + 5;
+ ymax = (ymin + radianceRect.y);
+ if (DispatchThreadID.x <= xmax && DispatchThreadID.y > ymin && DispatchThreadID.y <= ymax)
+ {
+ Texture2D RayData = GetDDGIVolumeRayDataSRV(volumeIndex);
+
+ // Sample the ray data texture
+ coords = float2(DispatchThreadID.x, (DispatchThreadID.y - ymin)) / radianceRect.xy;
+
+ if (DDGIVolume.probeRayDataFormat == RTXGI_DDGI_FORMAT_PROBE_RAY_DATA_R32G32B32A32_FLOAT)
+ {
+ color = RayData.SampleLevel(PointClampSampler, coords, 0).rgb;
+ }
+ else if (DDGIVolume.probeRayDataFormat == RTXGI_DDGI_FORMAT_PROBE_RAY_DATA_R32G32_FLOAT)
+ {
+ color = RTXGIUintToFloat3(asuint(RayData.SampleLevel(PointClampSampler, coords, 0).r));
+ }
+
+ // Overwrite GBufferA's albedo and mark the pixel to not be lit
+ GBufferA[DispatchThreadID.xy] = float4(color, 0.f);
+
+ return;
+ }
+
}
diff --git a/samples/test-harness/src/Benchmark.cpp b/samples/test-harness/src/Benchmark.cpp
new file mode 100644
index 0000000..8cac600
--- /dev/null
+++ b/samples/test-harness/src/Benchmark.cpp
@@ -0,0 +1,92 @@
+/*
+* 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
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#include "Benchmark.h"
+
+namespace Benchmark
+{
+ void StartBenchmark(BenchmarkRun& benchmarkRun, Instrumentation::Performance& perf, Configs::Config& config, Graphics::Globals& gfx)
+ {
+ benchmarkRun.cpuTimingCsv.str("");
+ benchmarkRun.gpuTimingCsv.str("");
+ // Clear timer history if beginning benchmark mode, this should not break timers that are currently running
+ perf.Reset(NumBenchmarkFrames);
+ if (config.app.renderMode == ERenderMode::DDGI)
+ {
+ // reload ddgi configs in order to reset RNG state
+ config.ddgi.reload = true;
+ }
+ gfx.frameNumber = 1;
+ }
+
+ bool UpdateBenchmark(BenchmarkRun& benchmarkRun, Instrumentation::Performance& perf, Configs::Config& config, Graphics::Globals& gfx, std::ofstream& log)
+ {
+ // if benchmark is currently running, make a csv row for the frame's timings
+ benchmarkRun.cpuTimingCsv << gfx.frameNumber << ",";
+ benchmarkRun.gpuTimingCsv << gfx.frameNumber << ",";
+
+ // print the timer values to the row
+ benchmarkRun.cpuTimingCsv << perf.cpuTimes;
+ benchmarkRun.gpuTimingCsv << perf.gpuTimes;
+
+ // if benchmark is done, print the timing results to files
+ if (gfx.frameNumber >= NumBenchmarkFrames)
+ {
+ // generate the header row of the csvs
+ std::stringstream header;
+ header << "FrameIndex,";
+ for (std::vector::const_iterator& it = perf.cpuTimes.cbegin(); it != perf.cpuTimes.cend(); it++)
+ {
+ Instrumentation::Stat* stat = *it;
+ header << stat->name << ",";
+ }
+ std::string cpuHeader = header.str();
+
+ header.str("");
+ header << "FrameIndex,";
+ for (std::vector::const_iterator& it = perf.gpuTimes.cbegin(); it != perf.gpuTimes.cend(); it++)
+ {
+ Instrumentation::Stat* stat = *it;
+ header << stat->name << ",";
+ }
+ std::string gpuHeader = header.str();
+
+ // write csv to file
+ std::ofstream csv;
+ csv.open(config.scene.screenshotPath + "\\benchmarkCpu.csv", std::ios::out);
+ if (csv.is_open())
+ {
+ csv << cpuHeader << std::endl << benchmarkRun.cpuTimingCsv.str();
+ }
+ csv.close();
+ csv.open(config.scene.screenshotPath + "\\benchmarkGpu.csv", std::ios::out);
+ if (csv.is_open())
+ {
+ csv << gpuHeader << std::endl << benchmarkRun.gpuTimingCsv.str();
+ }
+ csv.close();
+ log << "wrote benchmark results to csv." << std::endl;
+
+ // print averages to the log file
+ log << "Benchmark Timings:" << std::endl;
+ for (Instrumentation::Stat* stat : perf.cpuTimes)
+ {
+ log << "\t" << stat->name << "=" << stat->average << "ms(CPU)" << std::endl;;
+ }
+ for (Instrumentation::Stat* stat : perf.gpuTimes)
+ {
+ log << "\t" << stat->name << "=" << stat->average << "ms(GPU)" << std::endl;;
+ }
+
+ return false;
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/samples/test-harness/src/Configs.cpp b/samples/test-harness/src/Configs.cpp
index b961ac2..fb42656 100644
--- a/samples/test-harness/src/Configs.cpp
+++ b/samples/test-harness/src/Configs.cpp
@@ -172,6 +172,7 @@ namespace Configs
if (tokens[3].compare("probeMaxRayDistance") == 0) { Store(data, config.ddgi.volumes[volumeIndex].probeMaxRayDistance); return true; }
if (tokens[3].compare("probeIrradianceThreshold") == 0) { Store(data, config.ddgi.volumes[volumeIndex].probeIrradianceThreshold); return true; }
if (tokens[3].compare("probeBrightnessThreshold") == 0) { Store(data, config.ddgi.volumes[volumeIndex].probeBrightnessThreshold); return true; }
+ if (tokens[3].compare("rngSeed") == 0) { Store(data, config.ddgi.volumes[volumeIndex].rngSeed); return true; }
if (tokens[3].compare("probeRelocation") == 0)
{
diff --git a/samples/test-harness/src/Direct3D12.cpp b/samples/test-harness/src/Direct3D12.cpp
index 0b3f9ae..d4956fe 100644
--- a/samples/test-harness/src/Direct3D12.cpp
+++ b/samples/test-harness/src/Direct3D12.cpp
@@ -10,6 +10,7 @@
#include "Graphics.h"
#include "UI.h"
+#include "ImageCapture.h"
#include
#include
@@ -1592,6 +1593,25 @@ 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.
*/
@@ -1599,7 +1619,208 @@ namespace Graphics
{
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;
+ //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
+ const D3D12_RESOURCE_DESC desc = pResource->GetDesc();
+ UINT64 totalResourceSize = 0, fpRowPitch = 0;
+ UINT fpRowCount = 0;
+ // Get the rowcount, pitch and size of the top mip
+ d3d.device->GetCopyableFootprints(
+ &desc,
+ 0,
+ 1,
+ 0,
+ nullptr,
+ &fpRowCount,
+ &fpRowPitch,
+ &totalResourceSize);
+ // Round up the srcPitch to multiples of 256
+ UINT64 dstRowPitch = (fpRowPitch + 255) & ~0xFF;
+ ID3D12Resource* pStaging = nullptr;
+
+ D3D12_HEAP_PROPERTIES sourceHeapProperties = {};
+ D3D12_HEAP_FLAGS sourceHeapFlags = {};
+ HRESULT hr = pResource->GetHeapProperties(&sourceHeapProperties, &sourceHeapFlags);
+ ID3D12CommandAllocator* commandAlloc = nullptr;
+ hr = d3d.device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAlloc));
+ ID3D12GraphicsCommandList* commandList = nullptr;
+ hr = d3d.device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAlloc, nullptr, IID_PPV_ARGS(&commandList));
+ 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
+ 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 = dstRowPitch * desc.Height;
+ bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+ bufferDesc.MipLevels = 1;
+ bufferDesc.SampleDesc.Count = 1;
+ bufferDesc.SampleDesc.Quality = 0;
+ // Create a staging texture
+ hr = d3d.device->CreateCommittedResource(
+ &readBackHeapProperties,
+ D3D12_HEAP_FLAG_NONE,
+ &bufferDesc,
+ D3D12_RESOURCE_STATE_COPY_DEST,
+ nullptr,
+ 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);
+ }
+
+ // 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(dstRowPitch);
+ bufferFootprint.Footprint.Format = desc.Format;
+
+ D3D12_TEXTURE_COPY_LOCATION copySrc = {}, copyDest = {};
+ copySrc.pResource = pResource;
+ copySrc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
+ copySrc.SubresourceIndex = 0;
+ copyDest.pResource = pStaging;
+ copyDest.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
+ copyDest.PlacedFootprint = bufferFootprint;
+
+ // Copy the texture
+ 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);
+ }
+
+ hr = commandList->Close();
+
+ // Execute the command list
+ d3d.cmdQueue->ExecuteCommandLists(1, reinterpret_cast(&commandList));
+ // Signal the fence
+ hr = d3d.cmdQueue->Signal(fence, 1);
+ // Block until the copy is complete
+ while (fence->GetCompletedValue() < 1)
+ SwitchToThread();
+
+ 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);
+
+ // 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;
+
+ 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);
+ }
+
+ 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;
}
@@ -2324,6 +2545,15 @@ namespace Graphics
Cleanup(d3d);
}
+ /**
+ * Write the back buffer texture resources to disk.
+ */
+ 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;
+ }
}
/**
@@ -2435,4 +2665,12 @@ namespace Graphics
{
Graphics::D3D12::Cleanup(gfx, gfxResources);
}
+
+ /**
+ * Write the back buffer texture resources to disk.
+ */
+ bool WriteBackBufferToDisk(Globals& d3d, std::string directory)
+ {
+ return Graphics::D3D12::WriteBackBufferToDisk(d3d, directory);
+ }
}
diff --git a/samples/test-harness/src/ImageCapture.cpp b/samples/test-harness/src/ImageCapture.cpp
new file mode 100644
index 0000000..4dee7fc
--- /dev/null
+++ b/samples/test-harness/src/ImageCapture.cpp
@@ -0,0 +1,68 @@
+/*
+* 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
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#include "ImageCapture.h"
+#include
+#include
+
+namespace ImageCapture
+{
+ bool CapturePng(std::string file, uint32_t width, uint32_t height, std::vector& rows)
+ {
+ FILE* fp = nullptr;
+ errno_t ferror = fopen_s(&fp, file.c_str(), "wb");
+ if (ferror != 0)
+ {
+ return false;
+ }
+
+ 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)
+ {
+ png_destroy_write_struct(&pngWrite, (png_infopp)nullptr);
+ return false;
+ }
+
+ if (setjmp(png_jmpbuf(pngWrite)))
+ {
+ png_destroy_write_struct(&pngWrite, &pngInfo);
+ fclose(fp);
+ return false;
+ }
+
+ 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);
+ // stripping 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;
+ }
+}
\ No newline at end of file
diff --git a/samples/test-harness/src/Inputs.cpp b/samples/test-harness/src/Inputs.cpp
index 14c6f81..bcc22b3 100644
--- a/samples/test-harness/src/Inputs.cpp
+++ b/samples/test-harness/src/Inputs.cpp
@@ -64,8 +64,16 @@ void KeyHandler(GLFWwindow* window, int key, int scancode, int action, int mods)
// Save debug images
if(IsKeyReleased(key, action, GLFW_KEY_F1))
{
- inputPtr->saveImages = true;
inputPtr->event = Inputs::EInputEvent::SAVE_IMAGE;
+ return;
+ }
+
+ // Run benchmark
+ if (IsKeyReleased(key, action, GLFW_KEY_F2))
+ {
+ inputPtr->event = Inputs::EInputEvent::RUN_BENCHMARK;
+ inputPtr->runBenchmark = true;
+ return;
}
// Toggle pan inversion
diff --git a/samples/test-harness/src/Instrumentation.cpp b/samples/test-harness/src/Instrumentation.cpp
index 3116621..51acd50 100644
--- a/samples/test-harness/src/Instrumentation.cpp
+++ b/samples/test-harness/src/Instrumentation.cpp
@@ -96,4 +96,20 @@ namespace Instrumentation
Resolve(s);
}
+ std::ostream& operator<<(std::ostream& os, const Stat& stat)
+ {
+ os << stat.elapsed;
+ return os;
+ }
+
+ std::ostream& operator<<(std::ostream& os, std::vector& stats)
+ {
+ for (std::vector::const_iterator& it = stats.cbegin(); it != stats.cend(); it++)
+ {
+ os << **it << ",";
+ }
+ os << std::endl;
+ return os;
+ }
+
}
diff --git a/samples/test-harness/src/Vulkan.cpp b/samples/test-harness/src/Vulkan.cpp
index 9d0cb82..f9ec73e 100644
--- a/samples/test-harness/src/Vulkan.cpp
+++ b/samples/test-harness/src/Vulkan.cpp
@@ -11,6 +11,7 @@
#include "Graphics.h"
#include "VulkanExtensions.h"
#include "UI.h"
+#include "ImageCapture.h"
namespace Graphics
{
@@ -1364,7 +1365,7 @@ namespace Graphics
bool CreateRenderTargets(Globals& vk, Resources& resources)
{
// Create the GBufferA (R8G8B8A8_UNORM) texture resource
- TextureDesc desc = { static_cast(vk.width), static_cast(vk.height), 1, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT };
+ TextureDesc desc = { static_cast(vk.width), static_cast(vk.height), 1, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT };
if(!CreateTexture(vk, desc, &resources.rt.GBufferA, &resources.rt.GBufferAMemory, &resources.rt.GBufferAView)) return false;
#ifdef GFX_NAME_OBJECTS
SetObjectName(vk.device, reinterpret_cast(resources.rt.GBufferA), "GBufferA", VK_OBJECT_TYPE_IMAGE);
@@ -1994,10 +1995,223 @@ namespace Graphics
/**
* Write an image to disk from the given Vulkan resource.
*/
- bool WriteResourceToDisk(Globals& d3d, std::string file)
+ bool WriteResourceToDisk(Globals& vk, std::string file, VkImage image, uint32_t width, uint32_t height, VkFormat imageFormat, VkImageLayout originalLayout)
{
- // TODO
- return false;
+ VkCommandPool pool;
+ VkCommandBuffer cmd;
+
+ // create custom 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
+ }
+
+ // create custom command buffer
+ {
+ uint32_t numCommandBuffers = 1;
+
+ VkCommandBufferAllocateInfo commandBufferAllocateInfo = {};
+ commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ commandBufferAllocateInfo.commandBufferCount = numCommandBuffers;
+ commandBufferAllocateInfo.commandPool = pool;
+ commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+
+ VKCHECK(vkAllocateCommandBuffers(vk.device, &commandBufferAllocateInfo, &cmd));
+
+#ifdef GFX_NAME_OBJECTS
+ SetObjectName(vk.device, reinterpret_cast(cmd), "Image capture Command Buffer", VK_OBJECT_TYPE_COMMAND_BUFFER);
+#endif
+ VkCommandBufferBeginInfo commandBufferBeginInfo = {};
+ commandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ VKCHECK(vkBeginCommandBuffer(cmd, &commandBufferBeginInfo));
+ }
+
+ // using vr_sli_vk demo for reference
+ VkImage linearScreenshotImage, optimalScreenshotImage;
+ VkDeviceMemory linearScreenshotImageMemory, optimalScreenshotImageMemory;
+ {
+ // same as CreateTexture() but don't create a view
+ VkImageCreateInfo imageCreateInfo = {};
+ imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+ imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
+ imageCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
+ imageCreateInfo.extent.width = width;
+ imageCreateInfo.extent.height = height;
+ imageCreateInfo.extent.depth = 1;
+ imageCreateInfo.mipLevels = 1;
+ imageCreateInfo.arrayLayers = 1;
+ imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
+ imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR;
+ imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+ VKCHECK(vkCreateImage(vk.device, &imageCreateInfo, nullptr, &linearScreenshotImage));
+ 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));
+
+ AllocateMemoryDesc desc = {};
+ vkGetImageMemoryRequirements(vk.device, linearScreenshotImage, &desc.requirements);
+ desc.properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
+ desc.flags = 0;
+
+ if (!AllocateMemory(vk, desc, &linearScreenshotImageMemory)) return false;
+ VKCHECK(vkBindImageMemory(vk.device, linearScreenshotImage, linearScreenshotImageMemory, 0));
+
+ vkGetImageMemoryRequirements(vk.device, optimalScreenshotImage, &desc.requirements);
+ desc.properties = 0;
+ desc.flags = 0;
+ if (!AllocateMemory(vk, desc, &optimalScreenshotImageMemory)) return false;
+ VKCHECK(vkBindImageMemory(vk.device, optimalScreenshotImage, optimalScreenshotImageMemory, 0));
+ }
+
+ {
+ ImageBarrierDesc barrier =
+ {
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
+ };
+ SetImageMemoryBarrier(cmd, linearScreenshotImage, barrier);
+ SetImageMemoryBarrier(cmd, optimalScreenshotImage, barrier);
+ barrier.oldLayout = originalLayout;
+ barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+ SetImageMemoryBarrier(cmd, image, barrier);
+ }
+
+ {
+ // blit image (format conversion if necessary)
+ VkImageBlit region = {};
+ VkImageSubresourceLayers subres = {};
+ subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ subres.mipLevel = 0;
+ subres.baseArrayLayer = 0;
+ subres.layerCount = 1;
+ region.srcSubresource = subres;
+ region.dstSubresource = subres;
+ region.srcOffsets[0] = {};
+ 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);
+ }
+
+ {
+ ImageBarrierDesc barrier =
+ {
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
+ };
+ SetImageMemoryBarrier(cmd, optimalScreenshotImage, barrier);
+ barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+ barrier.newLayout = originalLayout;
+ SetImageMemoryBarrier(cmd, image, barrier);
+ }
+
+ {
+ // 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;
+ region.srcOffset = { 0, 0, 0 };
+ region.dstOffset = { 0, 0, 0 };
+ region.extent.width = width;
+ region.extent.height = height;
+ region.extent.depth = 1;
+ vkCmdCopyImage(
+ cmd,
+ optimalScreenshotImage,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ linearScreenshotImage,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ 1, ®ion
+ );
+ }
+
+ {
+ ImageBarrierDesc barrier =
+ {
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ VK_IMAGE_LAYOUT_GENERAL,
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
+ };
+ SetImageMemoryBarrier(cmd, linearScreenshotImage, barrier);
+ }
+
+ {
+ // Execute GPU work to finish initialization
+ VKCHECK(vkEndCommandBuffer(cmd));
+
+ VkSubmitInfo submitInfo = {};
+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &cmd;
+
+ VKCHECK(vkQueueSubmit(vk.queue, 1, &submitInfo, VK_NULL_HANDLE));
+ VKCHECK(vkQueueWaitIdle(vk.queue));
+
+ WaitForGPU(vk);
+ }
+
+ // copy screenshot image to cpu-side 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;
+ }
+
+ // 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;
+ }
+
+ // output the image file to disk
+ ImageCapture::CapturePng(file, width, height, rows);
+
+ vkUnmapMemory(vk.device, linearScreenshotImageMemory);
+ }
+
+ {
+ // 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);
+ }
+
+ return true;
}
#ifdef GFX_NAME_OBJECTS
@@ -3033,15 +3247,6 @@ namespace Graphics
}
#endif
- /**
- * Write the GBuffer texture resources to disk.
- */
- bool WriteGBufferToDisk(Globals& vk, Resources& resources, std::string directory)
- {
- // TODO: implement
- return true;
- }
-
/**
* Release Vulkan resources.
*/
@@ -3051,6 +3256,16 @@ namespace Graphics
Cleanup(vk);
}
+ /**
+ * Write the back buffer texture resources to disk.
+ */
+ bool WriteBackBufferToDisk(Globals& vk, std::string directory)
+ {
+ CoInitialize(NULL);
+ bool success = WriteResourceToDisk(vk, directory + "\\backbuffer.png", vk.swapChainImage[vk.frameIndex], vk.width, vk.height, vk.swapChainFormat, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
+ return success;
+ }
+
}
/**
@@ -3156,19 +3371,19 @@ namespace Graphics
#endif
/**
- * Write GBuffer resources to disk.
+ * Cleanup global graphics resources.
*/
- bool WriteGBufferToDisk(Globals& gfx, GlobalResources& gfxResources, std::string directory)
+ void Cleanup(Globals& gfx, GlobalResources& gfxResources)
{
- return Graphics::Vulkan::WriteGBufferToDisk(gfx, gfxResources, directory);
+ Graphics::Vulkan::Cleanup(gfx, gfxResources);
}
/**
- * Cleanup global graphics resources.
+ * Write the back buffer texture resources to disk.
*/
- void Cleanup(Globals& gfx, GlobalResources& gfxResources)
+ bool WriteBackBufferToDisk(Globals& vk, std::string directory)
{
- Graphics::Vulkan::Cleanup(gfx, gfxResources);
+ return Graphics::Vulkan::WriteBackBufferToDisk(vk, directory);
}
}
diff --git a/samples/test-harness/src/graphics/DDGI_D3D12.cpp b/samples/test-harness/src/graphics/DDGI_D3D12.cpp
index 32d1557..299d818 100644
--- a/samples/test-harness/src/graphics/DDGI_D3D12.cpp
+++ b/samples/test-harness/src/graphics/DDGI_D3D12.cpp
@@ -372,6 +372,7 @@ namespace Graphics
{
volumeDesc.name = config.name;
volumeDesc.index = config.index;
+ volumeDesc.rngSeed = config.rngSeed;
volumeDesc.origin = { config.origin.x, config.origin.y, config.origin.z };
volumeDesc.eulerAngles = { config.eulerAngles.x, config.eulerAngles.y, config.eulerAngles.z, };
volumeDesc.probeSpacing = { config.probeSpacing.x, config.probeSpacing.y, config.probeSpacing.z };
@@ -940,8 +941,8 @@ namespace Graphics
// Validate the SDK version
assert(RTXGI_VERSION::major == 1);
assert(RTXGI_VERSION::minor == 2);
- assert(RTXGI_VERSION::revision == 4);
- assert(std::strcmp(RTXGI_VERSION::getVersionString(), "1.2.04") == 0);
+ assert(RTXGI_VERSION::revision == 7);
+ assert(std::strcmp(RTXGI_VERSION::getVersionString(), "1.2.07") == 0);
UINT numVolumes = static_cast(config.ddgi.volumes.size());
@@ -1181,6 +1182,31 @@ namespace Graphics
}
}
+ /**
+ * Write the DDGI Volume texture resources to disk.
+ */
+ bool WriteVolumesToDisk(Globals& globals, GlobalResources& gfxResources, Resources& resources, std::string directory)
+ {
+ CoInitialize(NULL);
+ bool success = true;
+ for (rtxgi::DDGIVolumeBase* volumeBase : resources.volumes)
+ {
+ std::string baseName = directory + "\\" + volumeBase->GetName();
+ std::string filename = baseName + "-irradiance.png";
+
+ rtxgi::d3d12::DDGIVolume* volume = static_cast(volumeBase);
+ success &= WriteResourceToDisk(globals, filename, volume->GetProbeIrradiance(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
+
+ // not capturing distances because WIC doesn't like two-channel textures
+ //filename = baseName + "-distance.png";
+ //success &= WriteResourceToDisk(globals, filename, volume->GetProbeDistance(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
+
+ filename = baseName + "-data.png";
+ success &= WriteResourceToDisk(globals, filename, volume->GetProbeData(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
+ }
+ return success;
+ }
+
} // namespace Graphics::D3D12::RTAO
} // namespace Graphics::D3D12
@@ -1218,5 +1244,10 @@ namespace Graphics
Graphics::D3D12::DDGI::Cleanup(resources);
}
+ bool WriteVolumesToDisk(Globals& globals, GlobalResources& gfxResources, Resources& resources, std::string directory)
+ {
+ return Graphics::D3D12::DDGI::WriteVolumesToDisk(globals, gfxResources, resources, directory);
+ }
+
} // namespace Graphics::DDGI
}
diff --git a/samples/test-harness/src/graphics/DDGI_VK.cpp b/samples/test-harness/src/graphics/DDGI_VK.cpp
index 0277923..794f93c 100644
--- a/samples/test-harness/src/graphics/DDGI_VK.cpp
+++ b/samples/test-harness/src/graphics/DDGI_VK.cpp
@@ -189,7 +189,7 @@ namespace Graphics
GetDDGIVolumeTextureDimensions(volumeDesc, EDDGIVolumeTextureType::Irradiance, width, height);
format = GetDDGIVolumeTextureFormat(EDDGIVolumeTextureType::Irradiance, volumeDesc.probeIrradianceFormat);
- TextureDesc desc = { width, height, 1, format, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT };
+ TextureDesc desc = { width, height, 1, format, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT };
CHECK(CreateTexture(vk, desc, &volumeResources.unmanaged.probeIrradiance, &volumeResources.unmanaged.probeIrradianceMemory, &volumeResources.unmanaged.probeIrradianceView), "create DDGIVolume irradiance texture!", log);
#ifdef GFX_NAME_OBJECTS
std::string n = "DDGIVolume[" + std::to_string(volumeDesc.index) + "], Probe Irradiance";
@@ -205,7 +205,7 @@ namespace Graphics
GetDDGIVolumeTextureDimensions(volumeDesc, EDDGIVolumeTextureType::Distance, width, height);
format = GetDDGIVolumeTextureFormat(EDDGIVolumeTextureType::Distance, volumeDesc.probeDistanceFormat);
- TextureDesc desc = { width, height, 1, format, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT };
+ TextureDesc desc = { width, height, 1, format, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT };
CHECK(CreateTexture(vk, desc, &volumeResources.unmanaged.probeDistance, &volumeResources.unmanaged.probeDistanceMemory, &volumeResources.unmanaged.probeDistanceView), "create DDGIVolume distance texture!", log);
#ifdef GFX_NAME_OBJECTS
std::string n = "DDGIVolume[" + std::to_string(volumeDesc.index) + "], Probe Distance";
@@ -222,7 +222,7 @@ namespace Graphics
if (width <= 0) return false;
format = GetDDGIVolumeTextureFormat(EDDGIVolumeTextureType::Data, volumeDesc.probeDataFormat);
- TextureDesc desc = { width, height, 1, format, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT };
+ TextureDesc desc = { width, height, 1, format, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT };
CHECK(CreateTexture(vk, desc, &volumeResources.unmanaged.probeData, &volumeResources.unmanaged.probeDataMemory, &volumeResources.unmanaged.probeDataView), "", log);
#ifdef GFX_NAME_OBJECTS
std::string n = "DDGIVolume[" + std::to_string(volumeDesc.index) + "], Probe Data";
@@ -579,6 +579,7 @@ namespace Graphics
{
volumeDesc.name = config.name;
volumeDesc.index = config.index;
+ volumeDesc.rngSeed = config.rngSeed;
volumeDesc.origin = { config.origin.x, config.origin.y, config.origin.z };
volumeDesc.eulerAngles = { config.eulerAngles.x, config.eulerAngles.y, config.eulerAngles.z, };
volumeDesc.probeSpacing = { config.probeSpacing.x, config.probeSpacing.y, config.probeSpacing.z };
@@ -795,7 +796,7 @@ namespace Graphics
vkFreeMemory(vk.device, resources.outputMemory, nullptr);
// Create the output (R16G16B16A16_FLOAT) texture resource
- TextureDesc desc = { static_cast(vk.width), static_cast(vk.height), 1, VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT };
+ TextureDesc desc = { static_cast(vk.width), static_cast(vk.height), 1, VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT };
CHECK(CreateTexture(vk, desc, &resources.output, &resources.outputMemory, &resources.outputView), "create DDGI output texture resource!\n", log);
#ifdef GFX_NAME_OBJECTS
SetObjectName(vk.device, reinterpret_cast(resources.output), "DDGI Output", VK_OBJECT_TYPE_IMAGE);
@@ -1367,8 +1368,8 @@ namespace Graphics
// Validate the SDK version
assert(RTXGI_VERSION::major == 1);
assert(RTXGI_VERSION::minor == 2);
- assert(RTXGI_VERSION::revision == 4);
- assert(std::strcmp(RTXGI_VERSION::getVersionString(), "1.2.04") == 0);
+ assert(RTXGI_VERSION::revision == 7);
+ assert(std::strcmp(RTXGI_VERSION::getVersionString(), "1.2.07") == 0);
// Reset the command list before initialization
CHECK(ResetCmdList(vk), "reset command list!", log);
@@ -1650,6 +1651,37 @@ namespace Graphics
}
}
+ /**
+ * Write the DDGI Volume texture resources to disk.
+ */
+ bool WriteVolumesToDisk(Globals& vk, GlobalResources& vkResources, Resources& resources, std::string directory)
+ {
+ CoInitialize(NULL);
+ bool success = true;
+ for (rtxgi::DDGIVolumeBase* volumeBase : resources.volumes)
+ {
+ std::string baseName = directory + "\\" + volumeBase->GetName();
+ std::string filename = baseName + "-irradiance.png";
+
+ rtxgi::vulkan::DDGIVolume* volume = static_cast(volumeBase);
+ rtxgi::DDGIVolumeDesc desc = volumeBase->GetDesc();
+ uint32_t width = 0, height = 0;
+ GetDDGIVolumeTextureDimensions(desc, EDDGIVolumeTextureType::Irradiance, width, height);
+ VkFormat format = GetDDGIVolumeTextureFormat(EDDGIVolumeTextureType::Irradiance, desc.probeIrradianceFormat);
+ success &= WriteResourceToDisk(vk, filename, volume->GetProbeIrradiance(), width, height, format, VK_IMAGE_LAYOUT_GENERAL);
+
+ // not capturing distances because WIC doesn't like two-channel textures
+ //filename = baseName + "-distance.png";
+ //success &= WriteResourceToDisk(globals, filename, volume->GetProbeDistance(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
+
+ filename = baseName + "-data.png";
+ GetDDGIVolumeTextureDimensions(desc, EDDGIVolumeTextureType::Data, width, height);
+ format = GetDDGIVolumeTextureFormat(EDDGIVolumeTextureType::RayData, desc.probeDataFormat);
+ success &= WriteResourceToDisk(vk, filename, volume->GetProbeData(), width, height, format,VK_IMAGE_LAYOUT_GENERAL);
+ }
+ return success;
+ }
+
} // namespace Graphics::Vulkan::DDGI
} // namespace Graphics::Vulkan
@@ -1687,5 +1719,10 @@ namespace Graphics
Graphics::Vulkan::DDGI::Cleanup(vk.device, resources);
}
+ bool WriteVolumesToDisk(Globals& vk, GlobalResources& vkResources, Resources& resources, std::string directory)
+ {
+ return Graphics::Vulkan::DDGI::WriteVolumesToDisk(vk, vkResources, resources, directory);
+ }
+
} // namespace Graphics::DDGI
}
diff --git a/samples/test-harness/src/graphics/GBuffer_D3D12.cpp b/samples/test-harness/src/graphics/GBuffer_D3D12.cpp
index a59653a..3ccbfe9 100644
--- a/samples/test-harness/src/graphics/GBuffer_D3D12.cpp
+++ b/samples/test-harness/src/graphics/GBuffer_D3D12.cpp
@@ -304,19 +304,6 @@ namespace Graphics
#endif
}
- /**
- * Write the GBuffer texture resources to disk.
- */
- bool WriteGBufferToDisk(Globals& d3d, GlobalResources& d3dResources, std::string directory)
- {
- CoInitialize(NULL);
- bool success = WriteResourceToDisk(d3d, directory + "GBufferA.png", d3dResources.rt.GBufferA, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
- success &= WriteResourceToDisk(d3d, directory + "GBufferB.png", d3dResources.rt.GBufferB, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
- success &= WriteResourceToDisk(d3d, directory + "GBufferC.png", d3dResources.rt.GBufferC, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
- success &= WriteResourceToDisk(d3d, directory + "GBufferD.png", d3dResources.rt.GBufferD, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
- return success;
- }
-
/**
* Release resources.
*/
@@ -332,6 +319,19 @@ namespace Graphics
SAFE_RELEASE(resources.rtpso);
}
+ /**
+ * Write the GBuffer texture resources to disk.
+ */
+ bool WriteGBufferToDisk(Globals& d3d, GlobalResources& d3dResources, std::string directory)
+ {
+ CoInitialize(NULL);
+ bool success = WriteResourceToDisk(d3d, directory + "\\GBufferA.png", d3dResources.rt.GBufferA, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
+ success &= WriteResourceToDisk(d3d, directory + "\\GBufferB.png", d3dResources.rt.GBufferB, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
+ success &= WriteResourceToDisk(d3d, directory + "\\GBufferC.png", d3dResources.rt.GBufferC, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
+ success &= WriteResourceToDisk(d3d, directory + "\\GBufferD.png", d3dResources.rt.GBufferD, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
+ return success;
+ }
+
} // namespace Graphics::D3D12::GBuffer
} // namespace Graphics::D3D12
diff --git a/samples/test-harness/src/graphics/GBuffer_VK.cpp b/samples/test-harness/src/graphics/GBuffer_VK.cpp
index fb70524..9a302a2 100644
--- a/samples/test-harness/src/graphics/GBuffer_VK.cpp
+++ b/samples/test-harness/src/graphics/GBuffer_VK.cpp
@@ -536,15 +536,6 @@ namespace Graphics
CPU_TIMESTAMP_ENDANDRESOLVE(resources.cpuStat);
}
- /**
- * Write the GBuffer texture resources to disk.
- */
- bool WriteGBufferToDisk(Globals& d3d, GlobalResources& vkResources, std::string directory)
- {
- // TODO: implement
- return true;
- }
-
/**
* Release resources.
*/
@@ -568,6 +559,20 @@ namespace Graphics
resources.shaderTableHitGroupTableSize = 0;
}
+ /**
+ * Write the GBuffer texture resources to disk.
+ */
+ bool WriteGBufferToDisk(Globals& vk, GlobalResources& vkResources, std::string directory)
+ {
+ CoInitialize(NULL);
+ // formats should match those from Graphics::Vulkan::CreateRenderTargets() in Vulkan.cpp
+ bool success = WriteResourceToDisk(vk, directory + "\\GBufferA.png", vkResources.rt.GBufferA, vk.width, vk.height, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_LAYOUT_GENERAL);
+ success &= WriteResourceToDisk(vk, directory + "\\GBufferB.png", vkResources.rt.GBufferB, vk.width, vk.height, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_GENERAL);
+ success &= WriteResourceToDisk(vk, directory + "\\GBufferC.png", vkResources.rt.GBufferC, vk.width, vk.height, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_GENERAL);
+ success &= WriteResourceToDisk(vk, directory + "\\GBufferD.png", vkResources.rt.GBufferD, vk.width, vk.height, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_GENERAL);
+ return success;
+ }
+
} // namespace Graphics::Vulkan::GBuffer
} // namespace Graphics::Vulkan
@@ -600,14 +605,14 @@ namespace Graphics
return Graphics::Vulkan::GBuffer::Execute(vk, vkResources, resources);
}
- bool WriteGBufferToDisk(Globals& vk, GlobalResources& vkResources, std::string directory)
+ void Cleanup(Globals& vk, Resources& resources)
{
- return Graphics::Vulkan::GBuffer::WriteGBufferToDisk(vk, vkResources, directory);
+ Graphics::Vulkan::GBuffer::Cleanup(vk.device, resources);
}
- void Cleanup(Globals& vk, Resources& resources)
+ bool WriteGBufferToDisk(Globals& vk, GlobalResources& vkResources, std::string directory)
{
- Graphics::Vulkan::GBuffer::Cleanup(vk.device, resources);
+ return Graphics::Vulkan::GBuffer::WriteGBufferToDisk(vk, vkResources, directory);
}
} // namespace Graphics::GBuffer
diff --git a/samples/test-harness/src/graphics/RTAO_D3D12.cpp b/samples/test-harness/src/graphics/RTAO_D3D12.cpp
index 2cd0b9a..20a8099 100644
--- a/samples/test-harness/src/graphics/RTAO_D3D12.cpp
+++ b/samples/test-harness/src/graphics/RTAO_D3D12.cpp
@@ -434,6 +434,17 @@ namespace Graphics
resources.shaderTableHitGroupTableStartAddress = 0;
}
+ /**
+ * Write the RTAO texture resources to disk.
+ */
+ bool WriteRTAOBuffersToDisk(Globals& d3d, GlobalResources& d3dResources, Resources& resources, std::string directory)
+ {
+ CoInitialize(NULL);
+ bool success = WriteResourceToDisk(d3d, directory + "\\rtaoraw.png", resources.RTAORaw, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
+ success &= WriteResourceToDisk(d3d, directory + "\\rtaofiltered.png", resources.RTAOOutput, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
+ return success;
+ }
+
} // namespace Graphics::D3D12::RTAO
} // namespace Graphics::D3D12
@@ -471,5 +482,10 @@ namespace Graphics
Graphics::D3D12::RTAO::Cleanup(resources);
}
+ bool WriteRTAOBuffersToDisk(Globals& d3d, GlobalResources& d3dResources, Resources& resources, std::string directory)
+ {
+ return Graphics::D3D12::RTAO::WriteRTAOBuffersToDisk(d3d, d3dResources, resources, directory);
+ }
+
} // namespace Graphics::RTAO
}
diff --git a/samples/test-harness/src/graphics/RTAO_VK.cpp b/samples/test-harness/src/graphics/RTAO_VK.cpp
index d086818..a449a82 100644
--- a/samples/test-harness/src/graphics/RTAO_VK.cpp
+++ b/samples/test-harness/src/graphics/RTAO_VK.cpp
@@ -25,7 +25,7 @@ namespace Graphics
bool CreateTextures(Globals& vk, GlobalResources& vkResources, Resources& resources, std::ofstream& log)
{
// Create the output (R8G8B8A8_UNORM) texture resource
- TextureDesc desc = { static_cast(vk.width), static_cast(vk.height), 1, VK_FORMAT_R8_UNORM, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT };
+ TextureDesc desc = { static_cast(vk.width), static_cast(vk.height), 1, VK_FORMAT_R8_UNORM, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT };
CHECK(CreateTexture(vk, desc, &resources.RTAOOutput, &resources.RTAOOutputMemory, &resources.RTAOOutputView), "create RTAO output texture resource!\n", log);
#ifdef GFX_NAME_OBJECTS
SetObjectName(vk.device, reinterpret_cast(resources.RTAOOutput), "RTAO Output", VK_OBJECT_TYPE_IMAGE);
@@ -651,6 +651,18 @@ namespace Graphics
resources.shaderTableHitGroupTableStartAddress = 0;
}
+ /**
+ * Write the RTAO texture resources to disk.
+ */
+ bool WriteRTAOBuffersToDisk(Globals& vk, GlobalResources& vkResources, Resources& resources, std::string directory)
+ {
+ CoInitialize(NULL);
+ // format should match those from CreateTextures() function above
+ bool success = WriteResourceToDisk(vk, directory + "\\rtaoraw.png", resources.RTAORaw, vk.width, vk.height, VK_FORMAT_R8_UNORM, VK_IMAGE_LAYOUT_GENERAL);
+ success &= WriteResourceToDisk(vk, directory + "\\rtaofiltered.png", resources.RTAOOutput, vk.width, vk.height, VK_FORMAT_R8_UNORM, VK_IMAGE_LAYOUT_GENERAL);
+ return success;
+ }
+
} // namespace Graphics::Vulkan::RTAO
} // namespace Graphics::Vulkan
@@ -688,5 +700,10 @@ namespace Graphics
Graphics::Vulkan::RTAO::Cleanup(vk.device, resources);
}
+ bool WriteRTAOBuffersToDisk(Globals& vk, GlobalResources& vkResources, Resources& resources, std::string directory)
+ {
+ return Graphics::Vulkan::RTAO::WriteRTAOBuffersToDisk(vk, vkResources, resources, directory);
+ }
+
} // namespace Graphics::RTAO
}
diff --git a/samples/test-harness/src/main.cpp b/samples/test-harness/src/main.cpp
index 1ead7ce..9e37068 100644
--- a/samples/test-harness/src/main.cpp
+++ b/samples/test-harness/src/main.cpp
@@ -16,6 +16,7 @@
#include "Graphics.h"
#include "UI.h"
#include "Window.h"
+#include "Benchmark.h"
#include "graphics/PathTracing.h"
#include "graphics/GBuffer.h"
@@ -24,6 +25,8 @@
#include "graphics/RTAO.h"
#include "graphics/Composite.h"
+#include
+
/**
* Run the Test Harness.
*/
@@ -57,6 +60,7 @@ int Run(const std::vector& arguments)
perf.AddGPUStat("Frame");
perf.AddCPUStat("Input");
perf.AddCPUStat("Update");
+ Benchmark::BenchmarkRun benchmarkRun;
CPU_TIMESTAMP_BEGIN(&startupShutdown);
@@ -200,6 +204,12 @@ int Run(const std::vector& arguments)
continue;
}
+ if (input.event == Inputs::EInputEvent::RUN_BENCHMARK)
+ {
+ Benchmark::StartBenchmark(benchmarkRun, perf, config, gfx);
+ input.event = Inputs::EInputEvent::NONE;
+ }
+
// Reload shaders and PSOs for graphics workloads
{
if (config.pathTrace.reload)
@@ -325,17 +335,32 @@ int Run(const std::vector& arguments)
if (!Graphics::SubmitCmdList(gfx)) break;
if (!Graphics::Present(gfx)) continue;
if (!Graphics::WaitForGPU(gfx)) break;
+
+ bool saveImages = (input.event == Inputs::EInputEvent::SAVE_IMAGE) || (input.runBenchmark && gfx.frameNumber >= Benchmark::NumBenchmarkFrames);
+
+ if (saveImages)
+ {
+ CreateDirectory(config.scene.screenshotPath.c_str(), NULL);
+ Graphics::WriteBackBufferToDisk(gfx, config.scene.screenshotPath);
+ Graphics::GBuffer::WriteGBufferToDisk(gfx, gfxResources, config.scene.screenshotPath);
+ Graphics::RTAO::WriteRTAOBuffersToDisk(gfx, gfxResources, rtao, config.scene.screenshotPath);
+ Graphics::DDGI::WriteVolumesToDisk(gfx, gfxResources, ddgi, config.scene.screenshotPath);
+ input.event = Inputs::EInputEvent::NONE;
+ }
+
if (!Graphics::MoveToNextFrame(gfx)) break;
if (!Graphics::ResetCmdList(gfx)) break;
CPU_TIMESTAMP_ENDANDRESOLVE(perf.cpuTimes.back());
#ifdef GFX_PERF_INSTRUMENTATION
if (!Graphics::UpdateTimestamps(gfx, gfxResources, perf)) break;
+ if (input.runBenchmark)
+ {
+ input.runBenchmark = Benchmark::UpdateBenchmark(benchmarkRun, perf, config, gfx, log);
+ }
Graphics::BeginFrame(gfx, gfxResources, perf);
#endif
- // TODO: add GBuffer image dump code for debugging
-
CPU_TIMESTAMP_ENDANDRESOLVE(perf.cpuTimes[0]);
}
diff --git a/thirdparty/libpng b/thirdparty/libpng
new file mode 160000
index 0000000..a37d483
--- /dev/null
+++ b/thirdparty/libpng
@@ -0,0 +1 @@
+Subproject commit a37d4836519517bdce6cb9d956092321eca3e73b
diff --git a/thirdparty/zlib b/thirdparty/zlib
new file mode 160000
index 0000000..cacf7f1
--- /dev/null
+++ b/thirdparty/zlib
@@ -0,0 +1 @@
+Subproject commit cacf7f1d4e3d44d871b605da3b647f07d718623f