/* * Copyright © Microsoft Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include "clc_compiler.h" using std::runtime_error; using Microsoft::WRL::ComPtr; inline D3D12_CPU_DESCRIPTOR_HANDLE offset_cpu_handle(D3D12_CPU_DESCRIPTOR_HANDLE handle, UINT offset) { handle.ptr += offset; return handle; } inline size_t align(size_t value, unsigned alignment) { assert(alignment > 0); return ((value + (alignment - 1)) / alignment) * alignment; } class ComputeTest : public ::testing::Test { protected: struct Shader { std::shared_ptr obj; std::shared_ptr metadata; std::shared_ptr dxil; }; static void enable_d3d12_debug_layer(); static IDXGIFactory4 * get_dxgi_factory(); static IDXGIAdapter1 * choose_adapter(IDXGIFactory4 *factory); static ID3D12Device * create_device(IDXGIAdapter1 *adapter); struct Resources { void add(ComPtr res, D3D12_DESCRIPTOR_RANGE_TYPE type, unsigned spaceid, unsigned resid) { descs.push_back(res); if(!ranges.empty() && ranges.back().RangeType == type && ranges.back().RegisterSpace == spaceid && ranges.back().BaseShaderRegister + ranges.back().NumDescriptors == resid) { ranges.back().NumDescriptors++; return; } D3D12_DESCRIPTOR_RANGE1 range; range.RangeType = type; range.NumDescriptors = 1; range.BaseShaderRegister = resid; range.RegisterSpace = spaceid; range.OffsetInDescriptorsFromTableStart = descs.size() - 1; range.Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS; ranges.push_back(range); } std::vector ranges; std::vector> descs; }; ComPtr create_root_signature(const Resources &resources); ComPtr create_pipeline_state(ComPtr &root_sig, const struct clc_dxil_object &dxil); ComPtr create_buffer(int size, D3D12_HEAP_TYPE heap_type); ComPtr create_upload_buffer_with_data(const void *data, size_t size); ComPtr create_sized_buffer_with_data(size_t buffer_size, const void *data, size_t data_size); ComPtr create_buffer_with_data(const void *data, size_t size) { return create_sized_buffer_with_data(size, data, size); } void get_buffer_data(ComPtr res, void *buf, size_t size); void resource_barrier(ComPtr &res, D3D12_RESOURCE_STATES state_before, D3D12_RESOURCE_STATES state_after); void execute_cmdlist(); void create_uav_buffer(ComPtr res, size_t width, size_t byte_stride, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle); void create_cbv(ComPtr res, size_t size, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle); ComPtr add_uav_resource(Resources &resources, unsigned spaceid, unsigned resid, const void *data = NULL, size_t num_elems = 0, size_t elem_size = 0); ComPtr add_cbv_resource(Resources &resources, unsigned spaceid, unsigned resid, const void *data, size_t size); void SetUp() override; void TearDown() override; Shader compile(const std::vector &sources, const std::vector &compile_args = {}, bool create_library = false); Shader link(const std::vector &sources, bool create_library = false); Shader assemble(const char *source); void configure(Shader &shader, const struct clc_runtime_kernel_conf *conf); void validate(Shader &shader); template Shader specialize(Shader &shader, uint32_t id, T const& val) { Shader new_shader; new_shader.obj = std::shared_ptr(new clc_binary{}, [](clc_binary *spirv) { clc_free_spirv(spirv); delete spirv; }); if (!shader.metadata) configure(shader, NULL); clc_spirv_specialization spec; spec.id = id; memcpy(&spec.value, &val, sizeof(val)); clc_spirv_specialization_consts consts; consts.specializations = &spec; consts.num_specializations = 1; if (!clc_specialize_spirv(shader.obj.get(), shader.metadata.get(), &consts, new_shader.obj.get())) throw runtime_error("failed to specialize"); configure(new_shader, NULL); return new_shader; } enum ShaderArgDirection { SHADER_ARG_INPUT = 1, SHADER_ARG_OUTPUT = 2, SHADER_ARG_INOUT = SHADER_ARG_INPUT | SHADER_ARG_OUTPUT, }; class RawShaderArg { public: RawShaderArg(enum ShaderArgDirection dir) : dir(dir) { } virtual size_t get_elem_size() const = 0; virtual size_t get_num_elems() const = 0; virtual const void *get_data() const = 0; virtual void *get_data() = 0; enum ShaderArgDirection get_direction() { return dir; } private: enum ShaderArgDirection dir; }; class NullShaderArg : public RawShaderArg { public: NullShaderArg() : RawShaderArg(SHADER_ARG_INPUT) { } size_t get_elem_size() const override { return 0; } size_t get_num_elems() const override { return 0; } const void *get_data() const override { return NULL; } void *get_data() override { return NULL; } }; template class ShaderArg : public std::vector, public RawShaderArg { public: ShaderArg(const T &v, enum ShaderArgDirection dir = SHADER_ARG_INOUT) : std::vector({ v }), RawShaderArg(dir) { } ShaderArg(const std::vector &v, enum ShaderArgDirection dir = SHADER_ARG_INOUT) : std::vector(v), RawShaderArg(dir) { } ShaderArg(const std::initializer_list v, enum ShaderArgDirection dir = SHADER_ARG_INOUT) : std::vector(v), RawShaderArg(dir) { } ShaderArg& operator =(const T &v) { this->clear(); this->push_back(v); return *this; } operator T&() { return this->at(0); } operator const T&() const { return this->at(0); } ShaderArg& operator =(const std::vector &v) { *this = v; return *this; } ShaderArg& operator =(std::initializer_list v) { *this = v; return *this; } size_t get_elem_size() const override { return sizeof(T); } size_t get_num_elems() const override { return this->size(); } const void *get_data() const override { return this->data(); } void *get_data() override { return this->data(); } }; struct CompileArgs { unsigned x, y, z; std::vector compiler_command_line; clc_work_properties_data work_props; }; private: void gather_args(std::vector &args) { } template void gather_args(std::vector &args, T &arg, Rest&... rest) { args.push_back(&arg); gather_args(args, rest...); } void run_shader_with_raw_args(Shader shader, const CompileArgs &compile_args, const std::vector &args); protected: template void run_shader(Shader shader, const CompileArgs &compile_args, Args&... args) { std::vector raw_args; gather_args(raw_args, args...); run_shader_with_raw_args(shader, compile_args, raw_args); } template void run_shader(const std::vector &sources, unsigned x, unsigned y, unsigned z, Args&... args) { std::vector raw_args; gather_args(raw_args, args...); CompileArgs compile_args = { x, y, z }; run_shader_with_raw_args(compile(sources), compile_args, raw_args); } template void run_shader(const std::vector &sources, const CompileArgs &compile_args, Args&... args) { std::vector raw_args; gather_args(raw_args, args...); run_shader_with_raw_args( compile(sources, compile_args.compiler_command_line), compile_args, raw_args); } template void run_shader(const char *source, unsigned x, unsigned y, unsigned z, Args&... args) { std::vector raw_args; gather_args(raw_args, args...); CompileArgs compile_args = { x, y, z }; run_shader_with_raw_args(compile({ source }), compile_args, raw_args); } IDXGIFactory4 *factory; IDXGIAdapter1 *adapter; ID3D12Device *dev; ID3D12Fence *cmdqueue_fence; ID3D12CommandQueue *cmdqueue; ID3D12CommandAllocator *cmdalloc; ID3D12GraphicsCommandList *cmdlist; ID3D12DescriptorHeap *uav_heap; struct clc_libclc *compiler_ctx; UINT uav_heap_incr; int fence_value; HANDLE event; static PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE D3D12SerializeVersionedRootSignature; };