mirror of https://gitlab.freedesktop.org/mesa/mesa
356 lines
11 KiB
C++
356 lines
11 KiB
C++
/*
|
||
* 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>
|
||
|
||
#include <directx/d3d12.h>
|
||
#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 {
|
||
std::shared_ptr<struct clc_binary> obj;
|
||
std::shared_ptr<struct clc_parsed_spirv> metadata;
|
||
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);
|
||
|
||
Shader
|
||
assemble(const char *source);
|
||
|
||
void
|
||
configure(Shader &shader,
|
||
const struct clc_runtime_kernel_conf *conf);
|
||
|
||
void
|
||
validate(Shader &shader);
|
||
|
||
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;
|
||
}
|
||
|
||
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;
|
||
|
||
struct clc_libclc *compiler_ctx;
|
||
|
||
UINT uav_heap_incr;
|
||
int fence_value;
|
||
|
||
HANDLE event;
|
||
static PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE D3D12SerializeVersionedRootSignature;
|
||
};
|