Path: blob/21.2-virgl/src/microsoft/clc/compute_test.cpp
4560 views
/*1* Copyright © Microsoft Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#include <stdio.h>24#include <stdint.h>25#include <stdexcept>2627#include <directx/d3d12.h>28#include <dxgi1_4.h>29#include <gtest/gtest.h>30#include <wrl.h>3132#include "util/u_debug.h"33#include "clc_compiler.h"34#include "compute_test.h"35#include "dxcapi.h"3637using std::runtime_error;38using Microsoft::WRL::ComPtr;3940enum compute_test_debug_flags {41COMPUTE_DEBUG_EXPERIMENTAL_SHADERS = 1 << 0,42COMPUTE_DEBUG_USE_HW_D3D = 1 << 1,43COMPUTE_DEBUG_OPTIMIZE_LIBCLC = 1 << 2,44COMPUTE_DEBUG_SERIALIZE_LIBCLC = 1 << 3,45};4647static const struct debug_named_value compute_debug_options[] = {48{ "experimental_shaders", COMPUTE_DEBUG_EXPERIMENTAL_SHADERS, "Enable experimental shaders" },49{ "use_hw_d3d", COMPUTE_DEBUG_USE_HW_D3D, "Use a hardware D3D device" },50{ "optimize_libclc", COMPUTE_DEBUG_OPTIMIZE_LIBCLC, "Optimize the clc_context before using it" },51{ "serialize_libclc", COMPUTE_DEBUG_SERIALIZE_LIBCLC, "Serialize and deserialize the clc_context" },52DEBUG_NAMED_VALUE_END53};5455DEBUG_GET_ONCE_FLAGS_OPTION(debug_compute, "COMPUTE_TEST_DEBUG", compute_debug_options, 0)5657static void warning_callback(void *priv, const char *msg)58{59fprintf(stderr, "WARNING: %s\n", msg);60}6162static void error_callback(void *priv, const char *msg)63{64fprintf(stderr, "ERROR: %s\n", msg);65}6667static const struct clc_logger logger = {68NULL,69error_callback,70warning_callback,71};7273void74ComputeTest::enable_d3d12_debug_layer()75{76HMODULE hD3D12Mod = LoadLibrary("D3D12.DLL");77if (!hD3D12Mod) {78fprintf(stderr, "D3D12: failed to load D3D12.DLL\n");79return;80}8182typedef HRESULT(WINAPI * PFN_D3D12_GET_DEBUG_INTERFACE)(REFIID riid,83void **ppFactory);84PFN_D3D12_GET_DEBUG_INTERFACE D3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress(hD3D12Mod, "D3D12GetDebugInterface");85if (!D3D12GetDebugInterface) {86fprintf(stderr, "D3D12: failed to load D3D12GetDebugInterface from D3D12.DLL\n");87return;88}8990ID3D12Debug *debug;91if (FAILED(D3D12GetDebugInterface(__uuidof(ID3D12Debug), (void **)& debug))) {92fprintf(stderr, "D3D12: D3D12GetDebugInterface failed\n");93return;94}9596debug->EnableDebugLayer();97}9899IDXGIFactory4 *100ComputeTest::get_dxgi_factory()101{102static const GUID IID_IDXGIFactory4 = {1030x1bc6ea02, 0xef36, 0x464f,104{ 0xbf, 0x0c, 0x21, 0xca, 0x39, 0xe5, 0x16, 0x8a }105};106107typedef HRESULT(WINAPI * PFN_CREATE_DXGI_FACTORY)(REFIID riid,108void **ppFactory);109PFN_CREATE_DXGI_FACTORY CreateDXGIFactory;110111HMODULE hDXGIMod = LoadLibrary("DXGI.DLL");112if (!hDXGIMod)113throw runtime_error("Failed to load DXGI.DLL");114115CreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(hDXGIMod, "CreateDXGIFactory");116if (!CreateDXGIFactory)117throw runtime_error("Failed to load CreateDXGIFactory from DXGI.DLL");118119IDXGIFactory4 *factory = NULL;120HRESULT hr = CreateDXGIFactory(IID_IDXGIFactory4, (void **)&factory);121if (FAILED(hr))122throw runtime_error("CreateDXGIFactory failed");123124return factory;125}126127IDXGIAdapter1 *128ComputeTest::choose_adapter(IDXGIFactory4 *factory)129{130IDXGIAdapter1 *ret;131132if (debug_get_option_debug_compute() & COMPUTE_DEBUG_USE_HW_D3D) {133for (unsigned i = 0; SUCCEEDED(factory->EnumAdapters1(i, &ret)); i++) {134DXGI_ADAPTER_DESC1 desc;135ret->GetDesc1(&desc);136if (!(desc.Flags & D3D_DRIVER_TYPE_SOFTWARE))137return ret;138}139throw runtime_error("Failed to enum hardware adapter");140} else {141if (FAILED(factory->EnumWarpAdapter(__uuidof(IDXGIAdapter1),142(void **)& ret)))143throw runtime_error("Failed to enum warp adapter");144return ret;145}146}147148ID3D12Device *149ComputeTest::create_device(IDXGIAdapter1 *adapter)150{151typedef HRESULT(WINAPI *PFN_D3D12CREATEDEVICE)(IUnknown *, D3D_FEATURE_LEVEL, REFIID, void **);152PFN_D3D12CREATEDEVICE D3D12CreateDevice;153154HMODULE hD3D12Mod = LoadLibrary("D3D12.DLL");155if (!hD3D12Mod)156throw runtime_error("failed to load D3D12.DLL");157158if (debug_get_option_debug_compute() & COMPUTE_DEBUG_EXPERIMENTAL_SHADERS) {159typedef HRESULT(WINAPI *PFN_D3D12ENABLEEXPERIMENTALFEATURES)(UINT, const IID *, void *, UINT *);160PFN_D3D12ENABLEEXPERIMENTALFEATURES D3D12EnableExperimentalFeatures;161D3D12EnableExperimentalFeatures = (PFN_D3D12ENABLEEXPERIMENTALFEATURES)162GetProcAddress(hD3D12Mod, "D3D12EnableExperimentalFeatures");163if (FAILED(D3D12EnableExperimentalFeatures(1, &D3D12ExperimentalShaderModels, NULL, NULL)))164throw runtime_error("failed to enable experimental shader models");165}166167D3D12CreateDevice = (PFN_D3D12CREATEDEVICE)GetProcAddress(hD3D12Mod, "D3D12CreateDevice");168if (!D3D12CreateDevice)169throw runtime_error("failed to load D3D12CreateDevice from D3D12.DLL");170171ID3D12Device *dev;172if (FAILED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_12_0,173__uuidof(ID3D12Device), (void **)& dev)))174throw runtime_error("D3D12CreateDevice failed");175176return dev;177}178179ComPtr<ID3D12RootSignature>180ComputeTest::create_root_signature(const ComputeTest::Resources &resources)181{182D3D12_ROOT_PARAMETER1 root_param;183root_param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;184root_param.DescriptorTable.NumDescriptorRanges = resources.ranges.size();185root_param.DescriptorTable.pDescriptorRanges = resources.ranges.data();186root_param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;187188D3D12_ROOT_SIGNATURE_DESC1 root_sig_desc;189root_sig_desc.NumParameters = 1;190root_sig_desc.pParameters = &root_param;191root_sig_desc.NumStaticSamplers = 0;192root_sig_desc.pStaticSamplers = NULL;193root_sig_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;194195D3D12_VERSIONED_ROOT_SIGNATURE_DESC versioned_desc;196versioned_desc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;197versioned_desc.Desc_1_1 = root_sig_desc;198199ID3DBlob *sig, *error;200if (FAILED(D3D12SerializeVersionedRootSignature(&versioned_desc,201&sig, &error)))202throw runtime_error("D3D12SerializeVersionedRootSignature failed");203204ComPtr<ID3D12RootSignature> ret;205if (FAILED(dev->CreateRootSignature(0,206sig->GetBufferPointer(),207sig->GetBufferSize(),208__uuidof(ret),209(void **)& ret)))210throw runtime_error("CreateRootSignature failed");211212return ret;213}214215ComPtr<ID3D12PipelineState>216ComputeTest::create_pipeline_state(ComPtr<ID3D12RootSignature> &root_sig,217const struct clc_dxil_object &dxil)218{219D3D12_COMPUTE_PIPELINE_STATE_DESC pipeline_desc = { root_sig.Get() };220pipeline_desc.CS.pShaderBytecode = dxil.binary.data;221pipeline_desc.CS.BytecodeLength = dxil.binary.size;222223ComPtr<ID3D12PipelineState> pipeline_state;224if (FAILED(dev->CreateComputePipelineState(&pipeline_desc,225__uuidof(pipeline_state),226(void **)& pipeline_state)))227throw runtime_error("Failed to create pipeline state");228return pipeline_state;229}230231ComPtr<ID3D12Resource>232ComputeTest::create_buffer(int size, D3D12_HEAP_TYPE heap_type)233{234D3D12_RESOURCE_DESC desc;235desc.Format = DXGI_FORMAT_UNKNOWN;236desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;237desc.Width = size;238desc.Height = 1;239desc.DepthOrArraySize = 1;240desc.MipLevels = 1;241desc.SampleDesc.Count = 1;242desc.SampleDesc.Quality = 0;243desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;244desc.Flags = heap_type == D3D12_HEAP_TYPE_DEFAULT ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS : D3D12_RESOURCE_FLAG_NONE;245desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;246247D3D12_HEAP_PROPERTIES heap_pris = dev->GetCustomHeapProperties(0, heap_type);248249ComPtr<ID3D12Resource> res;250if (FAILED(dev->CreateCommittedResource(&heap_pris,251D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON,252NULL, __uuidof(ID3D12Resource), (void **)&res)))253throw runtime_error("CreateCommittedResource failed");254255return res;256}257258ComPtr<ID3D12Resource>259ComputeTest::create_upload_buffer_with_data(const void *data, size_t size)260{261auto upload_res = create_buffer(size, D3D12_HEAP_TYPE_UPLOAD);262263void *ptr = NULL;264D3D12_RANGE res_range = { 0, (SIZE_T)size };265if (FAILED(upload_res->Map(0, &res_range, (void **)&ptr)))266throw runtime_error("Failed to map upload-buffer");267assert(ptr);268memcpy(ptr, data, size);269upload_res->Unmap(0, &res_range);270return upload_res;271}272273ComPtr<ID3D12Resource>274ComputeTest::create_sized_buffer_with_data(size_t buffer_size,275const void *data,276size_t data_size)277{278auto upload_res = create_upload_buffer_with_data(data, data_size);279280auto res = create_buffer(buffer_size, D3D12_HEAP_TYPE_DEFAULT);281resource_barrier(res, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST);282cmdlist->CopyBufferRegion(res.Get(), 0, upload_res.Get(), 0, data_size);283resource_barrier(res, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COMMON);284execute_cmdlist();285286return res;287}288289void290ComputeTest::get_buffer_data(ComPtr<ID3D12Resource> res,291void *buf, size_t size)292{293auto readback_res = create_buffer(align(size, 4), D3D12_HEAP_TYPE_READBACK);294resource_barrier(res, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_SOURCE);295cmdlist->CopyResource(readback_res.Get(), res.Get());296resource_barrier(res, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_COMMON);297execute_cmdlist();298299void *ptr = NULL;300D3D12_RANGE res_range = { 0, size };301if (FAILED(readback_res->Map(0, &res_range, &ptr)))302throw runtime_error("Failed to map readback-buffer");303304memcpy(buf, ptr, size);305306D3D12_RANGE empty_range = { 0, 0 };307readback_res->Unmap(0, &empty_range);308}309310void311ComputeTest::resource_barrier(ComPtr<ID3D12Resource> &res,312D3D12_RESOURCE_STATES state_before,313D3D12_RESOURCE_STATES state_after)314{315D3D12_RESOURCE_BARRIER barrier;316barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;317barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;318barrier.Transition.pResource = res.Get();319barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;320barrier.Transition.StateBefore = state_before;321barrier.Transition.StateAfter = state_after;322cmdlist->ResourceBarrier(1, &barrier);323}324325void326ComputeTest::execute_cmdlist()327{328if (FAILED(cmdlist->Close()))329throw runtime_error("Closing ID3D12GraphicsCommandList failed");330331ID3D12CommandList *cmdlists[] = { cmdlist };332cmdqueue->ExecuteCommandLists(1, cmdlists);333cmdqueue_fence->SetEventOnCompletion(fence_value, event);334cmdqueue->Signal(cmdqueue_fence, fence_value);335fence_value++;336WaitForSingleObject(event, INFINITE);337338if (FAILED(cmdalloc->Reset()))339throw runtime_error("resetting ID3D12CommandAllocator failed");340341if (FAILED(cmdlist->Reset(cmdalloc, NULL)))342throw runtime_error("resetting ID3D12GraphicsCommandList failed");343}344345void346ComputeTest::create_uav_buffer(ComPtr<ID3D12Resource> res,347size_t width, size_t byte_stride,348D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle)349{350D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc;351uav_desc.Format = DXGI_FORMAT_R32_TYPELESS;352uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;353uav_desc.Buffer.FirstElement = 0;354uav_desc.Buffer.NumElements = DIV_ROUND_UP(width * byte_stride, 4);355uav_desc.Buffer.StructureByteStride = 0;356uav_desc.Buffer.CounterOffsetInBytes = 0;357uav_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;358359dev->CreateUnorderedAccessView(res.Get(), NULL, &uav_desc, cpu_handle);360}361362void363ComputeTest::create_cbv(ComPtr<ID3D12Resource> res, size_t size,364D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle)365{366D3D12_CONSTANT_BUFFER_VIEW_DESC cbv_desc;367cbv_desc.BufferLocation = res ? res->GetGPUVirtualAddress() : 0;368cbv_desc.SizeInBytes = size;369370dev->CreateConstantBufferView(&cbv_desc, cpu_handle);371}372373ComPtr<ID3D12Resource>374ComputeTest::add_uav_resource(ComputeTest::Resources &resources,375unsigned spaceid, unsigned resid,376const void *data, size_t num_elems,377size_t elem_size)378{379size_t size = align(elem_size * num_elems, 4);380D3D12_CPU_DESCRIPTOR_HANDLE handle;381ComPtr<ID3D12Resource> res;382handle = uav_heap->GetCPUDescriptorHandleForHeapStart();383handle = offset_cpu_handle(handle, resources.descs.size() * uav_heap_incr);384385if (size) {386if (data)387res = create_buffer_with_data(data, size);388else389res = create_buffer(size, D3D12_HEAP_TYPE_DEFAULT);390391resource_barrier(res, D3D12_RESOURCE_STATE_COMMON,392D3D12_RESOURCE_STATE_UNORDERED_ACCESS);393}394create_uav_buffer(res, num_elems, elem_size, handle);395resources.add(res, D3D12_DESCRIPTOR_RANGE_TYPE_UAV, spaceid, resid);396return res;397}398399ComPtr<ID3D12Resource>400ComputeTest::add_cbv_resource(ComputeTest::Resources &resources,401unsigned spaceid, unsigned resid,402const void *data, size_t size)403{404unsigned aligned_size = align(size, 256);405D3D12_CPU_DESCRIPTOR_HANDLE handle;406ComPtr<ID3D12Resource> res;407handle = uav_heap->GetCPUDescriptorHandleForHeapStart();408handle = offset_cpu_handle(handle, resources.descs.size() * uav_heap_incr);409410if (size) {411assert(data);412res = create_sized_buffer_with_data(aligned_size, data, size);413}414create_cbv(res, aligned_size, handle);415resources.add(res, D3D12_DESCRIPTOR_RANGE_TYPE_CBV, spaceid, resid);416return res;417}418419void420ComputeTest::run_shader_with_raw_args(Shader shader,421const CompileArgs &compile_args,422const std::vector<RawShaderArg *> &args)423{424if (args.size() < 1)425throw runtime_error("no inputs");426427static HMODULE hD3D12Mod = LoadLibrary("D3D12.DLL");428if (!hD3D12Mod)429throw runtime_error("Failed to load D3D12.DLL");430431D3D12SerializeVersionedRootSignature = (PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE)GetProcAddress(hD3D12Mod, "D3D12SerializeVersionedRootSignature");432433if (args.size() != shader.dxil->kernel->num_args)434throw runtime_error("incorrect number of inputs");435436struct clc_runtime_kernel_conf conf = { 0 };437438// Older WARP and some hardware doesn't support int64, so for these tests, unconditionally lower away int64439// A more complex runtime can be smarter about detecting when this needs to be done440conf.lower_bit_size = 64;441442if (!shader.dxil->metadata.local_size[0])443conf.local_size[0] = compile_args.x;444else445conf.local_size[0] = shader.dxil->metadata.local_size[0];446447if (!shader.dxil->metadata.local_size[1])448conf.local_size[1] = compile_args.y;449else450conf.local_size[1] = shader.dxil->metadata.local_size[1];451452if (!shader.dxil->metadata.local_size[2])453conf.local_size[2] = compile_args.z;454else455conf.local_size[2] = shader.dxil->metadata.local_size[2];456457if (compile_args.x % conf.local_size[0] ||458compile_args.y % conf.local_size[1] ||459compile_args.z % conf.local_size[2])460throw runtime_error("invalid global size must be a multiple of local size");461462std::vector<struct clc_runtime_arg_info> argsinfo(args.size());463464conf.args = argsinfo.data();465conf.support_global_work_id_offsets =466compile_args.work_props.global_offset_x != 0 ||467compile_args.work_props.global_offset_y != 0 ||468compile_args.work_props.global_offset_z != 0;469conf.support_workgroup_id_offsets =470compile_args.work_props.group_id_offset_x != 0 ||471compile_args.work_props.group_id_offset_y != 0 ||472compile_args.work_props.group_id_offset_z != 0;473474for (unsigned i = 0; i < shader.dxil->kernel->num_args; ++i) {475RawShaderArg *arg = args[i];476size_t size = arg->get_elem_size() * arg->get_num_elems();477478switch (shader.dxil->kernel->args[i].address_qualifier) {479case CLC_KERNEL_ARG_ADDRESS_LOCAL:480argsinfo[i].localptr.size = size;481break;482default:483break;484}485}486487configure(shader, &conf);488validate(shader);489490std::shared_ptr<struct clc_dxil_object> &dxil = shader.dxil;491492std::vector<uint8_t> argsbuf(dxil->metadata.kernel_inputs_buf_size);493std::vector<ComPtr<ID3D12Resource>> argres(shader.dxil->kernel->num_args);494clc_work_properties_data work_props = compile_args.work_props;495if (!conf.support_workgroup_id_offsets) {496work_props.group_count_total_x = compile_args.x / conf.local_size[0];497work_props.group_count_total_y = compile_args.y / conf.local_size[1];498work_props.group_count_total_z = compile_args.z / conf.local_size[2];499}500if (work_props.work_dim == 0)501work_props.work_dim = 3;502Resources resources;503504for (unsigned i = 0; i < dxil->kernel->num_args; ++i) {505RawShaderArg *arg = args[i];506size_t size = arg->get_elem_size() * arg->get_num_elems();507void *slot = argsbuf.data() + dxil->metadata.args[i].offset;508509switch (dxil->kernel->args[i].address_qualifier) {510case CLC_KERNEL_ARG_ADDRESS_CONSTANT:511case CLC_KERNEL_ARG_ADDRESS_GLOBAL: {512assert(dxil->metadata.args[i].size == sizeof(uint64_t));513uint64_t *ptr_slot = (uint64_t *)slot;514if (arg->get_data())515*ptr_slot = (uint64_t)dxil->metadata.args[i].globconstptr.buf_id << 32;516else517*ptr_slot = ~0ull;518break;519}520case CLC_KERNEL_ARG_ADDRESS_LOCAL: {521assert(dxil->metadata.args[i].size == sizeof(uint64_t));522uint64_t *ptr_slot = (uint64_t *)slot;523*ptr_slot = dxil->metadata.args[i].localptr.sharedmem_offset;524break;525}526case CLC_KERNEL_ARG_ADDRESS_PRIVATE: {527assert(size == dxil->metadata.args[i].size);528memcpy(slot, arg->get_data(), size);529break;530}531default:532assert(0);533}534}535536for (unsigned i = 0; i < dxil->kernel->num_args; ++i) {537RawShaderArg *arg = args[i];538539if (dxil->kernel->args[i].address_qualifier == CLC_KERNEL_ARG_ADDRESS_GLOBAL ||540dxil->kernel->args[i].address_qualifier == CLC_KERNEL_ARG_ADDRESS_CONSTANT) {541argres[i] = add_uav_resource(resources, 0,542dxil->metadata.args[i].globconstptr.buf_id,543arg->get_data(), arg->get_num_elems(),544arg->get_elem_size());545}546}547548if (dxil->metadata.printf.uav_id > 0)549add_uav_resource(resources, 0, dxil->metadata.printf.uav_id, NULL, 1024 * 1024 / 4, 4);550551for (unsigned i = 0; i < dxil->metadata.num_consts; ++i)552add_uav_resource(resources, 0, dxil->metadata.consts[i].uav_id,553dxil->metadata.consts[i].data,554dxil->metadata.consts[i].size / 4, 4);555556if (argsbuf.size())557add_cbv_resource(resources, 0, dxil->metadata.kernel_inputs_cbv_id,558argsbuf.data(), argsbuf.size());559560add_cbv_resource(resources, 0, dxil->metadata.work_properties_cbv_id,561&work_props, sizeof(work_props));562563auto root_sig = create_root_signature(resources);564auto pipeline_state = create_pipeline_state(root_sig, *dxil);565566cmdlist->SetDescriptorHeaps(1, &uav_heap);567cmdlist->SetComputeRootSignature(root_sig.Get());568cmdlist->SetComputeRootDescriptorTable(0, uav_heap->GetGPUDescriptorHandleForHeapStart());569cmdlist->SetPipelineState(pipeline_state.Get());570571cmdlist->Dispatch(compile_args.x / conf.local_size[0],572compile_args.y / conf.local_size[1],573compile_args.z / conf.local_size[2]);574575for (auto &range : resources.ranges) {576if (range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV) {577for (unsigned i = range.OffsetInDescriptorsFromTableStart;578i < range.NumDescriptors; i++) {579if (!resources.descs[i].Get())580continue;581582resource_barrier(resources.descs[i],583D3D12_RESOURCE_STATE_UNORDERED_ACCESS,584D3D12_RESOURCE_STATE_COMMON);585}586}587}588589execute_cmdlist();590591for (unsigned i = 0; i < args.size(); i++) {592if (!(args[i]->get_direction() & SHADER_ARG_OUTPUT))593continue;594595assert(dxil->kernel->args[i].address_qualifier == CLC_KERNEL_ARG_ADDRESS_GLOBAL);596get_buffer_data(argres[i], args[i]->get_data(),597args[i]->get_elem_size() * args[i]->get_num_elems());598}599600ComPtr<ID3D12InfoQueue> info_queue;601dev->QueryInterface(info_queue.ReleaseAndGetAddressOf());602if (info_queue)603{604EXPECT_EQ(0, info_queue->GetNumStoredMessages());605for (unsigned i = 0; i < info_queue->GetNumStoredMessages(); ++i) {606SIZE_T message_size = 0;607info_queue->GetMessageA(i, nullptr, &message_size);608D3D12_MESSAGE* message = (D3D12_MESSAGE*)malloc(message_size);609info_queue->GetMessageA(i, message, &message_size);610FAIL() << message->pDescription;611free(message);612}613}614}615616void617ComputeTest::SetUp()618{619static struct clc_context *compiler_ctx_g = nullptr;620621if (!compiler_ctx_g) {622clc_context_options options = { };623options.optimize = (debug_get_option_debug_compute() & COMPUTE_DEBUG_OPTIMIZE_LIBCLC) != 0;624625compiler_ctx_g = clc_context_new(&logger, &options);626if (!compiler_ctx_g)627throw runtime_error("failed to create CLC compiler context");628629if (debug_get_option_debug_compute() & COMPUTE_DEBUG_SERIALIZE_LIBCLC) {630void *serialized = nullptr;631size_t serialized_size = 0;632clc_context_serialize(compiler_ctx_g, &serialized, &serialized_size);633if (!serialized)634throw runtime_error("failed to serialize CLC compiler context");635636clc_free_context(compiler_ctx_g);637compiler_ctx_g = nullptr;638639compiler_ctx_g = clc_context_deserialize(serialized, serialized_size);640if (!compiler_ctx_g)641throw runtime_error("failed to deserialize CLC compiler context");642643clc_context_free_serialized(serialized);644}645}646compiler_ctx = compiler_ctx_g;647648enable_d3d12_debug_layer();649650factory = get_dxgi_factory();651if (!factory)652throw runtime_error("failed to create DXGI factory");653654adapter = choose_adapter(factory);655if (!adapter)656throw runtime_error("failed to choose adapter");657658dev = create_device(adapter);659if (!dev)660throw runtime_error("failed to create device");661662if (FAILED(dev->CreateFence(0, D3D12_FENCE_FLAG_NONE,663__uuidof(cmdqueue_fence),664(void **)&cmdqueue_fence)))665throw runtime_error("failed to create fence\n");666667D3D12_COMMAND_QUEUE_DESC queue_desc;668queue_desc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE;669queue_desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;670queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;671queue_desc.NodeMask = 0;672if (FAILED(dev->CreateCommandQueue(&queue_desc,673__uuidof(cmdqueue),674(void **)&cmdqueue)))675throw runtime_error("failed to create command queue");676677if (FAILED(dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COMPUTE,678__uuidof(cmdalloc), (void **)&cmdalloc)))679throw runtime_error("failed to create command allocator");680681if (FAILED(dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COMPUTE,682cmdalloc, NULL, __uuidof(cmdlist), (void **)&cmdlist)))683throw runtime_error("failed to create command list");684685D3D12_DESCRIPTOR_HEAP_DESC heap_desc;686heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;687heap_desc.NumDescriptors = 1000;688heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;689heap_desc.NodeMask = 0;690if (FAILED(dev->CreateDescriptorHeap(&heap_desc,691__uuidof(uav_heap), (void **)&uav_heap)))692throw runtime_error("failed to create descriptor heap");693694uav_heap_incr = dev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);695696event = CreateEvent(NULL, FALSE, FALSE, NULL);697if (!event)698throw runtime_error("Failed to create event");699fence_value = 1;700}701702void703ComputeTest::TearDown()704{705CloseHandle(event);706707uav_heap->Release();708cmdlist->Release();709cmdalloc->Release();710cmdqueue->Release();711cmdqueue_fence->Release();712dev->Release();713adapter->Release();714factory->Release();715}716717PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE ComputeTest::D3D12SerializeVersionedRootSignature;718719bool720validate_module(const struct clc_dxil_object &dxil)721{722static HMODULE hmod = LoadLibrary("DXIL.DLL");723if (!hmod) {724/* Enabling experimental shaders allows us to run unsigned shader code,725* such as when under the debugger where we can't run the validator. */726if (debug_get_option_debug_compute() & COMPUTE_DEBUG_EXPERIMENTAL_SHADERS)727return true;728else729throw runtime_error("failed to load DXIL.DLL");730}731732DxcCreateInstanceProc pfnDxcCreateInstance =733(DxcCreateInstanceProc)GetProcAddress(hmod, "DxcCreateInstance");734if (!pfnDxcCreateInstance)735throw runtime_error("failed to load DxcCreateInstance");736737struct shader_blob : public IDxcBlob {738shader_blob(void *data, size_t size) : data(data), size(size) {}739LPVOID STDMETHODCALLTYPE GetBufferPointer() override { return data; }740SIZE_T STDMETHODCALLTYPE GetBufferSize() override { return size; }741HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void **) override { return E_NOINTERFACE; }742ULONG STDMETHODCALLTYPE AddRef() override { return 1; }743ULONG STDMETHODCALLTYPE Release() override { return 0; }744void *data;745size_t size;746} blob(dxil.binary.data, dxil.binary.size);747748IDxcValidator *validator;749if (FAILED(pfnDxcCreateInstance(CLSID_DxcValidator, __uuidof(IDxcValidator),750(void **)&validator)))751throw runtime_error("failed to create IDxcValidator");752753IDxcOperationResult *result;754if (FAILED(validator->Validate(&blob, DxcValidatorFlags_InPlaceEdit,755&result)))756throw runtime_error("Validate failed");757758HRESULT hr;759if (FAILED(result->GetStatus(&hr)) ||760FAILED(hr)) {761IDxcBlobEncoding *message;762result->GetErrorBuffer(&message);763fprintf(stderr, "D3D12: validation failed: %*s\n",764(int)message->GetBufferSize(),765(char *)message->GetBufferPointer());766message->Release();767validator->Release();768result->Release();769return false;770}771772validator->Release();773result->Release();774return true;775}776777static void778dump_blob(const char *path, const struct clc_dxil_object &dxil)779{780FILE *fp = fopen(path, "wb");781if (fp) {782fwrite(dxil.binary.data, 1, dxil.binary.size, fp);783fclose(fp);784printf("D3D12: wrote '%s'...\n", path);785}786}787788ComputeTest::Shader789ComputeTest::compile(const std::vector<const char *> &sources,790const std::vector<const char *> &compile_args,791bool create_library)792{793struct clc_compile_args args = { 0 };794args.args = compile_args.data();795args.num_args = (unsigned)compile_args.size();796ComputeTest::Shader shader;797798std::vector<Shader> shaders;799800args.source.name = "obj.cl";801802for (unsigned i = 0; i < sources.size(); i++) {803args.source.value = sources[i];804805auto obj = clc_compile(compiler_ctx, &args, &logger);806if (!obj)807throw runtime_error("failed to compile object!");808809Shader shader;810shader.obj = std::shared_ptr<struct clc_object>(obj, clc_free_object);811shaders.push_back(shader);812}813814if (shaders.size() == 1 && create_library)815return shaders[0];816817return link(shaders, create_library);818}819820ComputeTest::Shader821ComputeTest::link(const std::vector<Shader> &sources,822bool create_library)823{824std::vector<const clc_object*> objs;825for (auto& source : sources)826objs.push_back(&*source.obj);827828struct clc_linker_args link_args = {};829link_args.in_objs = objs.data();830link_args.num_in_objs = (unsigned)objs.size();831link_args.create_library = create_library;832struct clc_object *obj = clc_link(compiler_ctx,833&link_args,834&logger);835if (!obj)836throw runtime_error("failed to link objects!");837838ComputeTest::Shader shader;839shader.obj = std::shared_ptr<struct clc_object>(obj, clc_free_object);840if (!link_args.create_library)841configure(shader, NULL);842843return shader;844}845846void847ComputeTest::configure(Shader &shader,848const struct clc_runtime_kernel_conf *conf)849{850struct clc_dxil_object *dxil;851852dxil = clc_to_dxil(compiler_ctx, shader.obj.get(), "main_test", conf, &logger);853if (!dxil)854throw runtime_error("failed to compile kernel!");855856shader.dxil = std::shared_ptr<struct clc_dxil_object>(dxil, clc_free_dxil_object);857}858859void860ComputeTest::validate(ComputeTest::Shader &shader)861{862dump_blob("unsigned.cso", *shader.dxil);863if (!validate_module(*shader.dxil))864throw runtime_error("failed to validate module!");865866dump_blob("signed.cso", *shader.dxil);867}868869870