2020-11-06 16:09:30 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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 <stdio.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
2020-11-24 19:54:07 +00:00
|
|
|
|
#include <directx/d3d12.h>
|
2020-11-06 16:09:30 +00:00
|
|
|
|
#include <dxgi1_4.h>
|
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
#include <wrl.h>
|
|
|
|
|
|
|
|
|
|
#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 {
|
2021-04-19 14:54:13 +01:00
|
|
|
|
std::shared_ptr<struct clc_binary> obj;
|
|
|
|
|
std::shared_ptr<struct clc_parsed_spirv> metadata;
|
2020-11-06 16:09:30 +00:00
|
|
|
|
std::shared_ptr<struct clc_dxil_object> 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<ID3D12Resource> 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<D3D12_DESCRIPTOR_RANGE1> ranges;
|
|
|
|
|
std::vector<ComPtr<ID3D12Resource>> descs;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ComPtr<ID3D12RootSignature>
|
|
|
|
|
create_root_signature(const Resources &resources);
|
|
|
|
|
|
|
|
|
|
ComPtr<ID3D12PipelineState>
|
|
|
|
|
create_pipeline_state(ComPtr<ID3D12RootSignature> &root_sig,
|
|
|
|
|
const struct clc_dxil_object &dxil);
|
|
|
|
|
|
|
|
|
|
ComPtr<ID3D12Resource>
|
|
|
|
|
create_buffer(int size, D3D12_HEAP_TYPE heap_type);
|
|
|
|
|
|
|
|
|
|
ComPtr<ID3D12Resource>
|
|
|
|
|
create_upload_buffer_with_data(const void *data, size_t size);
|
|
|
|
|
|
|
|
|
|
ComPtr<ID3D12Resource>
|
|
|
|
|
create_sized_buffer_with_data(size_t buffer_size, const void *data,
|
|
|
|
|
size_t data_size);
|
|
|
|
|
|
|
|
|
|
ComPtr<ID3D12Resource>
|
|
|
|
|
create_buffer_with_data(const void *data, size_t size)
|
|
|
|
|
{
|
|
|
|
|
return create_sized_buffer_with_data(size, data, size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
get_buffer_data(ComPtr<ID3D12Resource> res,
|
|
|
|
|
void *buf, size_t size);
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
resource_barrier(ComPtr<ID3D12Resource> &res,
|
|
|
|
|
D3D12_RESOURCE_STATES state_before,
|
|
|
|
|
D3D12_RESOURCE_STATES state_after);
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
execute_cmdlist();
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
create_uav_buffer(ComPtr<ID3D12Resource> res,
|
|
|
|
|
size_t width, size_t byte_stride,
|
|
|
|
|
D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle);
|
|
|
|
|
|
|
|
|
|
void create_cbv(ComPtr<ID3D12Resource> res, size_t size,
|
|
|
|
|
D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle);
|
|
|
|
|
|
|
|
|
|
ComPtr<ID3D12Resource>
|
|
|
|
|
add_uav_resource(Resources &resources, unsigned spaceid, unsigned resid,
|
|
|
|
|
const void *data = NULL, size_t num_elems = 0,
|
|
|
|
|
size_t elem_size = 0);
|
|
|
|
|
|
|
|
|
|
ComPtr<ID3D12Resource>
|
|
|
|
|
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<const char *> &sources,
|
|
|
|
|
const std::vector<const char *> &compile_args = {},
|
|
|
|
|
bool create_library = false);
|
|
|
|
|
|
|
|
|
|
Shader
|
|
|
|
|
link(const std::vector<Shader> &sources,
|
|
|
|
|
bool create_library = false);
|
|
|
|
|
|
2021-04-19 13:38:42 +01:00
|
|
|
|
Shader
|
|
|
|
|
assemble(const char *source);
|
|
|
|
|
|
2020-11-06 16:09:30 +00:00
|
|
|
|
void
|
|
|
|
|
configure(Shader &shader,
|
|
|
|
|
const struct clc_runtime_kernel_conf *conf);
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
validate(Shader &shader);
|
|
|
|
|
|
2021-04-19 13:38:42 +01:00
|
|
|
|
template <typename T>
|
|
|
|
|
Shader
|
|
|
|
|
specialize(Shader &shader, uint32_t id, T const& val)
|
|
|
|
|
{
|
|
|
|
|
Shader new_shader;
|
|
|
|
|
new_shader.obj = std::shared_ptr<clc_binary>(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;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-06 16:09:30 +00:00
|
|
|
|
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 <typename T>
|
|
|
|
|
class ShaderArg : public std::vector<T>, public RawShaderArg
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
ShaderArg(const T &v, enum ShaderArgDirection dir = SHADER_ARG_INOUT) :
|
|
|
|
|
std::vector<T>({ v }), RawShaderArg(dir) { }
|
|
|
|
|
ShaderArg(const std::vector<T> &v, enum ShaderArgDirection dir = SHADER_ARG_INOUT) :
|
|
|
|
|
std::vector<T>(v), RawShaderArg(dir) { }
|
|
|
|
|
ShaderArg(const std::initializer_list<T> v, enum ShaderArgDirection dir = SHADER_ARG_INOUT) :
|
|
|
|
|
std::vector<T>(v), RawShaderArg(dir) { }
|
|
|
|
|
|
|
|
|
|
ShaderArg<T>& 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<T>& operator =(const std::vector<T> &v)
|
|
|
|
|
{
|
|
|
|
|
*this = v;
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ShaderArg<T>& operator =(std::initializer_list<T> 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<const char *> compiler_command_line;
|
|
|
|
|
clc_work_properties_data work_props;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void gather_args(std::vector<RawShaderArg *> &args) { }
|
|
|
|
|
|
|
|
|
|
template <typename T, typename... Rest>
|
|
|
|
|
void gather_args(std::vector<RawShaderArg *> &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<RawShaderArg *> &args);
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
template <typename... Args>
|
|
|
|
|
void run_shader(Shader shader,
|
|
|
|
|
const CompileArgs &compile_args,
|
|
|
|
|
Args&... args)
|
|
|
|
|
{
|
|
|
|
|
std::vector<RawShaderArg *> raw_args;
|
|
|
|
|
gather_args(raw_args, args...);
|
|
|
|
|
run_shader_with_raw_args(shader, compile_args, raw_args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename... Args>
|
|
|
|
|
void run_shader(const std::vector<const char *> &sources,
|
|
|
|
|
unsigned x, unsigned y, unsigned z,
|
|
|
|
|
Args&... args)
|
|
|
|
|
{
|
|
|
|
|
std::vector<RawShaderArg *> 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 <typename... Args>
|
|
|
|
|
void run_shader(const std::vector<const char *> &sources,
|
|
|
|
|
const CompileArgs &compile_args,
|
|
|
|
|
Args&... args)
|
|
|
|
|
{
|
|
|
|
|
std::vector<RawShaderArg *> raw_args;
|
|
|
|
|
gather_args(raw_args, args...);
|
|
|
|
|
run_shader_with_raw_args(
|
|
|
|
|
compile(sources, compile_args.compiler_command_line),
|
|
|
|
|
compile_args, raw_args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename... Args>
|
|
|
|
|
void run_shader(const char *source,
|
|
|
|
|
unsigned x, unsigned y, unsigned z,
|
|
|
|
|
Args&... args)
|
|
|
|
|
{
|
|
|
|
|
std::vector<RawShaderArg *> 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;
|
|
|
|
|
|
2021-04-19 14:00:50 +01:00
|
|
|
|
struct clc_libclc *compiler_ctx;
|
2020-11-06 16:09:30 +00:00
|
|
|
|
|
|
|
|
|
UINT uav_heap_incr;
|
|
|
|
|
int fence_value;
|
|
|
|
|
|
|
|
|
|
HANDLE event;
|
|
|
|
|
static PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE D3D12SerializeVersionedRootSignature;
|
|
|
|
|
};
|