summaryrefslogtreecommitdiff
path: root/src/gpu/pipeline_builder.cc
blob: 2d9ec07d8d06d24ad215a008411da25ad89284ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// WGPU render pipeline builder - implementation
#include "gpu/pipeline_builder.h"
#include "util/fatal_error.h"

RenderPipelineBuilder::RenderPipelineBuilder(WGPUDevice device)
    : device_(device) {
  desc_.primitive.topology = WGPUPrimitiveTopology_TriangleList;
  desc_.primitive.cullMode = WGPUCullMode_None;
  desc_.multisample.count = 1;
  desc_.multisample.mask = 0xFFFFFFFF;
}

RenderPipelineBuilder& RenderPipelineBuilder::shader(const char* wgsl,
                                                     bool compose) {
  shader_text_ = compose ? ShaderComposer::Get().Compose({}, wgsl) : wgsl;
  if (device_ == nullptr)
    return *this;
  WGPUShaderSourceWGSL wgsl_src{};
  wgsl_src.chain.sType = WGPUSType_ShaderSourceWGSL;
  wgsl_src.code = str_view(shader_text_.c_str());
  WGPUShaderModuleDescriptor shader_desc{};
  shader_desc.nextInChain = &wgsl_src.chain;
  shader_module_ = wgpuDeviceCreateShaderModule(device_, &shader_desc);
  desc_.vertex.module = shader_module_;
  desc_.vertex.entryPoint = str_view("vs_main");
  return *this;
}

RenderPipelineBuilder&
RenderPipelineBuilder::bind_group_layout(WGPUBindGroupLayout layout) {
  layouts_.push_back(layout);
  return *this;
}

RenderPipelineBuilder& RenderPipelineBuilder::format(WGPUTextureFormat fmt) {
  color_.format = fmt;
  return *this;
}

RenderPipelineBuilder& RenderPipelineBuilder::blend_alpha() {
  has_blend_ = true;
  blend_.color.operation = WGPUBlendOperation_Add;
  blend_.color.srcFactor = WGPUBlendFactor_SrcAlpha;
  blend_.color.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha;
  blend_.alpha.operation = WGPUBlendOperation_Add;
  blend_.alpha.srcFactor = WGPUBlendFactor_One;
  blend_.alpha.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha;
  return *this;
}

RenderPipelineBuilder&
RenderPipelineBuilder::depth(WGPUTextureFormat depth_fmt) {
  has_depth_ = true;
  depth_.format = depth_fmt;
  depth_.depthWriteEnabled = WGPUOptionalBool_True;
  depth_.depthCompare = WGPUCompareFunction_Less;
  // Vulkan backend panics on WGPUCompareFunction_Undefined (zero) in stencil
  depth_.stencilFront.compare = WGPUCompareFunction_Always;
  depth_.stencilBack.compare = WGPUCompareFunction_Always;
  return *this;
}

RenderPipelineBuilder& RenderPipelineBuilder::cull_back() {
  desc_.primitive.cullMode = WGPUCullMode_Back;
  return *this;
}

WGPURenderPipeline RenderPipelineBuilder::build() {
  HEADLESS_RETURN_VAL_IF_NULL(device_, nullptr);

  color_.writeMask = WGPUColorWriteMask_All;
  if (has_blend_)
    color_.blend = &blend_;

  WGPUFragmentState fragment{};
  fragment.module = shader_module_;
  fragment.entryPoint = str_view("fs_main");
  fragment.targetCount = 1;
  fragment.targets = &color_;

  WGPUPipelineLayoutDescriptor pl_desc{};
  pl_desc.bindGroupLayoutCount = layouts_.size();
  pl_desc.bindGroupLayouts = layouts_.data();
  WGPUPipelineLayout layout = wgpuDeviceCreatePipelineLayout(device_, &pl_desc);

  desc_.layout = layout;
  desc_.fragment = &fragment;
  if (has_depth_)
    desc_.depthStencil = &depth_;

  WGPURenderPipeline pipeline = wgpuDeviceCreateRenderPipeline(device_, &desc_);
  wgpuPipelineLayoutRelease(layout);
  return pipeline;
}