ShaderOpTest.cpp 83 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // ShaderOpTest.cpp //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // Provides the implementation to run tests based on descriptions. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include <windows.h>
  12. #include <d3d12.h>
  13. #include <dxgi1_4.h>
  14. #include <D3dx12.h>
  15. #include <d3dcompiler.h>
  16. #include <atlbase.h>
  17. #include "ShaderOpTest.h"
  18. #include "dxc/dxcapi.h" // IDxcCompiler
  19. #include "dxc/Support/Global.h" // OutputDebugBytes
  20. #include "dxc/Support/Unicode.h" // IsStarMatchUTF16
  21. #include "dxc/Support/dxcapi.use.h" // DxcDllSupport
  22. #include "dxc/HLSL/DxilConstants.h" // ComponentType
  23. #include "WexTestClass.h" // TAEF
  24. #include "HLSLTestUtils.h" // LogCommentFmt
  25. #include <stdlib.h>
  26. #include <DirectXMath.h>
  27. #include <intsafe.h>
  28. #include <strsafe.h>
  29. #include <xmllite.h>
  30. #pragma comment(lib, "xmllite.lib")
  31. ///////////////////////////////////////////////////////////////////////////////
  32. // Useful helper functions.
  33. static st::OutputStringFn g_OutputStrFn;
  34. static void * g_OutputStrFnCtx;
  35. void st::SetOutputFn(void *pCtx, OutputStringFn F) {
  36. g_OutputStrFnCtx = pCtx;
  37. g_OutputStrFn = F;
  38. }
  39. static void ShaderOpLogFmt(_In_z_ _Printf_format_string_ const wchar_t *fmt, ...) {
  40. va_list args;
  41. va_start(args, fmt);
  42. std::wstring buf(hlsl_test::vFormatToWString(fmt, args));
  43. va_end(args);
  44. if (g_OutputStrFn == nullptr)
  45. WEX::Logging::Log::Comment(buf.data());
  46. else
  47. g_OutputStrFn(g_OutputStrFnCtx, buf.data());
  48. }
  49. // Rely on TAEF Verifier helpers.
  50. #define CHECK_HR(x) { \
  51. if (!g_OutputStrFn) VERIFY_SUCCEEDED(x); else { \
  52. HRESULT _check_hr = (x); \
  53. if (FAILED(_check_hr)) AtlThrow(x); } \
  54. }
  55. // Check the specified HRESULT and return the success value.
  56. static HRESULT CHECK_HR_RET(HRESULT hr) {
  57. CHECK_HR(hr);
  58. return hr;
  59. }
  60. HRESULT LogIfLost(HRESULT hr, ID3D12Device *pDevice) {
  61. if (hr == DXGI_ERROR_DEVICE_REMOVED) {
  62. HRESULT reason = pDevice->GetDeviceRemovedReason();
  63. LPCWSTR reasonText = L"?";
  64. if (reason == DXGI_ERROR_DEVICE_HUNG) reasonText = L"DXGI_ERROR_DEVICE_HUNG";
  65. if (reason == DXGI_ERROR_DEVICE_REMOVED) reasonText = L"DXGI_ERROR_DEVICE_REMOVED";
  66. if (reason == DXGI_ERROR_DEVICE_RESET) reasonText = L"DXGI_ERROR_DEVICE_RESET";
  67. if (reason == DXGI_ERROR_DRIVER_INTERNAL_ERROR) reasonText = L"DXGI_ERROR_DRIVER_INTERNAL_ERROR";
  68. if (reason == DXGI_ERROR_INVALID_CALL) reasonText = L"DXGI_ERROR_INVALID_CALL";
  69. ShaderOpLogFmt(L"Device lost: 0x%08x (%s)", reason, reasonText);
  70. }
  71. return hr;
  72. }
  73. HRESULT LogIfLost(HRESULT hr, ID3D12Resource *pResource) {
  74. if (hr == DXGI_ERROR_DEVICE_REMOVED) {
  75. CComPtr<ID3D12Device> pDevice;
  76. pResource->GetDevice(__uuidof(ID3D12Device), (void**)&pDevice);
  77. LogIfLost(hr, pDevice);
  78. }
  79. return hr;
  80. }
  81. bool UseHardwareDevice(const DXGI_ADAPTER_DESC1 &desc, LPCWSTR AdapterName) {
  82. if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
  83. // Don't select the Basic Render Driver adapter.
  84. return false;
  85. }
  86. if (!AdapterName)
  87. return true;
  88. return Unicode::IsStarMatchUTF16(AdapterName, wcslen(AdapterName),
  89. desc.Description, wcslen(desc.Description));
  90. }
  91. void GetHardwareAdapter(IDXGIFactory2 *pFactory, LPCWSTR AdapterName,
  92. IDXGIAdapter1 **ppAdapter) {
  93. CComPtr<IDXGIAdapter1> adapter;
  94. *ppAdapter = nullptr;
  95. for (UINT adapterIndex = 0;
  96. DXGI_ERROR_NOT_FOUND != pFactory->EnumAdapters1(adapterIndex, &adapter);
  97. ++adapterIndex) {
  98. DXGI_ADAPTER_DESC1 desc;
  99. adapter->GetDesc1(&desc);
  100. if (!UseHardwareDevice(desc, AdapterName)) {
  101. adapter.Release();
  102. continue;
  103. }
  104. // Check to see if the adapter supports Direct3D 12, but don't create the
  105. // actual device yet.
  106. if (SUCCEEDED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0,
  107. _uuidof(ID3D12Device), nullptr))) {
  108. break;
  109. }
  110. adapter.Release();
  111. }
  112. *ppAdapter = adapter.Detach();
  113. }
  114. void RecordTransitionBarrier(ID3D12GraphicsCommandList *pCommandList,
  115. ID3D12Resource *pResource,
  116. D3D12_RESOURCE_STATES before,
  117. D3D12_RESOURCE_STATES after) {
  118. CD3DX12_RESOURCE_BARRIER barrier(
  119. CD3DX12_RESOURCE_BARRIER::Transition(pResource, before, after));
  120. pCommandList->ResourceBarrier(1, &barrier);
  121. }
  122. void ExecuteCommandList(ID3D12CommandQueue *pQueue, ID3D12CommandList *pList) {
  123. ID3D12CommandList *ppCommandLists[] = { pList };
  124. pQueue->ExecuteCommandLists(1, ppCommandLists);
  125. }
  126. HRESULT SetObjectName(ID3D12Object *pObject, LPCSTR pName) {
  127. if (pObject && pName) {
  128. CA2W WideName(pName);
  129. return pObject->SetName(WideName);
  130. }
  131. return S_FALSE;
  132. }
  133. void WaitForSignal(ID3D12CommandQueue *pCQ, ID3D12Fence *pFence,
  134. HANDLE hFence, UINT64 fenceValue) {
  135. // Signal and increment the fence value.
  136. const UINT64 fence = fenceValue;
  137. CHECK_HR(pCQ->Signal(pFence, fence));
  138. if (pFence->GetCompletedValue() < fenceValue) {
  139. CHECK_HR(pFence->SetEventOnCompletion(fenceValue, hFence));
  140. WaitForSingleObject(hFence, INFINITE);
  141. //CHECK_HR(pCQ->Wait(pFence, fenceValue));
  142. }
  143. }
  144. static void SetupComputeValuePattern(std::vector<uint32_t> &values, size_t count) {
  145. values.resize(count); // one element per dispatch group, in bytes
  146. for (size_t i = 0; i < count; ++i) {
  147. values[i] = (uint32_t)i;
  148. }
  149. }
  150. void MappedData::dump() const {
  151. OutputDebugBytes(m_pData, m_size);
  152. }
  153. void MappedData::reset() {
  154. if (m_pResource != nullptr) {
  155. m_pResource->Unmap(0, nullptr);
  156. m_pResource.Release();
  157. }
  158. m_pData = nullptr;
  159. }
  160. ///////////////////////////////////////////////////////////////////////////////
  161. // Helper class for mapped data.
  162. void MappedData::reset(ID3D12Resource *pResource, UINT32 sizeInBytes) {
  163. reset();
  164. D3D12_RANGE r;
  165. r.Begin = 0;
  166. r.End = sizeInBytes;
  167. CHECK_HR(LogIfLost(pResource->Map(0, &r, &m_pData), pResource));
  168. m_pResource = pResource;
  169. m_size = sizeInBytes;
  170. }
  171. ///////////////////////////////////////////////////////////////////////////////
  172. // ShaderOpTest library implementation.
  173. namespace st {
  174. LPCSTR string_table::insert(LPCSTR pValue) {
  175. std::unordered_set<LPCSTR, HashStr, PredStr>::iterator i = m_values.find(pValue);
  176. if (i == m_values.end()) {
  177. size_t bufSize = strlen(pValue) + 1;
  178. std::vector<char> s;
  179. s.resize(bufSize);
  180. strcpy_s(s.data(), bufSize, pValue);
  181. LPCSTR result = s.data();
  182. m_values.insert(result);
  183. m_strings.push_back(std::move(s));
  184. return result;
  185. }
  186. else {
  187. return *i;
  188. }
  189. }
  190. LPCSTR string_table::insert(LPCWSTR pValue) {
  191. CW2A pValueAnsi(pValue);
  192. return insert(pValueAnsi.m_psz);
  193. }
  194. void CommandListRefs::CreateForDevice(ID3D12Device *pDevice, bool compute) {
  195. D3D12_COMMAND_LIST_TYPE T = compute ? D3D12_COMMAND_LIST_TYPE_COMPUTE
  196. : D3D12_COMMAND_LIST_TYPE_DIRECT;
  197. D3D12_COMMAND_QUEUE_DESC queueDesc = {};
  198. queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
  199. queueDesc.Type = T;
  200. if (Queue == nullptr) {
  201. CHECK_HR(pDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&Queue)));
  202. }
  203. CHECK_HR(pDevice->CreateCommandAllocator(T, IID_PPV_ARGS(&Allocator)));
  204. CHECK_HR(pDevice->CreateCommandList(0, T, Allocator, nullptr,
  205. IID_PPV_ARGS(&List)));
  206. }
  207. void ShaderOpTest::CopyBackResources() {
  208. CommandListRefs ResCommandList;
  209. ResCommandList.CreateForDevice(m_pDevice, m_pShaderOp->IsCompute());
  210. ID3D12GraphicsCommandList *pList = ResCommandList.List;
  211. pList->SetName(L"ShaderOpTest Resource ReadBack CommandList");
  212. for (ShaderOpResource &R : m_pShaderOp->Resources) {
  213. if (!R.ReadBack)
  214. continue;
  215. ShaderOpResourceData &D = m_ResourceData[R.Name];
  216. RecordTransitionBarrier(pList, D.Resource, D.ResourceState,
  217. D3D12_RESOURCE_STATE_COPY_SOURCE);
  218. D.ResourceState = D3D12_RESOURCE_STATE_COPY_SOURCE;
  219. D3D12_RESOURCE_DESC &Desc = D.ShaderOpRes->Desc;
  220. if (Desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) {
  221. pList->CopyResource(D.ReadBack, D.Resource);
  222. }
  223. else {
  224. UINT rowPitch = Desc.Width * GetByteSizeForFormat(Desc.Format);
  225. if (rowPitch % D3D12_TEXTURE_DATA_PITCH_ALIGNMENT)
  226. rowPitch += D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - (rowPitch % D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
  227. D3D12_PLACED_SUBRESOURCE_FOOTPRINT Footprint;
  228. Footprint.Offset = 0;
  229. Footprint.Footprint = CD3DX12_SUBRESOURCE_FOOTPRINT(Desc.Format, Desc.Width, Desc.Height, 1, rowPitch);
  230. CD3DX12_TEXTURE_COPY_LOCATION DstLoc(D.ReadBack, Footprint);
  231. CD3DX12_TEXTURE_COPY_LOCATION SrcLoc(D.Resource, 0);
  232. pList->CopyTextureRegion(&DstLoc, 0, 0, 0, &SrcLoc, nullptr);
  233. }
  234. }
  235. pList->Close();
  236. ExecuteCommandList(ResCommandList.Queue, pList);
  237. WaitForSignal(ResCommandList.Queue, m_pFence, m_hFence, m_FenceValue++);
  238. }
  239. void ShaderOpTest::CreateCommandList() {
  240. bool priorQueue = m_CommandList.Queue != nullptr;
  241. m_CommandList.CreateForDevice(m_pDevice, m_pShaderOp->IsCompute());
  242. m_CommandList.Allocator->SetName(L"ShaderOpTest Allocator");
  243. m_CommandList.List->SetName(L"ShaderOpTest CommandList");
  244. if (!priorQueue)
  245. m_CommandList.Queue->SetName(L"ShaderOpTest CommandList");
  246. }
  247. void ShaderOpTest::CreateDescriptorHeaps() {
  248. for (ShaderOpDescriptorHeap &H : m_pShaderOp->DescriptorHeaps) {
  249. CComPtr<ID3D12DescriptorHeap> pHeap;
  250. if (H.Desc.NumDescriptors == 0) {
  251. H.Desc.NumDescriptors = (UINT)H.Descriptors.size();
  252. }
  253. CHECK_HR(m_pDevice->CreateDescriptorHeap(&H.Desc, IID_PPV_ARGS(&pHeap)));
  254. m_DescriptorHeaps.push_back(pHeap);
  255. m_DescriptorHeapsByName[H.Name] = pHeap;
  256. SetObjectName(pHeap, H.Name);
  257. const UINT descriptorSize = m_pDevice->GetDescriptorHandleIncrementSize(H.Desc.Type);
  258. CD3DX12_CPU_DESCRIPTOR_HANDLE cpuHandle(pHeap->GetCPUDescriptorHandleForHeapStart());
  259. CD3DX12_GPU_DESCRIPTOR_HANDLE gpuHandle(pHeap->GetGPUDescriptorHandleForHeapStart());
  260. for (ShaderOpDescriptor &D : H.Descriptors) {
  261. ShaderOpResource *R = m_pShaderOp->GetResourceByName(D.ResName);
  262. if (R == nullptr) {
  263. LPCSTR DescName = D.Name ? D.Name : "[unnamed descriptor]";
  264. ShaderOpLogFmt(L"Descriptor '%S' references missing resource '%S'", DescName, D.ResName);
  265. CHECK_HR(E_INVALIDARG);
  266. }
  267. ShaderOpResourceData &Data = m_ResourceData[D.ResName];
  268. ShaderOpDescriptorData DData;
  269. DData.Descriptor = &D;
  270. DData.ResData = &Data;
  271. if (0 == _stricmp(D.Kind, "UAV")) {
  272. ID3D12Resource *pCounterResource = nullptr;
  273. if (D.CounterName && *D.CounterName) {
  274. ShaderOpResourceData &CounterData = m_ResourceData[D.CounterName];
  275. pCounterResource = CounterData.Resource;
  276. }
  277. m_pDevice->CreateUnorderedAccessView(Data.Resource, pCounterResource,
  278. &D.UavDesc, cpuHandle);
  279. }
  280. else if (0 == _stricmp(D.Kind, "SRV")) {
  281. D3D12_SHADER_RESOURCE_VIEW_DESC *pSrvDesc = nullptr;
  282. m_pDevice->CreateShaderResourceView(Data.Resource, pSrvDesc, cpuHandle);
  283. }
  284. else if (0 == _stricmp(D.Kind, "RTV")) {
  285. m_pDevice->CreateRenderTargetView(Data.Resource, nullptr, cpuHandle);
  286. }
  287. else if (0 == _stricmp(D.Kind, "CBV")) {
  288. D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc;
  289. cbvDesc.BufferLocation = Data.Resource->GetGPUVirtualAddress();
  290. cbvDesc.SizeInBytes = Data.Resource->GetDesc().Width;
  291. m_pDevice->CreateConstantBufferView(&cbvDesc, cpuHandle);
  292. }
  293. DData.GPUHandle = gpuHandle;
  294. DData.CPUHandle = cpuHandle;
  295. m_DescriptorData[R->Name] = DData;
  296. cpuHandle = cpuHandle.Offset(descriptorSize);
  297. gpuHandle = gpuHandle.Offset(descriptorSize);
  298. }
  299. }
  300. // Create query descriptor heap.
  301. D3D12_QUERY_HEAP_DESC queryHeapDesc;
  302. ZeroMemory(&queryHeapDesc, sizeof(queryHeapDesc));
  303. queryHeapDesc.Count = 1;
  304. queryHeapDesc.Type = D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS;
  305. CHECK_HR(m_pDevice->CreateQueryHeap(&queryHeapDesc, IID_PPV_ARGS(&m_pQueryHeap)));
  306. }
  307. void ShaderOpTest::CreateDevice() {
  308. if (m_pDevice == nullptr) {
  309. const D3D_FEATURE_LEVEL FeatureLevelRequired = D3D_FEATURE_LEVEL_11_0;
  310. CComPtr<IDXGIFactory4> factory;
  311. CComPtr<ID3D12Device> pDevice;
  312. CHECK_HR(CreateDXGIFactory1(IID_PPV_ARGS(&factory)));
  313. if (m_pShaderOp->UseWarpDevice) {
  314. CComPtr<IDXGIAdapter> warpAdapter;
  315. CHECK_HR(factory->EnumWarpAdapter(IID_PPV_ARGS(&warpAdapter)));
  316. CHECK_HR(D3D12CreateDevice(warpAdapter, FeatureLevelRequired,
  317. IID_PPV_ARGS(&pDevice)));
  318. } else {
  319. CComPtr<IDXGIAdapter1> hardwareAdapter;
  320. GetHardwareAdapter(factory, m_pShaderOp->AdapterName, &hardwareAdapter);
  321. if (hardwareAdapter == nullptr) {
  322. CHECK_HR(HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
  323. }
  324. CHECK_HR(D3D12CreateDevice(hardwareAdapter, FeatureLevelRequired,
  325. IID_PPV_ARGS(&pDevice)));
  326. }
  327. m_pDevice.Attach(pDevice.Detach());
  328. m_pDevice->SetName(L"ShaderOpTest Device");
  329. }
  330. m_FenceValue = 1;
  331. CHECK_HR(m_pDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE,
  332. __uuidof(ID3D12Fence), (void **)&m_pFence));
  333. m_pFence->SetName(L"ShaderOpTest Fence");
  334. m_hFence = CreateEvent(nullptr, FALSE, FALSE, nullptr);
  335. if (m_hFence == nullptr) {
  336. AtlThrow(HRESULT_FROM_WIN32(GetLastError()));
  337. }
  338. }
  339. static void InitByteCode(D3D12_SHADER_BYTECODE *pBytecode, ID3D10Blob *pBlob) {
  340. if (pBlob == nullptr) {
  341. pBytecode->BytecodeLength = 0;
  342. pBytecode->pShaderBytecode = nullptr;
  343. }
  344. else {
  345. pBytecode->BytecodeLength = pBlob->GetBufferSize();
  346. pBytecode->pShaderBytecode = pBlob->GetBufferPointer();
  347. }
  348. }
  349. void ShaderOpTest::CreatePipelineState() {
  350. CreateRootSignature();
  351. CreateShaders();
  352. if (m_pShaderOp->IsCompute()) {
  353. CComPtr<ID3D10Blob> pCS;
  354. pCS = m_Shaders[m_pShaderOp->CS];
  355. D3D12_COMPUTE_PIPELINE_STATE_DESC CDesc;
  356. ZeroMemory(&CDesc, sizeof(CDesc));
  357. CDesc.pRootSignature = m_pRootSignature.p;
  358. InitByteCode(&CDesc.CS, pCS);
  359. CHECK_HR(m_pDevice->CreateComputePipelineState(&CDesc, IID_PPV_ARGS(&m_pPSO)));
  360. }
  361. else {
  362. CComPtr<ID3D10Blob> pPS;
  363. CComPtr<ID3D10Blob> pVS;
  364. pPS = m_Shaders[m_pShaderOp->PS];
  365. pVS = m_Shaders[m_pShaderOp->VS];
  366. D3D12_GRAPHICS_PIPELINE_STATE_DESC GDesc;
  367. ZeroMemory(&GDesc, sizeof(GDesc));
  368. InitByteCode(&GDesc.VS, pVS);
  369. InitByteCode(&GDesc.PS, pPS);
  370. GDesc.InputLayout.NumElements = m_pShaderOp->InputElements.size();
  371. GDesc.InputLayout.pInputElementDescs = m_pShaderOp->InputElements.data();
  372. GDesc.PrimitiveTopologyType = m_pShaderOp->PrimitiveTopologyType;
  373. GDesc.NumRenderTargets = m_pShaderOp->RenderTargets.size();
  374. GDesc.SampleMask = m_pShaderOp->SampleMask;
  375. for (size_t i = 0; i < m_pShaderOp->RenderTargets.size(); ++i) {
  376. ShaderOpResource *R = m_pShaderOp->GetResourceByName(m_pShaderOp->RenderTargets[i]);
  377. GDesc.RTVFormats[i] = R->Desc.Format;
  378. }
  379. GDesc.SampleDesc.Count = 1; // TODO: read from file, set from shader operation; also apply to count
  380. GDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); // TODO: read from file, set from op
  381. GDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); // TODO: read from file, set from op
  382. // TODO: pending values to set
  383. #if 0
  384. D3D12_STREAM_OUTPUT_DESC StreamOutput;
  385. D3D12_DEPTH_STENCIL_DESC DepthStencilState;
  386. D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue;
  387. DXGI_FORMAT DSVFormat;
  388. UINT NodeMask;
  389. D3D12_PIPELINE_STATE_FLAGS Flags;
  390. #endif
  391. GDesc.pRootSignature = m_pRootSignature.p;
  392. CHECK_HR(m_pDevice->CreateGraphicsPipelineState(&GDesc, IID_PPV_ARGS(&m_pPSO)));
  393. }
  394. }
  395. void ShaderOpTest::CreateResources() {
  396. CommandListRefs ResCommandList;
  397. ResCommandList.CreateForDevice(m_pDevice, true);
  398. ResCommandList.Allocator->SetName(L"ShaderOpTest Resource Creation Allocation");
  399. ResCommandList.Queue->SetName(L"ShaderOpTest Resource Creation Queue");
  400. ResCommandList.List->SetName(L"ShaderOpTest Resource Creation CommandList");
  401. ID3D12GraphicsCommandList *pList = ResCommandList.List.p;
  402. std::vector<CComPtr<ID3D12Resource> > intermediates;
  403. for (ShaderOpResource &R : m_pShaderOp->Resources) {
  404. if (m_ResourceData.count(R.Name) > 0) continue;
  405. // Initialize the upload resource early, to allow a by-name initializer
  406. // to set the desired width.
  407. bool initByName = R.Init && 0 == _stricmp("byname", R.Init);
  408. bool initZero = R.Init && 0 == _stricmp("zero", R.Init);
  409. bool initFromBytes = R.Init && 0 == _stricmp("frombytes", R.Init);
  410. bool hasInit = initByName || initZero || initFromBytes;
  411. bool isBuffer = R.Desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER;
  412. std::vector<BYTE> values;
  413. if (hasInit) {
  414. if (isBuffer) {
  415. values.resize((size_t)R.Desc.Width);
  416. }
  417. else {
  418. // Probably needs more information.
  419. values.resize((size_t)(R.Desc.Width * R.Desc.Height *
  420. GetByteSizeForFormat(R.Desc.Format)));
  421. }
  422. if (initZero) {
  423. memset(values.data(), 0, values.size());
  424. }
  425. else if (initByName) {
  426. m_InitCallbackFn(R.Name, values, m_pShaderOp);
  427. if (isBuffer) {
  428. R.Desc.Width = values.size();
  429. }
  430. }
  431. else if (initFromBytes) {
  432. values = R.InitBytes;
  433. if (R.Desc.Width == 0) {
  434. if (isBuffer) {
  435. R.Desc.Width = values.size();
  436. }
  437. else if (R.Desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D) {
  438. R.Desc.Width = values.size() / GetByteSizeForFormat(R.Desc.Format);
  439. }
  440. }
  441. }
  442. }
  443. CComPtr<ID3D12Resource> pResource;
  444. CHECK_HR(m_pDevice->CreateCommittedResource(
  445. &R.HeapProperties, R.HeapFlags, &R.Desc, R.InitialResourceState,
  446. nullptr, IID_PPV_ARGS(&pResource)));
  447. ShaderOpResourceData &D = m_ResourceData[R.Name];
  448. D.ShaderOpRes = &R;
  449. D.Resource = pResource;
  450. D.ResourceState = R.InitialResourceState;
  451. SetObjectName(pResource, R.Name);
  452. if (hasInit) {
  453. CComPtr<ID3D12Resource> pIntermediate;
  454. CD3DX12_HEAP_PROPERTIES upload(D3D12_HEAP_TYPE_UPLOAD);
  455. D3D12_RESOURCE_DESC uploadDesc = R.Desc;
  456. // Calculate size required for intermediate buffer
  457. UINT64 totalBytes;
  458. m_pDevice->GetCopyableFootprints(&uploadDesc, 0, 1, 0, nullptr, nullptr, nullptr, &totalBytes);
  459. if (!isBuffer) {
  460. // Assuming a simple linear layout here.
  461. uploadDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
  462. uploadDesc.Width = totalBytes;
  463. uploadDesc.Height = 1;
  464. uploadDesc.MipLevels = 1;
  465. uploadDesc.Format = DXGI_FORMAT_UNKNOWN;
  466. uploadDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
  467. }
  468. uploadDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
  469. CHECK_HR(m_pDevice->CreateCommittedResource(
  470. &upload, D3D12_HEAP_FLAG_NONE, &uploadDesc,
  471. D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
  472. IID_PPV_ARGS(&pIntermediate)));
  473. intermediates.push_back(pIntermediate);
  474. char uploadObjectName[128];
  475. if (R.Name && SUCCEEDED(StringCchPrintfA(
  476. uploadObjectName, _countof(uploadObjectName),
  477. "Upload resource for %s", R.Name))) {
  478. SetObjectName(pIntermediate, uploadObjectName);
  479. }
  480. D3D12_SUBRESOURCE_DATA transferData;
  481. transferData.pData = values.data();
  482. transferData.RowPitch = values.size() / R.Desc.Height;
  483. transferData.SlicePitch = values.size();
  484. UpdateSubresources<1>(pList, pResource.p, pIntermediate.p, 0, 0, 1,
  485. &transferData);
  486. }
  487. if (R.ReadBack) {
  488. CComPtr<ID3D12Resource> pReadbackResource;
  489. CD3DX12_HEAP_PROPERTIES readback(D3D12_HEAP_TYPE_READBACK);
  490. UINT64 width = R.Desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER
  491. ? R.Desc.Width
  492. : (R.Desc.Height * R.Desc.Width *
  493. GetByteSizeForFormat(R.Desc.Format));
  494. CD3DX12_RESOURCE_DESC readbackDesc(CD3DX12_RESOURCE_DESC::Buffer(width));
  495. readbackDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
  496. CHECK_HR(m_pDevice->CreateCommittedResource(
  497. &readback, D3D12_HEAP_FLAG_NONE, &readbackDesc,
  498. D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
  499. IID_PPV_ARGS(&pReadbackResource)));
  500. D.ReadBack = pReadbackResource;
  501. char readbackObjectName[128];
  502. if (R.Name && SUCCEEDED(StringCchPrintfA(
  503. readbackObjectName, _countof(readbackObjectName),
  504. "Readback resource for %s", R.Name))) {
  505. SetObjectName(pReadbackResource, readbackObjectName);
  506. }
  507. }
  508. if (R.TransitionTo != D.ResourceState) {
  509. RecordTransitionBarrier(pList, D.Resource, D.ResourceState,
  510. R.TransitionTo);
  511. D.ResourceState = R.TransitionTo;
  512. }
  513. }
  514. // Create a buffer to receive query results.
  515. {
  516. CComPtr<ID3D12Resource> pReadbackResource;
  517. CD3DX12_HEAP_PROPERTIES readback(D3D12_HEAP_TYPE_READBACK);
  518. CD3DX12_RESOURCE_DESC readbackDesc(CD3DX12_RESOURCE_DESC::Buffer(sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS)));
  519. CHECK_HR(m_pDevice->CreateCommittedResource(
  520. &readback, D3D12_HEAP_FLAG_NONE, &readbackDesc,
  521. D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
  522. IID_PPV_ARGS(&m_pQueryBuffer)));
  523. SetObjectName(m_pQueryBuffer, "Query Pipeline Readback Buffer");
  524. }
  525. CHECK_HR(pList->Close());
  526. ExecuteCommandList(ResCommandList.Queue, pList);
  527. WaitForSignal(ResCommandList.Queue, m_pFence, m_hFence, m_FenceValue++);
  528. }
  529. void ShaderOpTest::CreateRootSignature() {
  530. if (m_pShaderOp->RootSignature == nullptr) {
  531. AtlThrow(E_INVALIDARG);
  532. }
  533. CComPtr<ID3DBlob> pCode;
  534. CComPtr<ID3DBlob> pRootSignatureBlob;
  535. CComPtr<ID3DBlob> pError;
  536. std::string sQuoted;
  537. sQuoted.reserve(2 + strlen(m_pShaderOp->RootSignature) + 1);
  538. sQuoted.append("\"");
  539. sQuoted.append(m_pShaderOp->RootSignature);
  540. sQuoted.append("\"");
  541. char *ch = (char *)sQuoted.data();
  542. while (*ch) {
  543. if (*ch == '\r' || *ch == '\n') *ch = ' ';
  544. ++ch;
  545. }
  546. D3D_SHADER_MACRO M[2] = {
  547. { "RootSigVal", sQuoted.c_str() },
  548. { nullptr, nullptr }
  549. };
  550. HRESULT hr = D3DCompile(nullptr, 0, "RootSigShader", M, nullptr, sQuoted.c_str(),
  551. "rootsig_1_0", 0, 0, &pCode, &pError);
  552. if (FAILED(hr) && pError != nullptr) {
  553. ShaderOpLogFmt(L"Failed to compile root signature:\r\n%*S",
  554. (int)pError->GetBufferSize(),
  555. (LPCSTR)pError->GetBufferPointer());
  556. }
  557. CHECK_HR(hr);
  558. CHECK_HR(D3DGetBlobPart(pCode->GetBufferPointer(), pCode->GetBufferSize(),
  559. D3D_BLOB_ROOT_SIGNATURE, 0, &pRootSignatureBlob));
  560. CHECK_HR(m_pDevice->CreateRootSignature(
  561. 0, pRootSignatureBlob->GetBufferPointer(),
  562. pRootSignatureBlob->GetBufferSize(), IID_PPV_ARGS(&m_pRootSignature)));
  563. }
  564. static bool TargetUsesDxil(LPCSTR pText) {
  565. return (strlen(pText) > 3) && pText[3] >= '6'; // xx_6xx
  566. }
  567. static void splitWStringIntoVectors(LPWSTR str, wchar_t delim, std::vector<LPWSTR> &list) {
  568. if (str) {
  569. LPWSTR cur = str;
  570. list.push_back(cur);
  571. while (*cur != L'\0') {
  572. if (*cur == delim) {
  573. list.push_back(cur+1);
  574. *(cur) = L'\0';
  575. }
  576. cur++;
  577. }
  578. }
  579. }
  580. void ShaderOpTest::CreateShaders() {
  581. for (ShaderOpShader &S : m_pShaderOp->Shaders) {
  582. CComPtr<ID3DBlob> pCode;
  583. HRESULT hr = S_OK;
  584. LPCSTR pText = m_pShaderOp->GetShaderText(&S);
  585. if (TargetUsesDxil(S.Target)) {
  586. CComPtr<IDxcCompiler> pCompiler;
  587. CComPtr<IDxcLibrary> pLibrary;
  588. CComPtr<IDxcBlobEncoding> pTextBlob;
  589. CComPtr<IDxcOperationResult> pResult;
  590. CA2W nameW(S.Name, CP_UTF8);
  591. CA2W entryPointW(S.EntryPoint, CP_UTF8);
  592. CA2W targetW(S.Target, CP_UTF8);
  593. CA2W argumentsW(S.Arguments, CP_UTF8);
  594. std::vector<LPWSTR> argumentsWList;
  595. splitWStringIntoVectors(argumentsW, L' ', argumentsWList);
  596. HRESULT resultCode;
  597. CHECK_HR(m_pDxcSupport->CreateInstance(CLSID_DxcLibrary, &pLibrary));
  598. CHECK_HR(pLibrary->CreateBlobWithEncodingFromPinned(
  599. (LPBYTE)pText, (UINT32)strlen(pText), CP_UTF8, &pTextBlob));
  600. CHECK_HR(m_pDxcSupport->CreateInstance(CLSID_DxcCompiler, &pCompiler));
  601. CHECK_HR(pCompiler->Compile(pTextBlob, nameW, entryPointW, targetW,
  602. (LPCWSTR *)argumentsWList.data(), argumentsWList.size(),
  603. nullptr, 0,
  604. nullptr, &pResult));
  605. CHECK_HR(pResult->GetStatus(&resultCode));
  606. if (FAILED(resultCode)) {
  607. CComPtr<IDxcBlobEncoding> errors;
  608. CHECK_HR(pResult->GetErrorBuffer(&errors));
  609. ShaderOpLogFmt(L"Failed to compile shader: %*S\r\n",
  610. (int)errors->GetBufferSize(),
  611. errors->GetBufferPointer());
  612. }
  613. CHECK_HR(resultCode);
  614. CHECK_HR(pResult->GetResult((IDxcBlob **)&pCode));
  615. } else {
  616. CComPtr<ID3DBlob> pError;
  617. hr = D3DCompile(pText, strlen(pText), S.Name, nullptr, nullptr,
  618. S.EntryPoint, S.Target, 0, 0, &pCode, &pError);
  619. if (FAILED(hr) && pError != nullptr) {
  620. ShaderOpLogFmt(L"%*S\r\n", (int)pError->GetBufferSize(),
  621. ((LPCSTR)pError->GetBufferPointer()));
  622. }
  623. }
  624. CHECK_HR(hr);
  625. m_Shaders[S.Name] = pCode;
  626. }
  627. }
  628. void ShaderOpTest::GetPipelineStats(D3D12_QUERY_DATA_PIPELINE_STATISTICS *pStats) {
  629. MappedData M;
  630. M.reset(m_pQueryBuffer, sizeof(*pStats));
  631. memcpy(pStats, M.data(), sizeof(*pStats));
  632. }
  633. void ShaderOpTest::GetReadBackData(LPCSTR pResourceName, MappedData *pData) {
  634. pResourceName = m_pShaderOp->Strings.insert(pResourceName); // Unique
  635. ShaderOpResourceData &D = m_ResourceData.at(pResourceName);
  636. D3D12_RESOURCE_DESC Desc = D.ReadBack->GetDesc();
  637. UINT32 sizeInBytes = (UINT32)Desc.Width;
  638. pData->reset(D.ReadBack, sizeInBytes);
  639. }
  640. static void SetDescriptorHeaps(ID3D12GraphicsCommandList *pList,
  641. std::vector<ID3D12DescriptorHeap *> &heaps) {
  642. if (heaps.empty())
  643. return;
  644. std::vector<ID3D12DescriptorHeap *> localHeaps;
  645. for (auto &H : heaps) {
  646. if (H->GetDesc().Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE) {
  647. localHeaps.push_back(H);
  648. }
  649. }
  650. if (!localHeaps.empty())
  651. pList->SetDescriptorHeaps((UINT)localHeaps.size(), localHeaps.data());
  652. }
  653. void ShaderOpTest::RunCommandList() {
  654. ID3D12GraphicsCommandList *pList = m_CommandList.List.p;
  655. if (m_pShaderOp->IsCompute()) {
  656. pList->SetPipelineState(m_pPSO);
  657. pList->SetComputeRootSignature(m_pRootSignature);
  658. SetDescriptorHeaps(pList, m_DescriptorHeaps);
  659. SetRootValues(pList, m_pShaderOp->IsCompute());
  660. pList->Dispatch(m_pShaderOp->DispatchX, m_pShaderOp->DispatchY,
  661. m_pShaderOp->DispatchZ);
  662. } else {
  663. pList->SetPipelineState(m_pPSO);
  664. pList->SetGraphicsRootSignature(m_pRootSignature);
  665. SetDescriptorHeaps(pList, m_DescriptorHeaps);
  666. SetRootValues(pList, m_pShaderOp->IsCompute());
  667. if (!m_pShaderOp->RenderTargets.empty()) {
  668. // Use the first render target to set up the viewport and scissors.
  669. ShaderOpResource *R = m_pShaderOp->GetResourceByName(m_pShaderOp->RenderTargets[0]);
  670. D3D12_VIEWPORT viewport;
  671. D3D12_RECT scissorRect;
  672. memset(&viewport, 0, sizeof(viewport));
  673. viewport.Height = R->Desc.Height;
  674. viewport.Width = R->Desc.Width;
  675. viewport.MaxDepth = 1.0f;
  676. memset(&scissorRect, 0, sizeof(scissorRect));
  677. scissorRect.right = viewport.Width;
  678. scissorRect.bottom = viewport.Height;
  679. pList->RSSetViewports(1, &viewport);
  680. pList->RSSetScissorRects(1, &scissorRect);
  681. }
  682. // Indicate that the buffers will be used as render targets.
  683. D3D12_CPU_DESCRIPTOR_HANDLE rtvHandles[8];
  684. UINT rtvHandleCount = m_pShaderOp->RenderTargets.size();
  685. for (size_t i = 0; i < rtvHandleCount; ++i) {
  686. auto &rt = m_pShaderOp->RenderTargets[i];
  687. ShaderOpDescriptorData &DData = m_DescriptorData[rt];
  688. rtvHandles[i] = DData.CPUHandle;
  689. RecordTransitionBarrier(pList, DData.ResData->Resource,
  690. DData.ResData->ResourceState,
  691. D3D12_RESOURCE_STATE_RENDER_TARGET);
  692. DData.ResData->ResourceState = D3D12_RESOURCE_STATE_RENDER_TARGET;
  693. }
  694. pList->OMSetRenderTargets(rtvHandleCount, rtvHandles, FALSE, nullptr);
  695. const float ClearColor[4] = { 0.0f, 0.2f, 0.4f, 1.0f };
  696. pList->ClearRenderTargetView(rtvHandles[0], ClearColor, 0, nullptr);
  697. // TODO: set all of this from m_pShaderOp.
  698. ShaderOpResourceData &VBufferData = this->m_ResourceData[m_pShaderOp->Strings.insert("VBuffer")];
  699. D3D_PRIMITIVE_TOPOLOGY topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
  700. for (ShaderOpResource &resource : m_pShaderOp->Resources) {
  701. if (_strcmpi(resource.Name, "VBuffer") == 0) {
  702. topology = resource.PrimitiveTopology;
  703. break;
  704. }
  705. }
  706. pList->IASetPrimitiveTopology(topology);
  707. // Calculate the stride in bytes from the inputs, assuming linear & contiguous.
  708. UINT strideInBytes = 0;
  709. for (auto && IE : m_pShaderOp->InputElements) {
  710. strideInBytes += GetByteSizeForFormat(IE.Format);
  711. }
  712. D3D12_VERTEX_BUFFER_VIEW vertexBufferView;
  713. vertexBufferView.BufferLocation = VBufferData.Resource->GetGPUVirtualAddress();
  714. vertexBufferView.StrideInBytes = strideInBytes;
  715. vertexBufferView.SizeInBytes = VBufferData.ShaderOpRes->Desc.Width;
  716. pList->IASetVertexBuffers(0, 1, &vertexBufferView);
  717. UINT vertexCount = vertexBufferView.SizeInBytes / vertexBufferView.StrideInBytes;
  718. UINT instanceCount = 1;
  719. UINT vertexCountPerInstance = vertexCount / instanceCount;
  720. pList->BeginQuery(m_pQueryHeap, D3D12_QUERY_TYPE_PIPELINE_STATISTICS, 0);
  721. pList->DrawInstanced(vertexCountPerInstance, instanceCount, 0, 0);
  722. pList->EndQuery(m_pQueryHeap, D3D12_QUERY_TYPE_PIPELINE_STATISTICS, 0);
  723. pList->ResolveQueryData(m_pQueryHeap, D3D12_QUERY_TYPE_PIPELINE_STATISTICS,
  724. 0, 1, m_pQueryBuffer, 0);
  725. }
  726. CHECK_HR(pList->Close());
  727. ExecuteCommandList(m_CommandList.Queue, pList);
  728. WaitForSignal(m_CommandList.Queue, m_pFence, m_hFence, m_FenceValue++);
  729. }
  730. void ShaderOpTest::RunShaderOp(ShaderOp *pShaderOp) {
  731. m_pShaderOp = pShaderOp;
  732. CreateDevice();
  733. CreateResources();
  734. CreateDescriptorHeaps();
  735. CreatePipelineState();
  736. CreateCommandList();
  737. RunCommandList();
  738. CopyBackResources();
  739. }
  740. void ShaderOpTest::RunShaderOp(std::shared_ptr<ShaderOp> ShaderOp) {
  741. m_OrigShaderOp = ShaderOp;
  742. RunShaderOp(m_OrigShaderOp.get());
  743. }
  744. void ShaderOpTest::SetRootValues(ID3D12GraphicsCommandList *pList,
  745. bool isCompute) {
  746. for (size_t i = 0; i < m_pShaderOp->RootValues.size(); ++i) {
  747. ShaderOpRootValue &V = m_pShaderOp->RootValues[i];
  748. UINT idx = V.Index == 0 ? (UINT)i : V.Index;
  749. if (V.ResName) {
  750. auto r_it = m_ResourceData.find(V.ResName);
  751. if (r_it == m_ResourceData.end()) {
  752. ShaderOpLogFmt(L"Root value #%u refers to missing resource %S", (unsigned)i, V.ResName);
  753. CHECK_HR(E_INVALIDARG);
  754. }
  755. // Issue a warning for trying to bind textures (GPU address will return null)
  756. ShaderOpResourceData &D = r_it->second;
  757. ID3D12Resource *pRes = D.Resource;
  758. if (isCompute) {
  759. switch (D.ShaderOpRes->TransitionTo) {
  760. case D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER:
  761. pList->SetComputeRootConstantBufferView(idx,
  762. pRes->GetGPUVirtualAddress());
  763. break;
  764. case D3D12_RESOURCE_STATE_UNORDERED_ACCESS:
  765. pList->SetComputeRootUnorderedAccessView(idx,
  766. pRes->GetGPUVirtualAddress());
  767. break;
  768. case D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE:
  769. default:
  770. pList->SetComputeRootShaderResourceView(idx,
  771. pRes->GetGPUVirtualAddress());
  772. break;
  773. }
  774. }
  775. else {
  776. switch (D.ShaderOpRes->TransitionTo) {
  777. case D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER:
  778. pList->SetGraphicsRootConstantBufferView(idx,
  779. pRes->GetGPUVirtualAddress());
  780. break;
  781. case D3D12_RESOURCE_STATE_UNORDERED_ACCESS:
  782. pList->SetGraphicsRootUnorderedAccessView(idx,
  783. pRes->GetGPUVirtualAddress());
  784. break;
  785. case D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE:
  786. default:
  787. pList->SetGraphicsRootShaderResourceView(idx,
  788. pRes->GetGPUVirtualAddress());
  789. break;
  790. }
  791. }
  792. }
  793. else if (V.HeapName) {
  794. D3D12_GPU_DESCRIPTOR_HANDLE heapBase(m_DescriptorHeapsByName[V.HeapName]->GetGPUDescriptorHandleForHeapStart());
  795. if (isCompute) {
  796. pList->SetComputeRootDescriptorTable(idx, heapBase);
  797. }
  798. else {
  799. pList->SetGraphicsRootDescriptorTable(idx, heapBase);
  800. }
  801. }
  802. }
  803. }
  804. void ShaderOpTest::SetDevice(ID3D12Device *pDevice) {
  805. m_pDevice = pDevice;
  806. }
  807. void ShaderOpTest::SetDxcSupport(dxc::DxcDllSupport *pDxcSupport) {
  808. m_pDxcSupport = pDxcSupport;
  809. }
  810. void ShaderOpTest::SetInitCallback(TInitCallbackFn InitCallbackFn) {
  811. m_InitCallbackFn = InitCallbackFn;
  812. }
  813. void ShaderOpTest::SetupRenderTarget(ShaderOp *pShaderOp, ID3D12Device *pDevice,
  814. ID3D12CommandQueue *pCommandQueue,
  815. ID3D12Resource *pRenderTarget) {
  816. SetDevice(pDevice);
  817. m_CommandList.Queue = pCommandQueue;
  818. // Simplification - add the render target name if missing, set it up 'by hand' if not.
  819. if (pShaderOp->RenderTargets.empty()) {
  820. pShaderOp->RenderTargets.push_back(pShaderOp->Strings.insert("RTarget"));
  821. ShaderOpResource R;
  822. ZeroMemory(&R, sizeof(R));
  823. R.Desc = pRenderTarget->GetDesc();
  824. R.Name = pShaderOp->Strings.insert("RTarget");
  825. R.HeapFlags = D3D12_HEAP_FLAG_NONE;
  826. R.Init = nullptr;
  827. R.InitialResourceState = D3D12_RESOURCE_STATE_PRESENT;
  828. R.ReadBack = FALSE;
  829. pShaderOp->Resources.push_back(R);
  830. ShaderOpResourceData &D = m_ResourceData[R.Name];
  831. D.ShaderOpRes = &pShaderOp->Resources.back();
  832. D.Resource = pRenderTarget;
  833. D.ResourceState = R.InitialResourceState;
  834. }
  835. // Create a render target heap to put this in.
  836. ShaderOpDescriptorHeap *pRtvHeap = pShaderOp->GetDescriptorHeapByName("RtvHeap");
  837. if (pRtvHeap == nullptr) {
  838. ShaderOpDescriptorHeap H;
  839. ZeroMemory(&H, sizeof(H));
  840. H.Name = pShaderOp->Strings.insert("RtvHeap");
  841. H.Desc.NumDescriptors = 1;
  842. H.Desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
  843. pShaderOp->DescriptorHeaps.push_back(H);
  844. pRtvHeap = &pShaderOp->DescriptorHeaps.back();
  845. }
  846. if (pRtvHeap->Descriptors.empty()) {
  847. ShaderOpDescriptor D;
  848. ZeroMemory(&D, sizeof(D));
  849. D.Name = pShaderOp->Strings.insert("RTarget");
  850. D.ResName = D.Name;
  851. D.Kind = pShaderOp->Strings.insert("RTV");
  852. pRtvHeap->Descriptors.push_back(D);
  853. }
  854. }
  855. void ShaderOpTest::PresentRenderTarget(ShaderOp *pShaderOp,
  856. ID3D12CommandQueue *pCommandQueue,
  857. ID3D12Resource *pRenderTarget) {
  858. CommandListRefs ResCommandList;
  859. ResCommandList.Queue = pCommandQueue;
  860. ResCommandList.CreateForDevice(m_pDevice, m_pShaderOp->IsCompute());
  861. ID3D12GraphicsCommandList *pList = ResCommandList.List;
  862. pList->SetName(L"ShaderOpTest Resource Present CommandList");
  863. RecordTransitionBarrier(pList, pRenderTarget,
  864. D3D12_RESOURCE_STATE_RENDER_TARGET,
  865. D3D12_RESOURCE_STATE_PRESENT);
  866. pList->Close();
  867. ExecuteCommandList(ResCommandList.Queue, pList);
  868. WaitForSignal(ResCommandList.Queue, m_pFence, m_hFence, m_FenceValue++);
  869. }
  870. ShaderOp *ShaderOpSet::GetShaderOp(LPCSTR pName) {
  871. for (auto &S : ShaderOps) {
  872. if (S->Name && 0 == _stricmp(pName, S->Name)) {
  873. return S.get();
  874. }
  875. }
  876. return nullptr;
  877. }
  878. ///////////////////////////////////////////////////////////////////////////////
  879. // ShaderOpTest library implementation for deserialization.
  880. #pragma region Parsing support
  881. // Use this class to initialize a ShaderOp object from an XML document.
  882. class ShaderOpParser {
  883. private:
  884. string_table *m_pStrings;
  885. bool ReadAtElementName(IXmlReader *pReader, LPCWSTR pName);
  886. HRESULT ReadAttrStr(IXmlReader *pReader, LPCWSTR pAttrName, LPCSTR *ppValue);
  887. HRESULT ReadAttrBOOL(IXmlReader *pReader, LPCWSTR pAttrName, BOOL *pValue, BOOL defaultValue = FALSE);
  888. HRESULT ReadAttrUINT64(IXmlReader *pReader, LPCWSTR pAttrName, UINT64 *pValue, UINT64 defaultValue = 0);
  889. HRESULT ReadAttrUINT16(IXmlReader *pReader, LPCWSTR pAttrName, UINT16 *pValue, UINT16 defaultValue = 0);
  890. HRESULT ReadAttrUINT(IXmlReader *pReader, LPCWSTR pAttrName, UINT *pValue, UINT defaultValue = 0);
  891. void ReadElementContentStr(IXmlReader *pReader, LPCSTR *ppValue);
  892. void ParseDescriptor(IXmlReader *pReader, ShaderOpDescriptor *pDesc);
  893. void ParseDescriptorHeap(IXmlReader *pReader, ShaderOpDescriptorHeap *pHeap);
  894. void ParseInputElement(IXmlReader *pReader, D3D12_INPUT_ELEMENT_DESC *pInputElement);
  895. void ParseInputElements(IXmlReader *pReader, std::vector<D3D12_INPUT_ELEMENT_DESC> *pInputElements);
  896. void ParseRenderTargets(IXmlReader *pReader, std::vector<LPCSTR> *pRenderTargets);
  897. void ParseRootValue(IXmlReader *pReader, ShaderOpRootValue *pRootValue);
  898. void ParseRootValues(IXmlReader *pReader, std::vector<ShaderOpRootValue> *pRootValues);
  899. void ParseResource(IXmlReader *pReader, ShaderOpResource *pResource);
  900. void ParseShader(IXmlReader *pReader, ShaderOpShader *pShader);
  901. public:
  902. void ParseShaderOpSet(IStream *pStream, ShaderOpSet *pShaderOpSet);
  903. void ParseShaderOpSet(IXmlReader *pReader, ShaderOpSet *pShaderOpSet);
  904. void ParseShaderOp(IXmlReader *pReader, ShaderOp *pShaderOp);
  905. };
  906. void ParseShaderOpSetFromStream(IStream *pStream, st::ShaderOpSet *pShaderOpSet) {
  907. ShaderOpParser parser;
  908. parser.ParseShaderOpSet(pStream, pShaderOpSet);
  909. }
  910. void ParseShaderOpSetFromXml(IXmlReader *pReader, st::ShaderOpSet *pShaderOpSet) {
  911. ShaderOpParser parser;
  912. parser.ParseShaderOpSet(pReader, pShaderOpSet);
  913. }
  914. enum class ParserEnumKind {
  915. INPUT_CLASSIFICATION,
  916. DXGI_FORMAT,
  917. HEAP_TYPE,
  918. CPU_PAGE_PROPERTY,
  919. MEMORY_POOL,
  920. RESOURCE_DIMENSION,
  921. TEXTURE_LAYOUT,
  922. RESOURCE_FLAG,
  923. HEAP_FLAG,
  924. RESOURCE_STATE,
  925. DESCRIPTOR_HEAP_TYPE,
  926. DESCRIPTOR_HEAP_FLAG,
  927. UAV_DIMENSION,
  928. PRIMITIVE_TOPOLOGY,
  929. PRIMITIVE_TOPOLOGY_TYPE
  930. };
  931. struct ParserEnumValue {
  932. LPCWSTR Name;
  933. UINT Value;
  934. };
  935. struct ParserEnumTable {
  936. size_t ValueCount;
  937. const ParserEnumValue *Values;
  938. ParserEnumKind Kind;
  939. };
  940. static const ParserEnumValue INPUT_CLASSIFICATION_TABLE[] = {
  941. { L"INSTANCE", D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA },
  942. { L"VERTEX", D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA }
  943. };
  944. static const ParserEnumValue DXGI_FORMAT_TABLE[] = {
  945. { L"UNKNOWN", DXGI_FORMAT_UNKNOWN },
  946. { L"R32G32B32A32_TYPELESS", DXGI_FORMAT_R32G32B32A32_TYPELESS },
  947. { L"R32G32B32A32_FLOAT", DXGI_FORMAT_R32G32B32A32_FLOAT },
  948. { L"R32G32B32A32_UINT", DXGI_FORMAT_R32G32B32A32_UINT },
  949. { L"R32G32B32A32_SINT", DXGI_FORMAT_R32G32B32A32_SINT },
  950. { L"R32G32B32_TYPELESS", DXGI_FORMAT_R32G32B32_TYPELESS },
  951. { L"R32G32B32_FLOAT", DXGI_FORMAT_R32G32B32_FLOAT },
  952. { L"R32G32B32_UINT", DXGI_FORMAT_R32G32B32_UINT },
  953. { L"R32G32B32_SINT", DXGI_FORMAT_R32G32B32_SINT },
  954. { L"R16G16B16A16_TYPELESS", DXGI_FORMAT_R16G16B16A16_TYPELESS },
  955. { L"R16G16B16A16_FLOAT", DXGI_FORMAT_R16G16B16A16_FLOAT },
  956. { L"R16G16B16A16_UNORM", DXGI_FORMAT_R16G16B16A16_UNORM },
  957. { L"R16G16B16A16_UINT", DXGI_FORMAT_R16G16B16A16_UINT },
  958. { L"R16G16B16A16_SNORM", DXGI_FORMAT_R16G16B16A16_SNORM },
  959. { L"R16G16B16A16_SINT", DXGI_FORMAT_R16G16B16A16_SINT },
  960. { L"R32G32_TYPELESS", DXGI_FORMAT_R32G32_TYPELESS },
  961. { L"R32G32_FLOAT", DXGI_FORMAT_R32G32_FLOAT },
  962. { L"R32G32_UINT", DXGI_FORMAT_R32G32_UINT },
  963. { L"R32G32_SINT", DXGI_FORMAT_R32G32_SINT },
  964. { L"R32G8X24_TYPELESS", DXGI_FORMAT_R32G8X24_TYPELESS },
  965. { L"D32_FLOAT_S8X24_UINT", DXGI_FORMAT_D32_FLOAT_S8X24_UINT },
  966. { L"R32_FLOAT_X8X24_TYPELESS", DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS },
  967. { L"X32_TYPELESS_G8X24_UINT", DXGI_FORMAT_X32_TYPELESS_G8X24_UINT },
  968. { L"R10G10B10A2_TYPELESS", DXGI_FORMAT_R10G10B10A2_TYPELESS },
  969. { L"R10G10B10A2_UNORM", DXGI_FORMAT_R10G10B10A2_UNORM },
  970. { L"R10G10B10A2_UINT", DXGI_FORMAT_R10G10B10A2_UINT },
  971. { L"R11G11B10_FLOAT", DXGI_FORMAT_R11G11B10_FLOAT },
  972. { L"R8G8B8A8_TYPELESS", DXGI_FORMAT_R8G8B8A8_TYPELESS },
  973. { L"R8G8B8A8_UNORM", DXGI_FORMAT_R8G8B8A8_UNORM },
  974. { L"R8G8B8A8_UNORM_SRGB", DXGI_FORMAT_R8G8B8A8_UNORM_SRGB },
  975. { L"R8G8B8A8_UINT", DXGI_FORMAT_R8G8B8A8_UINT },
  976. { L"R8G8B8A8_SNORM", DXGI_FORMAT_R8G8B8A8_SNORM },
  977. { L"R8G8B8A8_SINT", DXGI_FORMAT_R8G8B8A8_SINT },
  978. { L"R16G16_TYPELESS", DXGI_FORMAT_R16G16_TYPELESS },
  979. { L"R16G16_FLOAT", DXGI_FORMAT_R16G16_FLOAT },
  980. { L"R16G16_UNORM", DXGI_FORMAT_R16G16_UNORM },
  981. { L"R16G16_UINT", DXGI_FORMAT_R16G16_UINT },
  982. { L"R16G16_SNORM", DXGI_FORMAT_R16G16_SNORM },
  983. { L"R16G16_SINT", DXGI_FORMAT_R16G16_SINT },
  984. { L"R32_TYPELESS", DXGI_FORMAT_R32_TYPELESS },
  985. { L"D32_FLOAT", DXGI_FORMAT_D32_FLOAT },
  986. { L"R32_FLOAT", DXGI_FORMAT_R32_FLOAT },
  987. { L"R32_UINT", DXGI_FORMAT_R32_UINT },
  988. { L"R32_SINT", DXGI_FORMAT_R32_SINT },
  989. { L"R24G8_TYPELESS", DXGI_FORMAT_R24G8_TYPELESS },
  990. { L"D24_UNORM_S8_UINT", DXGI_FORMAT_D24_UNORM_S8_UINT },
  991. { L"R24_UNORM_X8_TYPELESS", DXGI_FORMAT_R24_UNORM_X8_TYPELESS },
  992. { L"X24_TYPELESS_G8_UINT", DXGI_FORMAT_X24_TYPELESS_G8_UINT },
  993. { L"R8G8_TYPELESS", DXGI_FORMAT_R8G8_TYPELESS },
  994. { L"R8G8_UNORM", DXGI_FORMAT_R8G8_UNORM },
  995. { L"R8G8_UINT", DXGI_FORMAT_R8G8_UINT },
  996. { L"R8G8_SNORM", DXGI_FORMAT_R8G8_SNORM },
  997. { L"R8G8_SINT", DXGI_FORMAT_R8G8_SINT },
  998. { L"R16_TYPELESS", DXGI_FORMAT_R16_TYPELESS },
  999. { L"R16_FLOAT", DXGI_FORMAT_R16_FLOAT },
  1000. { L"D16_UNORM", DXGI_FORMAT_D16_UNORM },
  1001. { L"R16_UNORM", DXGI_FORMAT_R16_UNORM },
  1002. { L"R16_UINT", DXGI_FORMAT_R16_UINT },
  1003. { L"R16_SNORM", DXGI_FORMAT_R16_SNORM },
  1004. { L"R16_SINT", DXGI_FORMAT_R16_SINT },
  1005. { L"R8_TYPELESS", DXGI_FORMAT_R8_TYPELESS },
  1006. { L"R8_UNORM", DXGI_FORMAT_R8_UNORM },
  1007. { L"R8_UINT", DXGI_FORMAT_R8_UINT },
  1008. { L"R8_SNORM", DXGI_FORMAT_R8_SNORM },
  1009. { L"R8_SINT", DXGI_FORMAT_R8_SINT },
  1010. { L"A8_UNORM", DXGI_FORMAT_A8_UNORM },
  1011. { L"R1_UNORM", DXGI_FORMAT_R1_UNORM },
  1012. { L"R9G9B9E5_SHAREDEXP", DXGI_FORMAT_R9G9B9E5_SHAREDEXP },
  1013. { L"R8G8_B8G8_UNORM", DXGI_FORMAT_R8G8_B8G8_UNORM },
  1014. { L"G8R8_G8B8_UNORM", DXGI_FORMAT_G8R8_G8B8_UNORM },
  1015. { L"BC1_TYPELESS", DXGI_FORMAT_BC1_TYPELESS },
  1016. { L"BC1_UNORM", DXGI_FORMAT_BC1_UNORM },
  1017. { L"BC1_UNORM_SRGB", DXGI_FORMAT_BC1_UNORM_SRGB },
  1018. { L"BC2_TYPELESS", DXGI_FORMAT_BC2_TYPELESS },
  1019. { L"BC2_UNORM", DXGI_FORMAT_BC2_UNORM },
  1020. { L"BC2_UNORM_SRGB", DXGI_FORMAT_BC2_UNORM_SRGB },
  1021. { L"BC3_TYPELESS", DXGI_FORMAT_BC3_TYPELESS },
  1022. { L"BC3_UNORM", DXGI_FORMAT_BC3_UNORM },
  1023. { L"BC3_UNORM_SRGB", DXGI_FORMAT_BC3_UNORM_SRGB },
  1024. { L"BC4_TYPELESS", DXGI_FORMAT_BC4_TYPELESS },
  1025. { L"BC4_UNORM", DXGI_FORMAT_BC4_UNORM },
  1026. { L"BC4_SNORM", DXGI_FORMAT_BC4_SNORM },
  1027. { L"BC5_TYPELESS", DXGI_FORMAT_BC5_TYPELESS },
  1028. { L"BC5_UNORM", DXGI_FORMAT_BC5_UNORM },
  1029. { L"BC5_SNORM", DXGI_FORMAT_BC5_SNORM },
  1030. { L"B5G6R5_UNORM", DXGI_FORMAT_B5G6R5_UNORM },
  1031. { L"B5G5R5A1_UNORM", DXGI_FORMAT_B5G5R5A1_UNORM },
  1032. { L"B8G8R8A8_UNORM", DXGI_FORMAT_B8G8R8A8_UNORM },
  1033. { L"B8G8R8X8_UNORM", DXGI_FORMAT_B8G8R8X8_UNORM },
  1034. { L"R10G10B10_XR_BIAS_A2_UNORM", DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM },
  1035. { L"B8G8R8A8_TYPELESS", DXGI_FORMAT_B8G8R8A8_TYPELESS },
  1036. { L"B8G8R8A8_UNORM_SRGB", DXGI_FORMAT_B8G8R8A8_UNORM_SRGB },
  1037. { L"B8G8R8X8_TYPELESS", DXGI_FORMAT_B8G8R8X8_TYPELESS },
  1038. { L"B8G8R8X8_UNORM_SRGB", DXGI_FORMAT_B8G8R8X8_UNORM_SRGB },
  1039. { L"BC6H_TYPELESS", DXGI_FORMAT_BC6H_TYPELESS },
  1040. { L"BC6H_UF16", DXGI_FORMAT_BC6H_UF16 },
  1041. { L"BC6H_SF16", DXGI_FORMAT_BC6H_SF16 },
  1042. { L"BC7_TYPELESS", DXGI_FORMAT_BC7_TYPELESS },
  1043. { L"BC7_UNORM", DXGI_FORMAT_BC7_UNORM },
  1044. { L"BC7_UNORM_SRGB", DXGI_FORMAT_BC7_UNORM_SRGB },
  1045. { L"AYUV", DXGI_FORMAT_AYUV },
  1046. { L"Y410", DXGI_FORMAT_Y410 },
  1047. { L"Y416", DXGI_FORMAT_Y416 },
  1048. { L"NV12", DXGI_FORMAT_NV12 },
  1049. { L"P010", DXGI_FORMAT_P010 },
  1050. { L"P016", DXGI_FORMAT_P016 },
  1051. { L"420_OPAQUE", DXGI_FORMAT_420_OPAQUE },
  1052. { L"YUY2", DXGI_FORMAT_YUY2 },
  1053. { L"Y210", DXGI_FORMAT_Y210 },
  1054. { L"Y216", DXGI_FORMAT_Y216 },
  1055. { L"NV11", DXGI_FORMAT_NV11 },
  1056. { L"AI44", DXGI_FORMAT_AI44 },
  1057. { L"IA44", DXGI_FORMAT_IA44 },
  1058. { L"P8", DXGI_FORMAT_P8 },
  1059. { L"A8P8", DXGI_FORMAT_A8P8 },
  1060. { L"B4G4R4A4_UNORM", DXGI_FORMAT_B4G4R4A4_UNORM },
  1061. { L"P208", DXGI_FORMAT_P208 },
  1062. { L"V208", DXGI_FORMAT_V208 },
  1063. { L"V408", DXGI_FORMAT_V408 }
  1064. };
  1065. static const ParserEnumValue HEAP_TYPE_TABLE[] = {
  1066. { L"DEFAULT", D3D12_HEAP_TYPE_DEFAULT },
  1067. { L"UPLOAD", D3D12_HEAP_TYPE_UPLOAD },
  1068. { L"READBACK", D3D12_HEAP_TYPE_READBACK },
  1069. { L"CUSTOM", D3D12_HEAP_TYPE_CUSTOM }
  1070. };
  1071. static const ParserEnumValue CPU_PAGE_PROPERTY_TABLE[] = {
  1072. { L"UNKNOWN", D3D12_CPU_PAGE_PROPERTY_UNKNOWN },
  1073. { L"NOT_AVAILABLE", D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE },
  1074. { L"WRITE_COMBINE", D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE },
  1075. { L"WRITE_BACK", D3D12_CPU_PAGE_PROPERTY_WRITE_BACK }
  1076. };
  1077. static const ParserEnumValue MEMORY_POOL_TABLE[] = {
  1078. { L"UNKNOWN", D3D12_MEMORY_POOL_UNKNOWN },
  1079. { L"L0 ", D3D12_MEMORY_POOL_L0 },
  1080. { L"L1", D3D12_MEMORY_POOL_L1 }
  1081. };
  1082. static const ParserEnumValue RESOURCE_DIMENSION_TABLE[] = {
  1083. { L"UNKNOWN", D3D12_RESOURCE_DIMENSION_UNKNOWN },
  1084. { L"BUFFER", D3D12_RESOURCE_DIMENSION_BUFFER },
  1085. { L"TEXTURE1D", D3D12_RESOURCE_DIMENSION_TEXTURE1D },
  1086. { L"TEXTURE2D", D3D12_RESOURCE_DIMENSION_TEXTURE2D },
  1087. { L"TEXTURE3D", D3D12_RESOURCE_DIMENSION_TEXTURE3D }
  1088. };
  1089. static const ParserEnumValue TEXTURE_LAYOUT_TABLE[] = {
  1090. { L"UNKNOWN", D3D12_TEXTURE_LAYOUT_UNKNOWN },
  1091. { L"ROW_MAJOR", D3D12_TEXTURE_LAYOUT_ROW_MAJOR },
  1092. { L"UNDEFINED_SWIZZLE", D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE },
  1093. { L"STANDARD_SWIZZLE", D3D12_TEXTURE_LAYOUT_64KB_STANDARD_SWIZZLE }
  1094. };
  1095. static const ParserEnumValue RESOURCE_FLAG_TABLE[] = {
  1096. { L"NONE", D3D12_RESOURCE_FLAG_NONE },
  1097. { L"ALLOW_RENDER_TARGET", D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET },
  1098. { L"ALLOW_DEPTH_STENCIL", D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL },
  1099. { L"ALLOW_UNORDERED_ACCESS", D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS },
  1100. { L"DENY_SHADER_RESOURCE", D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE },
  1101. { L"ALLOW_CROSS_ADAPTER", D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER },
  1102. { L"ALLOW_SIMULTANEOUS_ACCESS", D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS }
  1103. };
  1104. static const ParserEnumValue HEAP_FLAG_TABLE[] = {
  1105. { L"NONE", D3D12_HEAP_FLAG_NONE },
  1106. { L"SHARED", D3D12_HEAP_FLAG_SHARED },
  1107. { L"DENY_BUFFERS", D3D12_HEAP_FLAG_DENY_BUFFERS },
  1108. { L"ALLOW_DISPLAY", D3D12_HEAP_FLAG_ALLOW_DISPLAY },
  1109. { L"SHARED_CROSS_ADAPTER", D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER },
  1110. { L"DENY_RT_DS_TEXTURES", D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES },
  1111. { L"DENY_NON_RT_DS_TEXTURES", D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES },
  1112. { L"ALLOW_ALL_BUFFERS_AND_TEXTURES",D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES },
  1113. { L"ALLOW_ONLY_BUFFERS", D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS },
  1114. { L"ALLOW_ONLY_NON_RT_DS_TEXTURES", D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES },
  1115. { L"ALLOW_ONLY_RT_DS_TEXTURES", D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES }
  1116. };
  1117. static const ParserEnumValue RESOURCE_STATE_TABLE[] = {
  1118. { L"COMMON", D3D12_RESOURCE_STATE_COMMON },
  1119. { L"VERTEX_AND_CONSTANT_BUFFER", D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER },
  1120. { L"INDEX_BUFFER", D3D12_RESOURCE_STATE_INDEX_BUFFER },
  1121. { L"RENDER_TARGET", D3D12_RESOURCE_STATE_RENDER_TARGET },
  1122. { L"UNORDERED_ACCESS", D3D12_RESOURCE_STATE_UNORDERED_ACCESS },
  1123. { L"DEPTH_WRITE", D3D12_RESOURCE_STATE_DEPTH_WRITE },
  1124. { L"DEPTH_READ", D3D12_RESOURCE_STATE_DEPTH_READ },
  1125. { L"NON_PIXEL_SHADER_RESOURCE", D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE },
  1126. { L"PIXEL_SHADER_RESOURCE", D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE },
  1127. { L"STREAM_OUT", D3D12_RESOURCE_STATE_STREAM_OUT },
  1128. { L"INDIRECT_ARGUMENT", D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT },
  1129. { L"COPY_DEST", D3D12_RESOURCE_STATE_COPY_DEST },
  1130. { L"COPY_SOURCE", D3D12_RESOURCE_STATE_COPY_SOURCE },
  1131. { L"RESOLVE_DEST", D3D12_RESOURCE_STATE_RESOLVE_DEST },
  1132. { L"RESOLVE_SOURCE", D3D12_RESOURCE_STATE_RESOLVE_SOURCE },
  1133. { L"GENERIC_READ", D3D12_RESOURCE_STATE_GENERIC_READ },
  1134. { L"PRESENT", D3D12_RESOURCE_STATE_PRESENT },
  1135. { L"PREDICATION", D3D12_RESOURCE_STATE_PREDICATION }
  1136. };
  1137. static const ParserEnumValue DESCRIPTOR_HEAP_TYPE_TABLE[] = {
  1138. { L"CBV_SRV_UAV", D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV },
  1139. { L"SAMPLER", D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER },
  1140. { L"RTV", D3D12_DESCRIPTOR_HEAP_TYPE_RTV },
  1141. { L"DSV", D3D12_DESCRIPTOR_HEAP_TYPE_DSV }
  1142. };
  1143. static const ParserEnumValue DESCRIPTOR_HEAP_FLAG_TABLE[] = {
  1144. { L"NONE", D3D12_DESCRIPTOR_HEAP_FLAG_NONE },
  1145. { L"SHADER_VISIBLE", D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE }
  1146. };
  1147. static const ParserEnumValue UAV_DIMENSION_TABLE[] = {
  1148. { L"UNKNOWN", D3D12_UAV_DIMENSION_UNKNOWN },
  1149. { L"BUFFER", D3D12_UAV_DIMENSION_BUFFER },
  1150. { L"TEXTURE1D", D3D12_UAV_DIMENSION_TEXTURE1D },
  1151. { L"TEXTURE1DARRAY", D3D12_UAV_DIMENSION_TEXTURE1DARRAY },
  1152. { L"TEXTURE2D", D3D12_UAV_DIMENSION_TEXTURE2D },
  1153. { L"TEXTURE2DARRAY", D3D12_UAV_DIMENSION_TEXTURE2DARRAY },
  1154. { L"TEXTURE3D", D3D12_UAV_DIMENSION_TEXTURE3D }
  1155. };
  1156. static const ParserEnumValue PRIMITIVE_TOPOLOGY_TABLE[] = {
  1157. { L"UNDEFINED",D3D_PRIMITIVE_TOPOLOGY_UNDEFINED },
  1158. { L"POINTLIST",D3D_PRIMITIVE_TOPOLOGY_POINTLIST },
  1159. { L"LINELIST",D3D_PRIMITIVE_TOPOLOGY_LINELIST },
  1160. { L"LINESTRIP",D3D_PRIMITIVE_TOPOLOGY_LINESTRIP },
  1161. { L"TRIANGLELIST",D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST },
  1162. { L"TRIANGLESTRIP",D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP },
  1163. { L"LINELIST_ADJ",D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ },
  1164. { L"LINESTRIP_ADJ",D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ },
  1165. { L"TRIANGLELIST_ADJ",D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ },
  1166. { L"TRIANGLESTRIP_ADJ",D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ },
  1167. { L"1_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST },
  1168. { L"2_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST },
  1169. { L"3_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST },
  1170. { L"4_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST },
  1171. { L"5_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST },
  1172. { L"6_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST },
  1173. { L"7_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST },
  1174. { L"8_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST },
  1175. { L"9_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST },
  1176. { L"10_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST },
  1177. { L"11_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST },
  1178. { L"12_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST },
  1179. { L"13_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST },
  1180. { L"14_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST },
  1181. { L"15_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST },
  1182. { L"16_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST },
  1183. { L"17_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST },
  1184. { L"18_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST },
  1185. { L"19_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST },
  1186. { L"20_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST },
  1187. { L"21_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST },
  1188. { L"22_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST },
  1189. { L"23_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST },
  1190. { L"24_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST },
  1191. { L"25_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST },
  1192. { L"26_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST },
  1193. { L"27_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST },
  1194. { L"28_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST },
  1195. { L"29_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST },
  1196. { L"30_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST },
  1197. { L"31_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST },
  1198. { L"32_CONTROL_POINT_PATCHLIST",D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST }
  1199. };
  1200. static const ParserEnumValue PRIMITIVE_TOPOLOGY_TYPE_TABLE[] = {
  1201. { L"UNDEFINED", D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED },
  1202. { L"POINT", D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT },
  1203. { L"LINE", D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE },
  1204. { L"TRIANGLE", D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE },
  1205. { L"PATCH", D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH }
  1206. };
  1207. static const ParserEnumTable g_ParserEnumTables[] = {
  1208. { _countof(INPUT_CLASSIFICATION_TABLE), INPUT_CLASSIFICATION_TABLE, ParserEnumKind::INPUT_CLASSIFICATION },
  1209. { _countof(DXGI_FORMAT_TABLE), DXGI_FORMAT_TABLE, ParserEnumKind::DXGI_FORMAT },
  1210. { _countof(HEAP_TYPE_TABLE), HEAP_TYPE_TABLE, ParserEnumKind::HEAP_TYPE },
  1211. { _countof(CPU_PAGE_PROPERTY_TABLE), CPU_PAGE_PROPERTY_TABLE, ParserEnumKind::CPU_PAGE_PROPERTY },
  1212. { _countof(MEMORY_POOL_TABLE), MEMORY_POOL_TABLE, ParserEnumKind::MEMORY_POOL },
  1213. { _countof(RESOURCE_DIMENSION_TABLE), RESOURCE_DIMENSION_TABLE, ParserEnumKind::RESOURCE_DIMENSION },
  1214. { _countof(TEXTURE_LAYOUT_TABLE), TEXTURE_LAYOUT_TABLE, ParserEnumKind::TEXTURE_LAYOUT },
  1215. { _countof(RESOURCE_FLAG_TABLE), RESOURCE_FLAG_TABLE, ParserEnumKind::RESOURCE_FLAG },
  1216. { _countof(HEAP_FLAG_TABLE), HEAP_FLAG_TABLE, ParserEnumKind::HEAP_FLAG },
  1217. { _countof(RESOURCE_STATE_TABLE), RESOURCE_STATE_TABLE, ParserEnumKind::RESOURCE_STATE },
  1218. { _countof(DESCRIPTOR_HEAP_TYPE_TABLE), DESCRIPTOR_HEAP_TYPE_TABLE, ParserEnumKind::DESCRIPTOR_HEAP_TYPE },
  1219. { _countof(DESCRIPTOR_HEAP_FLAG_TABLE), DESCRIPTOR_HEAP_FLAG_TABLE, ParserEnumKind::DESCRIPTOR_HEAP_FLAG },
  1220. { _countof(UAV_DIMENSION_TABLE), UAV_DIMENSION_TABLE, ParserEnumKind::UAV_DIMENSION },
  1221. { _countof(PRIMITIVE_TOPOLOGY_TABLE), PRIMITIVE_TOPOLOGY_TABLE, ParserEnumKind::PRIMITIVE_TOPOLOGY },
  1222. { _countof(PRIMITIVE_TOPOLOGY_TYPE_TABLE), PRIMITIVE_TOPOLOGY_TYPE_TABLE, ParserEnumKind::PRIMITIVE_TOPOLOGY_TYPE },
  1223. };
  1224. static HRESULT GetEnumValue(LPCWSTR name, ParserEnumKind K, UINT *pValue) {
  1225. for (size_t i = 0; i < _countof(g_ParserEnumTables); ++i) {
  1226. const ParserEnumTable &T = g_ParserEnumTables[i];
  1227. if (T.Kind != K) {
  1228. continue;
  1229. }
  1230. for (size_t j = 0; j < T.ValueCount; ++j) {
  1231. if (_wcsicmp(name, T.Values[j].Name) == 0) {
  1232. *pValue = T.Values[j].Value;
  1233. return S_OK;
  1234. }
  1235. }
  1236. }
  1237. return E_INVALIDARG;
  1238. }
  1239. template <typename T>
  1240. static HRESULT GetEnumValueT(LPCWSTR name, ParserEnumKind K, T *pValue) {
  1241. UINT u;
  1242. HRESULT hr = GetEnumValue(name, K, &u);
  1243. *pValue = (T)u;
  1244. return hr;
  1245. }
  1246. template <typename T>
  1247. static HRESULT ReadAttrEnumT(IXmlReader *pReader, LPCWSTR pAttrName, ParserEnumKind K, T *pValue, T defaultValue, LPCWSTR pStripPrefix = nullptr) {
  1248. if (S_FALSE == CHECK_HR_RET(pReader->MoveToAttributeByName(pAttrName, nullptr))) {
  1249. *pValue = defaultValue;
  1250. return S_FALSE;
  1251. }
  1252. LPCWSTR pText;
  1253. CHECK_HR(pReader->GetValue(&pText, nullptr));
  1254. if (pStripPrefix && *pStripPrefix && _wcsnicmp(pAttrName, pText, wcslen(pStripPrefix)) == 0)
  1255. pText += wcslen(pStripPrefix);
  1256. CHECK_HR(GetEnumValueT(pText, K, pValue));
  1257. CHECK_HR(pReader->MoveToElement());
  1258. return S_OK;
  1259. }
  1260. static HRESULT ReadAttrINPUT_CLASSIFICATION(IXmlReader *pReader, LPCWSTR pAttrName, D3D12_INPUT_CLASSIFICATION *pValue) {
  1261. return ReadAttrEnumT(pReader, pAttrName, ParserEnumKind::INPUT_CLASSIFICATION, pValue, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA);
  1262. }
  1263. static HRESULT ReadAttrDESCRIPTOR_HEAP_TYPE(IXmlReader *pReader, LPCWSTR pAttrName, D3D12_DESCRIPTOR_HEAP_TYPE *pValue) {
  1264. return ReadAttrEnumT(pReader, pAttrName, ParserEnumKind::DESCRIPTOR_HEAP_TYPE, pValue, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
  1265. }
  1266. static HRESULT ReadAttrDESCRIPTOR_HEAP_FLAGS(IXmlReader *pReader, LPCWSTR pAttrName, D3D12_DESCRIPTOR_HEAP_FLAGS *pValue) {
  1267. return ReadAttrEnumT(pReader, pAttrName, ParserEnumKind::DESCRIPTOR_HEAP_FLAG, pValue, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE);
  1268. }
  1269. static HRESULT ReadAttrDXGI_FORMAT(IXmlReader *pReader, LPCWSTR pAttrName, DXGI_FORMAT *pValue) {
  1270. return ReadAttrEnumT(pReader, pAttrName, ParserEnumKind::DXGI_FORMAT, pValue, DXGI_FORMAT_UNKNOWN, L"DXGI_FORMAT_");
  1271. }
  1272. static HRESULT ReadAttrHEAP_TYPE(IXmlReader *pReader, LPCWSTR pAttrName, D3D12_HEAP_TYPE *pValue) {
  1273. return ReadAttrEnumT(pReader, pAttrName, ParserEnumKind::HEAP_TYPE, pValue, D3D12_HEAP_TYPE_DEFAULT);
  1274. }
  1275. static HRESULT ReadAttrCPU_PAGE_PROPERTY(IXmlReader *pReader, LPCWSTR pAttrName, D3D12_CPU_PAGE_PROPERTY *pValue) {
  1276. return ReadAttrEnumT(pReader, pAttrName, ParserEnumKind::CPU_PAGE_PROPERTY, pValue, D3D12_CPU_PAGE_PROPERTY_UNKNOWN);
  1277. }
  1278. static HRESULT ReadAttrMEMORY_POOL(IXmlReader *pReader, LPCWSTR pAttrName, D3D12_MEMORY_POOL *pValue) {
  1279. return ReadAttrEnumT(pReader, pAttrName, ParserEnumKind::MEMORY_POOL, pValue, D3D12_MEMORY_POOL_UNKNOWN);
  1280. }
  1281. static HRESULT ReadAttrRESOURCE_DIMENSION(IXmlReader *pReader, LPCWSTR pAttrName, D3D12_RESOURCE_DIMENSION *pValue) {
  1282. return ReadAttrEnumT(pReader, pAttrName, ParserEnumKind::RESOURCE_DIMENSION, pValue, D3D12_RESOURCE_DIMENSION_BUFFER);
  1283. }
  1284. static HRESULT ReadAttrTEXTURE_LAYOUT(IXmlReader *pReader, LPCWSTR pAttrName, D3D12_TEXTURE_LAYOUT *pValue) {
  1285. return ReadAttrEnumT(pReader, pAttrName, ParserEnumKind::TEXTURE_LAYOUT, pValue, D3D12_TEXTURE_LAYOUT_UNKNOWN);
  1286. }
  1287. static HRESULT ReadAttrRESOURCE_FLAGS(IXmlReader *pReader, LPCWSTR pAttrName, D3D12_RESOURCE_FLAGS *pValue) {
  1288. return ReadAttrEnumT(pReader, pAttrName, ParserEnumKind::RESOURCE_FLAG, pValue, D3D12_RESOURCE_FLAG_NONE);
  1289. }
  1290. static HRESULT ReadAttrHEAP_FLAGS(IXmlReader *pReader, LPCWSTR pAttrName, D3D12_HEAP_FLAGS *pValue) {
  1291. return ReadAttrEnumT(pReader, pAttrName, ParserEnumKind::HEAP_FLAG, pValue, D3D12_HEAP_FLAG_NONE);
  1292. }
  1293. static HRESULT ReadAttrRESOURCE_STATES(IXmlReader *pReader, LPCWSTR pAttrName, D3D12_RESOURCE_STATES *pValue) {
  1294. return ReadAttrEnumT(pReader, pAttrName, ParserEnumKind::RESOURCE_STATE, pValue, D3D12_RESOURCE_STATE_COMMON);
  1295. }
  1296. static HRESULT ReadAttrUAV_DIMENSION(IXmlReader *pReader, LPCWSTR pAttrName, D3D12_UAV_DIMENSION *pValue) {
  1297. return ReadAttrEnumT(pReader, pAttrName, ParserEnumKind::UAV_DIMENSION, pValue, D3D12_UAV_DIMENSION_BUFFER);
  1298. }
  1299. static HRESULT ReadAttrPRIMITIVE_TOPOLOGY(IXmlReader *pReader, LPCWSTR pAttrName, D3D_PRIMITIVE_TOPOLOGY *pValue) {
  1300. return ReadAttrEnumT(pReader, pAttrName, ParserEnumKind::PRIMITIVE_TOPOLOGY, pValue, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
  1301. }
  1302. static HRESULT ReadAttrPRIMITIVE_TOPOLOGY_TYPE(IXmlReader *pReader, LPCWSTR pAttrName, D3D12_PRIMITIVE_TOPOLOGY_TYPE *pValue) {
  1303. return ReadAttrEnumT(pReader, pAttrName, ParserEnumKind::PRIMITIVE_TOPOLOGY_TYPE, pValue, D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
  1304. }
  1305. HRESULT ShaderOpParser::ReadAttrStr(IXmlReader *pReader, LPCWSTR pAttrName, LPCSTR *ppValue) {
  1306. if (S_FALSE == CHECK_HR_RET(pReader->MoveToAttributeByName(pAttrName, nullptr))) {
  1307. *ppValue = nullptr;
  1308. return S_FALSE;
  1309. }
  1310. LPCWSTR pValue;
  1311. CHECK_HR(pReader->GetValue(&pValue, nullptr));
  1312. *ppValue = m_pStrings->insert(pValue);
  1313. CHECK_HR(pReader->MoveToElement());
  1314. return S_OK;
  1315. }
  1316. HRESULT ShaderOpParser::ReadAttrBOOL(IXmlReader *pReader, LPCWSTR pAttrName, BOOL *pValue, BOOL defaultValue) {
  1317. if (S_FALSE == CHECK_HR_RET(pReader->MoveToAttributeByName(pAttrName, nullptr))) {
  1318. *pValue = defaultValue;
  1319. return S_FALSE;
  1320. }
  1321. LPCWSTR pText;
  1322. CHECK_HR(pReader->GetValue(&pText, nullptr));
  1323. if (_wcsicmp(pText, L"true") == 0) {
  1324. *pValue = TRUE;
  1325. }
  1326. else {
  1327. *pValue = FALSE;
  1328. }
  1329. CHECK_HR(pReader->MoveToElement());
  1330. return S_OK;
  1331. }
  1332. HRESULT ShaderOpParser::ReadAttrUINT64(IXmlReader *pReader, LPCWSTR pAttrName, UINT64 *pValue, UINT64 defaultValue) {
  1333. if (S_FALSE == CHECK_HR_RET(pReader->MoveToAttributeByName(pAttrName, nullptr))) {
  1334. *pValue = defaultValue;
  1335. return S_FALSE;
  1336. }
  1337. LPCWSTR pText;
  1338. CHECK_HR(pReader->GetValue(&pText, nullptr));
  1339. long long ll = _wtol(pText);
  1340. if (errno == ERANGE) CHECK_HR(E_INVALIDARG);
  1341. *pValue = ll;
  1342. CHECK_HR(pReader->MoveToElement());
  1343. return S_OK;
  1344. }
  1345. HRESULT ShaderOpParser::ReadAttrUINT(IXmlReader *pReader, LPCWSTR pAttrName, UINT *pValue, UINT defaultValue) {
  1346. UINT64 u64;
  1347. CHECK_HR(ReadAttrUINT64(pReader, pAttrName, &u64, defaultValue));
  1348. CHECK_HR(UInt64ToUInt(u64, pValue));
  1349. return S_OK;
  1350. }
  1351. HRESULT ShaderOpParser::ReadAttrUINT16(IXmlReader *pReader, LPCWSTR pAttrName, UINT16 *pValue, UINT16 defaultValue) {
  1352. UINT64 u64;
  1353. CHECK_HR(ReadAttrUINT64(pReader, pAttrName, &u64, defaultValue));
  1354. CHECK_HR(UInt64ToUInt16(u64, pValue));
  1355. return S_OK;
  1356. }
  1357. void ShaderOpParser::ReadElementContentStr(IXmlReader *pReader, LPCSTR *ppValue) {
  1358. *ppValue = nullptr;
  1359. if (pReader->IsEmptyElement())
  1360. return;
  1361. UINT startDepth;
  1362. XmlNodeType nt;
  1363. CHECK_HR(pReader->GetDepth(&startDepth));
  1364. std::wstring value;
  1365. for (;;) {
  1366. UINT depth;
  1367. CHECK_HR(pReader->Read(&nt));
  1368. CHECK_HR(pReader->GetDepth(&depth));
  1369. if (nt == XmlNodeType_EndElement && depth == startDepth + 1)
  1370. break;
  1371. if (nt == XmlNodeType_CDATA || nt == XmlNodeType_Text || nt == XmlNodeType_Whitespace) {
  1372. LPCWSTR pText;
  1373. CHECK_HR(pReader->GetValue(&pText, nullptr));
  1374. value += pText;
  1375. }
  1376. }
  1377. *ppValue = m_pStrings->insert(value.c_str());
  1378. }
  1379. void ShaderOpParser::ParseDescriptor(IXmlReader *pReader, ShaderOpDescriptor *pDesc) {
  1380. if (!ReadAtElementName(pReader, L"Descriptor"))
  1381. return;
  1382. CHECK_HR(ReadAttrStr(pReader, L"Name", &pDesc->Name));
  1383. CHECK_HR(ReadAttrStr(pReader, L"ResName", &pDesc->ResName));
  1384. CHECK_HR(ReadAttrStr(pReader, L"CounterName", &pDesc->CounterName));
  1385. CHECK_HR(ReadAttrStr(pReader, L"Kind", &pDesc->Kind));
  1386. // D3D12_UNORDERED_ACCESS_VIEW_DESC
  1387. HRESULT hrFormat = ReadAttrDXGI_FORMAT(pReader, L"Format", &pDesc->UavDesc.Format);
  1388. CHECK_HR(hrFormat);
  1389. CHECK_HR(ReadAttrUAV_DIMENSION(pReader, L"Dimension", &pDesc->UavDesc.ViewDimension));
  1390. switch (pDesc->UavDesc.ViewDimension) {
  1391. case D3D12_UAV_DIMENSION_BUFFER:
  1392. CHECK_HR(ReadAttrUINT64(pReader, L"FirstElement", &pDesc->UavDesc.Buffer.FirstElement));
  1393. CHECK_HR(ReadAttrUINT(pReader, L"NumElements", &pDesc->UavDesc.Buffer.NumElements));
  1394. CHECK_HR(ReadAttrUINT(pReader, L"StructureByteStride", &pDesc->UavDesc.Buffer.StructureByteStride));
  1395. CHECK_HR(ReadAttrUINT64(pReader, L"CounterOffsetInBytes", &pDesc->UavDesc.Buffer.CounterOffsetInBytes));
  1396. LPCSTR pFlags;
  1397. CHECK_HR(ReadAttrStr(pReader, L"Flags", &pFlags));
  1398. if (pFlags && *pFlags && 0 == _stricmp(pFlags, "RAW")) {
  1399. pDesc->UavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
  1400. }
  1401. else {
  1402. pDesc->UavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
  1403. }
  1404. if (hrFormat == S_FALSE && pDesc->UavDesc.Buffer.Flags & D3D12_BUFFER_UAV_FLAG_RAW) {
  1405. pDesc->UavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
  1406. }
  1407. break;
  1408. case D3D12_UAV_DIMENSION_TEXTURE1D:
  1409. CHECK_HR(ReadAttrUINT(pReader, L"MipSlice", &pDesc->UavDesc.Texture1D.MipSlice));
  1410. break;
  1411. case D3D12_UAV_DIMENSION_TEXTURE1DARRAY:
  1412. CHECK_HR(ReadAttrUINT(pReader, L"MipSlice", &pDesc->UavDesc.Texture1DArray.MipSlice));
  1413. CHECK_HR(ReadAttrUINT(pReader, L"FirstArraySlice", &pDesc->UavDesc.Texture1DArray.FirstArraySlice));
  1414. CHECK_HR(ReadAttrUINT(pReader, L"ArraySize", &pDesc->UavDesc.Texture1DArray.ArraySize));
  1415. break;
  1416. case D3D12_UAV_DIMENSION_TEXTURE2D:
  1417. CHECK_HR(ReadAttrUINT(pReader, L"MipSlice", &pDesc->UavDesc.Texture2D.MipSlice));
  1418. CHECK_HR(ReadAttrUINT(pReader, L"PlaneSlice", &pDesc->UavDesc.Texture2D.PlaneSlice));
  1419. break;
  1420. case D3D12_UAV_DIMENSION_TEXTURE2DARRAY:
  1421. CHECK_HR(ReadAttrUINT(pReader, L"MipSlice", &pDesc->UavDesc.Texture2DArray.MipSlice));
  1422. CHECK_HR(ReadAttrUINT(pReader, L"FirstArraySlice", &pDesc->UavDesc.Texture2DArray.FirstArraySlice));
  1423. CHECK_HR(ReadAttrUINT(pReader, L"ArraySize", &pDesc->UavDesc.Texture2DArray.ArraySize));
  1424. CHECK_HR(ReadAttrUINT(pReader, L"MipSlice", &pDesc->UavDesc.Texture2DArray.PlaneSlice));
  1425. break;
  1426. case D3D12_UAV_DIMENSION_TEXTURE3D:
  1427. CHECK_HR(ReadAttrUINT(pReader, L"MipSlice", &pDesc->UavDesc.Texture3D.MipSlice));
  1428. CHECK_HR(ReadAttrUINT(pReader, L"FirstWSlice", &pDesc->UavDesc.Texture3D.FirstWSlice));
  1429. CHECK_HR(ReadAttrUINT(pReader, L"WSize", &pDesc->UavDesc.Texture3D.WSize));
  1430. break;
  1431. }
  1432. // If either is missing, set one from the other.
  1433. if (pDesc->Name && !pDesc->ResName) pDesc->ResName = pDesc->Name;
  1434. if (pDesc->ResName && !pDesc->Name) pDesc->Name = pDesc->ResName;
  1435. LPCSTR K = pDesc->Kind;
  1436. if (K == nullptr) {
  1437. ShaderOpLogFmt(L"Descriptor '%S' is missing Kind attribute.", pDesc->Name);
  1438. CHECK_HR(E_INVALIDARG);
  1439. } else if (0 != _stricmp(K, "UAV") && 0 != _stricmp(K, "SRV") &&
  1440. 0 != _stricmp(K, "CBV") && 0 != _stricmp(K, "RTV")) {
  1441. ShaderOpLogFmt(L"Descriptor '%S' references unknown kind '%S'",
  1442. pDesc->Name, K);
  1443. CHECK_HR(E_INVALIDARG);
  1444. }
  1445. }
  1446. void ShaderOpParser::ParseDescriptorHeap(IXmlReader *pReader, ShaderOpDescriptorHeap *pHeap) {
  1447. if (!ReadAtElementName(pReader, L"DescriptorHeap"))
  1448. return;
  1449. CHECK_HR(ReadAttrStr(pReader, L"Name", &pHeap->Name));
  1450. HRESULT hrFlags = ReadAttrDESCRIPTOR_HEAP_FLAGS(pReader, L"Flags", &pHeap->Desc.Flags);
  1451. CHECK_HR(hrFlags);
  1452. CHECK_HR(ReadAttrUINT(pReader, L"NodeMask", &pHeap->Desc.NodeMask));
  1453. CHECK_HR(ReadAttrUINT(pReader, L"NumDescriptors", &pHeap->Desc.NumDescriptors));
  1454. CHECK_HR(ReadAttrDESCRIPTOR_HEAP_TYPE(pReader, L"Type", &pHeap->Desc.Type));
  1455. if (pHeap->Desc.Type == D3D12_DESCRIPTOR_HEAP_TYPE_RTV && hrFlags == S_FALSE)
  1456. pHeap->Desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
  1457. if (pReader->IsEmptyElement())
  1458. return;
  1459. UINT startDepth;
  1460. XmlNodeType nt;
  1461. CHECK_HR(pReader->GetDepth(&startDepth));
  1462. std::wstring value;
  1463. for (;;) {
  1464. UINT depth;
  1465. CHECK_HR(pReader->Read(&nt));
  1466. CHECK_HR(pReader->GetDepth(&depth));
  1467. if (nt == XmlNodeType_EndElement && depth == startDepth + 1)
  1468. break;
  1469. if (nt == XmlNodeType_Element) {
  1470. LPCWSTR pLocalName;
  1471. CHECK_HR(pReader->GetLocalName(&pLocalName, nullptr));
  1472. if (0 == wcscmp(pLocalName, L"Descriptor")) {
  1473. ShaderOpDescriptor D;
  1474. ParseDescriptor(pReader, &D);
  1475. pHeap->Descriptors.push_back(D);
  1476. }
  1477. }
  1478. }
  1479. }
  1480. void ShaderOpParser::ParseInputElement(IXmlReader *pReader, D3D12_INPUT_ELEMENT_DESC *pInputElement) {
  1481. if (!ReadAtElementName(pReader, L"InputElement"))
  1482. return;
  1483. CHECK_HR(ReadAttrStr(pReader, L"SemanticName", &pInputElement->SemanticName));
  1484. CHECK_HR(ReadAttrUINT(pReader, L"SemanticIndex", &pInputElement->SemanticIndex));
  1485. CHECK_HR(ReadAttrDXGI_FORMAT(pReader, L"Format", &pInputElement->Format));
  1486. CHECK_HR(ReadAttrUINT(pReader, L"InputSlot", &pInputElement->InputSlot));
  1487. CHECK_HR(ReadAttrUINT(pReader, L"AlignedByteOffset", &pInputElement->AlignedByteOffset, D3D12_APPEND_ALIGNED_ELEMENT));
  1488. CHECK_HR(ReadAttrINPUT_CLASSIFICATION(pReader, L"InputSlotClass", &pInputElement->InputSlotClass));
  1489. CHECK_HR(ReadAttrUINT(pReader, L"InstanceDataStepRate", &pInputElement->InstanceDataStepRate));
  1490. }
  1491. void ShaderOpParser::ParseInputElements(IXmlReader *pReader, std::vector<D3D12_INPUT_ELEMENT_DESC> *pInputElements) {
  1492. if (!ReadAtElementName(pReader, L"InputElements"))
  1493. return;
  1494. if (pReader->IsEmptyElement()) return;
  1495. UINT startDepth;
  1496. XmlNodeType nt;
  1497. CHECK_HR(pReader->GetDepth(&startDepth));
  1498. for (;;) {
  1499. UINT depth;
  1500. CHECK_HR(pReader->Read(&nt));
  1501. CHECK_HR(pReader->GetDepth(&depth));
  1502. if (nt == XmlNodeType_EndElement && depth == startDepth + 1)
  1503. return;
  1504. if (nt == XmlNodeType_Element) {
  1505. LPCWSTR pLocalName;
  1506. CHECK_HR(pReader->GetLocalName(&pLocalName, nullptr));
  1507. if (0 == wcscmp(pLocalName, L"InputElement")) {
  1508. D3D12_INPUT_ELEMENT_DESC desc;
  1509. ParseInputElement(pReader, &desc);
  1510. pInputElements->push_back(desc);
  1511. }
  1512. }
  1513. }
  1514. }
  1515. void ShaderOpParser::ParseRenderTargets(IXmlReader *pReader, std::vector<LPCSTR> *pRenderTargets) {
  1516. if (!ReadAtElementName(pReader, L"RenderTargets"))
  1517. return;
  1518. if (pReader->IsEmptyElement()) return;
  1519. UINT startDepth;
  1520. XmlNodeType nt;
  1521. CHECK_HR(pReader->GetDepth(&startDepth));
  1522. for (;;) {
  1523. UINT depth;
  1524. CHECK_HR(pReader->Read(&nt));
  1525. CHECK_HR(pReader->GetDepth(&depth));
  1526. if (nt == XmlNodeType_EndElement && depth == startDepth + 1)
  1527. return;
  1528. if (nt == XmlNodeType_Element) {
  1529. LPCWSTR pLocalName;
  1530. CHECK_HR(pReader->GetLocalName(&pLocalName, nullptr));
  1531. if (0 == wcscmp(pLocalName, L"RenderTarget")) {
  1532. LPCSTR pName;
  1533. CHECK_HR(ReadAttrStr(pReader, L"Name", &pName));
  1534. pRenderTargets->push_back(pName);
  1535. }
  1536. }
  1537. }
  1538. }
  1539. void ShaderOpParser::ParseRootValue(IXmlReader *pReader, ShaderOpRootValue *pRootValue) {
  1540. if (!ReadAtElementName(pReader, L"RootValue"))
  1541. return;
  1542. CHECK_HR(ReadAttrStr(pReader, L"ResName", &pRootValue->ResName));
  1543. CHECK_HR(ReadAttrStr(pReader, L"HeapName", &pRootValue->HeapName));
  1544. CHECK_HR(ReadAttrUINT(pReader, L"Index", &pRootValue->Index));
  1545. }
  1546. void ShaderOpParser::ParseRootValues(IXmlReader *pReader, std::vector<ShaderOpRootValue> *pRootValues) {
  1547. if (!ReadAtElementName(pReader, L"RootValues"))
  1548. return;
  1549. if (pReader->IsEmptyElement()) return;
  1550. UINT startDepth;
  1551. XmlNodeType nt;
  1552. CHECK_HR(pReader->GetDepth(&startDepth));
  1553. for (;;) {
  1554. UINT depth;
  1555. CHECK_HR(pReader->Read(&nt));
  1556. CHECK_HR(pReader->GetDepth(&depth));
  1557. if (nt == XmlNodeType_EndElement && depth == startDepth + 1)
  1558. return;
  1559. if (nt == XmlNodeType_Element) {
  1560. LPCWSTR pLocalName;
  1561. CHECK_HR(pReader->GetLocalName(&pLocalName, nullptr));
  1562. if (0 == wcscmp(pLocalName, L"RootValue")) {
  1563. ShaderOpRootValue V;
  1564. ParseRootValue(pReader, &V);
  1565. pRootValues->push_back(V);
  1566. }
  1567. }
  1568. }
  1569. }
  1570. void ShaderOpParser::ParseShaderOpSet(IStream *pStream, ShaderOpSet *pShaderOpSet) {
  1571. CComPtr<IXmlReader> pReader;
  1572. CHECK_HR(CreateXmlReader(__uuidof(IXmlReader), (void **)&pReader, nullptr));
  1573. CHECK_HR(pReader->SetInput(pStream));
  1574. ParseShaderOpSet(pReader, pShaderOpSet);
  1575. }
  1576. void ShaderOpParser::ParseShaderOpSet(IXmlReader *pReader, ShaderOpSet *pShaderOpSet) {
  1577. if (!ReadAtElementName(pReader, L"ShaderOpSet"))
  1578. return;
  1579. UINT startDepth;
  1580. CHECK_HR(pReader->GetDepth(&startDepth));
  1581. XmlNodeType nt = XmlNodeType_Element;
  1582. for (;;) {
  1583. if (nt == XmlNodeType_Element) {
  1584. LPCWSTR pLocalName;
  1585. CHECK_HR(pReader->GetLocalName(&pLocalName, nullptr));
  1586. if (0 == wcscmp(pLocalName, L"ShaderOp")) {
  1587. pShaderOpSet->ShaderOps.emplace_back(std::make_unique<ShaderOp>());
  1588. ParseShaderOp(pReader, pShaderOpSet->ShaderOps.back().get());
  1589. }
  1590. }
  1591. else if (nt == XmlNodeType_EndElement) {
  1592. UINT depth;
  1593. CHECK_HR(pReader->GetDepth(&depth));
  1594. if (depth == startDepth + 1)
  1595. return;
  1596. }
  1597. CHECK_HR(pReader->Read(&nt));
  1598. }
  1599. }
  1600. void ShaderOpParser::ParseShaderOp(IXmlReader *pReader, ShaderOp *pShaderOp) {
  1601. m_pStrings = &pShaderOp->Strings;
  1602. // Look for a ShaderOp element.
  1603. if (!ReadAtElementName(pReader, L"ShaderOp"))
  1604. return;
  1605. CHECK_HR(ReadAttrStr(pReader, L"Name", &pShaderOp->Name));
  1606. CHECK_HR(ReadAttrStr(pReader, L"CS", &pShaderOp->CS));
  1607. CHECK_HR(ReadAttrStr(pReader, L"VS", &pShaderOp->VS));
  1608. CHECK_HR(ReadAttrStr(pReader, L"PS", &pShaderOp->PS));
  1609. CHECK_HR(ReadAttrUINT(pReader, L"DispatchX", &pShaderOp->DispatchX, 1));
  1610. CHECK_HR(ReadAttrUINT(pReader, L"DispatchY", &pShaderOp->DispatchY, 1));
  1611. CHECK_HR(ReadAttrUINT(pReader, L"DispatchZ", &pShaderOp->DispatchZ, 1));
  1612. CHECK_HR(ReadAttrPRIMITIVE_TOPOLOGY_TYPE(pReader, L"TopologyType", &pShaderOp->PrimitiveTopologyType));
  1613. UINT startDepth;
  1614. CHECK_HR(pReader->GetDepth(&startDepth));
  1615. XmlNodeType nt = XmlNodeType_Element;
  1616. for (;;) {
  1617. if (nt == XmlNodeType_Element) {
  1618. LPCWSTR pLocalName;
  1619. CHECK_HR(pReader->GetLocalName(&pLocalName, nullptr));
  1620. if (0 == wcscmp(pLocalName, L"InputElements")) {
  1621. ParseInputElements(pReader, &pShaderOp->InputElements);
  1622. }
  1623. else if (0 == wcscmp(pLocalName, L"Shader")) {
  1624. ShaderOpShader shader;
  1625. ParseShader(pReader, &shader);
  1626. pShaderOp->Shaders.push_back(shader);
  1627. }
  1628. else if (0 == wcscmp(pLocalName, L"RootSignature")) {
  1629. ReadElementContentStr(pReader, &pShaderOp->RootSignature);
  1630. }
  1631. else if (0 == wcscmp(pLocalName, L"RenderTargets")) {
  1632. ParseRenderTargets(pReader, &pShaderOp->RenderTargets);
  1633. }
  1634. else if (0 == wcscmp(pLocalName, L"Resource")) {
  1635. ShaderOpResource resource;
  1636. ParseResource(pReader, &resource);
  1637. pShaderOp->Resources.push_back(resource);
  1638. }
  1639. else if (0 == wcscmp(pLocalName, L"DescriptorHeap")) {
  1640. ShaderOpDescriptorHeap heap;
  1641. ParseDescriptorHeap(pReader, &heap);
  1642. pShaderOp->DescriptorHeaps.push_back(heap);
  1643. }
  1644. else if (0 == wcscmp(pLocalName, L"RootValues")) {
  1645. ParseRootValues(pReader, &pShaderOp->RootValues);
  1646. }
  1647. }
  1648. else if (nt == XmlNodeType_EndElement) {
  1649. UINT depth;
  1650. CHECK_HR(pReader->GetDepth(&depth));
  1651. if (depth == startDepth + 1)
  1652. return;
  1653. }
  1654. if (S_FALSE == CHECK_HR_RET(pReader->Read(&nt)))
  1655. return;
  1656. }
  1657. }
  1658. LPCWSTR SkipByteInitSeparators(LPCWSTR pText) {
  1659. while (*pText && (*pText == L' ' || *pText == L'\t' ||
  1660. *pText == L'\r' || *pText == L'\n' || *pText == L'{' ||
  1661. *pText == L'}' || *pText == L','))
  1662. ++pText;
  1663. return pText;
  1664. }
  1665. LPCWSTR FindByteInitSeparators(LPCWSTR pText) {
  1666. while (*pText &&
  1667. !(*pText == L' ' || *pText == L'\t' ||
  1668. *pText == L'\r' || *pText == L'\n' || *pText == L'{' ||
  1669. *pText == L'}' || *pText == L','))
  1670. ++pText;
  1671. return pText;
  1672. }
  1673. using namespace hlsl;
  1674. DXIL::ComponentType GetCompType(LPCWSTR pText, LPCWSTR pEnd) {
  1675. // if no prefix shown, use it as a default
  1676. if (pText == pEnd) return DXIL::ComponentType::F32;
  1677. // check if suffix starts with (half)
  1678. if (wcsncmp(pText, L"(half)", 6) == 0) {
  1679. return DXIL::ComponentType::F16;
  1680. }
  1681. switch (*(pEnd - 1)) {
  1682. case L'h':
  1683. case L'H':
  1684. return DXIL::ComponentType::F16;
  1685. case L'l':
  1686. case L'L':
  1687. return DXIL::ComponentType::F64;
  1688. case L'u':
  1689. case L'U':
  1690. return DXIL::ComponentType::U32;
  1691. case L'i':
  1692. case L'I':
  1693. return DXIL::ComponentType::I32;
  1694. case L'f':
  1695. case L'F':
  1696. default:
  1697. return DXIL::ComponentType::F32;
  1698. }
  1699. }
  1700. bool GetSign(float x) {
  1701. return std::signbit(x);
  1702. }
  1703. int GetMantissa(float x) {
  1704. int bits = reinterpret_cast<int &>(x);
  1705. return bits & 0x7fffff;
  1706. }
  1707. int GetExponent(float x) {
  1708. int bits = reinterpret_cast<int &>(x);
  1709. return (bits >> 23) & 0xff;
  1710. }
  1711. // Note: This is not a precise float32 to float16 conversion.
  1712. // This function should be used to convert float values read from ShaderOp data that were intended to be used for halves.
  1713. // So special values (nan, denorm, inf) for float32 will map to their corresponding bits in float16,
  1714. // and it will not handle true conversions that spans float16 denorms and float32 non-denorms.
  1715. uint16_t ConvertFloat32ToFloat16(float x) {
  1716. bool isNeg = GetSign(x);
  1717. int exp = GetExponent(x);
  1718. int mantissa = GetMantissa(x);
  1719. if (isnan(x)) return Float16NaN;
  1720. if (isinf(x) || exp - 127 > 15) {
  1721. return isNeg ? Float16NegInf : Float16PosInf;
  1722. }
  1723. if (isdenorm(x)) return isNeg ? Float16NegDenorm : Float16PosDenorm;
  1724. if (exp == 0 && mantissa == 0) return isNeg ? Float16NegZero : Float16PosZero;
  1725. else {
  1726. DXASSERT(exp - 127 <= 15, "else invalid float conversion");
  1727. uint16_t val = 0;
  1728. val |= isNeg ? 0x8000 : 0;
  1729. val |= (exp - 127 + 15) << 10; // subtract from float32 exponent bias and add float16 exponent bias
  1730. val |= mantissa >> 13; // only first 10 significands taken
  1731. return val;
  1732. }
  1733. }
  1734. void ParseDataFromText(LPCWSTR pText, LPCWSTR pEnd, DXIL::ComponentType compType, std::vector<BYTE> &V) {
  1735. BYTE *pB;
  1736. if (compType == DXIL::ComponentType::F16 || compType == DXIL::ComponentType::F32) {
  1737. float fVal;
  1738. size_t wordSize = pEnd - pText;
  1739. if (wordSize >= 3 && 0 == _wcsnicmp(pEnd - 3, L"nan", 3)) {
  1740. fVal = NAN;
  1741. }
  1742. else if (wordSize >= 4 && 0 == _wcsnicmp(pEnd - 4, L"-inf", 4)) {
  1743. fVal = -(INFINITY);
  1744. }
  1745. else if ((wordSize >= 3 && 0 == _wcsnicmp(pEnd - 3, L"inf", 3)) ||
  1746. (wordSize >= 4 && 0 == _wcsnicmp(pEnd - 4, L"+inf", 4))) {
  1747. fVal = INFINITY;
  1748. }
  1749. else if (wordSize >= 7 && 0 == _wcsnicmp(pEnd - 7, L"-denorm", 7)) {
  1750. fVal = -(FLT_MIN / 2);
  1751. }
  1752. else if (wordSize >= 6 && 0 == _wcsnicmp(pEnd - 6, L"denorm", 6)) {
  1753. fVal = (FLT_MIN / 2);
  1754. }
  1755. else {
  1756. fVal = wcstof(pText, nullptr);
  1757. }
  1758. if (compType == DXIL::ComponentType::F16) {
  1759. uint16_t fp16Val = ConvertFloat32ToFloat16(fVal);
  1760. pB = (BYTE *)&fp16Val;
  1761. V.insert(V.end(), pB, pB + sizeof(uint16_t));
  1762. }
  1763. else {
  1764. pB = (BYTE *)&fVal;
  1765. V.insert(V.end(), pB, pB + sizeof(float));
  1766. }
  1767. }
  1768. else if (compType == DXIL::ComponentType::I32) {
  1769. int val = _wtoi(pText);
  1770. pB = (BYTE *)&val;
  1771. V.insert(V.end(), pB, pB + sizeof(int));
  1772. }
  1773. else {
  1774. DXASSERT(false, "Unsupported stream component type : %u", compType);
  1775. }
  1776. }
  1777. void ShaderOpParser::ParseResource(IXmlReader *pReader, ShaderOpResource *pResource) {
  1778. if (!ReadAtElementName(pReader, L"Resource"))
  1779. return;
  1780. CHECK_HR(ReadAttrStr(pReader, L"Name", &pResource->Name));
  1781. CHECK_HR(ReadAttrStr(pReader, L"Init", &pResource->Init));
  1782. CHECK_HR(ReadAttrBOOL(pReader, L"ReadBack", &pResource->ReadBack));
  1783. CHECK_HR(ReadAttrHEAP_TYPE(pReader, L"HeapType", &pResource->HeapProperties.Type));
  1784. CHECK_HR(ReadAttrCPU_PAGE_PROPERTY(pReader, L"CPUPageProperty", &pResource->HeapProperties.CPUPageProperty));
  1785. CHECK_HR(ReadAttrMEMORY_POOL(pReader, L"MemoryPoolPreference", &pResource->HeapProperties.MemoryPoolPreference));
  1786. CHECK_HR(ReadAttrUINT(pReader, L"CreationNodeMask", &pResource->HeapProperties.CreationNodeMask));
  1787. CHECK_HR(ReadAttrUINT(pReader, L"VisibleNodeMask", &pResource->HeapProperties.VisibleNodeMask));
  1788. // D3D12_RESOURCE_DESC Desc;
  1789. CHECK_HR(ReadAttrRESOURCE_DIMENSION(pReader, L"Dimension", &pResource->Desc.Dimension));
  1790. CHECK_HR(ReadAttrUINT64(pReader, L"Alignment", &pResource->Desc.Alignment));
  1791. CHECK_HR(ReadAttrUINT64(pReader, L"Width", &pResource->Desc.Width));
  1792. CHECK_HR(ReadAttrUINT(pReader, L"Height", &pResource->Desc.Height));
  1793. CHECK_HR(ReadAttrUINT16(pReader, L"DepthOrArraySize", &pResource->Desc.DepthOrArraySize));
  1794. CHECK_HR(ReadAttrUINT16(pReader, L"MipLevels", &pResource->Desc.MipLevels));
  1795. CHECK_HR(ReadAttrDXGI_FORMAT(pReader, L"Format", &pResource->Desc.Format));
  1796. CHECK_HR(ReadAttrUINT(pReader, L"SampleCount", &pResource->Desc.SampleDesc.Count));
  1797. CHECK_HR(ReadAttrUINT(pReader, L"SampleQual", &pResource->Desc.SampleDesc.Quality));
  1798. CHECK_HR(ReadAttrTEXTURE_LAYOUT(pReader, L"Layout", &pResource->Desc.Layout));
  1799. CHECK_HR(ReadAttrRESOURCE_FLAGS(pReader, L"Flags", &pResource->Desc.Flags));
  1800. CHECK_HR(ReadAttrHEAP_FLAGS(pReader, L"HeapFlags", &pResource->HeapFlags));
  1801. CHECK_HR(ReadAttrRESOURCE_STATES(pReader, L"InitialResourceState", &pResource->InitialResourceState));
  1802. CHECK_HR(ReadAttrRESOURCE_STATES(pReader, L"TransitionTo", &pResource->TransitionTo));
  1803. CHECK_HR(ReadAttrPRIMITIVE_TOPOLOGY(pReader, L"Topology", &pResource->PrimitiveTopology));
  1804. // Set some fixed values.
  1805. if (pResource->Desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) {
  1806. pResource->Desc.Height = 1;
  1807. pResource->Desc.DepthOrArraySize = 1;
  1808. pResource->Desc.MipLevels = 1;
  1809. pResource->Desc.Format = DXGI_FORMAT_UNKNOWN;
  1810. pResource->Desc.SampleDesc.Count = 1;
  1811. pResource->Desc.SampleDesc.Quality = 0;
  1812. pResource->Desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
  1813. }
  1814. if (pResource->Desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D) {
  1815. if (pResource->Desc.Height == 0) pResource->Desc.Height = 1;
  1816. if (pResource->Desc.DepthOrArraySize == 0) pResource->Desc.DepthOrArraySize = 1;
  1817. if (pResource->Desc.SampleDesc.Count == 0) pResource->Desc.SampleDesc.Count = 1;
  1818. }
  1819. if (pResource->Desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D) {
  1820. if (pResource->Desc.DepthOrArraySize == 0) pResource->Desc.DepthOrArraySize = 1;
  1821. if (pResource->Desc.SampleDesc.Count == 0 ) pResource->Desc.SampleDesc.Count = 1;
  1822. }
  1823. // If the resource has text, that goes into the bytes initialization area.
  1824. if (pReader->IsEmptyElement())
  1825. return;
  1826. std::vector<BYTE> &V = pResource->InitBytes;
  1827. XmlNodeType nt;
  1828. CHECK_HR(pReader->GetNodeType(&nt));
  1829. for (;;) {
  1830. if (nt == XmlNodeType_EndElement) {
  1831. return;
  1832. }
  1833. if (nt == XmlNodeType_Text) {
  1834. // Handle the byte payload. '{', '}', ',', whitespace - these are all
  1835. // separators and are ignored in terms of structure. We simply read
  1836. // literals, figure out their type based on suffix, and write the bytes
  1837. // into the target array.
  1838. LPCWSTR pText;
  1839. pReader->GetValue(&pText, nullptr);
  1840. while (*pText) {
  1841. pText = SkipByteInitSeparators(pText);
  1842. if (!*pText) continue;
  1843. LPCWSTR pEnd = FindByteInitSeparators(pText);
  1844. // Consider looking for prefixes/suffixes to handle bases and types.
  1845. DXIL::ComponentType compType = GetCompType(pText, pEnd);
  1846. ParseDataFromText(pText, pEnd, compType, V);
  1847. pText = pEnd;
  1848. }
  1849. }
  1850. if (S_FALSE == CHECK_HR_RET(pReader->Read(&nt)))
  1851. return;
  1852. }
  1853. }
  1854. void ShaderOpParser::ParseShader(IXmlReader *pReader, ShaderOpShader *pShader) {
  1855. if (!ReadAtElementName(pReader, L"Shader"))
  1856. return;
  1857. CHECK_HR(ReadAttrStr(pReader, L"Name", &pShader->Name));
  1858. CHECK_HR(ReadAttrStr(pReader, L"EntryPoint", &pShader->EntryPoint));
  1859. CHECK_HR(ReadAttrStr(pReader, L"Target", &pShader->Target));
  1860. CHECK_HR(ReadAttrStr(pReader, L"Arguments", &pShader->Arguments))
  1861. ReadElementContentStr(pReader, &pShader->Text);
  1862. bool hasText = pShader->Text && *pShader->Text;
  1863. if (hasText) {
  1864. LPCSTR pCheck;
  1865. CHECK_HR(ReadAttrStr(pReader, L"Text", &pCheck));
  1866. if (pCheck && *pCheck) {
  1867. ShaderOpLogFmt(L"Shader %S has text content and a Text attribute; it "
  1868. L"should only have one",
  1869. pShader->Name);
  1870. CHECK_HR(E_INVALIDARG);
  1871. }
  1872. }
  1873. else {
  1874. CHECK_HR(ReadAttrStr(pReader, L"Text", &pShader->Text));
  1875. }
  1876. if (pShader->EntryPoint == nullptr)
  1877. pShader->EntryPoint = m_pStrings->insert("main");
  1878. }
  1879. bool ShaderOpParser::ReadAtElementName(IXmlReader *pReader, LPCWSTR pName) {
  1880. XmlNodeType nt;
  1881. CHECK_HR(pReader->GetNodeType(&nt));
  1882. for (;;) {
  1883. if (nt == XmlNodeType_Element) {
  1884. LPCWSTR pLocalName;
  1885. CHECK_HR(pReader->GetLocalName(&pLocalName, nullptr));
  1886. if (0 == wcscmp(pLocalName, pName)) {
  1887. return true;
  1888. }
  1889. }
  1890. if (S_FALSE == CHECK_HR_RET(pReader->Read(&nt)))
  1891. return false;
  1892. }
  1893. }
  1894. #pragma endregion Parsing support
  1895. } // namespace st