WebGPU wrapper wip: add render pipeline object

This commit is contained in:
Nikita Lisitsa 2023-12-31 15:21:20 +03:00
parent cde91b55a9
commit ea71e1878e
7 changed files with 446 additions and 3 deletions

View file

@ -0,0 +1,25 @@
#pragma once
#include <psemek/wgpu/detail/object.hpp>
namespace psemek::wgpu
{
struct bind_group_layout
: detail::object<bind_group_layout>
{
using detail::object<bind_group_layout>::object;
static void reference(void * ptr);
static void release(void * ptr);
private:
explicit bind_group_layout(void * ptr)
: detail::object<bind_group_layout>(ptr)
{}
friend struct device;
friend struct render_pipeline;
};
}

View file

@ -3,11 +3,12 @@
#include <psemek/wgpu/chained_struct.hpp>
#include <psemek/wgpu/queue.hpp>
#include <psemek/wgpu/buffer.hpp>
#include <psemek/wgpu/command_encoder.hpp>
#include <psemek/wgpu/query_set.hpp>
#include <psemek/wgpu/render_pipeline.hpp>
#include <psemek/wgpu/sampler.hpp>
#include <psemek/wgpu/shader_module.hpp>
#include <psemek/wgpu/texture.hpp>
#include <psemek/wgpu/command_encoder.hpp>
#include <psemek/wgpu/detail/object.hpp>
#include <cstdint>
@ -110,6 +111,7 @@ namespace psemek::wgpu
buffer create_buffer(buffer::descriptor const & desc);
command_encoder create_command_encoder(command_encoder::descriptor const & desc);
query_set create_query_set(query_set::descriptor const & desc);
render_pipeline create_render_pipeline(render_pipeline::descriptor const & desc);
sampler create_sampler(sampler::descriptor const & desc);
shader_module create_shader_module(shader_module::descriptor const & desc);
texture create_texture(texture::descriptor const & desc);

View file

