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;
|
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() {
|
destroy() {
|
||||||
this._handle?.destroy();
|
this._handle?.destroy();
|
||||||
this._handle = null;
|
this._handle = null;
|
||||||
|
@ -6320,7 +6332,8 @@
|
||||||
return this._reflection;
|
return this._reflection;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var ReflectedShader = class {
|
var ReflectedShader = class _ReflectedShader {
|
||||||
|
static _reflectTypes = ["uniforms", "storage", "textures", "samplers"];
|
||||||
_module;
|
_module;
|
||||||
get module() {
|
get module() {
|
||||||
return this._module;
|
return this._module;
|
||||||
|
@ -6331,6 +6344,23 @@
|
||||||
constructor(shader) {
|
constructor(shader) {
|
||||||
this._module = 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
|
* @param {string} stageName
|
||||||
* @returns {string | undefined}
|
* @returns {string | undefined}
|
||||||
|
@ -6592,6 +6622,18 @@
|
||||||
buffers: descriptor.buffers || []
|
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
|
* @param {ShaderPairStateDescriptor} descriptor
|
||||||
* @returns {Pick<GPURenderPipelineDescriptor, 'vertex' | 'fragment'>}
|
* @returns {Pick<GPURenderPipelineDescriptor, 'vertex' | 'fragment'>}
|
||||||
|
@ -6836,6 +6878,9 @@
|
||||||
getView() {
|
getView() {
|
||||||
return this.createDefaultView();
|
return this.createDefaultView();
|
||||||
}
|
}
|
||||||
|
toBindingResource() {
|
||||||
|
return this._handle;
|
||||||
|
}
|
||||||
destroy() {
|
destroy() {
|
||||||
this._handle?.destroy();
|
this._handle?.destroy();
|
||||||
this._handle = void 0;
|
this._handle = void 0;
|
||||||
|
@ -6878,6 +6923,9 @@
|
||||||
throw WebGPUObjectError.from(err, _Sampler);
|
throw WebGPUObjectError.from(err, _Sampler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
toBindingResource() {
|
||||||
|
return this._handle;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// src/resources/material.js
|
// src/resources/material.js
|
||||||
|
@ -6939,6 +6987,33 @@
|
||||||
const layouts = shaders.createBindGroupLayoutEntries();
|
const layouts = shaders.createBindGroupLayoutEntries();
|
||||||
return layouts.map((entries) => BindGroupLayout.create(device, { entries }));
|
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
|
* @typedef MaterialPipelineDescriptor
|
||||||
* @property {string} [label]
|
* @property {string} [label]
|
||||||
|
@ -7486,9 +7561,9 @@
|
||||||
binding: 0,
|
binding: 0,
|
||||||
resource: uniformBuffer
|
resource: uniformBuffer
|
||||||
}];
|
}];
|
||||||
const uniformBindGroup = graphicsDevice.createBindGroup(
|
const uniformBindGroup = material.createBindGroup(
|
||||||
material.bindGroupLayouts[0],
|
0,
|
||||||
uniformBindings,
|
{ transform: uniformBuffer },
|
||||||
"Uniforms"
|
"Uniforms"
|
||||||
);
|
);
|
||||||
async function frame() {
|
async function frame() {
|
||||||
|
|
12
index.js
12
index.js
|
@ -98,7 +98,6 @@ async function main() {
|
||||||
{ vertex: shaderModule },
|
{ vertex: shaderModule },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
const vertexBufferLayout = {
|
const vertexBufferLayout = {
|
||||||
arrayStride: 3 * 4,
|
arrayStride: 3 * 4,
|
||||||
attributes: [
|
attributes: [
|
||||||
|
@ -124,11 +123,16 @@ async function main() {
|
||||||
resource: uniformBuffer
|
resource: uniformBuffer
|
||||||
}]
|
}]
|
||||||
|
|
||||||
const uniformBindGroup = graphicsDevice.createBindGroup(
|
const uniformBindGroup = material.createBindGroup(
|
||||||
material.bindGroupLayouts[0],
|
0,
|
||||||
uniformBindings,
|
{ transform: uniformBuffer },
|
||||||
'Uniforms'
|
'Uniforms'
|
||||||
)
|
)
|
||||||
|
//const uniformBindGroup = graphicsDevice.createBindGroup(
|
||||||
|
// material.bindGroupLayouts[0],
|
||||||
|
// uniformBindings,
|
||||||
|
// 'Uniforms'
|
||||||
|
//)
|
||||||
|
|
||||||
async function frame() {
|
async function frame() {
|
||||||
if (!graphicsDevice.isInitialized) {
|
if (!graphicsDevice.isInitialized) {
|
||||||
|
|
|
@ -173,6 +173,19 @@ export class Buffer {
|
||||||
return result
|
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() {
|
destroy() {
|
||||||
this._handle?.destroy()
|
this._handle?.destroy()
|
||||||
this._handle = null
|
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 { BindGroupLayout } from './bind-group-layout.js'
|
||||||
import { ShaderPair, ShaderModule } from './shader-module.js'
|
import { ShaderPair, ShaderModule } from './shader-module.js'
|
||||||
import { MaterialError, WebGPUObjectError } from '../utils/errors.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' */
|
/** @import { FragmentStateDescriptor, VertexStateDescriptor } from './shader-module.js' */
|
||||||
|
|
||||||
|
@ -83,6 +85,43 @@ export class Material {
|
||||||
return layouts.map(entries => BindGroupLayout.create(device, { entries }))
|
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
|
* @typedef MaterialPipelineDescriptor
|
||||||
* @property {string} [label]
|
* @property {string} [label]
|
||||||
|
|
|
@ -42,5 +42,9 @@ export class Sampler {
|
||||||
throw WebGPUObjectError.from(err, Sampler)
|
throw WebGPUObjectError.from(err, Sampler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toBindingResource() {
|
||||||
|
return this._handle
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,7 @@ export class ShaderModule {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export class ReflectedShader {
|
export class ReflectedShader {
|
||||||
|
static _reflectTypes = ['uniforms', 'storage', 'textures', 'samplers']
|
||||||
_module
|
_module
|
||||||
|
|
||||||
get module() {
|
get module() {
|
||||||
|
@ -93,6 +94,25 @@ export class ReflectedShader {
|
||||||
this._module = 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(v => v.name === name && v.group === group)
|
||||||
|
if (variable) {
|
||||||
|
return variable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} stageName
|
* @param {string} stageName
|
||||||
* @returns {string | undefined}
|
* @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
|
* @param {ShaderPairStateDescriptor} descriptor
|
||||||
* @returns {Pick<GPURenderPipelineDescriptor, 'vertex' | 'fragment'>}
|
* @returns {Pick<GPURenderPipelineDescriptor, 'vertex' | 'fragment'>}
|
||||||
|
|
|
@ -100,6 +100,10 @@ export class Texture {
|
||||||
return this.createDefaultView()
|
return this.createDefaultView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toBindingResource() {
|
||||||
|
return this._handle
|
||||||
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
this._handle?.destroy()
|
this._handle?.destroy()
|
||||||
this._handle = undefined
|
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
|
* @template T, U
|
||||||
* @typedef {
|
* @typedef {
|
||||||
|
|
Loading…
Add table
Reference in a new issue