create static method
GpuRenderPipeline
create({
- required GpuShader vertexShader,
- required GpuShader fragmentShader,
- required List<
VertexBufferLayout> bufferLayouts, - BlendMode blendMode = BlendMode.opaque,
- bool enableDepth = false,
- WGPUTextureFormat depthFormat = WGPUTextureFormat.WGPUTextureFormat_Depth24Plus,
- String vertexEntryPoint = "main",
- String fragmentEntryPoint = "main",
- int sampleCount = 1,
- WGPUTextureFormat? targetFormat,
- WGPUPrimitiveTopology topology = WGPUPrimitiveTopology.WGPUPrimitiveTopology_TriangleStrip,
- WGPUCullMode cullMode = WGPUCullMode.WGPUCullMode_None,
- WGPUFrontFace frontFace = WGPUFrontFace.WGPUFrontFace_CCW,
Implementation
static GpuRenderPipeline create({
required GpuShader vertexShader,
required GpuShader fragmentShader,
required List<VertexBufferLayout> bufferLayouts,
BlendMode blendMode = BlendMode.opaque,
bool enableDepth = false,
WGPUTextureFormat depthFormat =
WGPUTextureFormat.WGPUTextureFormat_Depth24Plus,
String vertexEntryPoint = "main",
String fragmentEntryPoint = "main",
int sampleCount = 1,
WGPUTextureFormat? targetFormat,
WGPUPrimitiveTopology topology =
WGPUPrimitiveTopology.WGPUPrimitiveTopology_TriangleStrip,
WGPUCullMode cullMode = WGPUCullMode.WGPUCullMode_None,
WGPUFrontFace frontFace = WGPUFrontFace.WGPUFrontFace_CCW,
}) {
final wgpu = WebgpuRend.instance.wgpu;
final format = targetFormat ?? kPreferredTextureFormat;
return using((arena) {
// Vertex State Setup
final vertexState = arena<WGPUVertexState>();
vertexState.ref.module = vertexShader.handle.cast();
vertexState.ref.entryPoint = _createStringView(arena, vertexEntryPoint);
vertexState.ref.constantCount = 0;
if (bufferLayouts.isNotEmpty) {
final layouts = arena<WGPUVertexBufferLayout>(bufferLayouts.length);
int totalAttrs = 0;
for (var l in bufferLayouts) {
totalAttrs += l.attributes.length;
}
final attrs = arena<WGPUVertexAttribute>(totalAttrs);
int attrIdx = 0;
for (int i = 0; i < bufferLayouts.length; i++) {
final def = bufferLayouts[i];
final layout = layouts.elementAt(i);
layout.ref.arrayStride = def.arrayStride;
layout.ref.stepMode = def.stepMode;
layout.ref.attributeCount = def.attributes.length;
layout.ref.attributes = attrs.elementAt(attrIdx);
for (int j = 0; j < def.attributes.length; j++) {
final dartAttr = def.attributes[j];
final nativeAttr = attrs.elementAt(attrIdx + j);
nativeAttr.ref.format = dartAttr.format;
nativeAttr.ref.offset = dartAttr.offset;
nativeAttr.ref.shaderLocation = dartAttr.shaderLocation;
}
attrIdx += def.attributes.length;
}
vertexState.ref.bufferCount = bufferLayouts.length;
vertexState.ref.buffers = layouts;
} else {
vertexState.ref.bufferCount = 0;
vertexState.ref.buffers = nullptr;
}
// Fragment State Setup
final fragmentState = arena<WGPUFragmentState>();
fragmentState.ref.module = fragmentShader.handle.cast();
fragmentState.ref.entryPoint = _createStringView(arena, fragmentEntryPoint);
fragmentState.ref.constantCount = 0;
fragmentState.ref.targetCount = 1;
final target = arena<WGPUColorTargetState>();
target.ref.format = format;
target.ref.writeMask = WGPUColorWriteMask_All;
if (blendMode == BlendMode.opaque) {
target.ref.blend = nullptr;
} else {
final blend = arena<WGPUBlendState>();
// Default assignments
var srcFactorColor = WGPUBlendFactor.WGPUBlendFactor_One;
var dstFactorColor = WGPUBlendFactor.WGPUBlendFactor_Zero;
var opColor = WGPUBlendOperation.WGPUBlendOperation_Add;
var srcFactorAlpha = WGPUBlendFactor.WGPUBlendFactor_One;
var dstFactorAlpha = WGPUBlendFactor.WGPUBlendFactor_Zero;
var opAlpha = WGPUBlendOperation.WGPUBlendOperation_Add;
switch (blendMode) {
case BlendMode.alpha:
// Final = (Src * SrcAlpha) + (Dst * (1 - SrcAlpha))
srcFactorColor = WGPUBlendFactor.WGPUBlendFactor_SrcAlpha;
dstFactorColor = WGPUBlendFactor.WGPUBlendFactor_OneMinusSrcAlpha;
srcFactorAlpha = WGPUBlendFactor.WGPUBlendFactor_One;
dstFactorAlpha = WGPUBlendFactor.WGPUBlendFactor_OneMinusSrcAlpha;
break;
case BlendMode.add:
// Final = Src + Dst
srcFactorColor = WGPUBlendFactor.WGPUBlendFactor_One;
dstFactorColor = WGPUBlendFactor.WGPUBlendFactor_One;
srcFactorAlpha = WGPUBlendFactor.WGPUBlendFactor_One;
dstFactorAlpha = WGPUBlendFactor.WGPUBlendFactor_One;
break;
case BlendMode.max:
// Final = Max(Src, Dst) - Factors are ignored in Max/Min
opColor = WGPUBlendOperation.WGPUBlendOperation_Max;
opAlpha = WGPUBlendOperation.WGPUBlendOperation_Max;
break;
case BlendMode.min:
// Final = Min(Src, Dst)
opColor = WGPUBlendOperation.WGPUBlendOperation_Min;
opAlpha = WGPUBlendOperation.WGPUBlendOperation_Min;
break;
case BlendMode.erase:
// Final = Dst * (1 - SrcAlpha)
srcFactorColor = WGPUBlendFactor.WGPUBlendFactor_Zero;
dstFactorColor = WGPUBlendFactor.WGPUBlendFactor_OneMinusSrcAlpha;
srcFactorAlpha = WGPUBlendFactor.WGPUBlendFactor_Zero;
dstFactorAlpha = WGPUBlendFactor.WGPUBlendFactor_OneMinusSrcAlpha;
break;
case BlendMode.opaque:
break; // Handled above
}
blend.ref.color.srcFactor = srcFactorColor;
blend.ref.color.dstFactor = dstFactorColor;
blend.ref.color.operation = opColor;
blend.ref.alpha.srcFactor = srcFactorAlpha;
blend.ref.alpha.dstFactor = dstFactorAlpha;
blend.ref.alpha.operation = opAlpha;
target.ref.blend = blend;
}
fragmentState.ref.targets = target;
// Pipeline Descriptor
final desc = arena<WGPURenderPipelineDescriptor>();
desc.ref.label.data = nullptr;
desc.ref.label.length = 0;
desc.ref.layout = nullptr;
desc.ref.vertex = vertexState.ref;
desc.ref.fragment = fragmentState;
desc.ref.primitive.topology = topology;
desc.ref.primitive.stripIndexFormat = WGPUIndexFormat.WGPUIndexFormat_Undefined;
desc.ref.primitive.frontFace = frontFace;
desc.ref.primitive.cullMode = cullMode;
if (enableDepth) {
final ds = arena<WGPUDepthStencilState>();
ds.ref.format = depthFormat;
ds.ref.depthWriteEnabled = WGPUOptionalBool.WGPUOptionalBool_True;
ds.ref.depthCompare = WGPUCompareFunction.WGPUCompareFunction_Less;
ds.ref.stencilReadMask = 0;
ds.ref.stencilWriteMask = 0;
desc.ref.depthStencil = ds;
} else {
desc.ref.depthStencil = nullptr;
}
desc.ref.multisample.count = sampleCount;
desc.ref.multisample.mask = 0xFFFFFFFF;
desc.ref.multisample.alphaToCoverageEnabled = 0;
final handle = wgpu.wgpuDeviceCreateRenderPipeline(WebgpuRend.instance.device, desc);
return GpuRenderPipeline._(handle.cast());
});
}