1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © Microsoft Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include <stdio.h>
25bf215546Sopenharmony_ci#include <stdint.h>
26bf215546Sopenharmony_ci#include <stdexcept>
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include <unknwn.h>
29bf215546Sopenharmony_ci#include <directx/d3d12.h>
30bf215546Sopenharmony_ci#include <dxgi1_4.h>
31bf215546Sopenharmony_ci#include <gtest/gtest.h>
32bf215546Sopenharmony_ci#include <wrl.h>
33bf215546Sopenharmony_ci#include <dxguids/dxguids.h>
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci#include "util/u_debug.h"
36bf215546Sopenharmony_ci#include "clc_compiler.h"
37bf215546Sopenharmony_ci#include "compute_test.h"
38bf215546Sopenharmony_ci#include "dxil_validator.h"
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci#include <spirv-tools/libspirv.hpp>
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_ci#if (defined(_WIN32) && defined(_MSC_VER)) || D3D12_SDK_VERSION < 606
43bf215546Sopenharmony_ciinline D3D12_CPU_DESCRIPTOR_HANDLE
44bf215546Sopenharmony_ciGetCPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap *heap)
45bf215546Sopenharmony_ci{
46bf215546Sopenharmony_ci   return heap->GetCPUDescriptorHandleForHeapStart();
47bf215546Sopenharmony_ci}
48bf215546Sopenharmony_ciinline D3D12_GPU_DESCRIPTOR_HANDLE
49bf215546Sopenharmony_ciGetGPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap *heap)
50bf215546Sopenharmony_ci{
51bf215546Sopenharmony_ci   return heap->GetGPUDescriptorHandleForHeapStart();
52bf215546Sopenharmony_ci}
53bf215546Sopenharmony_ciinline D3D12_HEAP_PROPERTIES
54bf215546Sopenharmony_ciGetCustomHeapProperties(ID3D12Device *dev, D3D12_HEAP_TYPE type)
55bf215546Sopenharmony_ci{
56bf215546Sopenharmony_ci   return dev->GetCustomHeapProperties(0, type);
57bf215546Sopenharmony_ci}
58bf215546Sopenharmony_ci#else
59bf215546Sopenharmony_ciinline D3D12_CPU_DESCRIPTOR_HANDLE
60bf215546Sopenharmony_ciGetCPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap *heap)
61bf215546Sopenharmony_ci{
62bf215546Sopenharmony_ci   D3D12_CPU_DESCRIPTOR_HANDLE ret;
63bf215546Sopenharmony_ci   heap->GetCPUDescriptorHandleForHeapStart(&ret);
64bf215546Sopenharmony_ci   return ret;
65bf215546Sopenharmony_ci}
66bf215546Sopenharmony_ciinline D3D12_GPU_DESCRIPTOR_HANDLE
67bf215546Sopenharmony_ciGetGPUDescriptorHandleForHeapStart(ID3D12DescriptorHeap *heap)
68bf215546Sopenharmony_ci{
69bf215546Sopenharmony_ci   D3D12_GPU_DESCRIPTOR_HANDLE ret;
70bf215546Sopenharmony_ci   heap->GetGPUDescriptorHandleForHeapStart(&ret);
71bf215546Sopenharmony_ci   return ret;
72bf215546Sopenharmony_ci}
73bf215546Sopenharmony_ciinline D3D12_HEAP_PROPERTIES
74bf215546Sopenharmony_ciGetCustomHeapProperties(ID3D12Device *dev, D3D12_HEAP_TYPE type)
75bf215546Sopenharmony_ci{
76bf215546Sopenharmony_ci   D3D12_HEAP_PROPERTIES ret;
77bf215546Sopenharmony_ci   dev->GetCustomHeapProperties(&ret, 0, type);
78bf215546Sopenharmony_ci   return ret;
79bf215546Sopenharmony_ci}
80bf215546Sopenharmony_ci#endif
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_ciusing std::runtime_error;
83bf215546Sopenharmony_ciusing Microsoft::WRL::ComPtr;
84bf215546Sopenharmony_ci
85bf215546Sopenharmony_cienum compute_test_debug_flags {
86bf215546Sopenharmony_ci   COMPUTE_DEBUG_EXPERIMENTAL_SHADERS = 1 << 0,
87bf215546Sopenharmony_ci   COMPUTE_DEBUG_USE_HW_D3D           = 1 << 1,
88bf215546Sopenharmony_ci   COMPUTE_DEBUG_OPTIMIZE_LIBCLC      = 1 << 2,
89bf215546Sopenharmony_ci   COMPUTE_DEBUG_SERIALIZE_LIBCLC     = 1 << 3,
90bf215546Sopenharmony_ci};
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_cistatic const struct debug_named_value compute_debug_options[] = {
93bf215546Sopenharmony_ci   { "experimental_shaders",  COMPUTE_DEBUG_EXPERIMENTAL_SHADERS, "Enable experimental shaders" },
94bf215546Sopenharmony_ci   { "use_hw_d3d",            COMPUTE_DEBUG_USE_HW_D3D,           "Use a hardware D3D device"   },
95bf215546Sopenharmony_ci   { "optimize_libclc",       COMPUTE_DEBUG_OPTIMIZE_LIBCLC,      "Optimize the clc_libclc before using it" },
96bf215546Sopenharmony_ci   { "serialize_libclc",      COMPUTE_DEBUG_SERIALIZE_LIBCLC,     "Serialize and deserialize the clc_libclc" },
97bf215546Sopenharmony_ci   DEBUG_NAMED_VALUE_END
98bf215546Sopenharmony_ci};
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ciDEBUG_GET_ONCE_FLAGS_OPTION(debug_compute, "COMPUTE_TEST_DEBUG", compute_debug_options, 0)
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_cistatic void warning_callback(void *priv, const char *msg)
103bf215546Sopenharmony_ci{
104bf215546Sopenharmony_ci   fprintf(stderr, "WARNING: %s\n", msg);
105bf215546Sopenharmony_ci}
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_cistatic void error_callback(void *priv, const char *msg)
108bf215546Sopenharmony_ci{
109bf215546Sopenharmony_ci   fprintf(stderr, "ERROR: %s\n", msg);
110bf215546Sopenharmony_ci}
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_cistatic const struct clc_logger logger = {
113bf215546Sopenharmony_ci   NULL,
114bf215546Sopenharmony_ci   error_callback,
115bf215546Sopenharmony_ci   warning_callback,
116bf215546Sopenharmony_ci};
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_civoid
119bf215546Sopenharmony_ciComputeTest::enable_d3d12_debug_layer()
120bf215546Sopenharmony_ci{
121bf215546Sopenharmony_ci   HMODULE hD3D12Mod = LoadLibrary("D3D12.DLL");
122bf215546Sopenharmony_ci   if (!hD3D12Mod) {
123bf215546Sopenharmony_ci      fprintf(stderr, "D3D12: failed to load D3D12.DLL\n");
124bf215546Sopenharmony_ci      return;
125bf215546Sopenharmony_ci   }
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci   typedef HRESULT(WINAPI * PFN_D3D12_GET_DEBUG_INTERFACE)(REFIID riid,
128bf215546Sopenharmony_ci                                                           void **ppFactory);
129bf215546Sopenharmony_ci   PFN_D3D12_GET_DEBUG_INTERFACE D3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress(hD3D12Mod, "D3D12GetDebugInterface");
130bf215546Sopenharmony_ci   if (!D3D12GetDebugInterface) {
131bf215546Sopenharmony_ci      fprintf(stderr, "D3D12: failed to load D3D12GetDebugInterface from D3D12.DLL\n");
132bf215546Sopenharmony_ci      return;
133bf215546Sopenharmony_ci   }
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci   ID3D12Debug *debug;
136bf215546Sopenharmony_ci   if (FAILED(D3D12GetDebugInterface(__uuidof(ID3D12Debug), (void **)& debug))) {
137bf215546Sopenharmony_ci      fprintf(stderr, "D3D12: D3D12GetDebugInterface failed\n");
138bf215546Sopenharmony_ci      return;
139bf215546Sopenharmony_ci   }
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci   debug->EnableDebugLayer();
142bf215546Sopenharmony_ci}
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_ciIDXGIFactory4 *
145bf215546Sopenharmony_ciComputeTest::get_dxgi_factory()
146bf215546Sopenharmony_ci{
147bf215546Sopenharmony_ci   static const GUID IID_IDXGIFactory4 = {
148bf215546Sopenharmony_ci      0x1bc6ea02, 0xef36, 0x464f,
149bf215546Sopenharmony_ci      { 0xbf, 0x0c, 0x21, 0xca, 0x39, 0xe5, 0x16, 0x8a }
150bf215546Sopenharmony_ci   };
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci   typedef HRESULT(WINAPI * PFN_CREATE_DXGI_FACTORY)(REFIID riid,
153bf215546Sopenharmony_ci                                                     void **ppFactory);
154bf215546Sopenharmony_ci   PFN_CREATE_DXGI_FACTORY CreateDXGIFactory;
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci   HMODULE hDXGIMod = LoadLibrary("DXGI.DLL");
157bf215546Sopenharmony_ci   if (!hDXGIMod)
158bf215546Sopenharmony_ci      throw runtime_error("Failed to load DXGI.DLL");
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci   CreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(hDXGIMod, "CreateDXGIFactory");
161bf215546Sopenharmony_ci   if (!CreateDXGIFactory)
162bf215546Sopenharmony_ci      throw runtime_error("Failed to load CreateDXGIFactory from DXGI.DLL");
163bf215546Sopenharmony_ci
164bf215546Sopenharmony_ci   IDXGIFactory4 *factory = NULL;
165bf215546Sopenharmony_ci   HRESULT hr = CreateDXGIFactory(IID_IDXGIFactory4, (void **)&factory);
166bf215546Sopenharmony_ci   if (FAILED(hr))
167bf215546Sopenharmony_ci      throw runtime_error("CreateDXGIFactory failed");
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_ci   return factory;
170bf215546Sopenharmony_ci}
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ciIDXGIAdapter1 *
173bf215546Sopenharmony_ciComputeTest::choose_adapter(IDXGIFactory4 *factory)
174bf215546Sopenharmony_ci{
175bf215546Sopenharmony_ci   IDXGIAdapter1 *ret;
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci   if (debug_get_option_debug_compute() & COMPUTE_DEBUG_USE_HW_D3D) {
178bf215546Sopenharmony_ci      for (unsigned i = 0; SUCCEEDED(factory->EnumAdapters1(i, &ret)); i++) {
179bf215546Sopenharmony_ci         DXGI_ADAPTER_DESC1 desc;
180bf215546Sopenharmony_ci         ret->GetDesc1(&desc);
181bf215546Sopenharmony_ci         if (!(desc.Flags & D3D_DRIVER_TYPE_SOFTWARE))
182bf215546Sopenharmony_ci            return ret;
183bf215546Sopenharmony_ci      }
184bf215546Sopenharmony_ci      throw runtime_error("Failed to enum hardware adapter");
185bf215546Sopenharmony_ci   } else {
186bf215546Sopenharmony_ci      if (FAILED(factory->EnumWarpAdapter(__uuidof(IDXGIAdapter1),
187bf215546Sopenharmony_ci         (void **)& ret)))
188bf215546Sopenharmony_ci         throw runtime_error("Failed to enum warp adapter");
189bf215546Sopenharmony_ci      return ret;
190bf215546Sopenharmony_ci   }
191bf215546Sopenharmony_ci}
192bf215546Sopenharmony_ci
193bf215546Sopenharmony_ciID3D12Device *
194bf215546Sopenharmony_ciComputeTest::create_device(IDXGIAdapter1 *adapter)
195bf215546Sopenharmony_ci{
196bf215546Sopenharmony_ci   typedef HRESULT(WINAPI *PFN_D3D12CREATEDEVICE)(IUnknown *, D3D_FEATURE_LEVEL, REFIID, void **);
197bf215546Sopenharmony_ci   PFN_D3D12CREATEDEVICE D3D12CreateDevice;
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_ci   HMODULE hD3D12Mod = LoadLibrary("D3D12.DLL");
200bf215546Sopenharmony_ci   if (!hD3D12Mod)
201bf215546Sopenharmony_ci      throw runtime_error("failed to load D3D12.DLL");
202bf215546Sopenharmony_ci
203bf215546Sopenharmony_ci   if (debug_get_option_debug_compute() & COMPUTE_DEBUG_EXPERIMENTAL_SHADERS) {
204bf215546Sopenharmony_ci      typedef HRESULT(WINAPI *PFN_D3D12ENABLEEXPERIMENTALFEATURES)(UINT, const IID *, void *, UINT *);
205bf215546Sopenharmony_ci      PFN_D3D12ENABLEEXPERIMENTALFEATURES D3D12EnableExperimentalFeatures;
206bf215546Sopenharmony_ci      D3D12EnableExperimentalFeatures = (PFN_D3D12ENABLEEXPERIMENTALFEATURES)
207bf215546Sopenharmony_ci         GetProcAddress(hD3D12Mod, "D3D12EnableExperimentalFeatures");
208bf215546Sopenharmony_ci      if (FAILED(D3D12EnableExperimentalFeatures(1, &D3D12ExperimentalShaderModels, NULL, NULL)))
209bf215546Sopenharmony_ci         throw runtime_error("failed to enable experimental shader models");
210bf215546Sopenharmony_ci   }
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci   D3D12CreateDevice = (PFN_D3D12CREATEDEVICE)GetProcAddress(hD3D12Mod, "D3D12CreateDevice");
213bf215546Sopenharmony_ci   if (!D3D12CreateDevice)
214bf215546Sopenharmony_ci      throw runtime_error("failed to load D3D12CreateDevice from D3D12.DLL");
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_ci   ID3D12Device *dev;
217bf215546Sopenharmony_ci   if (FAILED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_12_0,
218bf215546Sopenharmony_ci       __uuidof(ID3D12Device), (void **)& dev)))
219bf215546Sopenharmony_ci      throw runtime_error("D3D12CreateDevice failed");
220bf215546Sopenharmony_ci
221bf215546Sopenharmony_ci   return dev;
222bf215546Sopenharmony_ci}
223bf215546Sopenharmony_ci
224bf215546Sopenharmony_ciComPtr<ID3D12RootSignature>
225bf215546Sopenharmony_ciComputeTest::create_root_signature(const ComputeTest::Resources &resources)
226bf215546Sopenharmony_ci{
227bf215546Sopenharmony_ci   D3D12_ROOT_PARAMETER1 root_param;
228bf215546Sopenharmony_ci   root_param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
229bf215546Sopenharmony_ci   root_param.DescriptorTable.NumDescriptorRanges = resources.ranges.size();
230bf215546Sopenharmony_ci   root_param.DescriptorTable.pDescriptorRanges = resources.ranges.data();
231bf215546Sopenharmony_ci   root_param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
232bf215546Sopenharmony_ci
233bf215546Sopenharmony_ci   D3D12_ROOT_SIGNATURE_DESC1 root_sig_desc;
234bf215546Sopenharmony_ci   root_sig_desc.NumParameters = 1;
235bf215546Sopenharmony_ci   root_sig_desc.pParameters = &root_param;
236bf215546Sopenharmony_ci   root_sig_desc.NumStaticSamplers = 0;
237bf215546Sopenharmony_ci   root_sig_desc.pStaticSamplers = NULL;
238bf215546Sopenharmony_ci   root_sig_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci   D3D12_VERSIONED_ROOT_SIGNATURE_DESC versioned_desc;
241bf215546Sopenharmony_ci   versioned_desc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
242bf215546Sopenharmony_ci   versioned_desc.Desc_1_1 = root_sig_desc;
243bf215546Sopenharmony_ci
244bf215546Sopenharmony_ci   ID3DBlob *sig, *error;
245bf215546Sopenharmony_ci   if (FAILED(D3D12SerializeVersionedRootSignature(&versioned_desc,
246bf215546Sopenharmony_ci       &sig, &error)))
247bf215546Sopenharmony_ci      throw runtime_error("D3D12SerializeVersionedRootSignature failed");
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_ci   ComPtr<ID3D12RootSignature> ret;
250bf215546Sopenharmony_ci   if (FAILED(dev->CreateRootSignature(0,
251bf215546Sopenharmony_ci       sig->GetBufferPointer(),
252bf215546Sopenharmony_ci       sig->GetBufferSize(),
253bf215546Sopenharmony_ci       __uuidof(ID3D12RootSignature),
254bf215546Sopenharmony_ci       (void **)& ret)))
255bf215546Sopenharmony_ci      throw runtime_error("CreateRootSignature failed");
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci   return ret;
258bf215546Sopenharmony_ci}
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ciComPtr<ID3D12PipelineState>
261bf215546Sopenharmony_ciComputeTest::create_pipeline_state(ComPtr<ID3D12RootSignature> &root_sig,
262bf215546Sopenharmony_ci                                   const struct clc_dxil_object &dxil)
263bf215546Sopenharmony_ci{
264bf215546Sopenharmony_ci   D3D12_COMPUTE_PIPELINE_STATE_DESC pipeline_desc = { root_sig.Get() };
265bf215546Sopenharmony_ci   pipeline_desc.CS.pShaderBytecode = dxil.binary.data;
266bf215546Sopenharmony_ci   pipeline_desc.CS.BytecodeLength = dxil.binary.size;
267bf215546Sopenharmony_ci
268bf215546Sopenharmony_ci   ComPtr<ID3D12PipelineState> pipeline_state;
269bf215546Sopenharmony_ci   if (FAILED(dev->CreateComputePipelineState(&pipeline_desc,
270bf215546Sopenharmony_ci                                              __uuidof(ID3D12PipelineState),
271bf215546Sopenharmony_ci                                              (void **)& pipeline_state)))
272bf215546Sopenharmony_ci      throw runtime_error("Failed to create pipeline state");
273bf215546Sopenharmony_ci   return pipeline_state;
274bf215546Sopenharmony_ci}
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ciComPtr<ID3D12Resource>
277bf215546Sopenharmony_ciComputeTest::create_buffer(int size, D3D12_HEAP_TYPE heap_type)
278bf215546Sopenharmony_ci{
279bf215546Sopenharmony_ci   D3D12_RESOURCE_DESC desc;
280bf215546Sopenharmony_ci   desc.Format = DXGI_FORMAT_UNKNOWN;
281bf215546Sopenharmony_ci   desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
282bf215546Sopenharmony_ci   desc.Width = size;
283bf215546Sopenharmony_ci   desc.Height = 1;
284bf215546Sopenharmony_ci   desc.DepthOrArraySize = 1;
285bf215546Sopenharmony_ci   desc.MipLevels = 1;
286bf215546Sopenharmony_ci   desc.SampleDesc.Count = 1;
287bf215546Sopenharmony_ci   desc.SampleDesc.Quality = 0;
288bf215546Sopenharmony_ci   desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
289bf215546Sopenharmony_ci   desc.Flags = heap_type == D3D12_HEAP_TYPE_DEFAULT ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS : D3D12_RESOURCE_FLAG_NONE;
290bf215546Sopenharmony_ci   desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_ci   D3D12_HEAP_PROPERTIES heap_pris = GetCustomHeapProperties(dev, heap_type);
293bf215546Sopenharmony_ci
294bf215546Sopenharmony_ci   ComPtr<ID3D12Resource> res;
295bf215546Sopenharmony_ci   if (FAILED(dev->CreateCommittedResource(&heap_pris,
296bf215546Sopenharmony_ci       D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON,
297bf215546Sopenharmony_ci       NULL, __uuidof(ID3D12Resource), (void **)&res)))
298bf215546Sopenharmony_ci      throw runtime_error("CreateCommittedResource failed");
299bf215546Sopenharmony_ci
300bf215546Sopenharmony_ci   return res;
301bf215546Sopenharmony_ci}
302bf215546Sopenharmony_ci
303bf215546Sopenharmony_ciComPtr<ID3D12Resource>
304bf215546Sopenharmony_ciComputeTest::create_upload_buffer_with_data(const void *data, size_t size)
305bf215546Sopenharmony_ci{
306bf215546Sopenharmony_ci   auto upload_res = create_buffer(size, D3D12_HEAP_TYPE_UPLOAD);
307bf215546Sopenharmony_ci
308bf215546Sopenharmony_ci   void *ptr = NULL;
309bf215546Sopenharmony_ci   D3D12_RANGE res_range = { 0, (SIZE_T)size };
310bf215546Sopenharmony_ci   if (FAILED(upload_res->Map(0, &res_range, (void **)&ptr)))
311bf215546Sopenharmony_ci      throw runtime_error("Failed to map upload-buffer");
312bf215546Sopenharmony_ci   assert(ptr);
313bf215546Sopenharmony_ci   memcpy(ptr, data, size);
314bf215546Sopenharmony_ci   upload_res->Unmap(0, &res_range);
315bf215546Sopenharmony_ci   return upload_res;
316bf215546Sopenharmony_ci}
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ciComPtr<ID3D12Resource>
319bf215546Sopenharmony_ciComputeTest::create_sized_buffer_with_data(size_t buffer_size,
320bf215546Sopenharmony_ci                                           const void *data,
321bf215546Sopenharmony_ci                                           size_t data_size)
322bf215546Sopenharmony_ci{
323bf215546Sopenharmony_ci   auto upload_res = create_upload_buffer_with_data(data, data_size);
324bf215546Sopenharmony_ci
325bf215546Sopenharmony_ci   auto res = create_buffer(buffer_size, D3D12_HEAP_TYPE_DEFAULT);
326bf215546Sopenharmony_ci   resource_barrier(res, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST);
327bf215546Sopenharmony_ci   cmdlist->CopyBufferRegion(res.Get(), 0, upload_res.Get(), 0, data_size);
328bf215546Sopenharmony_ci   resource_barrier(res, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COMMON);
329bf215546Sopenharmony_ci   execute_cmdlist();
330bf215546Sopenharmony_ci
331bf215546Sopenharmony_ci   return res;
332bf215546Sopenharmony_ci}
333bf215546Sopenharmony_ci
334bf215546Sopenharmony_civoid
335bf215546Sopenharmony_ciComputeTest::get_buffer_data(ComPtr<ID3D12Resource> res,
336bf215546Sopenharmony_ci                             void *buf, size_t size)
337bf215546Sopenharmony_ci{
338bf215546Sopenharmony_ci   auto readback_res = create_buffer(align(size, 4), D3D12_HEAP_TYPE_READBACK);
339bf215546Sopenharmony_ci   resource_barrier(res, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_SOURCE);
340bf215546Sopenharmony_ci   cmdlist->CopyResource(readback_res.Get(), res.Get());
341bf215546Sopenharmony_ci   resource_barrier(res, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_COMMON);
342bf215546Sopenharmony_ci   execute_cmdlist();
343bf215546Sopenharmony_ci
344bf215546Sopenharmony_ci   void *ptr = NULL;
345bf215546Sopenharmony_ci   D3D12_RANGE res_range = { 0, size };
346bf215546Sopenharmony_ci   if (FAILED(readback_res->Map(0, &res_range, &ptr)))
347bf215546Sopenharmony_ci      throw runtime_error("Failed to map readback-buffer");
348bf215546Sopenharmony_ci
349bf215546Sopenharmony_ci   memcpy(buf, ptr, size);
350bf215546Sopenharmony_ci
351bf215546Sopenharmony_ci   D3D12_RANGE empty_range = { 0, 0 };
352bf215546Sopenharmony_ci   readback_res->Unmap(0, &empty_range);
353bf215546Sopenharmony_ci}
354bf215546Sopenharmony_ci
355bf215546Sopenharmony_civoid
356bf215546Sopenharmony_ciComputeTest::resource_barrier(ComPtr<ID3D12Resource> &res,
357bf215546Sopenharmony_ci                              D3D12_RESOURCE_STATES state_before,
358bf215546Sopenharmony_ci                              D3D12_RESOURCE_STATES state_after)
359bf215546Sopenharmony_ci{
360bf215546Sopenharmony_ci   D3D12_RESOURCE_BARRIER barrier;
361bf215546Sopenharmony_ci   barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
362bf215546Sopenharmony_ci   barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
363bf215546Sopenharmony_ci   barrier.Transition.pResource = res.Get();
364bf215546Sopenharmony_ci   barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
365bf215546Sopenharmony_ci   barrier.Transition.StateBefore = state_before;
366bf215546Sopenharmony_ci   barrier.Transition.StateAfter = state_after;
367bf215546Sopenharmony_ci   cmdlist->ResourceBarrier(1, &barrier);
368bf215546Sopenharmony_ci}
369bf215546Sopenharmony_ci
370bf215546Sopenharmony_civoid
371bf215546Sopenharmony_ciComputeTest::execute_cmdlist()
372bf215546Sopenharmony_ci{
373bf215546Sopenharmony_ci   if (FAILED(cmdlist->Close()))
374bf215546Sopenharmony_ci      throw runtime_error("Closing ID3D12GraphicsCommandList failed");
375bf215546Sopenharmony_ci
376bf215546Sopenharmony_ci   ID3D12CommandList *cmdlists[] = { cmdlist };
377bf215546Sopenharmony_ci   cmdqueue->ExecuteCommandLists(1, cmdlists);
378bf215546Sopenharmony_ci   cmdqueue_fence->SetEventOnCompletion(fence_value, event);
379bf215546Sopenharmony_ci   cmdqueue->Signal(cmdqueue_fence, fence_value);
380bf215546Sopenharmony_ci   fence_value++;
381bf215546Sopenharmony_ci   WaitForSingleObject(event, INFINITE);
382bf215546Sopenharmony_ci
383bf215546Sopenharmony_ci   if (FAILED(cmdalloc->Reset()))
384bf215546Sopenharmony_ci      throw runtime_error("resetting ID3D12CommandAllocator failed");
385bf215546Sopenharmony_ci
386bf215546Sopenharmony_ci   if (FAILED(cmdlist->Reset(cmdalloc, NULL)))
387bf215546Sopenharmony_ci      throw runtime_error("resetting ID3D12GraphicsCommandList failed");
388bf215546Sopenharmony_ci}
389bf215546Sopenharmony_ci
390bf215546Sopenharmony_civoid
391bf215546Sopenharmony_ciComputeTest::create_uav_buffer(ComPtr<ID3D12Resource> res,
392bf215546Sopenharmony_ci                               size_t width, size_t byte_stride,
393bf215546Sopenharmony_ci                               D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle)
394bf215546Sopenharmony_ci{
395bf215546Sopenharmony_ci   D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc;
396bf215546Sopenharmony_ci   uav_desc.Format = DXGI_FORMAT_R32_TYPELESS;
397bf215546Sopenharmony_ci   uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
398bf215546Sopenharmony_ci   uav_desc.Buffer.FirstElement = 0;
399bf215546Sopenharmony_ci   uav_desc.Buffer.NumElements = DIV_ROUND_UP(width * byte_stride, 4);
400bf215546Sopenharmony_ci   uav_desc.Buffer.StructureByteStride = 0;
401bf215546Sopenharmony_ci   uav_desc.Buffer.CounterOffsetInBytes = 0;
402bf215546Sopenharmony_ci   uav_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
403bf215546Sopenharmony_ci
404bf215546Sopenharmony_ci   dev->CreateUnorderedAccessView(res.Get(), NULL, &uav_desc, cpu_handle);
405bf215546Sopenharmony_ci}
406bf215546Sopenharmony_ci
407bf215546Sopenharmony_civoid
408bf215546Sopenharmony_ciComputeTest::create_cbv(ComPtr<ID3D12Resource> res, size_t size,
409bf215546Sopenharmony_ci                        D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle)
410bf215546Sopenharmony_ci{
411bf215546Sopenharmony_ci   D3D12_CONSTANT_BUFFER_VIEW_DESC cbv_desc;
412bf215546Sopenharmony_ci   cbv_desc.BufferLocation = res ? res->GetGPUVirtualAddress() : 0;
413bf215546Sopenharmony_ci   cbv_desc.SizeInBytes = size;
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_ci   dev->CreateConstantBufferView(&cbv_desc, cpu_handle);
416bf215546Sopenharmony_ci}
417bf215546Sopenharmony_ci
418bf215546Sopenharmony_ciComPtr<ID3D12Resource>
419bf215546Sopenharmony_ciComputeTest::add_uav_resource(ComputeTest::Resources &resources,
420bf215546Sopenharmony_ci                              unsigned spaceid, unsigned resid,
421bf215546Sopenharmony_ci                              const void *data, size_t num_elems,
422bf215546Sopenharmony_ci                              size_t elem_size)
423bf215546Sopenharmony_ci{
424bf215546Sopenharmony_ci   size_t size = align(elem_size * num_elems, 4);
425bf215546Sopenharmony_ci   D3D12_CPU_DESCRIPTOR_HANDLE handle;
426bf215546Sopenharmony_ci   ComPtr<ID3D12Resource> res;
427bf215546Sopenharmony_ci   handle = GetCPUDescriptorHandleForHeapStart(uav_heap);
428bf215546Sopenharmony_ci   handle = offset_cpu_handle(handle, resources.descs.size() * uav_heap_incr);
429bf215546Sopenharmony_ci
430bf215546Sopenharmony_ci   if (size) {
431bf215546Sopenharmony_ci      if (data)
432bf215546Sopenharmony_ci         res = create_buffer_with_data(data, size);
433bf215546Sopenharmony_ci      else
434bf215546Sopenharmony_ci         res = create_buffer(size, D3D12_HEAP_TYPE_DEFAULT);
435bf215546Sopenharmony_ci
436bf215546Sopenharmony_ci      resource_barrier(res, D3D12_RESOURCE_STATE_COMMON,
437bf215546Sopenharmony_ci                       D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
438bf215546Sopenharmony_ci   }
439bf215546Sopenharmony_ci   create_uav_buffer(res, num_elems, elem_size, handle);
440bf215546Sopenharmony_ci   resources.add(res, D3D12_DESCRIPTOR_RANGE_TYPE_UAV, spaceid, resid);
441bf215546Sopenharmony_ci   return res;
442bf215546Sopenharmony_ci}
443bf215546Sopenharmony_ci
444bf215546Sopenharmony_ciComPtr<ID3D12Resource>
445bf215546Sopenharmony_ciComputeTest::add_cbv_resource(ComputeTest::Resources &resources,
446bf215546Sopenharmony_ci                              unsigned spaceid, unsigned resid,
447bf215546Sopenharmony_ci                              const void *data, size_t size)
448bf215546Sopenharmony_ci{
449bf215546Sopenharmony_ci   unsigned aligned_size = align(size, 256);
450bf215546Sopenharmony_ci   D3D12_CPU_DESCRIPTOR_HANDLE handle;
451bf215546Sopenharmony_ci   ComPtr<ID3D12Resource> res;
452bf215546Sopenharmony_ci   handle = GetCPUDescriptorHandleForHeapStart(uav_heap);
453bf215546Sopenharmony_ci   handle = offset_cpu_handle(handle, resources.descs.size() * uav_heap_incr);
454bf215546Sopenharmony_ci
455bf215546Sopenharmony_ci   if (size) {
456bf215546Sopenharmony_ci     assert(data);
457bf215546Sopenharmony_ci     res = create_sized_buffer_with_data(aligned_size, data, size);
458bf215546Sopenharmony_ci   }
459bf215546Sopenharmony_ci   create_cbv(res, aligned_size, handle);
460bf215546Sopenharmony_ci   resources.add(res, D3D12_DESCRIPTOR_RANGE_TYPE_CBV, spaceid, resid);
461bf215546Sopenharmony_ci   return res;
462bf215546Sopenharmony_ci}
463bf215546Sopenharmony_ci
464bf215546Sopenharmony_civoid
465bf215546Sopenharmony_ciComputeTest::run_shader_with_raw_args(Shader shader,
466bf215546Sopenharmony_ci                                      const CompileArgs &compile_args,
467bf215546Sopenharmony_ci                                      const std::vector<RawShaderArg *> &args)
468bf215546Sopenharmony_ci{
469bf215546Sopenharmony_ci   if (args.size() < 1)
470bf215546Sopenharmony_ci      throw runtime_error("no inputs");
471bf215546Sopenharmony_ci
472bf215546Sopenharmony_ci   static HMODULE hD3D12Mod = LoadLibrary("D3D12.DLL");
473bf215546Sopenharmony_ci   if (!hD3D12Mod)
474bf215546Sopenharmony_ci      throw runtime_error("Failed to load D3D12.DLL");
475bf215546Sopenharmony_ci
476bf215546Sopenharmony_ci   D3D12SerializeVersionedRootSignature = (PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE)GetProcAddress(hD3D12Mod, "D3D12SerializeVersionedRootSignature");
477bf215546Sopenharmony_ci
478bf215546Sopenharmony_ci   if (args.size() != shader.dxil->kernel->num_args)
479bf215546Sopenharmony_ci      throw runtime_error("incorrect number of inputs");
480bf215546Sopenharmony_ci
481bf215546Sopenharmony_ci   struct clc_runtime_kernel_conf conf = { 0 };
482bf215546Sopenharmony_ci
483bf215546Sopenharmony_ci   // Older WARP and some hardware doesn't support int64, so for these tests, unconditionally lower away int64
484bf215546Sopenharmony_ci   // A more complex runtime can be smarter about detecting when this needs to be done
485bf215546Sopenharmony_ci   conf.lower_bit_size = 64;
486bf215546Sopenharmony_ci
487bf215546Sopenharmony_ci   if (!shader.dxil->metadata.local_size[0])
488bf215546Sopenharmony_ci      conf.local_size[0] = compile_args.x;
489bf215546Sopenharmony_ci   else
490bf215546Sopenharmony_ci      conf.local_size[0] = shader.dxil->metadata.local_size[0];
491bf215546Sopenharmony_ci
492bf215546Sopenharmony_ci   if (!shader.dxil->metadata.local_size[1])
493bf215546Sopenharmony_ci      conf.local_size[1] = compile_args.y;
494bf215546Sopenharmony_ci   else
495bf215546Sopenharmony_ci      conf.local_size[1] = shader.dxil->metadata.local_size[1];
496bf215546Sopenharmony_ci
497bf215546Sopenharmony_ci   if (!shader.dxil->metadata.local_size[2])
498bf215546Sopenharmony_ci      conf.local_size[2] = compile_args.z;
499bf215546Sopenharmony_ci   else
500bf215546Sopenharmony_ci      conf.local_size[2] = shader.dxil->metadata.local_size[2];
501bf215546Sopenharmony_ci
502bf215546Sopenharmony_ci   if (compile_args.x % conf.local_size[0] ||
503bf215546Sopenharmony_ci       compile_args.y % conf.local_size[1] ||
504bf215546Sopenharmony_ci       compile_args.z % conf.local_size[2])
505bf215546Sopenharmony_ci      throw runtime_error("invalid global size must be a multiple of local size");
506bf215546Sopenharmony_ci
507bf215546Sopenharmony_ci   std::vector<struct clc_runtime_arg_info> argsinfo(args.size());
508bf215546Sopenharmony_ci
509bf215546Sopenharmony_ci   conf.args = argsinfo.data();
510bf215546Sopenharmony_ci   conf.support_global_work_id_offsets =
511bf215546Sopenharmony_ci      compile_args.work_props.global_offset_x != 0 ||
512bf215546Sopenharmony_ci      compile_args.work_props.global_offset_y != 0 ||
513bf215546Sopenharmony_ci      compile_args.work_props.global_offset_z != 0;
514bf215546Sopenharmony_ci   conf.support_workgroup_id_offsets =
515bf215546Sopenharmony_ci      compile_args.work_props.group_id_offset_x != 0 ||
516bf215546Sopenharmony_ci      compile_args.work_props.group_id_offset_y != 0 ||
517bf215546Sopenharmony_ci      compile_args.work_props.group_id_offset_z != 0;
518bf215546Sopenharmony_ci
519bf215546Sopenharmony_ci   for (unsigned i = 0; i < shader.dxil->kernel->num_args; ++i) {
520bf215546Sopenharmony_ci      RawShaderArg *arg = args[i];
521bf215546Sopenharmony_ci      size_t size = arg->get_elem_size() * arg->get_num_elems();
522bf215546Sopenharmony_ci
523bf215546Sopenharmony_ci      switch (shader.dxil->kernel->args[i].address_qualifier) {
524bf215546Sopenharmony_ci      case CLC_KERNEL_ARG_ADDRESS_LOCAL:
525bf215546Sopenharmony_ci         argsinfo[i].localptr.size = size;
526bf215546Sopenharmony_ci         break;
527bf215546Sopenharmony_ci      default:
528bf215546Sopenharmony_ci         break;
529bf215546Sopenharmony_ci      }
530bf215546Sopenharmony_ci   }
531bf215546Sopenharmony_ci
532bf215546Sopenharmony_ci   configure(shader, &conf);
533bf215546Sopenharmony_ci   validate(shader);
534bf215546Sopenharmony_ci
535bf215546Sopenharmony_ci   std::shared_ptr<struct clc_dxil_object> &dxil = shader.dxil;
536bf215546Sopenharmony_ci
537bf215546Sopenharmony_ci   std::vector<uint8_t> argsbuf(dxil->metadata.kernel_inputs_buf_size);
538bf215546Sopenharmony_ci   std::vector<ComPtr<ID3D12Resource>> argres(shader.dxil->kernel->num_args);
539bf215546Sopenharmony_ci   clc_work_properties_data work_props = compile_args.work_props;
540bf215546Sopenharmony_ci   if (!conf.support_workgroup_id_offsets) {
541bf215546Sopenharmony_ci      work_props.group_count_total_x = compile_args.x / conf.local_size[0];
542bf215546Sopenharmony_ci      work_props.group_count_total_y = compile_args.y / conf.local_size[1];
543bf215546Sopenharmony_ci      work_props.group_count_total_z = compile_args.z / conf.local_size[2];
544bf215546Sopenharmony_ci   }
545bf215546Sopenharmony_ci   if (work_props.work_dim == 0)
546bf215546Sopenharmony_ci      work_props.work_dim = 3;
547bf215546Sopenharmony_ci   Resources resources;
548bf215546Sopenharmony_ci
549bf215546Sopenharmony_ci   for (unsigned i = 0; i < dxil->kernel->num_args; ++i) {
550bf215546Sopenharmony_ci      RawShaderArg *arg = args[i];
551bf215546Sopenharmony_ci      size_t size = arg->get_elem_size() * arg->get_num_elems();
552bf215546Sopenharmony_ci      void *slot = argsbuf.data() + dxil->metadata.args[i].offset;
553bf215546Sopenharmony_ci
554bf215546Sopenharmony_ci      switch (dxil->kernel->args[i].address_qualifier) {
555bf215546Sopenharmony_ci      case CLC_KERNEL_ARG_ADDRESS_CONSTANT:
556bf215546Sopenharmony_ci      case CLC_KERNEL_ARG_ADDRESS_GLOBAL: {
557bf215546Sopenharmony_ci         assert(dxil->metadata.args[i].size == sizeof(uint64_t));
558bf215546Sopenharmony_ci         uint64_t *ptr_slot = (uint64_t *)slot;
559bf215546Sopenharmony_ci         if (arg->get_data())
560bf215546Sopenharmony_ci            *ptr_slot = (uint64_t)dxil->metadata.args[i].globconstptr.buf_id << 32;
561bf215546Sopenharmony_ci         else
562bf215546Sopenharmony_ci            *ptr_slot = ~0ull;
563bf215546Sopenharmony_ci         break;
564bf215546Sopenharmony_ci      }
565bf215546Sopenharmony_ci      case CLC_KERNEL_ARG_ADDRESS_LOCAL: {
566bf215546Sopenharmony_ci         assert(dxil->metadata.args[i].size == sizeof(uint64_t));
567bf215546Sopenharmony_ci         uint64_t *ptr_slot = (uint64_t *)slot;
568bf215546Sopenharmony_ci         *ptr_slot = dxil->metadata.args[i].localptr.sharedmem_offset;
569bf215546Sopenharmony_ci         break;
570bf215546Sopenharmony_ci      }
571bf215546Sopenharmony_ci      case CLC_KERNEL_ARG_ADDRESS_PRIVATE: {
572bf215546Sopenharmony_ci         assert(size == dxil->metadata.args[i].size);
573bf215546Sopenharmony_ci         memcpy(slot, arg->get_data(), size);
574bf215546Sopenharmony_ci         break;
575bf215546Sopenharmony_ci      }
576bf215546Sopenharmony_ci      default:
577bf215546Sopenharmony_ci         assert(0);
578bf215546Sopenharmony_ci      }
579bf215546Sopenharmony_ci   }
580bf215546Sopenharmony_ci
581bf215546Sopenharmony_ci   for (unsigned i = 0; i < dxil->kernel->num_args; ++i) {
582bf215546Sopenharmony_ci      RawShaderArg *arg = args[i];
583bf215546Sopenharmony_ci
584bf215546Sopenharmony_ci      if (dxil->kernel->args[i].address_qualifier == CLC_KERNEL_ARG_ADDRESS_GLOBAL ||
585bf215546Sopenharmony_ci          dxil->kernel->args[i].address_qualifier == CLC_KERNEL_ARG_ADDRESS_CONSTANT) {
586bf215546Sopenharmony_ci         argres[i] = add_uav_resource(resources, 0,
587bf215546Sopenharmony_ci                                      dxil->metadata.args[i].globconstptr.buf_id,
588bf215546Sopenharmony_ci                                      arg->get_data(), arg->get_num_elems(),
589bf215546Sopenharmony_ci                                      arg->get_elem_size());
590bf215546Sopenharmony_ci      }
591bf215546Sopenharmony_ci   }
592bf215546Sopenharmony_ci
593bf215546Sopenharmony_ci   if (dxil->metadata.printf.uav_id > 0)
594bf215546Sopenharmony_ci      add_uav_resource(resources, 0, dxil->metadata.printf.uav_id, NULL, 1024 * 1024 / 4, 4);
595bf215546Sopenharmony_ci
596bf215546Sopenharmony_ci   for (unsigned i = 0; i < dxil->metadata.num_consts; ++i)
597bf215546Sopenharmony_ci      add_uav_resource(resources, 0, dxil->metadata.consts[i].uav_id,
598bf215546Sopenharmony_ci                       dxil->metadata.consts[i].data,
599bf215546Sopenharmony_ci                       dxil->metadata.consts[i].size / 4, 4);
600bf215546Sopenharmony_ci
601bf215546Sopenharmony_ci   if (argsbuf.size())
602bf215546Sopenharmony_ci      add_cbv_resource(resources, 0, dxil->metadata.kernel_inputs_cbv_id,
603bf215546Sopenharmony_ci                       argsbuf.data(), argsbuf.size());
604bf215546Sopenharmony_ci
605bf215546Sopenharmony_ci   add_cbv_resource(resources, 0, dxil->metadata.work_properties_cbv_id,
606bf215546Sopenharmony_ci                    &work_props, sizeof(work_props));
607bf215546Sopenharmony_ci
608bf215546Sopenharmony_ci   auto root_sig = create_root_signature(resources);
609bf215546Sopenharmony_ci   auto pipeline_state = create_pipeline_state(root_sig, *dxil);
610bf215546Sopenharmony_ci
611bf215546Sopenharmony_ci   cmdlist->SetDescriptorHeaps(1, &uav_heap);
612bf215546Sopenharmony_ci   cmdlist->SetComputeRootSignature(root_sig.Get());
613bf215546Sopenharmony_ci   cmdlist->SetComputeRootDescriptorTable(0, GetGPUDescriptorHandleForHeapStart(uav_heap));
614bf215546Sopenharmony_ci   cmdlist->SetPipelineState(pipeline_state.Get());
615bf215546Sopenharmony_ci
616bf215546Sopenharmony_ci   cmdlist->Dispatch(compile_args.x / conf.local_size[0],
617bf215546Sopenharmony_ci                     compile_args.y / conf.local_size[1],
618bf215546Sopenharmony_ci                     compile_args.z / conf.local_size[2]);
619bf215546Sopenharmony_ci
620bf215546Sopenharmony_ci   for (auto &range : resources.ranges) {
621bf215546Sopenharmony_ci      if (range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV) {
622bf215546Sopenharmony_ci         for (unsigned i = range.OffsetInDescriptorsFromTableStart;
623bf215546Sopenharmony_ci              i < range.NumDescriptors; i++) {
624bf215546Sopenharmony_ci            if (!resources.descs[i].Get())
625bf215546Sopenharmony_ci               continue;
626bf215546Sopenharmony_ci
627bf215546Sopenharmony_ci            resource_barrier(resources.descs[i],
628bf215546Sopenharmony_ci                             D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
629bf215546Sopenharmony_ci                             D3D12_RESOURCE_STATE_COMMON);
630bf215546Sopenharmony_ci         }
631bf215546Sopenharmony_ci      }
632bf215546Sopenharmony_ci   }
633bf215546Sopenharmony_ci
634bf215546Sopenharmony_ci   execute_cmdlist();
635bf215546Sopenharmony_ci
636bf215546Sopenharmony_ci   for (unsigned i = 0; i < args.size(); i++) {
637bf215546Sopenharmony_ci      if (!(args[i]->get_direction() & SHADER_ARG_OUTPUT))
638bf215546Sopenharmony_ci         continue;
639bf215546Sopenharmony_ci
640bf215546Sopenharmony_ci      assert(dxil->kernel->args[i].address_qualifier == CLC_KERNEL_ARG_ADDRESS_GLOBAL);
641bf215546Sopenharmony_ci      get_buffer_data(argres[i], args[i]->get_data(),
642bf215546Sopenharmony_ci                      args[i]->get_elem_size() * args[i]->get_num_elems());
643bf215546Sopenharmony_ci   }
644bf215546Sopenharmony_ci
645bf215546Sopenharmony_ci   ComPtr<ID3D12InfoQueue> info_queue;
646bf215546Sopenharmony_ci   dev->QueryInterface(info_queue.ReleaseAndGetAddressOf());
647bf215546Sopenharmony_ci   if (info_queue)
648bf215546Sopenharmony_ci   {
649bf215546Sopenharmony_ci      EXPECT_EQ(0, info_queue->GetNumStoredMessages());
650bf215546Sopenharmony_ci      for (unsigned i = 0; i < info_queue->GetNumStoredMessages(); ++i) {
651bf215546Sopenharmony_ci         SIZE_T message_size = 0;
652bf215546Sopenharmony_ci         info_queue->GetMessageA(i, nullptr, &message_size);
653bf215546Sopenharmony_ci         D3D12_MESSAGE* message = (D3D12_MESSAGE*)malloc(message_size);
654bf215546Sopenharmony_ci         info_queue->GetMessageA(i, message, &message_size);
655bf215546Sopenharmony_ci         FAIL() << message->pDescription;
656bf215546Sopenharmony_ci         free(message);
657bf215546Sopenharmony_ci      }
658bf215546Sopenharmony_ci   }
659bf215546Sopenharmony_ci}
660bf215546Sopenharmony_ci
661bf215546Sopenharmony_civoid
662bf215546Sopenharmony_ciComputeTest::SetUp()
663bf215546Sopenharmony_ci{
664bf215546Sopenharmony_ci   static struct clc_libclc *compiler_ctx_g = nullptr;
665bf215546Sopenharmony_ci
666bf215546Sopenharmony_ci   if (!compiler_ctx_g) {
667bf215546Sopenharmony_ci      clc_libclc_dxil_options options = { };
668bf215546Sopenharmony_ci      options.optimize = (debug_get_option_debug_compute() & COMPUTE_DEBUG_OPTIMIZE_LIBCLC) != 0;
669bf215546Sopenharmony_ci
670bf215546Sopenharmony_ci      compiler_ctx_g = clc_libclc_new_dxil(&logger, &options);
671bf215546Sopenharmony_ci      if (!compiler_ctx_g)
672bf215546Sopenharmony_ci         throw runtime_error("failed to create CLC compiler context");
673bf215546Sopenharmony_ci
674bf215546Sopenharmony_ci      if (debug_get_option_debug_compute() & COMPUTE_DEBUG_SERIALIZE_LIBCLC) {
675bf215546Sopenharmony_ci         void *serialized = nullptr;
676bf215546Sopenharmony_ci         size_t serialized_size = 0;
677bf215546Sopenharmony_ci         clc_libclc_serialize(compiler_ctx_g, &serialized, &serialized_size);
678bf215546Sopenharmony_ci         if (!serialized)
679bf215546Sopenharmony_ci            throw runtime_error("failed to serialize CLC compiler context");
680bf215546Sopenharmony_ci
681bf215546Sopenharmony_ci         clc_free_libclc(compiler_ctx_g);
682bf215546Sopenharmony_ci         compiler_ctx_g = nullptr;
683bf215546Sopenharmony_ci
684bf215546Sopenharmony_ci         compiler_ctx_g = clc_libclc_deserialize(serialized, serialized_size);
685bf215546Sopenharmony_ci         if (!compiler_ctx_g)
686bf215546Sopenharmony_ci            throw runtime_error("failed to deserialize CLC compiler context");
687bf215546Sopenharmony_ci
688bf215546Sopenharmony_ci         clc_libclc_free_serialized(serialized);
689bf215546Sopenharmony_ci      }
690bf215546Sopenharmony_ci   }
691bf215546Sopenharmony_ci   compiler_ctx = compiler_ctx_g;
692bf215546Sopenharmony_ci
693bf215546Sopenharmony_ci   enable_d3d12_debug_layer();
694bf215546Sopenharmony_ci
695bf215546Sopenharmony_ci   factory = get_dxgi_factory();
696bf215546Sopenharmony_ci   if (!factory)
697bf215546Sopenharmony_ci      throw runtime_error("failed to create DXGI factory");
698bf215546Sopenharmony_ci
699bf215546Sopenharmony_ci   adapter = choose_adapter(factory);
700bf215546Sopenharmony_ci   if (!adapter)
701bf215546Sopenharmony_ci      throw runtime_error("failed to choose adapter");
702bf215546Sopenharmony_ci
703bf215546Sopenharmony_ci   dev = create_device(adapter);
704bf215546Sopenharmony_ci   if (!dev)
705bf215546Sopenharmony_ci      throw runtime_error("failed to create device");
706bf215546Sopenharmony_ci
707bf215546Sopenharmony_ci   if (FAILED(dev->CreateFence(0, D3D12_FENCE_FLAG_NONE,
708bf215546Sopenharmony_ci                               __uuidof(cmdqueue_fence),
709bf215546Sopenharmony_ci                               (void **)&cmdqueue_fence)))
710bf215546Sopenharmony_ci      throw runtime_error("failed to create fence\n");
711bf215546Sopenharmony_ci
712bf215546Sopenharmony_ci   D3D12_COMMAND_QUEUE_DESC queue_desc;
713bf215546Sopenharmony_ci   queue_desc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE;
714bf215546Sopenharmony_ci   queue_desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
715bf215546Sopenharmony_ci   queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
716bf215546Sopenharmony_ci   queue_desc.NodeMask = 0;
717bf215546Sopenharmony_ci   if (FAILED(dev->CreateCommandQueue(&queue_desc,
718bf215546Sopenharmony_ci                                      __uuidof(cmdqueue),
719bf215546Sopenharmony_ci                                      (void **)&cmdqueue)))
720bf215546Sopenharmony_ci      throw runtime_error("failed to create command queue");
721bf215546Sopenharmony_ci
722bf215546Sopenharmony_ci   if (FAILED(dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COMPUTE,
723bf215546Sopenharmony_ci             __uuidof(cmdalloc), (void **)&cmdalloc)))
724bf215546Sopenharmony_ci      throw runtime_error("failed to create command allocator");
725bf215546Sopenharmony_ci
726bf215546Sopenharmony_ci   if (FAILED(dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COMPUTE,
727bf215546Sopenharmony_ci             cmdalloc, NULL, __uuidof(cmdlist), (void **)&cmdlist)))
728bf215546Sopenharmony_ci      throw runtime_error("failed to create command list");
729bf215546Sopenharmony_ci
730bf215546Sopenharmony_ci   D3D12_DESCRIPTOR_HEAP_DESC heap_desc;
731bf215546Sopenharmony_ci   heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
732bf215546Sopenharmony_ci   heap_desc.NumDescriptors = 1000;
733bf215546Sopenharmony_ci   heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
734bf215546Sopenharmony_ci   heap_desc.NodeMask = 0;
735bf215546Sopenharmony_ci   if (FAILED(dev->CreateDescriptorHeap(&heap_desc,
736bf215546Sopenharmony_ci       __uuidof(uav_heap), (void **)&uav_heap)))
737bf215546Sopenharmony_ci      throw runtime_error("failed to create descriptor heap");
738bf215546Sopenharmony_ci
739bf215546Sopenharmony_ci   uav_heap_incr = dev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
740bf215546Sopenharmony_ci
741bf215546Sopenharmony_ci   event = CreateEvent(NULL, FALSE, FALSE, NULL);
742bf215546Sopenharmony_ci   if (!event)
743bf215546Sopenharmony_ci      throw runtime_error("Failed to create event");
744bf215546Sopenharmony_ci   fence_value = 1;
745bf215546Sopenharmony_ci}
746bf215546Sopenharmony_ci
747bf215546Sopenharmony_civoid
748bf215546Sopenharmony_ciComputeTest::TearDown()
749bf215546Sopenharmony_ci{
750bf215546Sopenharmony_ci   CloseHandle(event);
751bf215546Sopenharmony_ci
752bf215546Sopenharmony_ci   uav_heap->Release();
753bf215546Sopenharmony_ci   cmdlist->Release();
754bf215546Sopenharmony_ci   cmdalloc->Release();
755bf215546Sopenharmony_ci   cmdqueue->Release();
756bf215546Sopenharmony_ci   cmdqueue_fence->Release();
757bf215546Sopenharmony_ci   dev->Release();
758bf215546Sopenharmony_ci   adapter->Release();
759bf215546Sopenharmony_ci   factory->Release();
760bf215546Sopenharmony_ci}
761bf215546Sopenharmony_ci
762bf215546Sopenharmony_ciPFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE ComputeTest::D3D12SerializeVersionedRootSignature;
763bf215546Sopenharmony_ci
764bf215546Sopenharmony_cibool
765bf215546Sopenharmony_civalidate_module(const struct clc_dxil_object &dxil)
766bf215546Sopenharmony_ci{
767bf215546Sopenharmony_ci   struct dxil_validator *val = dxil_create_validator(NULL);
768bf215546Sopenharmony_ci   char *err;
769bf215546Sopenharmony_ci   bool res = dxil_validate_module(val, dxil.binary.data,
770bf215546Sopenharmony_ci                                   dxil.binary.size, &err);
771bf215546Sopenharmony_ci   if (!res && err)
772bf215546Sopenharmony_ci      fprintf(stderr, "D3D12: validation failed: %s", err);
773bf215546Sopenharmony_ci
774bf215546Sopenharmony_ci   dxil_destroy_validator(val);
775bf215546Sopenharmony_ci   return res;
776bf215546Sopenharmony_ci}
777bf215546Sopenharmony_ci
778bf215546Sopenharmony_cistatic void
779bf215546Sopenharmony_cidump_blob(const char *path, const struct clc_dxil_object &dxil)
780bf215546Sopenharmony_ci{
781bf215546Sopenharmony_ci   FILE *fp = fopen(path, "wb");
782bf215546Sopenharmony_ci   if (fp) {
783bf215546Sopenharmony_ci      fwrite(dxil.binary.data, 1, dxil.binary.size, fp);
784bf215546Sopenharmony_ci      fclose(fp);
785bf215546Sopenharmony_ci      printf("D3D12: wrote '%s'...\n", path);
786bf215546Sopenharmony_ci   }
787bf215546Sopenharmony_ci}
788bf215546Sopenharmony_ci
789bf215546Sopenharmony_ciComputeTest::Shader
790bf215546Sopenharmony_ciComputeTest::compile(const std::vector<const char *> &sources,
791bf215546Sopenharmony_ci                     const std::vector<const char *> &compile_args,
792bf215546Sopenharmony_ci                     bool create_library)
793bf215546Sopenharmony_ci{
794bf215546Sopenharmony_ci   struct clc_compile_args args = {
795bf215546Sopenharmony_ci   };
796bf215546Sopenharmony_ci   args.args = compile_args.data();
797bf215546Sopenharmony_ci   args.num_args = (unsigned)compile_args.size();
798bf215546Sopenharmony_ci   ComputeTest::Shader shader;
799bf215546Sopenharmony_ci
800bf215546Sopenharmony_ci   std::vector<Shader> shaders;
801bf215546Sopenharmony_ci
802bf215546Sopenharmony_ci   args.source.name = "obj.cl";
803bf215546Sopenharmony_ci
804bf215546Sopenharmony_ci   for (unsigned i = 0; i < sources.size(); i++) {
805bf215546Sopenharmony_ci      args.source.value = sources[i];
806bf215546Sopenharmony_ci
807bf215546Sopenharmony_ci      clc_binary spirv{};
808bf215546Sopenharmony_ci      if (!clc_compile_c_to_spirv(&args, &logger, &spirv))
809bf215546Sopenharmony_ci         throw runtime_error("failed to compile object!");
810bf215546Sopenharmony_ci
811bf215546Sopenharmony_ci      Shader shader;
812bf215546Sopenharmony_ci      shader.obj = std::shared_ptr<clc_binary>(new clc_binary(spirv), [](clc_binary *spirv)
813bf215546Sopenharmony_ci         {
814bf215546Sopenharmony_ci            clc_free_spirv(spirv);
815bf215546Sopenharmony_ci            delete spirv;
816bf215546Sopenharmony_ci         });
817bf215546Sopenharmony_ci      shaders.push_back(shader);
818bf215546Sopenharmony_ci   }
819bf215546Sopenharmony_ci
820bf215546Sopenharmony_ci   if (shaders.size() == 1 && create_library)
821bf215546Sopenharmony_ci      return shaders[0];
822bf215546Sopenharmony_ci
823bf215546Sopenharmony_ci   return link(shaders, create_library);
824bf215546Sopenharmony_ci}
825bf215546Sopenharmony_ci
826bf215546Sopenharmony_ciComputeTest::Shader
827bf215546Sopenharmony_ciComputeTest::link(const std::vector<Shader> &sources,
828bf215546Sopenharmony_ci                  bool create_library)
829bf215546Sopenharmony_ci{
830bf215546Sopenharmony_ci   std::vector<const clc_binary*> objs;
831bf215546Sopenharmony_ci   for (auto& source : sources)
832bf215546Sopenharmony_ci      objs.push_back(&*source.obj);
833bf215546Sopenharmony_ci
834bf215546Sopenharmony_ci   struct clc_linker_args link_args = {};
835bf215546Sopenharmony_ci   link_args.in_objs = objs.data();
836bf215546Sopenharmony_ci   link_args.num_in_objs = (unsigned)objs.size();
837bf215546Sopenharmony_ci   link_args.create_library = create_library;
838bf215546Sopenharmony_ci   clc_binary spirv{};
839bf215546Sopenharmony_ci   if (!clc_link_spirv(&link_args, &logger, &spirv))
840bf215546Sopenharmony_ci      throw runtime_error("failed to link objects!");
841bf215546Sopenharmony_ci
842bf215546Sopenharmony_ci   ComputeTest::Shader shader;
843bf215546Sopenharmony_ci   shader.obj = std::shared_ptr<clc_binary>(new clc_binary(spirv), [](clc_binary *spirv)
844bf215546Sopenharmony_ci      {
845bf215546Sopenharmony_ci         clc_free_spirv(spirv);
846bf215546Sopenharmony_ci         delete spirv;
847bf215546Sopenharmony_ci      });
848bf215546Sopenharmony_ci   if (!link_args.create_library)
849bf215546Sopenharmony_ci      configure(shader, NULL);
850bf215546Sopenharmony_ci
851bf215546Sopenharmony_ci   return shader;
852bf215546Sopenharmony_ci}
853bf215546Sopenharmony_ci
854bf215546Sopenharmony_ciComputeTest::Shader
855bf215546Sopenharmony_ciComputeTest::assemble(const char *source)
856bf215546Sopenharmony_ci{
857bf215546Sopenharmony_ci   spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
858bf215546Sopenharmony_ci   std::vector<uint32_t> binary;
859bf215546Sopenharmony_ci   if (!tools.Assemble(source, strlen(source), &binary))
860bf215546Sopenharmony_ci      throw runtime_error("failed to assemble");
861bf215546Sopenharmony_ci
862bf215546Sopenharmony_ci   ComputeTest::Shader shader;
863bf215546Sopenharmony_ci   shader.obj = std::shared_ptr<clc_binary>(new clc_binary{}, [](clc_binary *spirv)
864bf215546Sopenharmony_ci      {
865bf215546Sopenharmony_ci         free(spirv->data);
866bf215546Sopenharmony_ci         delete spirv;
867bf215546Sopenharmony_ci      });
868bf215546Sopenharmony_ci   shader.obj->size = binary.size() * 4;
869bf215546Sopenharmony_ci   shader.obj->data = malloc(shader.obj->size);
870bf215546Sopenharmony_ci   memcpy(shader.obj->data, binary.data(), shader.obj->size);
871bf215546Sopenharmony_ci
872bf215546Sopenharmony_ci   configure(shader, NULL);
873bf215546Sopenharmony_ci
874bf215546Sopenharmony_ci   return shader;
875bf215546Sopenharmony_ci}
876bf215546Sopenharmony_ci
877bf215546Sopenharmony_civoid
878bf215546Sopenharmony_ciComputeTest::configure(Shader &shader,
879bf215546Sopenharmony_ci                       const struct clc_runtime_kernel_conf *conf)
880bf215546Sopenharmony_ci{
881bf215546Sopenharmony_ci   if (!shader.metadata) {
882bf215546Sopenharmony_ci      shader.metadata = std::shared_ptr<clc_parsed_spirv>(new clc_parsed_spirv{}, [](clc_parsed_spirv *metadata)
883bf215546Sopenharmony_ci         {
884bf215546Sopenharmony_ci            clc_free_parsed_spirv(metadata);
885bf215546Sopenharmony_ci            delete metadata;
886bf215546Sopenharmony_ci         });
887bf215546Sopenharmony_ci      if (!clc_parse_spirv(shader.obj.get(), NULL, shader.metadata.get()))
888bf215546Sopenharmony_ci         throw runtime_error("failed to parse spirv!");
889bf215546Sopenharmony_ci   }
890bf215546Sopenharmony_ci
891bf215546Sopenharmony_ci   std::unique_ptr<clc_dxil_object> dxil(new clc_dxil_object{});
892bf215546Sopenharmony_ci   if (!clc_spirv_to_dxil(compiler_ctx, shader.obj.get(), shader.metadata.get(), "main_test", conf, nullptr, &logger, dxil.get()))
893bf215546Sopenharmony_ci      throw runtime_error("failed to compile kernel!");
894bf215546Sopenharmony_ci   shader.dxil = std::shared_ptr<clc_dxil_object>(dxil.release(), [](clc_dxil_object *dxil)
895bf215546Sopenharmony_ci      {
896bf215546Sopenharmony_ci         clc_free_dxil_object(dxil);
897bf215546Sopenharmony_ci         delete dxil;
898bf215546Sopenharmony_ci      });
899bf215546Sopenharmony_ci}
900bf215546Sopenharmony_ci
901bf215546Sopenharmony_civoid
902bf215546Sopenharmony_ciComputeTest::validate(ComputeTest::Shader &shader)
903bf215546Sopenharmony_ci{
904bf215546Sopenharmony_ci   dump_blob("unsigned.cso", *shader.dxil);
905bf215546Sopenharmony_ci   if (!validate_module(*shader.dxil))
906bf215546Sopenharmony_ci      throw runtime_error("failed to validate module!");
907bf215546Sopenharmony_ci
908bf215546Sopenharmony_ci   dump_blob("signed.cso", *shader.dxil);
909bf215546Sopenharmony_ci}
910