@ -0,0 +1,268 @@
#pragma once
#include <psemek/wgpu/pipeline_layout.hpp>
#include <psemek/wgpu/bind_group_layout.hpp>
#include <psemek/wgpu/shader_module.hpp>
#include <psemek/wgpu/sampler.hpp>
#include <psemek/wgpu/texture.hpp>
#include <psemek/wgpu/detail/object.hpp>
#include <psemek/wgpu/chained_struct.hpp>
#include <string>
#include <cstdint>
#include <vector>
#include <optional>
namespace psemek::wgpu
{
struct constant_entry
{
std::vector<chained_struct> chain;
std::string key;
double value;
};
enum class vertex_step_mode : std::uint32_t
{
vertex = 0x00000000,
instance = 0x00000001,
vertex_buffer_not_used = 0x00000002,
};
enum class vertex_format : std::uint32_t
{
undefined = 0x00000000,
uint8x2 = 0x00000001,
uint8x4 = 0x00000002,
sint8x2 = 0x00000003,
sint8x4 = 0x00000004,
unorm8x2 = 0x00000005,
unorm8x4 = 0x00000006,
snorm8x2 = 0x00000007,
snorm8x4 = 0x00000008,
uint16x2 = 0x00000009,
uint16x4 = 0x0000000a,
sint16x2 = 0x0000000b,
sint16x4 = 0x0000000c,
unorm16x2 = 0x0000000d,
unorm16x4 = 0x0000000e,
snorm16x2 = 0x0000000f,
snorm16x4 = 0x00000010,
float16x2 = 0x00000011,
float16x4 = 0x00000012,
float32 = 0x00000013,
float32x2 = 0x00000014,
float32x3 = 0x00000015,
float32x4 = 0x00000016,
uint32 = 0x00000017,
uint32x2 = 0x00000018,
uint32x3 = 0x00000019,
uint32x4 = 0x0000001a,
sint32 = 0x0000001b,
sint32x2 = 0x0000001c,
sint32x3 = 0x0000001d,
sint32x4 = 0x0000001e,
};
struct vertex_attribute
{
vertex_format format;
std::uint64_t offset;
std::uint32_t shader_location;
};
struct vertex_buffer_layout
{
std::uint64_t array_stride;
vertex_step_mode step_mode;
std::vector<vertex_attribute> attributes;
};
struct vertex_state
{
std::vector<chained_struct> chain = {};
shader_module module;
std::string entry_point;
std::vector<constant_entry> constants = {};
std::vector<vertex_buffer_layout> buffers;
};
enum class primitive_topology : std::uint32_t
{
point_list = 0x00000000,
line_list = 0x00000001,
line_strip = 0x00000002,
triangle_list = 0x00000003,
triangle_strip = 0x00000004,
};
enum class index_format : std::uint32_t
{
undefined = 0x00000000,
uint16 = 0x00000001,
uint32 = 0x00000002,
};
enum class front_face : std::uint32_t
{
ccw = 0x00000000,
cw = 0x00000001,
};
enum class cull_mode : std::uint32_t
{
none = 0x00000000,
front = 0x00000001,
back = 0x00000002,
};
struct primitive_state
{
std::vector<chained_struct> chain = {};
primitive_topology topology;
index_format strip_index_format = index_format::undefined;
enum front_face front_face;
enum cull_mode cull_mode;
};
enum class stencil_operation : std::uint32_t
{
keep = 0x00000000,
zero = 0x00000001,
replace = 0x00000002,
invert = 0x00000003,
increment_clamp = 0x00000004,
decrement_clamp = 0x00000005,
increment_wrap = 0x00000006,
decrement_wrap = 0x00000007,
};
struct stencil_face_state
{
compare_function compare = compare_function::always;
stencil_operation fail_op = stencil_operation::keep;
stencil_operation depth_fail_op = stencil_operation::keep;
stencil_operation pass_op = stencil_operation::keep;
};
struct depth_stencil_state
{
std::vector<chained_struct> chain = {};
texture::format format;
bool depth_write = true;
compare_function depth_compare;
stencil_face_state stencil_front = {};
stencil_face_state stencil_back = {};
std::uint32_t stencil_read_mask = 0;
std::uint32_t stencil_write_mask = 0;
std::int32_t depth_bias = 0;
float depth_bias_slope_scale = 0.f;
float depth_bias_clamp = 0.f;
};
struct multisample_state
{
std::vector<chained_struct> chain = {};
std::uint32_t count = 1;
std::uint32_t mask = -1;
bool alpha_to_coverage = false;
};
enum class blend_operation : std::uint32_t
{
add = 0x00000000,
subtract = 0x00000001,
reverse_subtract = 0x00000002,
min = 0x00000003,
max = 0x00000004,
};
enum class blend_factor : std::uint32_t
{
zero = 0x00000000,
one = 0x00000001,
src = 0x00000002,
one_minus_src = 0x00000003,
src_alpha = 0x00000004,
one_minus_src_alpha = 0x00000005,
dst = 0x00000006,
one_minus_dst = 0x00000007,
dst_alpha = 0x00000008,
one_minus_dst_alpha = 0x00000009,
src_alpha_saturated = 0x0000000a,
constant = 0x0000000b,
one_minus_constant = 0x0000000c,
};
struct blend_component
{
blend_operation operation;
blend_factor src_factor;
blend_factor dst_factor;
};
struct blend_state
{
blend_component color;
blend_component alpha;
};
enum color_write_mask : std::uint32_t
{
none = 0x00000000,
red = 0x00000001,
green = 0x00000002,
blue = 0x00000004,
alpha = 0x00000008,
all = 0x0000000f,
};
struct color_target_state
{
std::vector<chained_struct> chain = {};
texture::format format;
std::optional<blend_state> blend = {};
color_write_mask write_mask = color_write_mask::all;
};
struct fragment_state {
std::vector<chained_struct> chain = {};
shader_module module;
std::string entry_point;
std::vector<constant_entry> constants = {};
std::vector<color_target_state> targets;
};
struct render_pipeline
: detail::object<render_pipeline>
{
using detail::object<render_pipeline>::object;
struct descriptor
{
std::vector<chained_struct> chain = {};
std::string label = {};
pipeline_layout layout;
vertex_state vertex;
primitive_state primitive;
std::optional<depth_stencil_state> depth_stencil = {};
multisample_state multisample = {};
std::optional<fragment_state> fragment = {};
};
bind_group_layout get_bind_group_layout(std::uint32_t index);
void set_label(std::string const & label);
static void reference(void * ptr);
static void release(void * ptr);
private:
explicit render_pipeline(void * ptr)
: detail::object<render_pipeline>(ptr)
{}
friend struct device;
};
}

