diff --git a/README.md b/README.md index 988d481..6a43816 100644 --- a/README.md +++ b/README.md @@ -284,6 +284,11 @@ ID3D12CommandList* pCommandLists[] = { commandLists.m_beforeDrawCommands, m_comm ## Log +- 2022-10-24: Added DirectStorage trace playback utility to measure performance of file upload independent of rendering. For example, to capture and playback the DirectStorage requests and submits for 500 "stressful" frames with a staging buffer size of 128MB, cd to the build directory and: +``` +stress.bat -timingstart 200 -timingstop 700 -capturetrace +traceplayer.exe -file uploadTraceFile_1.json -mediadir media -staging 128 +``` - 2022-06-10: File format (.xet) change. DdsToXet can upgrade old Xet files to the new format. Assets in the DDS directory are exported at build time into media directory. Upgrade to DirectStorage v1.0.2. Many misc. improvements. - 2022-05-05: Workaround for rare race condition. Many tweaks and improvements. - 2022-03-14: DirectStorage 1.0.0 integrated into mainline diff --git a/SamplerFeedbackStreaming.sln b/SamplerFeedbackStreaming.sln index 611c774..14f76fb 100644 --- a/SamplerFeedbackStreaming.sln +++ b/SamplerFeedbackStreaming.sln @@ -3,10 +3,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29920.165 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Expanse", "src\Expanse.vcxproj", "{E9BCC846-C1E9-402F-AC99-0E72195202AC}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Expanse", "src\Expanse.vcxproj", "{A92A871F-FFF6-4A14-A3A2-EA583C0EA015}" ProjectSection(ProjectDependencies) = postProject + {273A5112-7D55-4A16-829A-E4F73E4BACE7} = {273A5112-7D55-4A16-829A-E4F73E4BACE7} {45087328-C272-4BB6-BB09-95D899D2276A} = {45087328-C272-4BB6-BB09-95D899D2276A} {12A36A45-4A15-48E3-B886-257E81FD57C6} = {12A36A45-4A15-48E3-B886-257E81FD57C6} + {369039E2-4C18-40D9-A7FE-E3D87BA23149} = {369039E2-4C18-40D9-A7FE-E3D87BA23149} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imgui", "imgui\imgui.vcxproj", "{45087328-C272-4BB6-BB09-95D899D2276A}" @@ -17,17 +19,19 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{EB9EA81E EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DdsToXet", "DdsToXet\DdsToXet.vcxproj", "{369039E2-4C18-40D9-A7FE-E3D87BA23149}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tracePlayer_2019", "tracePlayer\tracePlayer_2019.vcxproj", "{273A5112-7D55-4A16-829A-E4F73E4BACE7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E9BCC846-C1E9-402F-AC99-0E72195202AC}.Debug|x64.ActiveCfg = Debug|x64 - {E9BCC846-C1E9-402F-AC99-0E72195202AC}.Debug|x64.Build.0 = Debug|x64 - {E9BCC846-C1E9-402F-AC99-0E72195202AC}.Debug|x64.Deploy.0 = Debug|x64 - {E9BCC846-C1E9-402F-AC99-0E72195202AC}.Release|x64.ActiveCfg = Release|x64 - {E9BCC846-C1E9-402F-AC99-0E72195202AC}.Release|x64.Build.0 = Release|x64 + {A92A871F-FFF6-4A14-A3A2-EA583C0EA015}.Debug|x64.ActiveCfg = Debug|x64 + {A92A871F-FFF6-4A14-A3A2-EA583C0EA015}.Debug|x64.Build.0 = Debug|x64 + {A92A871F-FFF6-4A14-A3A2-EA583C0EA015}.Debug|x64.Deploy.0 = Debug|x64 + {A92A871F-FFF6-4A14-A3A2-EA583C0EA015}.Release|x64.ActiveCfg = Release|x64 + {A92A871F-FFF6-4A14-A3A2-EA583C0EA015}.Release|x64.Build.0 = Release|x64 {45087328-C272-4BB6-BB09-95D899D2276A}.Debug|x64.ActiveCfg = Debug|x64 {45087328-C272-4BB6-BB09-95D899D2276A}.Debug|x64.Build.0 = Debug|x64 {45087328-C272-4BB6-BB09-95D899D2276A}.Release|x64.ActiveCfg = Release|x64 @@ -40,12 +44,17 @@ Global {369039E2-4C18-40D9-A7FE-E3D87BA23149}.Debug|x64.Build.0 = Debug|x64 {369039E2-4C18-40D9-A7FE-E3D87BA23149}.Release|x64.ActiveCfg = Release|x64 {369039E2-4C18-40D9-A7FE-E3D87BA23149}.Release|x64.Build.0 = Release|x64 + {273A5112-7D55-4A16-829A-E4F73E4BACE7}.Debug|x64.ActiveCfg = Debug|x64 + {273A5112-7D55-4A16-829A-E4F73E4BACE7}.Debug|x64.Build.0 = Debug|x64 + {273A5112-7D55-4A16-829A-E4F73E4BACE7}.Release|x64.ActiveCfg = Release|x64 + {273A5112-7D55-4A16-829A-E4F73E4BACE7}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {369039E2-4C18-40D9-A7FE-E3D87BA23149} = {EB9EA81E-AD7B-4F2F-B8A9-AFC9282303C9} + {273A5112-7D55-4A16-829A-E4F73E4BACE7} = {EB9EA81E-AD7B-4F2F-B8A9-AFC9282303C9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {CECC8215-A95C-44A3-94DC-6A6AEE5A841B} diff --git a/SamplerFeedbackStreaming_vs2022.sln b/SamplerFeedbackStreaming_vs2022.sln index a41874c..f1584e1 100644 --- a/SamplerFeedbackStreaming_vs2022.sln +++ b/SamplerFeedbackStreaming_vs2022.sln @@ -14,10 +14,13 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Expanse", "src\Expanse_vs2022.vcxproj", "{E9BCC846-C1E9-402F-AC99-0E72195202AC}" ProjectSection(ProjectDependencies) = postProject {12A36A45-4A15-48E3-B886-257E81FD57C6} = {12A36A45-4A15-48E3-B886-257E81FD57C6} + {273A5112-7D55-4A16-829A-E4F73E4BACE7} = {273A5112-7D55-4A16-829A-E4F73E4BACE7} {369039E2-4C18-40D9-A7FE-E3D87BA23149} = {369039E2-4C18-40D9-A7FE-E3D87BA23149} {45087328-C272-4BB6-BB09-95D899D2276A} = {45087328-C272-4BB6-BB09-95D899D2276A} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tracePlayer", "tracePlayer\tracePlayer.vcxproj", "{273A5112-7D55-4A16-829A-E4F73E4BACE7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -40,12 +43,17 @@ Global {E9BCC846-C1E9-402F-AC99-0E72195202AC}.Debug|x64.Build.0 = Debug|x64 {E9BCC846-C1E9-402F-AC99-0E72195202AC}.Release|x64.ActiveCfg = Release|x64 {E9BCC846-C1E9-402F-AC99-0E72195202AC}.Release|x64.Build.0 = Release|x64 + {273A5112-7D55-4A16-829A-E4F73E4BACE7}.Debug|x64.ActiveCfg = Debug|x64 + {273A5112-7D55-4A16-829A-E4F73E4BACE7}.Debug|x64.Build.0 = Debug|x64 + {273A5112-7D55-4A16-829A-E4F73E4BACE7}.Release|x64.ActiveCfg = Release|x64 + {273A5112-7D55-4A16-829A-E4F73E4BACE7}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {369039E2-4C18-40D9-A7FE-E3D87BA23149} = {EB9EA81E-AD7B-4F2F-B8A9-AFC9282303C9} + {273A5112-7D55-4A16-829A-E4F73E4BACE7} = {EB9EA81E-AD7B-4F2F-B8A9-AFC9282303C9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {CECC8215-A95C-44A3-94DC-6A6AEE5A841B} diff --git a/TileUpdateManager/FileStreamer.cpp b/TileUpdateManager/FileStreamer.cpp index 1f41663..9261d94 100644 --- a/TileUpdateManager/FileStreamer.cpp +++ b/TileUpdateManager/FileStreamer.cpp @@ -101,6 +101,18 @@ Streaming::FileStreamer::~FileStreamer() // write trace file if (m_captureTrace) { + UINT resourceIndex = 0; + for (const auto& d : m_tracingResources) + { + auto& r = m_trace.GetRoot()["resources"][resourceIndex]; + r["rsrc"] = (UINT64)d.first; + r["fmt"] = (UINT32)d.second.Format; + r["dim"][0] = (UINT32)d.second.Width; + r["dim"][1] = (UINT32)d.second.Height; + r["dim"][2] = (UINT32)d.second.MipLevels; + resourceIndex++; + } + int index = 0; while (1) { @@ -117,16 +129,31 @@ Streaming::FileStreamer::~FileStreamer() //----------------------------------------------------------------------------- // append an upload request to the trace file //----------------------------------------------------------------------------- -void Streaming::FileStreamer::TraceRequest(const D3D12_TILED_RESOURCE_COORDINATE& in_coord, - UINT64 in_offset, UINT64 in_fileHandle, UINT32 in_numBytes) +void Streaming::FileStreamer::TraceRequest( + ID3D12Resource* in_pDstResource, const D3D12_TILED_RESOURCE_COORDINATE& in_dstCoord, + const std::wstring& in_srcFilename, UINT64 in_srcOffset, UINT32 in_srcNumBytes, UINT32 in_compressionFormat) { auto& r = m_trace.GetRoot()["submits"][m_traceSubmitIndex][m_traceRequestIndex++]; - r["coord"][0] = in_coord.X; - r["coord"][1] = in_coord.Y; - r["coord"][2] = in_coord.Subresource; - r["off"] = in_offset; - r["file"] = in_fileHandle; - r["size"] = in_numBytes; + r["rsrc"] = (UINT64)in_pDstResource; + r["coord"][0] = in_dstCoord.X; + r["coord"][1] = in_dstCoord.Y; + r["coord"][2] = in_dstCoord.Subresource; + + std::string filename; + int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, in_srcFilename.c_str(), -1, NULL, 0, NULL, NULL); + filename.resize(buf_len); + ::WideCharToMultiByte(CP_UTF8, 0, in_srcFilename.c_str(), -1, filename.data(), buf_len, NULL, NULL); + r["file"] = filename; + + r["off"] = in_srcOffset; + r["size"] = in_srcNumBytes; + if (in_compressionFormat) { r["comp"] = in_compressionFormat; } + + auto desc = m_tracingResources.find(in_pDstResource); + if (m_tracingResources.end() == desc) + { + m_tracingResources[in_pDstResource] = in_pDstResource->GetDesc(); + } } //----------------------------------------------------------------------------- diff --git a/TileUpdateManager/FileStreamer.h b/TileUpdateManager/FileStreamer.h index 5aec983..85d2006 100644 --- a/TileUpdateManager/FileStreamer.h +++ b/TileUpdateManager/FileStreamer.h @@ -28,6 +28,7 @@ #include "Streaming.h" #include "ConfigurationParser.h" +#include namespace Streaming { @@ -86,13 +87,15 @@ namespace Streaming // trace file bool m_captureTrace{ false }; - void TraceRequest(const D3D12_TILED_RESOURCE_COORDINATE& in_coord, - UINT64 in_offset, UINT64 in_fileHandle, UINT32 in_numBytes); + void TraceRequest( + ID3D12Resource* in_pDstResource, const D3D12_TILED_RESOURCE_COORDINATE& in_dstCoord, + const std::wstring& in_srcFilename, UINT64 in_srcOffset, UINT32 in_srcNumBytes, UINT32 in_compressionFormat); void TraceSubmit(); private: bool m_firstSubmit{ true }; ConfigurationParser m_trace; // array of submits, each submit is an array of requests UINT m_traceSubmitIndex{ 0 }; UINT m_traceRequestIndex{ 0 }; + std::unordered_map m_tracingResources; }; } diff --git a/TileUpdateManager/FileStreamerDS.cpp b/TileUpdateManager/FileStreamerDS.cpp index c91f641..b42a1e1 100644 --- a/TileUpdateManager/FileStreamerDS.cpp +++ b/TileUpdateManager/FileStreamerDS.cpp @@ -1,4 +1,28 @@ -#pragma once +//********************************************************* +// +// Copyright 2020 Intel Corporation +// +// Permission is hereby granted, free of charge, to any +// person obtaining a copy of this software and associated +// documentation files(the "Software"), to deal in the Software +// without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to +// whom the Software is furnished to do so, subject to the +// following conditions : +// The above copyright notice and this permission notice shall +// be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +//********************************************************* #include "pch.h" @@ -88,7 +112,11 @@ void Streaming::FileStreamerDS::StreamTexture(Streaming::UpdateList& in_updateLi if (m_captureTrace) { - TraceRequest(coord, request.Source.File.Offset, (UINT64)request.Source.File.Source, (UINT32)request.Source.File.Size); + std::wstring fileName = std::filesystem::path(in_updateList.m_pStreamingResource->GetFileName()).filename(); + TraceRequest(pAtlas, coord, fileName, + request.Source.File.Offset, + (UINT32)request.Source.File.Size, + (UINT32)request.Options.CompressionFormat); } } } diff --git a/TileUpdateManager/FileStreamerDS.h b/TileUpdateManager/FileStreamerDS.h index 69c81bd..9fefea0 100644 --- a/TileUpdateManager/FileStreamerDS.h +++ b/TileUpdateManager/FileStreamerDS.h @@ -1,3 +1,28 @@ +//********************************************************* +// +// Copyright 2020 Intel Corporation +// +// Permission is hereby granted, free of charge, to any +// person obtaining a copy of this software and associated +// documentation files(the "Software"), to deal in the Software +// without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to +// whom the Software is furnished to do so, subject to the +// following conditions : +// The above copyright notice and this permission notice shall +// be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +//********************************************************* #pragma once #include diff --git a/TileUpdateManager/FileStreamerReference.cpp b/TileUpdateManager/FileStreamerReference.cpp index 4c7f620..ce76067 100644 --- a/TileUpdateManager/FileStreamerReference.cpp +++ b/TileUpdateManager/FileStreamerReference.cpp @@ -32,6 +32,8 @@ #include "StreamingResourceDU.h" #include "StreamingHeap.h" +static const D3D12_COMMAND_LIST_TYPE g_commandListType = D3D12_COMMAND_LIST_TYPE_COPY; + //----------------------------------------------------------------------------- // Constructor //----------------------------------------------------------------------------- @@ -47,7 +49,7 @@ Streaming::FileStreamerReference::FileStreamerReference(ID3D12Device* in_pDevice D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COPY; + queueDesc.Type = g_commandListType; ThrowIfFailed(in_pDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_copyCommandQueue))); m_copyCommandQueue->SetName(L"FileStreamerReference::m_copyCommandQueue"); @@ -66,7 +68,7 @@ Streaming::FileStreamerReference::FileStreamerReference(ID3D12Device* in_pDevice copyBatchIndex++; } - ThrowIfFailed(in_pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COPY, m_copyBatches[0].GetCommandAllocator(), nullptr, IID_PPV_ARGS(&m_copyCommandList))); + ThrowIfFailed(in_pDevice->CreateCommandList(0, queueDesc.Type, m_copyBatches[0].GetCommandAllocator(), nullptr, IID_PPV_ARGS(&m_copyCommandList))); m_copyCommandList->SetName(L"FileStreamerReference::m_copyCommandList"); m_copyCommandList->Close(); @@ -98,7 +100,7 @@ Streaming::FileStreamerReference::~FileStreamerReference() //============================================================================= void Streaming::FileStreamerReference::CopyBatch::Init(ID3D12Device* in_pDevice) { - ThrowIfFailed(in_pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COPY, IID_PPV_ARGS(&m_commandAllocator))); + ThrowIfFailed(in_pDevice->CreateCommandAllocator(g_commandListType, IID_PPV_ARGS(&m_commandAllocator))); } diff --git a/TileUpdateManager/StreamingHeap.cpp b/TileUpdateManager/StreamingHeap.cpp index dde68bc..9c24b45 100644 --- a/TileUpdateManager/StreamingHeap.cpp +++ b/TileUpdateManager/StreamingHeap.cpp @@ -101,7 +101,7 @@ UINT Streaming::Atlas::CreateAtlas( // Layout must be D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE when creating reserved resources rd.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE; - // this will only every be a copy dest + // this will only ever be a copy dest ThrowIfFailed(device->CreateReservedResource(&rd, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&out_pDst))); out_pDst->SetName(L"DataUploader::m_atlas"); diff --git a/TileUpdateManager/StreamingResourceBase.h b/TileUpdateManager/StreamingResourceBase.h index 69abd44..e6d9d4a 100644 --- a/TileUpdateManager/StreamingResourceBase.h +++ b/TileUpdateManager/StreamingResourceBase.h @@ -155,6 +155,8 @@ namespace Streaming UINT GetNumTilesHeight() const { return m_tileReferencesHeight; } protected: + const std::wstring m_filename; + // object that streams data from a file std::unique_ptr m_pTextureFileInfo; std::unique_ptr m_resources; @@ -256,9 +258,6 @@ namespace Streaming std::atomic m_setZeroRefCounts{ false }; private: - - const std::wstring m_filename; - // do not immediately decmap: // need to withhold until in-flight command buffers have completed class EvictionDelay diff --git a/TileUpdateManager/StreamingResourceDU.h b/TileUpdateManager/StreamingResourceDU.h index a8ef4c4..53b4a94 100644 --- a/TileUpdateManager/StreamingResourceDU.h +++ b/TileUpdateManager/StreamingResourceDU.h @@ -50,6 +50,7 @@ namespace Streaming ID3D12Resource* GetTiledResource() const { return m_resources->GetTiledResource(); } const FileHandle* GetFileHandle() const { return m_pFileHandle.get(); } + const std::wstring& GetFileName() const { return m_filename; } std::vector& GetPaddedPackedMips(UINT& out_uncompressedSize) { out_uncompressedSize = m_packedMipsUncompressedSize; return m_packedMips; } diff --git a/TileUpdateManager/TileUpdateManagerBase.cpp b/TileUpdateManager/TileUpdateManagerBase.cpp index 786ec5f..e82eb9e 100644 --- a/TileUpdateManager/TileUpdateManagerBase.cpp +++ b/TileUpdateManager/TileUpdateManagerBase.cpp @@ -213,9 +213,11 @@ void Streaming::TileUpdateManagerBase::ProcessFeedbackThread() { UINT newStaleSize = 0; // track number of stale resources, then resize the array to the updated number UINT staleIndex = 0; + + // loop over stale resources for (; staleIndex < staleResources.size(); staleIndex++) { - if (m_pDataUploader->GetNumUpdateListsAvailable()) + if (m_pDataUploader->GetNumUpdateListsAvailable() && m_threadsRunning) { UINT resourceIndex = staleResources[staleIndex]; uploadsRequested += m_streamingResources[resourceIndex]->QueueTiles(); @@ -231,10 +233,8 @@ void Streaming::TileUpdateManagerBase::ProcessFeedbackThread() pending[resourceIndex] = 0; // clear the flag that prevents duplicates } } - else + else // compact the stale array with a memcpy and do no further processing. { - // if no UpdateLists, then compact the stale array with a memcpy and do no further processing. - UINT numNotUpdated = UINT(staleResources.size() - staleIndex); if (0 != staleIndex) // no need to move contents if no changes made { diff --git a/config/config.json b/config/config.json index e69c6b0..324f82e 100644 --- a/config/config.json +++ b/config/config.json @@ -25,7 +25,7 @@ "mediaDir": "media", // media directory "texture": "", // setting this overrides all textures, invalidates mediadir "skyTexture": "", // add a sky sphere. path relative to mediadir - "earthTexture": "", // when this texture is encountered, treat it as spherically projected (no uv mirror) + "earthTexture": "earth", // when a texture containing this string is encountered, treat it as a mercator projection (no uv mirror) "terrainTexture": "4kTiles.xet", // use this texture only for the terrain, no planets "maxNumObjects": 985, // maximum total number of objects in the scene "numSpheres": 0, // number of objects besides the terrain diff --git a/include/ArgParser.h b/include/ArgParser.h index 1373e26..50fa71b 100644 --- a/include/ArgParser.h +++ b/include/ArgParser.h @@ -198,7 +198,7 @@ inline void ArgParser::Parse() template inline void ArgParser::AddArg(std::wstring s, ArgFunction f, T default_value, std::wstring d) { std::wstringstream w; - w << ": " << d << " (default: " << default_value << ") "; + w << d << " (default: " << default_value << ") "; AddArg(s, f, w.str()); } diff --git a/include/ConfigurationParser.h b/include/ConfigurationParser.h index bdbff2d..2a4a25d 100644 --- a/include/ConfigurationParser.h +++ b/include/ConfigurationParser.h @@ -141,7 +141,7 @@ class ConfigurationParser KVP() {} template KVP(T in_t) { *this = in_t; } - // root["x"] = root["y"] has a race: root["y"] may bcome invalid if root["x"] must be created + // root["x"] = root["y"] has a race: root["y"] may become invalid if root["x"] must be created // this solution (copy source before copy assignment) is more expensive, but more robust KVP& operator= (const KVP o) { @@ -165,6 +165,12 @@ class ConfigurationParser friend ConfigurationParser; }; + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + ConfigurationParser() {}; + ConfigurationParser(const std::wstring& in_filePath) { m_readSuccess = Read(in_filePath); }; + bool GetReadSuccess() const { return m_readSuccess; } + //------------------------------------------------------------------------- // read file //------------------------------------------------------------------------- @@ -176,10 +182,12 @@ class ConfigurationParser void Write(const std::wstring& in_filePath) const; KVP& GetRoot() { return m_value; } + const KVP& GetRoot() const { return m_value; } private: using Tokens = std::vector; + bool m_readSuccess{ true }; // only false if Read() failed inline void ParseError(uint32_t in_pos) { @@ -638,7 +646,7 @@ inline void ConfigurationParser::KVP::Write(std::ofstream& in_ofs, uint32_t in_t { if (m_isString) { - in_ofs << '"' << m_data << '"'; + in_ofs << '\"' << m_data.c_str() << '\"'; } else { diff --git a/include/DebugHelper.h b/include/DebugHelper.h index d2a1c02..f3f9787 100644 --- a/include/DebugHelper.h +++ b/include/DebugHelper.h @@ -53,11 +53,6 @@ after running, m_float=20.27 and m_flipGravity=true -----------------------------------------------------------------------------*/ #pragma once -#ifdef _DEBUG -#include -#define ASSERT(X) assert(X) -inline void ThrowIfFailed(HRESULT hr) { assert(SUCCEEDED(hr)); } - //================================================== // auto t = AutoString::Concat("test: ", 3, "*", 2.75f, "\n"); //================================================== @@ -79,8 +74,12 @@ class AutoString Expander(in_w, ts...); } }; -#define DebugPrint(...) OutputDebugString(AutoString::Concat(__VA_ARGS__).c_str()); +#ifdef _DEBUG +#include +#define ASSERT(X) assert(X) +#define DebugPrint(...) OutputDebugString(AutoString::Concat(__VA_ARGS__).c_str()); +inline void ThrowIfFailed(HRESULT hr) { assert(SUCCEEDED(hr)); } #else #define ASSERT(X) #define DebugPrint(...) diff --git a/src/CreateSphere.h b/src/CreateSphere.h index 723b419..b0a1e59 100644 --- a/src/CreateSphere.h +++ b/src/CreateSphere.h @@ -31,6 +31,7 @@ #include #include #include +#include "DebugHelper.h" #include "TerrainGenerator.h" // for the shared vertex structure @@ -47,83 +48,95 @@ namespace SphereGen UINT m_numLong{ 128 }; // must be even, or there will be a discontinuity in texture coordinates UINT m_numLat{ 111 }; // must be odd, so there's an equator float m_exponent{ 3.14159265358979f }; // exponential function puts more triangles at the poles - bool m_mirrorU{ true }; // u goes 0..1..0 if true. if false, u = {0..1} + bool m_mirrorU{ true }; // mirror texture around axis of sphere + bool m_topBottom{ false }; // each hemisphere contains the texture, mirrored across the equator }; - inline void Create(std::vector& out_vertices, std::vector& out_indices, const Properties* in_pProperties = nullptr) + inline void Create(std::vector& out_vertices, std::vector& out_indices, Properties in_props) { - Properties sphereProperties; - if (in_pProperties) - { - sphereProperties = *in_pProperties; - sphereProperties.m_numLong &= ~1; // force even - sphereProperties.m_numLat |= 1; // force odd - } + in_props.m_numLong &= ~1; // force even + in_props.m_numLat |= 1; // force odd + + // when UVs are mirrored or using the "top-bottom" mirror mode, the edge vertices don't have to be duplicated + bool repeatEdge = !in_props.m_mirrorU; std::vector vertices; // compute sphere vertices // skip top and bottom rows (will just use single points) { - float dLat = DirectX::XM_PI * 2.0f / sphereProperties.m_numLong; // the number of vertical segments tells you how many horizontal steps to take - float dz = 1.0f / (sphereProperties.m_numLat - 1); // e.g. NumLat = 3, dv = 0.5, v = {0, .5, 1} + float dLat = DirectX::XM_PI * 2.0f / in_props.m_numLong; // the number of vertical segments tells you how many horizontal steps to take + float dz = 1.0f / (in_props.m_numLat - 1); // e.g. NumLat = 3, dv = 0.5, v = {0, .5, 1} // du is uniform - float du = 1.0f / float(sphereProperties.m_numLong); // u from 0..1 - if (sphereProperties.m_mirrorU) // when mirroring, u from 0..2 + float du = 1.0f / float(in_props.m_numLong); // u from 0..1 + if (in_props.m_mirrorU) // when mirroring, u from 0..2 { du *= 2; } - for (UINT longitude = 1; longitude < (sphereProperties.m_numLat - 1); longitude++) + for (UINT longitude = 1; longitude < (in_props.m_numLat - 1); longitude++) { float z = dz * longitude; // logarithmic step in z produces smoother poles - if (z < 0.5f) - { - z = -1 + std::powf(2 * z, sphereProperties.m_exponent); - } - else - { - z = 1 - std::powf(2 - (2 * z), sphereProperties.m_exponent); - } + if (z < 0.5f) { z = -1 + std::powf(2 * z, in_props.m_exponent); } + else { z = 1 - std::powf(2 - (2 * z), in_props.m_exponent); } - // radius of this latitude, just in x/y plane + // radius of this latitude in x/y plane float r = std::sqrtf(1 - (z * z)); // v is constant for this latitude float v = std::acosf(-z) / DirectX::XM_PI; - // start with u=0. last column repeats the first but with u = 1.0. - DirectX::XMFLOAT3 pos0{}; - for (UINT lat = 0; lat <= sphereProperties.m_numLong; lat++) + //float zs = 1.f - std::fabsf(z); zs = (1 + zs * zs) / 2;// too big at pole, pretty good along equator + //DebugPrint("<", z, ",", zs, ">") + // create row of vertices + for (UINT lat = 0; lat < in_props.m_numLong; lat++) { - DirectX::XMFLOAT3 pos; + float theta = lat * dLat; + float x = r * std::cosf(theta); + float y = r * std::sinf(theta); + DirectX::XMFLOAT3 pos = DirectX::XMFLOAT3(x, y, z); + DirectX::XMFLOAT2 uv; - if (lat == sphereProperties.m_numLong) + + // stretch texture across hemisphere. mirrored on other hemisphere. + if (in_props.m_topBottom) { - // repeat first position exactly - pos = pos0; - // exactly re-start uv - uv = DirectX::XMFLOAT2{ 0, v }; - if (!sphereProperties.m_mirrorU) + uv = DirectX::XMFLOAT2{ pos.x, pos.y }; + + float s = std::sqrtf(2); // corners touch the equator + + uv.x *= s; + uv.y *= s; + + if (theta > DirectX::XM_PI) { theta -= DirectX::XM_PI; } + if (theta > DirectX::XM_PIDIV2) { theta = DirectX::XM_PI - theta; } + if (theta < DirectX::XM_PIDIV4) { - uv = DirectX::XMFLOAT2{ 1.0f, v }; + s = std::cosf(DirectX::XM_PIDIV4) / std::cosf(theta); + s = std::powf(s, r); + uv.x *= s; } + else + { + s = std::cosf(DirectX::XM_PIDIV4) / std::cosf(DirectX::XM_PIDIV2 - theta); + s = std::powf(s, r); + uv.y *= s; + } + + uv.x *= std::powf(0.6f, std::fabsf(z)); + uv.y *= std::powf(0.6f, std::fabsf(z)); + + uv.x = (1 + uv.x) * .5f; + uv.y = (1 + uv.y) * .5f; } else { - float x = r * std::cosf(lat * dLat); - float y = r * std::sinf(lat * dLat); - pos = DirectX::XMFLOAT3(x, y, z); - - // remember so we can repeat first position exactly - if (0 == lat) pos0 = pos; - // mirror in u? 0..1..0 float u = lat * du; - if (sphereProperties.m_mirrorU && (u > 1)) + if (in_props.m_mirrorU && (u > 1)) { u = 2 - u; } @@ -132,29 +145,52 @@ namespace SphereGen } out_vertices.push_back(Vertex{ pos, pos, uv }); } // end loops around latitude + + if (repeatEdge) // duplicate the first position, but with u = 1 instead of 0. + { + out_vertices.push_back(out_vertices[out_vertices.size() - in_props.m_numLong]); + out_vertices.back().tex.x = 1; + } } // end vertical steps } - UINT numRows = sphereProperties.m_numLat - 3; // skip top and bottom - UINT vertsPerRow = sphereProperties.m_numLong + 1; + UINT numRows = in_props.m_numLat - 3; // skip top and bottom + UINT vertsPerRow = in_props.m_numLong; // generate connectivity to form rows of triangles { + UINT itersPerRow = in_props.m_numLong; + if (!repeatEdge) { itersPerRow--; } + else { vertsPerRow++; } + for (UINT v = 0; v < numRows; v++) { UINT base = v * vertsPerRow; - for (UINT i = 0; i < sphereProperties.m_numLong; i += 1) + for (UINT i = 0; i < itersPerRow; i += 1) { out_indices.push_back(base + i); - out_indices.push_back(base + i + vertsPerRow + 1); - out_indices.push_back(base + i + vertsPerRow); + out_indices.push_back(base + vertsPerRow + i + 1); + out_indices.push_back(base + vertsPerRow + i); out_indices.push_back(base + i); out_indices.push_back(base + i + 1); - out_indices.push_back(base + i + vertsPerRow + 1); + out_indices.push_back(base + vertsPerRow + i + 1); + } + + if (!repeatEdge) // connect to first vert of each row + { + out_indices.push_back(base + itersPerRow); + out_indices.push_back(base + vertsPerRow); + out_indices.push_back(base + itersPerRow + vertsPerRow); + + out_indices.push_back(base + itersPerRow); + out_indices.push_back(base); + out_indices.push_back(base + vertsPerRow); } } + } + // create top and bottom caps // this version creates many little top triangles, each connected to a different "pole" vertex // the pole vertices have a u value that equals one of the two base triangles @@ -163,21 +199,67 @@ namespace SphereGen // smooth slight pointiness at poles float southZ = (out_vertices[0].pos.z - 1.0f) / 2.f; float northZ = (out_vertices[vertsPerRow * numRows].pos.z + 1.0f) / 2.f; - - for (UINT i = 0; i < sphereProperties.m_numLong; i++) + + if (in_props.m_topBottom) { - out_indices.push_back((UINT)out_vertices.size()); - DirectX::XMFLOAT2 uv(out_vertices[i].tex.x, 0); + // poles are in the center of the image + DirectX::XMFLOAT2 uv(0.5f, 0.5f); + + UINT southIndex = (UINT)out_vertices.size(); out_vertices.push_back(Vertex{ DirectX::XMFLOAT3(0,0,southZ), DirectX::XMFLOAT3(0,0,-1), uv }); - out_indices.push_back(i + 1); - out_indices.push_back(i); - out_indices.push_back((UINT)out_vertices.size()); - uv = DirectX::XMFLOAT2(out_vertices[(vertsPerRow * numRows) + i].tex.x, 1); + UINT northIndex = (UINT)out_vertices.size(); out_vertices.push_back(Vertex{ DirectX::XMFLOAT3(0,0,northZ), DirectX::XMFLOAT3(0,0,1), uv }); - out_indices.push_back((vertsPerRow * numRows) + i); - out_indices.push_back((vertsPerRow * numRows) + i + 1); + + for (UINT i = 0; i < in_props.m_numLong; i++) + { + out_indices.push_back(southIndex); + UINT nextIndex = i + 1; + if (nextIndex == in_props.m_numLong) + { + nextIndex = 0; + } + out_indices.push_back(nextIndex); + out_indices.push_back(i); + + out_indices.push_back(northIndex); + out_indices.push_back((vertsPerRow * numRows) + i); + UINT lastIndex = (vertsPerRow * numRows) + i + 1; + if (0 == nextIndex) + { + lastIndex = (vertsPerRow * numRows); + } + out_indices.push_back(lastIndex); + } + } + else + { + for (UINT i = 0; i < in_props.m_numLong; i++) + { + out_indices.push_back((UINT)out_vertices.size()); + DirectX::XMFLOAT2 uv(out_vertices[i].tex.x, 0); + out_vertices.push_back(Vertex{ DirectX::XMFLOAT3(0,0,southZ), DirectX::XMFLOAT3(0,0,-1), uv }); + UINT nextIndex = i + 1; + if ((!repeatEdge) && (nextIndex == in_props.m_numLong)) + { + nextIndex = 0; + } + out_indices.push_back(nextIndex); + out_indices.push_back(i); + + out_indices.push_back((UINT)out_vertices.size()); + uv = DirectX::XMFLOAT2(out_vertices[(vertsPerRow * numRows) + i].tex.x, 1); + out_vertices.push_back(Vertex{ DirectX::XMFLOAT3(0,0,northZ), DirectX::XMFLOAT3(0,0,1), uv }); + out_indices.push_back((vertsPerRow * numRows) + i); + UINT lastIndex = (vertsPerRow * numRows) + i + 1; + if ((!repeatEdge) && (0 == nextIndex)) + { + lastIndex = (vertsPerRow * numRows); + } + out_indices.push_back(lastIndex); + } } } + } }; diff --git a/src/Gui.cpp b/src/Gui.cpp index d53c868..8e916f0 100644 --- a/src/Gui.cpp +++ b/src/Gui.cpp @@ -343,12 +343,19 @@ void Gui::Draw(ID3D12GraphicsCommandList* in_pCommandList, in_args.m_showFeedbackMaps = ImGui::CollapsingHeader("Terrain Object Feedback Viewer"); if (in_args.m_showFeedbackMaps) { + in_args.m_cameraUpLock = true; + ImGui::Indent(indent); ImGui::Checkbox("Mip Window Orientation", &in_args.m_showFeedbackMapVertical); ImGui::Checkbox("Raw Feedback", &in_args.m_showFeedbackViewer); ImGui::SliderInt("Scroll", &in_args.m_visualizationBaseMip, 0, in_drawParams.m_scrollMipDim); + ImGui::Checkbox("Lock \"Up\" Dir", &in_args.m_cameraUpLock); ImGui::Unindent(indent); } + else + { + in_args.m_cameraUpLock = false; + } //--------------------------------------------------------------------- // misc. options diff --git a/src/Scene.cpp b/src/Scene.cpp index fc277b4..5a39c4f 100644 --- a/src/Scene.cpp +++ b/src/Scene.cpp @@ -496,7 +496,7 @@ void Scene::CreateDescriptorHeaps() } //----------------------------------------------------------------------------- -// Create synchronization objects and wait until assets have been uploaded to the GPU. +// Create synchronization objects //----------------------------------------------------------------------------- void Scene::CreateFence() { @@ -797,6 +797,7 @@ void Scene::LoadSpheres() sphereProperties.m_numLat = m_args.m_sphereLat; sphereProperties.m_numLong = m_args.m_sphereLong; sphereProperties.m_mirrorU = true; + sphereProperties.m_topBottom = true; // 3 options: sphere, earth, sky @@ -821,6 +822,7 @@ void Scene::LoadSpheres() if (nullptr == m_pEarth) { sphereProperties.m_mirrorU = false; + sphereProperties.m_topBottom = false; o = new SceneObjects::Planet(textureFilename, m_pTileUpdateManager, pHeap, m_device.Get(), m_assetUploader, m_args.m_sampleCount, descCPU, sphereProperties); m_pEarth = o; } diff --git a/src/SceneObject.cpp b/src/SceneObject.cpp index 06907d9..00c8f9d 100644 --- a/src/SceneObject.cpp +++ b/src/SceneObject.cpp @@ -271,8 +271,7 @@ void SceneObjects::BaseObject::CopyGeometry(const BaseObject* in_pObjectForShare //------------------------------------------------------------------------- //------------------------------------------------------------------------- -void SceneObjects::BaseObject::SetGeometry(ID3D12Resource* in_pVertexBuffer, UINT in_numVertices, UINT in_vertexSize, - ID3D12Resource* in_pIndexBuffer, UINT in_numIndices, UINT in_lod) +void SceneObjects::BaseObject::SetGeometry(ID3D12Resource* in_pVertexBuffer, UINT in_vertexSize, ID3D12Resource* in_pIndexBuffer, UINT in_lod) { if (in_lod >= m_lods.size()) { @@ -287,9 +286,9 @@ void SceneObjects::BaseObject::SetGeometry(ID3D12Resource* in_pVertexBuffer, UIN in_pVertexBuffer->Release(); in_pIndexBuffer->Release(); - lod.m_numIndices = in_numIndices; - lod.m_vertexBufferView = { lod.m_vertexBuffer->GetGPUVirtualAddress(), in_numVertices * in_vertexSize, in_vertexSize }; - lod.m_indexBufferView = { lod.m_indexBuffer->GetGPUVirtualAddress(), UINT(in_numIndices * sizeof(UINT32)), DXGI_FORMAT_R32_UINT }; + lod.m_numIndices = (UINT)in_pIndexBuffer->GetDesc().Width / sizeof(UINT32); + lod.m_vertexBufferView = { lod.m_vertexBuffer->GetGPUVirtualAddress(), (UINT)in_pVertexBuffer->GetDesc().Width, in_vertexSize}; + lod.m_indexBufferView = { lod.m_indexBuffer->GetGPUVirtualAddress(), (UINT)in_pIndexBuffer->GetDesc().Width, DXGI_FORMAT_R32_UINT}; } //------------------------------------------------------------------------- @@ -310,19 +309,28 @@ void SceneObjects::BaseObject::Draw(ID3D12GraphicsCommandList1* in_pCommandList, DirectX::XMVECTOR distance = DirectX::XMVectorSubtract(pos, eye); distance = DirectX::XMVector3LengthEst(distance); - // FIXME? could store bounding sphere diameter in object - DirectX::XMVECTOR scale = DirectX::XMVector3LengthEst(m_matrix.r[0]); - float objectSize = DirectX::XMVectorGetX(scale); + // spheres behind the view won't be visible + if (DirectX::XMVectorGetX(distance) < 0) + { + lod = UINT(m_lods.size() - 1); + } + else + { - float distanceToEye = DirectX::XMVectorGetX(distance); - // slow lod progression with distance - distanceToEye = std::powf(distanceToEye, 0.95f); + // FIXME? could store bounding sphere diameter in object + DirectX::XMVECTOR scale = DirectX::XMVector3LengthEst(m_matrix.r[0]); + float objectSize = DirectX::XMVectorGetX(scale); - float lodBias = 0.1f * (float)SharedConstants::SPHERE_LOD_BIAS; - float ratio = distanceToEye / (objectSize * lodBias); + float distanceToEye = DirectX::XMVectorGetX(distance); + // slow lod progression with distance + distanceToEye = std::powf(distanceToEye, 0.95f); - // clamp to the number of lods - lod = std::min((UINT)m_lods.size() - 1, UINT(ratio)); + float lodBias = 0.1f * (float)SharedConstants::SPHERE_LOD_BIAS; + float ratio = distanceToEye / (objectSize * lodBias); + + // clamp to the number of lods + lod = std::min((UINT)m_lods.size() - 1, UINT(ratio)); + } } const auto& geometry = m_lods[lod]; @@ -375,7 +383,7 @@ void SceneObjects::CreateSphereResources( std::vector sphereVerts; std::vector sphereIndices; - SphereGen::Create(sphereVerts, sphereIndices, &in_sphereProperties); + SphereGen::Create(sphereVerts, sphereIndices, in_sphereProperties); // build vertex buffer { @@ -432,17 +440,10 @@ void SceneObjects::CreateSphere(SceneObjects::BaseObject* out_pObject, sphereProperties.m_numLong = UINT(in_sphereProperties.m_numLong * lodScaleFactor); lodScaleFactor -= lodStepFactor; - std::vector sphereVerts; - std::vector sphereIndices; - SphereGen::Create(sphereVerts, sphereIndices, &sphereProperties); - ID3D12Resource* pVertexBuffer{ nullptr }; ID3D12Resource* pIndexBuffer{ nullptr }; CreateSphereResources(&pVertexBuffer, &pIndexBuffer, in_pDevice, sphereProperties, in_assetUploader); - - out_pObject->SetGeometry( - pVertexBuffer, (UINT)sphereVerts.size(), (UINT)sizeof(SphereGen::Vertex), - pIndexBuffer, (UINT)sphereIndices.size(), lod); + out_pObject->SetGeometry(pVertexBuffer, (UINT)sizeof(SphereGen::Vertex), pIndexBuffer, lod); } } @@ -509,8 +510,7 @@ SceneObjects::Terrain::Terrain(const std::wstring& in_filename, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_INDEX_BUFFER); } - SetGeometry(pVertexBuffer, (UINT)mesh.GetVertices().size(), (UINT)sizeof(TerrainGenerator::Vertex), - pIndexBuffer, mesh.GetNumIndices()); + SetGeometry(pVertexBuffer, (UINT)sizeof(TerrainGenerator::Vertex), pIndexBuffer); } //========================================================================= @@ -578,6 +578,7 @@ SceneObjects::Sky::Sky(const std::wstring& in_filename, sphereProperties.m_numLong = 80; sphereProperties.m_numLat = 81; sphereProperties.m_mirrorU = true; + sphereProperties.m_topBottom = true; CreateSphere(this, in_pDevice, in_assetUploader, sphereProperties); float d = SharedConstants::SPHERE_SCALE * 200; GetModelMatrix() = DirectX::XMMatrixScaling(d, d, d); diff --git a/src/SceneObject.h b/src/SceneObject.h index 4d562b6..924e8f8 100644 --- a/src/SceneObject.h +++ b/src/SceneObject.h @@ -90,8 +90,8 @@ namespace SceneObjects void CopyGeometry(const BaseObject* in_pObjectForSharedHeap); - void SetGeometry(ID3D12Resource* in_pVertexBuffer, UINT in_numVertices, UINT in_vertexSize, - ID3D12Resource* in_pIndexBuffer, UINT in_numIndices, UINT in_lod = 0); + void SetGeometry(ID3D12Resource* in_pVertexBuffer, UINT in_vertexSize, + ID3D12Resource* in_pIndexBuffer, UINT in_lod = 0); void SetFeedbackEnabled(bool in_value) { m_feedbackEnabled = in_value; } protected: diff --git a/src/winMain.cpp b/src/winMain.cpp index b75e8c0..cfbae16 100644 --- a/src/winMain.cpp +++ b/src/winMain.cpp @@ -459,8 +459,8 @@ void LoadConfigFile(std::wstring& in_configFileName, CommandLineArgs& out_args) filePath.remove_filename().append(in_configFileName); if (std::filesystem::exists(filePath)) { - ConfigurationParser parser; - success = parser.Read(filePath); + const ConfigurationParser parser(filePath); + success = parser.GetReadSuccess(); if (success) { diff --git a/tracePlayer/packages.config b/tracePlayer/packages.config new file mode 100644 index 0000000..220e8cc --- /dev/null +++ b/tracePlayer/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/tracePlayer/tracePlayer.cpp b/tracePlayer/tracePlayer.cpp new file mode 100644 index 0000000..ff5ea0a --- /dev/null +++ b/tracePlayer/tracePlayer.cpp @@ -0,0 +1,573 @@ +//********************************************************* +// +// Copyright 2020 Intel Corporation +// +// Permission is hereby granted, free of charge, to any +// person obtaining a copy of this software and associated +// documentation files(the "Software"), to deal in the Software +// without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to +// whom the Software is furnished to do so, subject to the +// following conditions : +// The above copyright notice and this permission notice shall +// be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +// plays back trace files from expanse. trace files contain only DirectStorage Requests and Submits +// create trace files with the command line parameter "-captureTrace" +// for example, "expanse.exe -timingStart 100 -timingStop 150 -captureTrace" + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DebugHelper.h" +#include "ArgParser.h" +#include "ConfigurationParser.h" +#include "d3dx12.h" +#include "Timer.h" +#include "tracePlayer.h" + +#pragma comment(lib, "d3d12.lib") +#pragma comment(lib, "dxgi.lib") +#pragma comment(lib, "dxguid.lib") + +#define ErrorMessage(...) { std::wcout << AutoString::Concat(__VA_ARGS__); exit(-1); } + +//----------------------------------------------------------------------------- +// given a full path or a relative path (e.g. c:\foo or foo) +// return foo or exepath\foo or return an error +//----------------------------------------------------------------------------- +void FindPath(std::wstring& out_path) +{ + std::wstring inPath = std::filesystem::path(out_path); + + WCHAR buffer[MAX_PATH]; + GetModuleFileName(nullptr, buffer, MAX_PATH); + std::filesystem::path exePath(buffer); + exePath.remove_filename(); + + // if the desired media path doesn't exist, try looking relative to the executable + if (!std::filesystem::exists(inPath)) + { + std::filesystem::path testPath = exePath; + testPath.append(inPath); + if (std::filesystem::exists(testPath)) + { + out_path = testPath; + } + else + { + ErrorMessage("Path not found: \"", inPath, "\" also tried: ", testPath); + } + } +} + +//----------------------------------------------------------------------------- +// create device, optionally checking adapter description for e.g. "intel" +//----------------------------------------------------------------------------- +void TracePlayer::CreateDeviceWithName() +{ + UINT flags = 0; +#ifdef _DEBUG + flags |= DXGI_CREATE_FACTORY_DEBUG; +#endif + if (0 > CreateDXGIFactory2(flags, IID_PPV_ARGS(&m_factory))) + { + flags &= ~DXGI_CREATE_FACTORY_DEBUG; + CreateDXGIFactory2(flags, IID_PPV_ARGS(&m_factory)); + } + + ComPtr adapter; + std::wstring lowerCaseAdapterDesc = m_params.m_adapterDescription; + + if (lowerCaseAdapterDesc.size()) + { + for (auto& c : lowerCaseAdapterDesc) { c = ::towlower(c); } + } + + for (UINT i = 0; m_factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND; ++i) + { + DXGI_ADAPTER_DESC1 desc{}; + adapter->GetDesc1(&desc); + + if ((desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) || (std::wstring(L"Microsoft Basic Render Driver") == desc.Description)) + { + continue; + } + + if (lowerCaseAdapterDesc.size()) + { + std::wstring description(desc.Description); + for (auto& c : description) { c = ::towlower(c); } + std::size_t found = description.find(lowerCaseAdapterDesc); + if (found == std::string::npos) + { + continue; + } + } + + D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_12_0, IID_PPV_ARGS(&m_device)); + + // if we care about adapter architecture, check that UMA corresponds to integrated vs. discrete + if (Params::PreferredArchitecture::NONE != m_params.m_preferredArchitecture) + { + D3D12_FEATURE_DATA_ARCHITECTURE archFeatures{}; + m_device->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &archFeatures, sizeof(archFeatures)); + + if (((FALSE == archFeatures.UMA) && (Params::PreferredArchitecture::INTEGRATED == m_params.m_preferredArchitecture)) || + ((TRUE == archFeatures.UMA) && (Params::PreferredArchitecture::DISCRETE == m_params.m_preferredArchitecture))) + { + // adapter does not match requirements (name and/or architecture) + m_device = nullptr; + continue; + } + } + + // adapter matches requirements (name and/or architecture), exit loop + break; + } + + // get the description from whichever adapter was used to create the device + if (nullptr != m_device.Get()) + { + DXGI_ADAPTER_DESC1 desc{}; + adapter->GetDesc1(&desc); + m_params.m_adapterDescription = desc.Description; + } + else + { + ErrorMessage("No adapter found with name \"", m_params.m_adapterDescription, "\" or architecture \"", + (Params::PreferredArchitecture::NONE == m_params.m_preferredArchitecture ? "none" : + (Params::PreferredArchitecture::DISCRETE == m_params.m_preferredArchitecture ? "discrete" : "integrated")), + "\"\n"); + } +} + + +//----------------------------------------------------------------------------- +// Create synchronization objects +//----------------------------------------------------------------------------- +void TracePlayer::CreateFence() +{ + ThrowIfFailed(m_device->CreateFence( + m_fenceValue, + D3D12_FENCE_FLAG_NONE, + IID_PPV_ARGS(&m_fence))); + m_fenceValue++; + + // Create an event handle to use for frame synchronization. + m_fenceEvent = ::CreateEvent(nullptr, FALSE, FALSE, nullptr); + if (m_fenceEvent == nullptr) + { + ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); + } + + D3D12_COMMAND_QUEUE_DESC queueDesc = {}; + queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; + queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COPY; + ThrowIfFailed(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue))); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void TracePlayer::InitDirectStorage() +{ + // initialize to default values + DSTORAGE_CONFIGURATION dsConfig{}; + DStorageSetConfiguration(&dsConfig); + + ThrowIfFailed(DStorageGetFactory(IID_PPV_ARGS(&m_dsFactory))); + + DSTORAGE_DEBUG debugFlags = DSTORAGE_DEBUG_NONE; +#ifdef _DEBUG + debugFlags = DSTORAGE_DEBUG_SHOW_ERRORS; +#endif + m_dsFactory->SetDebugFlags(debugFlags); + + m_dsFactory->SetStagingBufferSize(m_params.m_stagingBufferSizeMB * 1024 * 1024); + + DSTORAGE_QUEUE_DESC queueDesc{}; + queueDesc.Capacity = DSTORAGE_MAX_QUEUE_CAPACITY; + queueDesc.Priority = DSTORAGE_PRIORITY_NORMAL; + queueDesc.SourceType = DSTORAGE_REQUEST_SOURCE_FILE; + queueDesc.Device = m_device.Get(); + ThrowIfFailed(m_dsFactory->CreateQueue(&queueDesc, IID_PPV_ARGS(&m_dsQueue))); + + ThrowIfFailed(m_device->CreateFence(m_fenceValue, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); + m_fenceValue++; +} + +//----------------------------------------------------------------------------- +// create internal atlas texture +//----------------------------------------------------------------------------- +ID3D12Resource* TracePlayer::CreateDestinationResource(UINT& out_numTiles, DXGI_FORMAT in_format, UINT in_width, UINT in_height, UINT in_subresourceCount) +{ + // create a maximum size reserved resource + D3D12_RESOURCE_DESC rd = CD3DX12_RESOURCE_DESC::Tex2D(in_format, in_width, in_height); + rd.MipLevels = (UINT16)in_subresourceCount; + + // Layout must be D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE when creating reserved resources + rd.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE; + + // this will only ever be a copy dest + ID3D12Resource* pResource{ nullptr }; + ThrowIfFailed(m_device->CreateReservedResource(&rd, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&pResource))); + + std::vector tiling(in_subresourceCount); + m_device->GetResourceTiling(pResource, &out_numTiles, nullptr, nullptr, nullptr, 0, nullptr); + + return pResource; +} + +//----------------------------------------------------------------------------- +// map resource using linear assignment order defined by D3D12_REGION_SIZE UseBox = FALSE +// https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_tile_region_size +//----------------------------------------------------------------------------- +void TracePlayer::UpdateTileMappings(ID3D12Resource* in_pResource, UINT in_tileOffset) +{ + D3D12_SUBRESOURCE_TILING tiling{}; + UINT subresourceCount = in_pResource->GetDesc().MipLevels; + UINT numTiles{ 0 }; + m_device->GetResourceTiling(in_pResource, &numTiles, nullptr, nullptr, &subresourceCount, 0, &tiling); + + // we are updating a single region: all the tiles + UINT numResourceRegions = 1; + D3D12_TILED_RESOURCE_COORDINATE resourceRegionStartCoordinates{ 0, 0, 0, 0 }; + D3D12_TILE_REGION_SIZE resourceRegionSizes{ numTiles, FALSE, 0, 0, 0 }; + + // we can do this with a single range + UINT numRanges = 1; + std::vectorrangeFlags(numRanges, D3D12_TILE_RANGE_FLAG_NONE); + std::vector rangeTileCounts(numRanges, numTiles); + + // D3D12 defines that tiles are linear, not swizzled relative to each other + // so all the tiles can be mapped in one call + m_commandQueue->UpdateTileMappings( + in_pResource, + numResourceRegions, + &resourceRegionStartCoordinates, + &resourceRegionSizes, + m_heap.Get(), + (UINT)rangeFlags.size(), + rangeFlags.data(), + &in_tileOffset, + rangeTileCounts.data(), + D3D12_TILE_MAPPING_FLAG_NONE + ); +} + +//----------------------------------------------------------------------------- +// parse trace file in to an efficient internal representation +// creates resources and opens files +//----------------------------------------------------------------------------- +void TracePlayer::LoadTraceFile() +{ + const ConfigurationParser traceFile(m_params.m_filename); + + std::map dstResources; + std::map srcFiles; + + //--------------------------------- + // create destination resources + //--------------------------------- + { + const auto& resources = traceFile.GetRoot()["resources"]; + UINT numTilesTotal{ 0 }; + std::vector tilesPerResource; + for (const auto& r : resources) + { + UINT numTiles{ 0 }; + ID3D12Resource* pResource = CreateDestinationResource( + numTiles, (DXGI_FORMAT)r["fmt"].asUInt(), + r["dim"][0].asUInt(), r["dim"][1].asUInt(), r["dim"][2].asUInt()); + numTilesTotal += numTiles; + + m_dstResources.push_back(pResource); + dstResources[r["rsrc"].asUInt64()] = pResource; + + tilesPerResource.push_back(numTiles); + } + UINT heapSize = numTilesTotal * D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES; + CD3DX12_HEAP_DESC heapDesc(heapSize, D3D12_HEAP_TYPE_DEFAULT, 0, D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES); + ThrowIfFailed(m_device->CreateHeap(&heapDesc, IID_PPV_ARGS(&m_heap))); + UINT tileOffset = 0; + for (UINT i = 0; i < m_dstResources.size(); i++) + { + UpdateTileMappings(m_dstResources[i], tileOffset); + tileOffset += tilesPerResource[i]; + } + } + + //--------------------------------- + // create submission array (and open files) + //--------------------------------- + { + const auto& submits = traceFile.GetRoot()["submits"]; + for (const auto& s : submits) + { + m_submits.resize(m_submits.size() + 1); + auto& requestArray = m_submits.back(); + for (const auto& r : s) + { + Request request{}; + request.m_dstCoord.X = r["coord"][0].asUInt(); + request.m_dstCoord.Y = r["coord"][1].asUInt(); + request.m_dstCoord.Subresource = r["coord"][2].asUInt(); + request.m_pDstResource = dstResources[r["rsrc"].asUInt64()]; + request.m_srcOffset = r["off"].asUInt(); + request.m_numBytes = r["size"].asUInt(); + m_numFileBytesRead += request.m_numBytes; + + if (r.isMember("comp")) request.m_compressionFormat = r["comp"].asUInt(); + + const std::string& filename = r["file"].asString(); + auto f = srcFiles.find(filename); + if (srcFiles.end() == f) + { + std::wstringstream wideFileName; + wideFileName << m_params.m_mediaDir << filename.c_str(); + IDStorageFile* dsFile{ nullptr }; + if (!std::filesystem::exists(wideFileName.str())) + { + ErrorMessage("file not found: ", wideFileName.str(), ". Did you set -mediadir?"); + } + ThrowIfFailed(m_dsFactory->OpenFile(wideFileName.str().c_str(), IID_PPV_ARGS(&dsFile))); + m_fileHandles.push_back(dsFile); + srcFiles[filename] = dsFile; + request.m_srcFile = dsFile; + } + else + { + request.m_srcFile = f->second; + } + m_numBytesWritten += D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES; + requestArray.push_back(request); + } + m_numRequestsTotal += s.size(); + } + } +} + +//----------------------------------------------------------------------------- +// execute all requests as quickly as possible +//----------------------------------------------------------------------------- +void TracePlayer::PlaybackTrace() +{ + DSTORAGE_REQUEST request{}; + request.Options.DestinationType = DSTORAGE_REQUEST_DESTINATION_TILES; + request.Destination.Tiles.TileRegionSize = D3D12_TILE_REGION_SIZE{ 1, FALSE, 0, 0, 0 }; + request.Options.SourceType = DSTORAGE_REQUEST_SOURCE_FILE; + request.UncompressedSize = D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES; + + for (const auto& s : m_submits) + { + for (const auto& r : s) + { + request.Source.File.Source = r.m_srcFile; + request.Source.File.Offset = r.m_srcOffset; + request.Source.File.Size = r.m_numBytes; + request.Destination.Tiles.Resource = r.m_pDstResource; + request.Destination.Tiles.TiledRegionStartCoordinate = r.m_dstCoord; + request.Options.CompressionFormat = (DSTORAGE_COMPRESSION_FORMAT)r.m_compressionFormat; + + m_dsQueue->EnqueueRequest(&request); + } + m_fenceValue++; + m_dsQueue->EnqueueSignal(m_fence.Get(), m_fenceValue); + m_dsQueue->Submit(); + } + + // Wait until the signal command has been processed. + ThrowIfFailed(m_fence->SetEventOnCompletion(m_fenceValue, m_fenceEvent)); + WaitForSingleObject(m_fenceEvent, INFINITE); +} + +//----------------------------------------------------------------------------- +// TracePlayer constructor/destructor +//----------------------------------------------------------------------------- +TracePlayer::TracePlayer(const Params& in_params) : m_params(in_params) +{ + CreateDeviceWithName(); + CreateFence(); + InitDirectStorage(); + + std::cout << "loading/parsing...\n"; + + if (m_params.m_inspect) + { + Inspect(); + } + else + { + LoadTraceFile(); + } +} + +TracePlayer::~TracePlayer() +{ + for (auto p : m_fileHandles) + { + p->Close(); + p->Release(); + } + for (auto p : m_dstResources) + { + p->Release(); + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +std::wstring AddCommaSeparators(UINT64 in_value) +{ + std::wstring value = std::to_wstring(in_value); + for (int offset = int(value.size() - 3); offset > 0; offset -= 3) + { + value.insert(offset, L","); + } + return value; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void TracePlayer::Inspect() +{ + const ConfigurationParser traceFile(m_params.m_filename); + + const auto& submits = traceFile.GetRoot()["submits"]; + size_t numSubmits = submits.size(); + size_t maxSubmit{ 0 }; + size_t minSubmit{ size_t(-1) }; + + std::cout << "# requests for each submit: "; + bool first = true; + for (const auto& s : submits) + { + if (first) { first = false; } + else { std::cout << ","; } + + size_t numRequests = s.size(); + minSubmit = std::min(minSubmit, numRequests); + maxSubmit = std::max(maxSubmit, numRequests); + m_numRequestsTotal += numRequests; + + std::cout << numRequests; + + for (const auto& r : s) + { + m_numFileBytesRead += r["size"].asUInt64(); + } + } + + UINT64 numTiles = m_numRequestsTotal; // FIXME? assumes all requests are single-tile read + m_numBytesWritten += numTiles * D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES; // FIXME? assumes all requests are single-tile read + + std::cout << std::endl; + + std::cout << "# submits: " << numSubmits << std::endl; + std::cout << "# requests: " << numTiles << std::endl; + float avgRequestsPerSubmit = float(numTiles) / float(numSubmits); + std::wcout << "average requests/submit: " << avgRequestsPerSubmit << " = " << AddCommaSeparators(UINT64(avgRequestsPerSubmit * 64 * 1024)) << " bytes/submit" << std::endl; + std::cout << "min # requests/1 submit: " << minSubmit << std::endl; + std::cout << "max # requests/1 submit: " << maxSubmit << std::endl; + std::wcout << "# bytes ssd (read): " << AddCommaSeparators(m_numFileBytesRead) << std::endl; + std::wcout << "# bytes gpu (written): " << AddCommaSeparators(m_numBytesWritten) << std::endl; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int main() +{ + TracePlayer::Params tracePlayerParams; + + UINT numItersPlayback{ 4 }; + bool inspect{ false }; + + ArgParser argParser; + tracePlayerParams.m_mediaDir = std::filesystem::current_path(); + + //--------------------------- + // parse command line + //--------------------------- + { + ArgParser argParser; + argParser.AddArg(L"-file", [&] + { + tracePlayerParams.m_filename = ArgParser::GetNextArg(); + FindPath(tracePlayerParams.m_filename); + }, tracePlayerParams.m_filename, L" trace file of DS requests and submits"); + argParser.AddArg(L"-mediaDir", [&] + { + tracePlayerParams.m_mediaDir = ArgParser::GetNextArg(); + FindPath(tracePlayerParams.m_mediaDir); + }, tracePlayerParams.m_mediaDir, L"directory containing texture files"); + + argParser.AddArg(L"-staging", tracePlayerParams.m_stagingBufferSizeMB, L"DirectStorage staging buffer size in MB"); + argParser.AddArg(L"-adapter", tracePlayerParams.m_adapterDescription, L"find an adapter containing this string in the description, ignoring case"); + argParser.AddArg(L"-arch", (UINT&)tracePlayerParams.m_preferredArchitecture, L"GPU architecture: don't care (0), discrete (1), integrated (2)"); + + argParser.AddArg(L"-iters", numItersPlayback, L"none (0), discrete (1), integrated (2)"); + argParser.AddArg(L"-inspect", tracePlayerParams.m_inspect, L"display information about archive, do not execute"); + argParser.Parse(); + + if (0 == tracePlayerParams.m_filename.size()) + { + ErrorMessage("trace file name not provided (-file filename.json)"); + } + if (L'\\' != tracePlayerParams.m_mediaDir.back()) + { + tracePlayerParams.m_mediaDir.append(L"\\"); + } + } + + //--------------------------- + // play back trace + //--------------------------- + TracePlayer tracePlayer(tracePlayerParams); + + if (tracePlayerParams.m_inspect) + { + return 0; + } + + std::wcout << "adapter string: " << tracePlayer.GetAdapterDescription().c_str() << "\n"; + std::wcout << "file bytes to read (per iter): " << AddCommaSeparators(tracePlayer.GetNumFileBytesRead()).c_str() << "\n"; + std::cout << "number of requests: " << tracePlayer.GetNumRequests() << "\n"; + std::cout << "staging buffer size MB: " << tracePlayerParams.m_stagingBufferSizeMB << "\n"; + std::cout << "executing trace, # iterations = " << numItersPlayback << "\n"; + Timer timer; + timer.Start(); + for (UINT i = 0; i < numItersPlayback; i++) + { + tracePlayer.PlaybackTrace(); + } + double seconds = timer.Stop(); + + double bytesToBandwidth = numItersPlayback / (1024. * 1024. * seconds); + + std::wcout << "bandwidth (MB/s from disk): " << tracePlayer.GetNumFileBytesRead() * bytesToBandwidth << "\n"; + std::cout << "bandwidth (MB/s uncompressed to GPU): " << tracePlayer.GetNumBytesWritten() * bytesToBandwidth << "\n"; +} diff --git a/tracePlayer/tracePlayer.h b/tracePlayer/tracePlayer.h new file mode 100644 index 0000000..54dc5f9 --- /dev/null +++ b/tracePlayer/tracePlayer.h @@ -0,0 +1,114 @@ +//********************************************************* +// +// Copyright 2020 Intel Corporation +// +// Permission is hereby granted, free of charge, to any +// person obtaining a copy of this software and associated +// documentation files(the "Software"), to deal in the Software +// without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to +// whom the Software is furnished to do so, subject to the +// following conditions : +// The above copyright notice and this permission notice shall +// be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +//********************************************************* +#pragma once + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include +#include +#include +#include +#include +#include + +class TracePlayer +{ +public: + struct Params + { + std::wstring m_filename; + std::wstring m_mediaDir; + UINT32 m_stagingBufferSizeMB{ 32 }; + + std::wstring m_adapterDescription{ L"intel" }; // e.g. "intel", will pick the GPU with this substring in the adapter description (not case sensitive) + enum class PreferredArchitecture + { + NONE = 0, + DISCRETE, + INTEGRATED + }; + PreferredArchitecture m_preferredArchitecture{ PreferredArchitecture::DISCRETE }; + + bool m_inspect{ false }; // inspect trace only, no playback + }; + + TracePlayer(const Params& in_params); + ~TracePlayer(); + + void PlaybackTrace(); // play trace (via DirectStorage) + void Inspect(); // display information about the trace, e.g. # submits + + UINT64 GetNumRequests() const { return m_numRequestsTotal; } + UINT64 GetNumFileBytesRead() const { return m_numFileBytesRead; } // bytes read during 1 playback + UINT64 GetNumBytesWritten() const { return m_numBytesWritten; } // uncompressed bytes written to GPU + const std::wstring& GetAdapterDescription() const { return m_params.m_adapterDescription; } +private: + template using ComPtr = Microsoft::WRL::ComPtr; + + Params m_params; + + ComPtr m_factory; + ComPtr m_device; + ComPtr m_dsFactory; + ComPtr m_dsQueue; + ComPtr m_commandQueue; + ComPtr m_heap; + + UINT64 m_fenceValue{ 0 }; + ComPtr m_fence; + HANDLE m_fenceEvent{ nullptr }; + + struct Request + { + ID3D12Resource* m_pDstResource; + D3D12_TILED_RESOURCE_COORDINATE m_dstCoord; + IDStorageFile* m_srcFile; + UINT32 m_srcOffset; + UINT32 m_numBytes; + UINT32 m_compressionFormat{ 0 }; + }; + typedef std::vector RequestArray; + std::vector m_submits; + + // release these when done + std::vector m_fileHandles; + std::vector m_dstResources; + + UINT64 m_numRequestsTotal{ 0 }; + UINT64 m_numFileBytesRead{ 0 }; + UINT64 m_numBytesWritten{ 0 }; + + void CreateDeviceWithName(); + void CreateFence(); + void InitDirectStorage(); + void LoadTraceFile(); + ID3D12Resource* CreateDestinationResource(UINT& out_numTiles, DXGI_FORMAT in_format, UINT in_width, UINT in_height, UINT in_subresourceCount); + void UpdateTileMappings(ID3D12Resource* in_pResource, UINT in_tileOffset); +}; diff --git a/tracePlayer/tracePlayer.vcxproj b/tracePlayer/tracePlayer.vcxproj new file mode 100644 index 0000000..902f6ac --- /dev/null +++ b/tracePlayer/tracePlayer.vcxproj @@ -0,0 +1,102 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {273a5112-7d55-4a16-829a-e4f73e4bace7} + tracePlayer + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/tracePlayer/tracePlayer.vcxproj.filters b/tracePlayer/tracePlayer.vcxproj.filters new file mode 100644 index 0000000..26cd730 --- /dev/null +++ b/tracePlayer/tracePlayer.vcxproj.filters @@ -0,0 +1,41 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + + + Source Files + + + + + Source Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + + \ No newline at end of file diff --git a/tracePlayer/tracePlayer_2019.vcxproj b/tracePlayer/tracePlayer_2019.vcxproj new file mode 100644 index 0000000..5cafe9e --- /dev/null +++ b/tracePlayer/tracePlayer_2019.vcxproj @@ -0,0 +1,102 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {273a5112-7d55-4a16-829a-e4f73e4bace7} + tracePlayer + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file