automatic material bind group generation
This commit is contained in:
parent
cad8a1555e
commit
d75f3b4c49
9 changed files with 231 additions and 8 deletions
83
dist/index.js
vendored
83
dist/index.js
vendored
|
@ -412,6 +412,18 @@
|
|||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* @param {Object} [descriptor={}]
|
||||
* @param {number} [descriptor.offset=0]
|
||||
* @param {number} [descriptor.size]
|
||||
*/
|
||||
toBindingResource({ offset, size } = {}) {
|
||||
return {
|
||||
buffer: this._handle,
|
||||
offset: offset || 0,
|
||||
size: size || this.size
|
||||
};
|
||||
}
|
||||
destroy() {
|
||||
this._handle?.destroy();
|
||||
this._handle = null;
|
||||
|
@ -6320,7 +6332,8 @@
|
|||
return this._reflection;
|
||||
}
|
||||
};
|
||||
var ReflectedShader = class {
|
||||
var ReflectedShader = class _ReflectedShader {
|
||||
static _reflectTypes = ["uniforms", "storage", "textures", "samplers"];
|
||||
_module;
|
||||
get module() {
|
||||
return this._module;
|
||||
|
@ -6331,6 +6344,23 @@
|
|||
constructor(shader) {
|
||||
this._module = shader;
|
||||
}
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {number} group
|
||||
* @returns {VariableInfo | undefined}
|
||||
*/
|
||||
findVariableInfo(name, group) {
|
||||
const reflection = this.module.reflect();
|
||||
for (const type of _ReflectedShader._reflectTypes) {
|
||||
const variables = reflection[type];
|
||||
if (variables) {
|
||||
const variable = variables.find((v2) => v2.name === name && v2.group === group);
|
||||
if (variable) {
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {string} stageName
|
||||
* @returns {string | undefined}
|
||||
|
@ -6592,6 +6622,18 @@
|
|||
buffers: descriptor.buffers || []
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {number} group
|
||||
* @returns {VariableInfo | undefined}
|
||||
*/
|
||||
findVariableInfo(name, group) {
|
||||
let variableInfo = this._vertex.findVariableInfo(name, group);
|
||||
if (!variableInfo && this._fragment !== this._vertex) {
|
||||
variableInfo = this._fragment.findVariableInfo(name, group);
|
||||
}
|
||||
return variableInfo;
|
||||
}
|
||||
/**
|
||||
* @param {ShaderPairStateDescriptor} descriptor
|
||||
* @returns {Pick<GPURenderPipelineDescriptor, 'vertex' | 'fragment'>}
|
||||
|
@ -6836,6 +6878,9 @@
|
|||
getView() {
|
||||
return this.createDefaultView();
|
||||
}
|
||||
toBindingResource() {
|
||||
return this._handle;
|
||||
}
|
||||
destroy() {
|
||||
this._handle?.destroy();
|
||||
this._handle = void 0;
|
||||
|
@ -6878,6 +6923,9 @@
|
|||
throw WebGPUObjectError.from(err, _Sampler);
|
||||
}
|
||||
}
|
||||
toBindingResource() {
|
||||
return this._handle;
|
||||
}
|
||||
};
|
||||
|
||||
// src/resources/material.js
|
||||
|
@ -6939,6 +6987,33 @@
|
|||
const layouts = shaders.createBindGroupLayoutEntries();
|
||||
return layouts.map((entries) => BindGroupLayout.create(device, { entries }));
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
createBindGroup(groupIndex, resources, label) {
|
||||
if (groupIndex < 0 || groupIndex >= this._bindGroupLayouts.length) {
|
||||
throw new Error(`Invalid bind group index: ${groupIndex}`);
|
||||
}
|
||||
const bgl = this._bindGroupLayouts[groupIndex];
|
||||
let entries = [];
|
||||
for (const name in resources) {
|
||||
const resource = resources[name];
|
||||
const variableInfo = this._shaders.findVariableInfo(name, groupIndex);
|
||||
const entry = {
|
||||
binding: variableInfo.binding,
|
||||
resource: resource.toBindingResource()
|
||||
};
|
||||
if (variableInfo.resourceType === a.Uniform || variableInfo.resourceType === a.Storage) {
|
||||
}
|
||||
entries.push(entry);
|
||||
}
|
||||
entries.sort((a2, b2) => a2.binding - b2.binding);
|
||||
return BindGroup.create(this._device, {
|
||||
layout: bgl.handle,
|
||||
entries,
|
||||
label
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @typedef MaterialPipelineDescriptor
|
||||
* @property {string} [label]
|
||||
|
@ -7486,9 +7561,9 @@
|
|||
binding: 0,
|
||||
resource: uniformBuffer
|
||||
}];
|
||||
const uniformBindGroup = graphicsDevice.createBindGroup(
|
||||
material.bindGroupLayouts[0],
|
||||
uniformBindings,
|
||||
const uniformBindGroup = material.createBindGroup(
|
||||
0,
|
||||
{ transform: uniformBuffer },
|
||||
"Uniforms"
|
||||
);
|
||||
async function frame() {
|
||||
|
|
12
index.js
12
index.js
|
@ -98,7 +98,6 @@ async function main() {
|
|||
{ vertex: shaderModule },
|
||||
)
|
||||
|
||||
|
||||
const vertexBufferLayout = {
|
||||
arrayStride: 3 * 4,
|
||||
attributes: [
|
||||
|
@ -124,11 +123,16 @@ async function main() {
|
|||
resource: uniformBuffer
|
||||
}]
|
||||
|
||||
const uniformBindGroup = graphicsDevice.createBindGroup(
|
||||
material.bindGroupLayouts[0],
|
||||
uniformBindings,
|
||||
const uniformBindGroup = material.createBindGroup(
|
||||
0,
|
||||
{ transform: uniformBuffer },
|
||||
'Uniforms'
|
||||
)
|
||||
//const uniformBindGroup = graphicsDevice.createBindGroup(
|
||||
// material.bindGroupLayouts[0],
|
||||
// uniformBindings,
|
||||
// 'Uniforms'
|
||||
//)
|
||||
|
||||
async function frame() {
|
||||
if (!graphicsDevice.isInitialized) {
|
||||
|
|
|
@ -173,6 +173,19 @@ export class Buffer {
|
|||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} [descriptor={}]
|
||||
* @param {number} [descriptor.offset=0]
|
||||
* @param {number} [descriptor.size]
|
||||
*/
|
||||
toBindingResource({ offset, size } = {}) {
|
||||
return {
|
||||
buffer: this._handle,
|
||||
offset: offset || 0,
|
||||
size: size || this.size
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._handle?.destroy()
|
||||
this._handle = null
|
||||
|
|
43
src/resources/geometry.js
Normal file
43
src/resources/geometry.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { Buffer } from './buffer.js'
|
||||
|
||||
/**
|
||||
* @typedef GeometryDescriptor
|
||||
* @param {Buffer} vertices
|
||||
* @param {number} [vertexCount]
|
||||
* @param {GPUVertexBufferLayout} layout
|
||||
* @property {Buffer} [indices]
|
||||
* @property {number} [indexCount]
|
||||
* @property {GPUIndexFormat} [format]
|
||||
*/
|
||||
|
||||
export class Geometry {
|
||||
_device
|
||||
_vertices
|
||||
_vertexCount
|
||||
_vertexBufferLayout
|
||||
_indices
|
||||
_indexCount
|
||||
_format
|
||||
|
||||
/**
|
||||
* @param {GPUDevice} device
|
||||
* @param {GeometryDescriptor} descriptor
|
||||
*/
|
||||
constructor(device, descriptor) {
|
||||
this._device = device
|
||||
this._vertices = descriptor.vertices
|
||||
this._vertexCount = descriptor.vertexCount
|
||||
this._vertexBufferLayout = descriptor.layout
|
||||
|
||||
if (descriptor.indices) {
|
||||
this._indices = descriptor.indices
|
||||
this._indexCount = descriptor.indexCount
|
||||
this._format = descriptor.format
|
||||
|
||||
if (this._indexCount == null || this._format == null) {
|
||||
throw new Error('indexCount or format is required when creating an indexed geometry')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
import { BindGroupLayout } from './bind-group-layout.js'
|
||||
import { ShaderPair, ShaderModule } from './shader-module.js'
|
||||
import { MaterialError, WebGPUObjectError } from '../utils/errors.js'
|
||||
import { ResourceType } from 'wgsl_reflect'
|
||||
import { BindGroup } from './bind-group.js'
|
||||
|
||||
/** @import { FragmentStateDescriptor, VertexStateDescriptor } from './shader-module.js' */
|
||||
|
||||
|
@ -83,6 +85,43 @@ export class Material {
|
|||
return layouts.map(entries => BindGroupLayout.create(device, { entries }))
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
createBindGroup(groupIndex, resources, label) {
|
||||
if (groupIndex < 0 || groupIndex >= this._bindGroupLayouts.length) {
|
||||
throw new Error(`Invalid bind group index: ${groupIndex}`)
|
||||
}
|
||||
|
||||
const bgl = this._bindGroupLayouts[groupIndex]
|
||||
|
||||
let entries = []
|
||||
for (const name in resources) {
|
||||
const resource = resources[name]
|
||||
|
||||
const variableInfo = this._shaders.findVariableInfo(name, groupIndex)
|
||||
|
||||
const entry = {
|
||||
binding: variableInfo.binding,
|
||||
resource: resource.toBindingResource()
|
||||
}
|
||||
|
||||
if (variableInfo.resourceType === ResourceType.Uniform || variableInfo.resourceType === ResourceType.Storage) {
|
||||
// TODO: handle user provided offset/size
|
||||
}
|
||||
|
||||
entries.push(entry)
|
||||
}
|
||||
|
||||
entries.sort((a, b) => a.binding - b.binding)
|
||||
|
||||
return BindGroup.create(this._device, {
|
||||
layout: bgl.handle,
|
||||
entries,
|
||||
label
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef MaterialPipelineDescriptor
|
||||
* @property {string} [label]
|
||||
|
|
|
@ -42,5 +42,9 @@ export class Sampler {
|
|||
throw WebGPUObjectError.from(err, Sampler)
|
||||
}
|
||||
}
|
||||
|
||||
toBindingResource() {
|
||||
return this._handle
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ export class ShaderModule {
|
|||
*/
|
||||
|
||||
export class ReflectedShader {
|
||||
static _reflectTypes = ['uniforms', 'storage', 'textures', 'samplers']
|
||||
_module
|
||||
|
||||
get module() {
|
||||
|
@ -93,6 +94,25 @@ export class ReflectedShader {
|
|||
this._module = shader
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {number} group
|
||||
* @returns {VariableInfo | undefined}
|
||||
*/
|
||||
findVariableInfo(name, group) {
|
||||
const reflection = this.module.reflect()
|
||||
for (const type of ReflectedShader._reflectTypes) {
|
||||
const variables = reflection[type]
|
||||
if (variables) {
|
||||
const variable = variables.find(v => v.name === name && v.group === group)
|
||||
if (variable) {
|
||||
return variable
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} stageName
|
||||
* @returns {string | undefined}
|
||||
|
@ -402,6 +422,21 @@ export class ShaderPair {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {number} group
|
||||
* @returns {VariableInfo | undefined}
|
||||
*/
|
||||
findVariableInfo(name, group) {
|
||||
let variableInfo = this._vertex.findVariableInfo(name, group)
|
||||
|
||||
if (!variableInfo && this._fragment !== this._vertex) {
|
||||
variableInfo = this._fragment.findVariableInfo(name, group)
|
||||
}
|
||||
|
||||
return variableInfo
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ShaderPairStateDescriptor} descriptor
|
||||
* @returns {Pick<GPURenderPipelineDescriptor, 'vertex' | 'fragment'>}
|
||||
|
|
|
@ -100,6 +100,10 @@ export class Texture {
|
|||
return this.createDefaultView()
|
||||
}
|
||||
|
||||
toBindingResource() {
|
||||
return this._handle
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._handle?.destroy()
|
||||
this._handle = undefined
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
* @template T
|
||||
* @template {keyof T} K
|
||||
* @typedef {Pick<Partial<T>, K> & Omit<T, K>} Optional
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T, U
|
||||
* @typedef {
|
||||
|
|
Loading…
Add table
Reference in a new issue