View file

@ -1,6 +1,6 @@
+ WGPUAdapter
WGPUBindGroup
WGPUBindGroupLayout
- WGPUBindGroupLayout
+ WGPUBuffer
+ WGPUCommandBuffer
- WGPUCommandEncoder
@ -14,7 +14,7 @@
WGPURenderBundle
WGPURenderBundleEncoder
- WGPURenderPassEncoder
WGPURenderPipeline
+ WGPURenderPipeline
+ WGPUSampler
+ WGPUShaderModule
+ WGPUSurface

View file

@ -0,0 +1,17 @@
#include <psemek/wgpu/bind_group_layout.hpp>
#include <psemek/wgpu/external/webgpu.h>
namespace psemek::wgpu
{
void bind_group_layout::reference(void * ptr)
{
wgpuBindGroupLayoutReference((WGPUBindGroupLayout)ptr);
}
void bind_group_layout::release(void * ptr)
{
wgpuBindGroupLayoutRelease((WGPUBindGroupLayout)ptr);
}
}

View file

@ -42,6 +42,110 @@ namespace psemek::wgpu
return query_set(wgpuDeviceCreateQuerySet((WGPUDevice)get(), &descriptor));
}
render_pipeline device::create_render_pipeline(render_pipeline::descriptor const & desc)
{
WGPURenderPipelineDescriptor descriptor = {};
std::vector<WGPUConstantEntry> vertex_constants;
for (auto const & constant_in : desc.vertex.constants)
{
auto & constant_out = vertex_constants.emplace_back();
constant_out.nextInChain = (WGPUChainedStruct const *)detail::fill_chain(constant_in.chain);
constant_out.key = constant_in.key.data();
constant_out.value = constant_in.value;
}
std::vector<WGPUVertexBufferLayout> vertex_buffers;
for (auto const & buffer_in : desc.vertex.buffers)
{
auto & buffer_out = vertex_buffers.emplace_back();
buffer_out.arrayStride = buffer_in.array_stride;
buffer_out.stepMode = (WGPUVertexStepMode)buffer_in.step_mode;
buffer_out.attributeCount = buffer_in.attributes.size();
static_assert(sizeof(WGPUVertexAttribute) == sizeof(vertex_attribute));
buffer_out.attributes = (WGPUVertexAttribute const *)buffer_in.attributes.data();
}
descriptor.vertex.nextInChain = (WGPUChainedStruct const *)detail::fill_chain(desc.vertex.chain);
descriptor.vertex.module = (WGPUShaderModule)desc.vertex.module.get();
descriptor.vertex.entryPoint = desc.vertex.entry_point.data();
descriptor.vertex.constantCount = vertex_constants.size();
descriptor.vertex.constants = vertex_constants.data();
descriptor.vertex.bufferCount = vertex_buffers.size();
descriptor.vertex.buffers = vertex_buffers.data();
descriptor.primitive.nextInChain = (WGPUChainedStruct const *)detail::fill_chain(desc.primitive.chain);
descriptor.primitive.topology = (WGPUPrimitiveTopology)desc.primitive.topology;
descriptor.primitive.stripIndexFormat = (WGPUIndexFormat)desc.primitive.strip_index_format;
descriptor.primitive.frontFace = (WGPUFrontFace)desc.primitive.front_face;
descriptor.primitive.cullMode = (WGPUCullMode)desc.primitive.cull_mode;
WGPUDepthStencilState depth_stencil_state = {};
if (desc.depth_stencil)
{
depth_stencil_state.nextInChain = (WGPUChainedStruct const *)detail::fill_chain(desc.depth_stencil->chain);
depth_stencil_state.format = (WGPUTextureFormat)desc.depth_stencil->format;
depth_stencil_state.depthWriteEnabled = desc.depth_stencil->depth_write;
depth_stencil_state.depthCompare = (WGPUCompareFunction)desc.depth_stencil->depth_compare;
depth_stencil_state.stencilFront.compare = (WGPUCompareFunction)desc.depth_stencil->stencil_front.compare;
depth_stencil_state.stencilFront.failOp = (WGPUStencilOperation)desc.depth_stencil->stencil_front.fail_op;
depth_stencil_state.stencilFront.depthFailOp = (WGPUStencilOperation)desc.depth_stencil->stencil_front.depth_fail_op;
depth_stencil_state.stencilFront.passOp = (WGPUStencilOperation)desc.depth_stencil->stencil_front.pass_op;
depth_stencil_state.stencilBack.compare = (WGPUCompareFunction)desc.depth_stencil->stencil_back.compare;
depth_stencil_state.stencilBack.failOp = (WGPUStencilOperation)desc.depth_stencil->stencil_back.fail_op;
depth_stencil_state.stencilBack.depthFailOp = (WGPUStencilOperation)desc.depth_stencil->stencil_back.depth_fail_op;
depth_stencil_state.stencilBack.passOp = (WGPUStencilOperation)desc.depth_stencil->stencil_back.pass_op;
depth_stencil_state.stencilReadMask = desc.depth_stencil->stencil_read_mask;
depth_stencil_state.stencilWriteMask = desc.depth_stencil->stencil_write_mask;
depth_stencil_state.depthBias = desc.depth_stencil->depth_bias;
depth_stencil_state.depthBiasSlopeScale = desc.depth_stencil->depth_bias_slope_scale;
depth_stencil_state.depthBiasClamp = desc.depth_stencil->depth_bias_clamp;
descriptor.depthStencil = &depth_stencil_state;
}
descriptor.multisample.nextInChain = (WGPUChainedStruct const *)detail::fill_chain(desc.multisample.chain);
descriptor.multisample.count = desc.multisample.count;
descriptor.multisample.mask = desc.multisample.mask;
descriptor.multisample.alphaToCoverageEnabled = desc.multisample.alpha_to_coverage;
WGPUFragmentState fragment_state = {};
std::vector<WGPUConstantEntry> fragment_constants;
std::vector<WGPUColorTargetState> color_targets;
if (desc.fragment)
{
for (auto const & constant_in : desc.fragment->constants)
{
auto & constant_out = fragment_constants.emplace_back();
constant_out.nextInChain = (WGPUChainedStruct const *)detail::fill_chain(constant_in.chain);
constant_out.key = constant_in.key.data();
constant_out.value = constant_in.value;
}
for (auto const & target_in : desc.fragment->targets)
{
auto & target_out = color_targets.emplace_back();
target_out.nextInChain = (WGPUChainedStruct const *)detail::fill_chain(target_in.chain);
target_out.format = (WGPUTextureFormat)target_in.format;
static_assert(sizeof(WGPUBlendState) == sizeof(blend_state));
target_out.blend = (WGPUBlendState *)(target_in.blend ? &(*target_in.blend) : nullptr);
target_out.writeMask = (WGPUColorWriteMaskFlags)target_in.write_mask;
}
fragment_state.nextInChain = (WGPUChainedStruct const *)detail::fill_chain(desc.fragment->chain);
fragment_state.module = (WGPUShaderModule)desc.fragment->module.get();
fragment_state.entryPoint = desc.fragment->entry_point.data();
fragment_state.constantCount = fragment_constants.size();
fragment_state.constants = fragment_constants.data();
fragment_state.targetCount = color_targets.size();
fragment_state.targets = color_targets.data();
descriptor.fragment = &fragment_state;
}
return render_pipeline(wgpuDeviceCreateRenderPipeline((WGPUDevice)get(), &descriptor));
}
sampler device::create_sampler(sampler::descriptor const & desc)
{
WGPUSamplerDescriptor descriptor = {};

View file

@ -0,0 +1,27 @@
#include <psemek/wgpu/render_pipeline.hpp>
#include <psemek/wgpu/external/webgpu.h>
namespace psemek::wgpu
{
bind_group_layout render_pipeline::get_bind_group_layout(std::uint32_t index)
{
return bind_group_layout(wgpuRenderPipelineGetBindGroupLayout((WGPURenderPipeline)get(), index));
}
void render_pipeline::set_label(std::string const & label)
{
wgpuRenderPipelineSetLabel((WGPURenderPipeline)get(), label.data());
}
void render_pipeline::reference(void * ptr)
{
wgpuRenderPipelineReference((WGPURenderPipeline)ptr);
}
void render_pipeline::release(void * ptr)
{
wgpuRenderPipelineRelease((WGPURenderPipeline)ptr);
}
}