Engine²
Open-source game engine written in C++.
Loading...
Searching...
No Matches
Shader.hpp
Go to the documentation of this file.
1#pragma once
2
9#include "utils/webgpu.hpp"
10#include <vector>
11
12namespace Graphic::Resource {
13
14class Shader {
15 public:
16 virtual ~Shader()
17 {
18 if (pipeline != nullptr)
19 {
20 pipeline.release();
21 pipeline = nullptr;
22 }
23 }
24
25 Shader(Shader &&other) noexcept
26 {
27 descriptor = other.descriptor;
28 pipeline = other.pipeline;
29 other.pipeline = nullptr;
30 }
31 Shader &operator=(Shader &&other) noexcept
32 {
33 if (this != &other)
34 {
35 descriptor = other.descriptor;
36 pipeline = other.pipeline;
37 other.pipeline = nullptr;
38 }
39 return *this;
40 }
41
42 Shader(const Shader &) = delete;
43 Shader &operator=(const Shader &) = delete;
44
46 {
47 wgpu::Device device = context.deviceContext.GetDevice().value();
48 Shader shader;
49 shader.descriptor = descriptor;
50
51 const std::string &name = descriptor.getName();
52
53 wgpu::ShaderModule shaderModule = _createShaderModule(name, descriptor.getShaderSource().value(), device);
54
55 wgpu::RenderPipelineDescriptor pipelineDescriptor(wgpu::Default);
56 const std::string pipelineLabel = fmt::format("{} Render Pipeline", name);
57 pipelineDescriptor.label = wgpu::StringView(pipelineLabel);
58
59 std::vector<wgpu::VertexBufferLayout> vertexBufferLayouts = _createVertexBufferLayouts(descriptor);
60 pipelineDescriptor.vertex.bufferCount = vertexBufferLayouts.size();
61 pipelineDescriptor.vertex.buffers = vertexBufferLayouts.data();
62 pipelineDescriptor.vertex.module = shaderModule;
63 pipelineDescriptor.vertex.entryPoint = wgpu::StringView(descriptor.getVertexEntryPoint());
64
65 wgpu::FragmentState fragmentState(wgpu::Default);
66 std::vector<wgpu::ColorTargetState> colorTargets;
67 colorTargets.reserve(descriptor.getOutputColorFormats().size());
68 for (const auto &format : descriptor.getOutputColorFormats())
69 {
70 wgpu::ColorTargetState colorTarget(wgpu::Default);
71 colorTarget.format = format.getFormat();
72 colorTarget.writeMask = wgpu::ColorWriteMask::All;
73 colorTarget.blend = &format.getBlendState();
74 colorTargets.emplace_back(colorTarget);
75 }
76 fragmentState.module = shaderModule;
77 fragmentState.entryPoint = wgpu::StringView(descriptor.getFragmentEntryPoint());
78 fragmentState.targetCount = colorTargets.size();
79 fragmentState.targets = colorTargets.data();
80 pipelineDescriptor.fragment = &fragmentState;
81
82 wgpu::PipelineLayoutDescriptor pipelineLayoutDescriptor(wgpu::Default);
83 const std::string pipelineLayoutLabel = fmt::format("{} Pipeline Layout", name);
84 pipelineLayoutDescriptor.label = wgpu::StringView(pipelineLayoutLabel);
85 std::vector<WGPUBindGroupLayout> bindGroupLayouts;
86 for (const auto &layout : descriptor.getBindGroupLayouts())
87 {
88 std::vector<WGPUBindGroupLayoutEntry> entries;
89 for (const auto &entry : layout.getEntries())
90 {
91 entries.push_back(entry->getEntry());
92 }
93 wgpu::BindGroupLayoutDescriptor bindGroupLayoutDescriptor(wgpu::Default);
94 const std::string layoutLabel = fmt::format("{}::{}", name, layout.getName());
95 bindGroupLayoutDescriptor.label = wgpu::StringView(layoutLabel);
96 bindGroupLayoutDescriptor.entryCount = entries.size();
97 bindGroupLayoutDescriptor.entries = entries.data();
98 bindGroupLayouts.push_back(device.createBindGroupLayout(bindGroupLayoutDescriptor));
99 }
100 pipelineLayoutDescriptor.bindGroupLayoutCount = bindGroupLayouts.size();
101 pipelineLayoutDescriptor.bindGroupLayouts = bindGroupLayouts.data();
102 pipelineDescriptor.layout = device.createPipelineLayout(pipelineLayoutDescriptor);
103
104 if (descriptor.getOutputDepthFormat().has_value())
105 pipelineDescriptor.depthStencil = &descriptor.getOutputDepthFormat()->getValue();
106 else
107 pipelineDescriptor.depthStencil = nullptr;
108
109 pipelineDescriptor.primitive.topology = descriptor.getPrimitiveTopology();
110 pipelineDescriptor.primitive.cullMode = descriptor.getCullMode();
111 pipelineDescriptor.primitive.frontFace = wgpu::FrontFace::CW;
112
113 shader.pipeline = device.createRenderPipeline(pipelineDescriptor);
114
115 shaderModule.release();
116 wgpu::PipelineLayout(pipelineDescriptor.layout).release();
117 for (auto layout : bindGroupLayouts)
118 {
119 wgpu::BindGroupLayout(layout).release();
120 }
121
122 return shader;
123 }
124
125 inline const ShaderDescriptor &GetDescriptor() const { return descriptor; }
126 inline wgpu::BindGroupLayout GetBindGroupLayout(uint32_t groupIndex = 0) const
127 {
128 // TODO: Create an appropriate class to handle RAII release
129 return pipeline.getBindGroupLayout(groupIndex);
130 }
131
132 inline const auto &GetPipeline() const { return pipeline; }
133
134 private:
135 Shader(void) = default;
136
137 static wgpu::ShaderModule _createShaderModule(std::string_view name, std::string_view source,
138 const wgpu::Device &device)
139 {
140 wgpu::ShaderSourceWGSL wgslDesc(wgpu::Default);
141 wgslDesc.code = wgpu::StringView(source);
142 wgpu::ShaderModuleDescriptor shaderModuleDesc(wgpu::Default);
143 shaderModuleDesc.nextInChain = &wgslDesc.chain;
144 const std::string label = fmt::format("{} Shader Module", name);
145 shaderModuleDesc.label = wgpu::StringView(label);
146 return device.createShaderModule(shaderModuleDesc);
147 }
148
149 static std::vector<wgpu::VertexBufferLayout> _createVertexBufferLayouts(const ShaderDescriptor &descriptor)
150 {
151 std::vector<wgpu::VertexBufferLayout> layouts;
152 for (const auto &layout : descriptor.getVertexBufferLayouts())
153 {
154 wgpu::VertexBufferLayout vertexBufferLayout(wgpu::Default);
155 vertexBufferLayout.arrayStride = layout.getArrayStride();
156 vertexBufferLayout.stepMode = layout.getStepMode();
157 vertexBufferLayout.attributeCount = layout.getVertexAttributes().size();
158 vertexBufferLayout.attributes = layout.getVertexAttributes().data();
159 layouts.push_back(vertexBufferLayout);
160 }
161 return layouts;
162 }
163
165 wgpu::RenderPipeline pipeline = nullptr;
166};
167
168} // namespace Graphic::Resource
Definition Context.hpp:8
DeviceContext deviceContext
Definition Context.hpp:43
Definition ShaderDescriptor.hpp:21
Shader & operator=(Shader &&other) noexcept
Definition Shader.hpp:31
Shader(const Shader &)=delete
const ShaderDescriptor & GetDescriptor() const
Definition Shader.hpp:125
const auto & GetPipeline() const
Definition Shader.hpp:132
ShaderDescriptor descriptor
Definition Shader.hpp:164
static std::vector< wgpu::VertexBufferLayout > _createVertexBufferLayouts(const ShaderDescriptor &descriptor)
Definition Shader.hpp:149
wgpu::RenderPipeline pipeline
Definition Shader.hpp:165
Shader(Shader &&other) noexcept
Definition Shader.hpp:25
virtual ~Shader()
Definition Shader.hpp:16
Shader & operator=(const Shader &)=delete
wgpu::BindGroupLayout GetBindGroupLayout(uint32_t groupIndex=0) const
Definition Shader.hpp:126
static Shader Create(const ShaderDescriptor &descriptor, Context &context)
Definition Shader.hpp:45
static wgpu::ShaderModule _createShaderModule(std::string_view name, std::string_view source, const wgpu::Device &device)
Definition Shader.hpp:137
Definition AGPUBuffer.hpp:6
constexpr DefaultFlag Default
Definition webgpu.hpp:78
StringView(const std::string_view &cpp)
Definition webgpu.hpp:618
auto & GetDevice()
Definition DeviceContext.hpp:13