This commit is contained in:
Akko
2025-08-04 18:57:35 +02:00
parent 8cf6e78a79
commit 9495868c2e
5030 changed files with 518594 additions and 17609 deletions

View File

@@ -0,0 +1,26 @@
/// <reference types="@webgpu/types" />
import { ExtensionType } from '../../../extensions/Extensions';
import type { System } from '../shared/system/System';
import type { GPU } from './GpuDeviceSystem';
import type { BindGroup } from './shader/BindGroup';
import type { GpuProgram } from './shader/GpuProgram';
import type { WebGPURenderer } from './WebGPURenderer';
/**
* This manages the WebGPU bind groups. this is how data is bound to a shader when rendering
* @memberof rendering
*/
export declare class BindGroupSystem implements System {
/** @ignore */
static extension: {
readonly type: readonly [ExtensionType.WebGPUSystem];
readonly name: "bindGroup";
};
private readonly _renderer;
private _hash;
private _gpu;
constructor(renderer: WebGPURenderer);
protected contextChange(gpu: GPU): void;
getBindGroup(bindGroup: BindGroup, program: GpuProgram, groupIndex: number): GPUBindGroup;
private _createBindGroup;
destroy(): void;
}

View File

@@ -0,0 +1,87 @@
'use strict';
var Extensions = require('../../../extensions/Extensions.js');
"use strict";
class BindGroupSystem {
constructor(renderer) {
this._hash = /* @__PURE__ */ Object.create(null);
this._renderer = renderer;
}
contextChange(gpu) {
this._gpu = gpu;
}
getBindGroup(bindGroup, program, groupIndex) {
bindGroup._updateKey();
const gpuBindGroup = this._hash[bindGroup._key] || this._createBindGroup(bindGroup, program, groupIndex);
return gpuBindGroup;
}
_createBindGroup(group, program, groupIndex) {
const device = this._gpu.device;
const groupLayout = program.layout[groupIndex];
const entries = [];
const renderer = this._renderer;
for (const j in groupLayout) {
const resource = group.resources[j] ?? group.resources[groupLayout[j]];
let gpuResource;
if (resource._resourceType === "uniformGroup") {
const uniformGroup = resource;
renderer.ubo.updateUniformGroup(uniformGroup);
const buffer = uniformGroup.buffer;
gpuResource = {
buffer: renderer.buffer.getGPUBuffer(buffer),
offset: 0,
size: buffer.descriptor.size
};
} else if (resource._resourceType === "buffer") {
const buffer = resource;
gpuResource = {
buffer: renderer.buffer.getGPUBuffer(buffer),
offset: 0,
size: buffer.descriptor.size
};
} else if (resource._resourceType === "bufferResource") {
const bufferResource = resource;
gpuResource = {
buffer: renderer.buffer.getGPUBuffer(bufferResource.buffer),
offset: bufferResource.offset,
size: bufferResource.size
};
} else if (resource._resourceType === "textureSampler") {
const sampler = resource;
gpuResource = renderer.texture.getGpuSampler(sampler);
} else if (resource._resourceType === "textureSource") {
const texture = resource;
gpuResource = renderer.texture.getGpuSource(texture).createView({});
}
entries.push({
binding: groupLayout[j],
resource: gpuResource
});
}
const layout = renderer.shader.getProgramData(program).bindGroups[groupIndex];
const gpuBindGroup = device.createBindGroup({
layout,
entries
});
this._hash[group._key] = gpuBindGroup;
return gpuBindGroup;
}
destroy() {
for (const key of Object.keys(this._hash)) {
this._hash[key] = null;
}
this._hash = null;
this._renderer = null;
}
}
/** @ignore */
BindGroupSystem.extension = {
type: [
Extensions.ExtensionType.WebGPUSystem
],
name: "bindGroup"
};
exports.BindGroupSystem = BindGroupSystem;
//# sourceMappingURL=BindGroupSystem.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,85 @@
import { ExtensionType } from '../../../extensions/Extensions.mjs';
"use strict";
class BindGroupSystem {
constructor(renderer) {
this._hash = /* @__PURE__ */ Object.create(null);
this._renderer = renderer;
}
contextChange(gpu) {
this._gpu = gpu;
}
getBindGroup(bindGroup, program, groupIndex) {
bindGroup._updateKey();
const gpuBindGroup = this._hash[bindGroup._key] || this._createBindGroup(bindGroup, program, groupIndex);
return gpuBindGroup;
}
_createBindGroup(group, program, groupIndex) {
const device = this._gpu.device;
const groupLayout = program.layout[groupIndex];
const entries = [];
const renderer = this._renderer;
for (const j in groupLayout) {
const resource = group.resources[j] ?? group.resources[groupLayout[j]];
let gpuResource;
if (resource._resourceType === "uniformGroup") {
const uniformGroup = resource;
renderer.ubo.updateUniformGroup(uniformGroup);
const buffer = uniformGroup.buffer;
gpuResource = {
buffer: renderer.buffer.getGPUBuffer(buffer),
offset: 0,
size: buffer.descriptor.size
};
} else if (resource._resourceType === "buffer") {
const buffer = resource;
gpuResource = {
buffer: renderer.buffer.getGPUBuffer(buffer),
offset: 0,
size: buffer.descriptor.size
};
} else if (resource._resourceType === "bufferResource") {
const bufferResource = resource;
gpuResource = {
buffer: renderer.buffer.getGPUBuffer(bufferResource.buffer),
offset: bufferResource.offset,
size: bufferResource.size
};
} else if (resource._resourceType === "textureSampler") {
const sampler = resource;
gpuResource = renderer.texture.getGpuSampler(sampler);
} else if (resource._resourceType === "textureSource") {
const texture = resource;
gpuResource = renderer.texture.getGpuSource(texture).createView({});
}
entries.push({
binding: groupLayout[j],
resource: gpuResource
});
}
const layout = renderer.shader.getProgramData(program).bindGroups[groupIndex];
const gpuBindGroup = device.createBindGroup({
layout,
entries
});
this._hash[group._key] = gpuBindGroup;
return gpuBindGroup;
}
destroy() {
for (const key of Object.keys(this._hash)) {
this._hash[key] = null;
}
this._hash = null;
this._renderer = null;
}
}
/** @ignore */
BindGroupSystem.extension = {
type: [
ExtensionType.WebGPUSystem
],
name: "bindGroup"
};
export { BindGroupSystem };
//# sourceMappingURL=BindGroupSystem.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,19 @@
import { ExtensionType } from '../../../extensions/Extensions';
import type { System } from '../shared/system/System';
import type { WebGPURenderer } from './WebGPURenderer';
/**
* The system that handles color masking for the GPU.
* @memberof rendering
*/
export declare class GpuColorMaskSystem implements System {
/** @ignore */
static extension: {
readonly type: readonly [ExtensionType.WebGPUSystem];
readonly name: "colorMask";
};
private readonly _renderer;
private _colorMaskCache;
constructor(renderer: WebGPURenderer);
setMask(colorMask: number): void;
destroy(): void;
}

View File

@@ -0,0 +1,31 @@
'use strict';
var Extensions = require('../../../extensions/Extensions.js');
"use strict";
class GpuColorMaskSystem {
constructor(renderer) {
this._colorMaskCache = 15;
this._renderer = renderer;
}
setMask(colorMask) {
if (this._colorMaskCache === colorMask)
return;
this._colorMaskCache = colorMask;
this._renderer.pipeline.setColorMask(colorMask);
}
destroy() {
this._renderer = null;
this._colorMaskCache = null;
}
}
/** @ignore */
GpuColorMaskSystem.extension = {
type: [
Extensions.ExtensionType.WebGPUSystem
],
name: "colorMask"
};
exports.GpuColorMaskSystem = GpuColorMaskSystem;
//# sourceMappingURL=GpuColorMaskSystem.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"GpuColorMaskSystem.js","sources":["../../../../src/rendering/renderers/gpu/GpuColorMaskSystem.ts"],"sourcesContent":["import { ExtensionType } from '../../../extensions/Extensions';\n\nimport type { System } from '../shared/system/System';\nimport type { WebGPURenderer } from './WebGPURenderer';\n\n/**\n * The system that handles color masking for the GPU.\n * @memberof rendering\n */\nexport class GpuColorMaskSystem implements System\n{\n /** @ignore */\n public static extension = {\n type: [\n ExtensionType.WebGPUSystem,\n ],\n name: 'colorMask',\n } as const;\n\n private readonly _renderer: WebGPURenderer;\n\n private _colorMaskCache = 0b1111;\n\n constructor(renderer: WebGPURenderer)\n {\n this._renderer = renderer;\n }\n\n public setMask(colorMask: number)\n {\n if (this._colorMaskCache === colorMask) return;\n this._colorMaskCache = colorMask;\n\n this._renderer.pipeline.setColorMask(colorMask);\n }\n\n public destroy()\n {\n (this._renderer as null) = null;\n this._colorMaskCache = null;\n }\n}\n"],"names":["ExtensionType"],"mappings":";;;;;AASO,MAAM,kBACb,CAAA;AAAA,EAaI,YAAY,QACZ,EAAA;AAHA,IAAA,IAAA,CAAQ,eAAkB,GAAA,EAAA,CAAA;AAItB,IAAA,IAAA,CAAK,SAAY,GAAA,QAAA,CAAA;AAAA,GACrB;AAAA,EAEO,QAAQ,SACf,EAAA;AACI,IAAA,IAAI,KAAK,eAAoB,KAAA,SAAA;AAAW,MAAA,OAAA;AACxC,IAAA,IAAA,CAAK,eAAkB,GAAA,SAAA,CAAA;AAEvB,IAAK,IAAA,CAAA,SAAA,CAAU,QAAS,CAAA,YAAA,CAAa,SAAS,CAAA,CAAA;AAAA,GAClD;AAAA,EAEO,OACP,GAAA;AACI,IAAC,KAAK,SAAqB,GAAA,IAAA,CAAA;AAC3B,IAAA,IAAA,CAAK,eAAkB,GAAA,IAAA,CAAA;AAAA,GAC3B;AACJ,CAAA;AAAA;AAhCa,kBAAA,CAGK,SAAY,GAAA;AAAA,EACtB,IAAM,EAAA;AAAA,IACFA,wBAAc,CAAA,YAAA;AAAA,GAClB;AAAA,EACA,IAAM,EAAA,WAAA;AACV,CAAA;;;;"}

View File

@@ -0,0 +1,29 @@
import { ExtensionType } from '../../../extensions/Extensions.mjs';
"use strict";
class GpuColorMaskSystem {
constructor(renderer) {
this._colorMaskCache = 15;
this._renderer = renderer;
}
setMask(colorMask) {
if (this._colorMaskCache === colorMask)
return;
this._colorMaskCache = colorMask;
this._renderer.pipeline.setColorMask(colorMask);
}
destroy() {
this._renderer = null;
this._colorMaskCache = null;
}
}
/** @ignore */
GpuColorMaskSystem.extension = {
type: [
ExtensionType.WebGPUSystem
],
name: "colorMask"
};
export { GpuColorMaskSystem };
//# sourceMappingURL=GpuColorMaskSystem.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"GpuColorMaskSystem.mjs","sources":["../../../../src/rendering/renderers/gpu/GpuColorMaskSystem.ts"],"sourcesContent":["import { ExtensionType } from '../../../extensions/Extensions';\n\nimport type { System } from '../shared/system/System';\nimport type { WebGPURenderer } from './WebGPURenderer';\n\n/**\n * The system that handles color masking for the GPU.\n * @memberof rendering\n */\nexport class GpuColorMaskSystem implements System\n{\n /** @ignore */\n public static extension = {\n type: [\n ExtensionType.WebGPUSystem,\n ],\n name: 'colorMask',\n } as const;\n\n private readonly _renderer: WebGPURenderer;\n\n private _colorMaskCache = 0b1111;\n\n constructor(renderer: WebGPURenderer)\n {\n this._renderer = renderer;\n }\n\n public setMask(colorMask: number)\n {\n if (this._colorMaskCache === colorMask) return;\n this._colorMaskCache = colorMask;\n\n this._renderer.pipeline.setColorMask(colorMask);\n }\n\n public destroy()\n {\n (this._renderer as null) = null;\n this._colorMaskCache = null;\n }\n}\n"],"names":[],"mappings":";;;AASO,MAAM,kBACb,CAAA;AAAA,EAaI,YAAY,QACZ,EAAA;AAHA,IAAA,IAAA,CAAQ,eAAkB,GAAA,EAAA,CAAA;AAItB,IAAA,IAAA,CAAK,SAAY,GAAA,QAAA,CAAA;AAAA,GACrB;AAAA,EAEO,QAAQ,SACf,EAAA;AACI,IAAA,IAAI,KAAK,eAAoB,KAAA,SAAA;AAAW,MAAA,OAAA;AACxC,IAAA,IAAA,CAAK,eAAkB,GAAA,SAAA,CAAA;AAEvB,IAAK,IAAA,CAAA,SAAA,CAAU,QAAS,CAAA,YAAA,CAAa,SAAS,CAAA,CAAA;AAAA,GAClD;AAAA,EAEO,OACP,GAAA;AACI,IAAC,KAAK,SAAqB,GAAA,IAAA,CAAA;AAC3B,IAAA,IAAA,CAAK,eAAkB,GAAA,IAAA,CAAA;AAAA,GAC3B;AACJ,CAAA;AAAA;AAhCa,kBAAA,CAGK,SAAY,GAAA;AAAA,EACtB,IAAM,EAAA;AAAA,IACF,aAAc,CAAA,YAAA;AAAA,GAClB;AAAA,EACA,IAAM,EAAA,WAAA;AACV,CAAA;;;;"}

View File

@@ -0,0 +1,75 @@
/// <reference types="@webgpu/types" />
import { ExtensionType } from '../../../extensions/Extensions';
import type { System } from '../shared/system/System';
import type { GpuPowerPreference } from '../types';
import type { WebGPURenderer } from './WebGPURenderer';
/** The GPU object. */
export interface GPU {
/** The GPU adapter */
adapter: GPUAdapter;
/** The GPU device */
device: GPUDevice;
}
/**
* Options for the WebGPU context.
* @property {GpuPowerPreference} [powerPreference=default] - An optional hint indicating what configuration of GPU
* is suitable for the WebGPU context, can be `'high-performance'` or `'low-power'`.
* Setting to `'high-performance'` will prioritize rendering performance over power consumption,
* while setting to `'low-power'` will prioritize power saving over rendering performance.
* @property {boolean} [forceFallbackAdapter=false] - Force the use of the fallback adapter
* @memberof rendering
*/
export interface GpuContextOptions {
/**
* An optional hint indicating what configuration of GPU is suitable for the WebGPU context,
* can be `'high-performance'` or `'low-power'`.
* Setting to `'high-performance'` will prioritize rendering performance over power consumption,
* while setting to `'low-power'` will prioritize power saving over rendering performance.
* @default undefined
* @memberof rendering.WebGPUOptions
*/
powerPreference?: GpuPowerPreference;
/**
* Force the use of the fallback adapter
* @default false
* @memberof rendering.WebGPUOptions
*/
forceFallbackAdapter: boolean;
}
/**
* System plugin to the renderer to manage the context.
* @class
* @memberof rendering
*/
export declare class GpuDeviceSystem implements System<GpuContextOptions> {
/** @ignore */
static extension: {
readonly type: readonly [ExtensionType.WebGPUSystem];
readonly name: "device";
};
/** The default options for the GpuDeviceSystem. */
static defaultOptions: GpuContextOptions;
/** The GPU device */
gpu: GPU;
private _renderer;
private _initPromise;
/**
* @param {WebGPURenderer} renderer - The renderer this System works for.
*/
constructor(renderer: WebGPURenderer);
init(options: GpuContextOptions): Promise<void>;
/**
* Handle the context change event
* @param gpu
*/
protected contextChange(gpu: GPU): void;
/**
* Helper class to create a WebGL Context
* @param {object} options - An options object that gets passed in to the canvas element containing the
* context attributes
* @see https://developer.mozilla.org/en/docs/Web/API/HTMLCanvasElement/getContext
* @returns {WebGLRenderingContext} the WebGL context
*/
private _createDeviceAndAdaptor;
destroy(): void;
}

View File

@@ -0,0 +1,79 @@
'use strict';
var adapter = require('../../../environment/adapter.js');
var Extensions = require('../../../extensions/Extensions.js');
"use strict";
class GpuDeviceSystem {
/**
* @param {WebGPURenderer} renderer - The renderer this System works for.
*/
constructor(renderer) {
this._renderer = renderer;
}
async init(options) {
if (this._initPromise)
return this._initPromise;
this._initPromise = this._createDeviceAndAdaptor(options).then((gpu) => {
this.gpu = gpu;
this._renderer.runners.contextChange.emit(this.gpu);
});
return this._initPromise;
}
/**
* Handle the context change event
* @param gpu
*/
contextChange(gpu) {
this._renderer.gpu = gpu;
}
/**
* Helper class to create a WebGL Context
* @param {object} options - An options object that gets passed in to the canvas element containing the
* context attributes
* @see https://developer.mozilla.org/en/docs/Web/API/HTMLCanvasElement/getContext
* @returns {WebGLRenderingContext} the WebGL context
*/
async _createDeviceAndAdaptor(options) {
const adapter$1 = await adapter.DOMAdapter.get().getNavigator().gpu.requestAdapter({
powerPreference: options.powerPreference,
forceFallbackAdapter: options.forceFallbackAdapter
});
const requiredFeatures = [
"texture-compression-bc",
"texture-compression-astc",
"texture-compression-etc2"
].filter((feature) => adapter$1.features.has(feature));
const device = await adapter$1.requestDevice({
requiredFeatures
});
return { adapter: adapter$1, device };
}
destroy() {
this.gpu = null;
this._renderer = null;
}
}
/** @ignore */
GpuDeviceSystem.extension = {
type: [
Extensions.ExtensionType.WebGPUSystem
],
name: "device"
};
/** The default options for the GpuDeviceSystem. */
GpuDeviceSystem.defaultOptions = {
/**
* {@link WebGPUOptions.powerPreference}
* @default default
*/
powerPreference: void 0,
/**
* Force the use of the fallback adapter
* @default false
*/
forceFallbackAdapter: false
};
exports.GpuDeviceSystem = GpuDeviceSystem;
//# sourceMappingURL=GpuDeviceSystem.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,77 @@
import { DOMAdapter } from '../../../environment/adapter.mjs';
import { ExtensionType } from '../../../extensions/Extensions.mjs';
"use strict";
class GpuDeviceSystem {
/**
* @param {WebGPURenderer} renderer - The renderer this System works for.
*/
constructor(renderer) {
this._renderer = renderer;
}
async init(options) {
if (this._initPromise)
return this._initPromise;
this._initPromise = this._createDeviceAndAdaptor(options).then((gpu) => {
this.gpu = gpu;
this._renderer.runners.contextChange.emit(this.gpu);
});
return this._initPromise;
}
/**
* Handle the context change event
* @param gpu
*/
contextChange(gpu) {
this._renderer.gpu = gpu;
}
/**
* Helper class to create a WebGL Context
* @param {object} options - An options object that gets passed in to the canvas element containing the
* context attributes
* @see https://developer.mozilla.org/en/docs/Web/API/HTMLCanvasElement/getContext
* @returns {WebGLRenderingContext} the WebGL context
*/
async _createDeviceAndAdaptor(options) {
const adapter = await DOMAdapter.get().getNavigator().gpu.requestAdapter({
powerPreference: options.powerPreference,
forceFallbackAdapter: options.forceFallbackAdapter
});
const requiredFeatures = [
"texture-compression-bc",
"texture-compression-astc",
"texture-compression-etc2"
].filter((feature) => adapter.features.has(feature));
const device = await adapter.requestDevice({
requiredFeatures
});
return { adapter, device };
}
destroy() {
this.gpu = null;
this._renderer = null;
}
}
/** @ignore */
GpuDeviceSystem.extension = {
type: [
ExtensionType.WebGPUSystem
],
name: "device"
};
/** The default options for the GpuDeviceSystem. */
GpuDeviceSystem.defaultOptions = {
/**
* {@link WebGPUOptions.powerPreference}
* @default default
*/
powerPreference: void 0,
/**
* Force the use of the fallback adapter
* @default false
*/
forceFallbackAdapter: false
};
export { GpuDeviceSystem };
//# sourceMappingURL=GpuDeviceSystem.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,65 @@
/// <reference types="@webgpu/types" />
import { ExtensionType } from '../../../extensions/Extensions';
import type { Rectangle } from '../../../maths/shapes/Rectangle';
import type { Topology } from '../shared/geometry/const';
import type { Geometry } from '../shared/geometry/Geometry';
import type { Shader } from '../shared/shader/Shader';
import type { State } from '../shared/state/State';
import type { System } from '../shared/system/System';
import type { GPU } from './GpuDeviceSystem';
import type { GpuRenderTarget } from './renderTarget/GpuRenderTarget';
import type { BindGroup } from './shader/BindGroup';
import type { GpuProgram } from './shader/GpuProgram';
import type { WebGPURenderer } from './WebGPURenderer';
/**
* The system that handles encoding commands for the GPU.
* @memberof rendering
*/
export declare class GpuEncoderSystem implements System {
/** @ignore */
static extension: {
readonly type: readonly [ExtensionType.WebGPUSystem];
readonly name: "encoder";
readonly priority: 1;
};
commandEncoder: GPUCommandEncoder;
renderPassEncoder: GPURenderPassEncoder;
commandFinished: Promise<void>;
private _resolveCommandFinished;
private _gpu;
private _boundBindGroup;
private _boundVertexBuffer;
private _boundIndexBuffer;
private _boundPipeline;
private readonly _renderer;
constructor(renderer: WebGPURenderer);
renderStart(): void;
beginRenderPass(gpuRenderTarget: GpuRenderTarget): void;
endRenderPass(): void;
setViewport(viewport: Rectangle): void;
setPipelineFromGeometryProgramAndState(geometry: Geometry, program: GpuProgram, state: any, topology?: Topology): void;
setPipeline(pipeline: GPURenderPipeline): void;
private _setVertexBuffer;
private _setIndexBuffer;
resetBindGroup(index: number): void;
setBindGroup(index: number, bindGroup: BindGroup, program: GpuProgram): void;
setGeometry(geometry: Geometry, program: GpuProgram): void;
private _setShaderBindGroups;
private _syncBindGroup;
draw(options: {
geometry: Geometry;
shader: Shader;
state?: State;
topology?: Topology;
size?: number;
start?: number;
instanceCount?: number;
skipSync?: boolean;
}): void;
finishRenderPass(): void;
postrender(): void;
restoreRenderPass(): void;
private _clearCache;
destroy(): void;
protected contextChange(gpu: GPU): void;
}

View File

@@ -0,0 +1,173 @@
'use strict';
var Extensions = require('../../../extensions/Extensions.js');
"use strict";
class GpuEncoderSystem {
constructor(renderer) {
this._boundBindGroup = /* @__PURE__ */ Object.create(null);
this._boundVertexBuffer = /* @__PURE__ */ Object.create(null);
this._renderer = renderer;
}
renderStart() {
this.commandFinished = new Promise((resolve) => {
this._resolveCommandFinished = resolve;
});
this.commandEncoder = this._renderer.gpu.device.createCommandEncoder();
}
beginRenderPass(gpuRenderTarget) {
this.endRenderPass();
this._clearCache();
this.renderPassEncoder = this.commandEncoder.beginRenderPass(gpuRenderTarget.descriptor);
}
endRenderPass() {
if (this.renderPassEncoder) {
this.renderPassEncoder.end();
}
this.renderPassEncoder = null;
}
setViewport(viewport) {
this.renderPassEncoder.setViewport(viewport.x, viewport.y, viewport.width, viewport.height, 0, 1);
}
setPipelineFromGeometryProgramAndState(geometry, program, state, topology) {
const pipeline = this._renderer.pipeline.getPipeline(geometry, program, state, topology);
this.setPipeline(pipeline);
}
setPipeline(pipeline) {
if (this._boundPipeline === pipeline)
return;
this._boundPipeline = pipeline;
this.renderPassEncoder.setPipeline(pipeline);
}
_setVertexBuffer(index, buffer) {
if (this._boundVertexBuffer[index] === buffer)
return;
this._boundVertexBuffer[index] = buffer;
this.renderPassEncoder.setVertexBuffer(index, this._renderer.buffer.updateBuffer(buffer));
}
_setIndexBuffer(buffer) {
if (this._boundIndexBuffer === buffer)
return;
this._boundIndexBuffer = buffer;
const indexFormat = buffer.data.BYTES_PER_ELEMENT === 2 ? "uint16" : "uint32";
this.renderPassEncoder.setIndexBuffer(this._renderer.buffer.updateBuffer(buffer), indexFormat);
}
resetBindGroup(index) {
this._boundBindGroup[index] = null;
}
setBindGroup(index, bindGroup, program) {
if (this._boundBindGroup[index] === bindGroup)
return;
this._boundBindGroup[index] = bindGroup;
bindGroup._touch(this._renderer.textureGC.count);
const gpuBindGroup = this._renderer.bindGroup.getBindGroup(bindGroup, program, index);
this.renderPassEncoder.setBindGroup(index, gpuBindGroup);
}
setGeometry(geometry, program) {
const buffersToBind = this._renderer.pipeline.getBufferNamesToBind(geometry, program);
for (const i in buffersToBind) {
this._setVertexBuffer(i, geometry.attributes[buffersToBind[i]].buffer);
}
if (geometry.indexBuffer) {
this._setIndexBuffer(geometry.indexBuffer);
}
}
_setShaderBindGroups(shader, skipSync) {
for (const i in shader.groups) {
const bindGroup = shader.groups[i];
if (!skipSync) {
this._syncBindGroup(bindGroup);
}
this.setBindGroup(i, bindGroup, shader.gpuProgram);
}
}
_syncBindGroup(bindGroup) {
for (const j in bindGroup.resources) {
const resource = bindGroup.resources[j];
if (resource.isUniformGroup) {
this._renderer.ubo.updateUniformGroup(resource);
}
}
}
draw(options) {
const { geometry, shader, state, topology, size, start, instanceCount, skipSync } = options;
this.setPipelineFromGeometryProgramAndState(geometry, shader.gpuProgram, state, topology);
this.setGeometry(geometry, shader.gpuProgram);
this._setShaderBindGroups(shader, skipSync);
if (geometry.indexBuffer) {
this.renderPassEncoder.drawIndexed(
size || geometry.indexBuffer.data.length,
instanceCount || geometry.instanceCount,
start || 0
);
} else {
this.renderPassEncoder.draw(size || geometry.getSize(), instanceCount || geometry.instanceCount, start || 0);
}
}
finishRenderPass() {
if (this.renderPassEncoder) {
this.renderPassEncoder.end();
this.renderPassEncoder = null;
}
}
postrender() {
this.finishRenderPass();
this._gpu.device.queue.submit([this.commandEncoder.finish()]);
this._resolveCommandFinished();
this.commandEncoder = null;
}
// restores a render pass if finishRenderPass was called
// not optimised as really used for debugging!
// used when we want to stop drawing and log a texture..
restoreRenderPass() {
const descriptor = this._renderer.renderTarget.adaptor.getDescriptor(
this._renderer.renderTarget.renderTarget,
false,
[0, 0, 0, 1]
);
this.renderPassEncoder = this.commandEncoder.beginRenderPass(descriptor);
const boundPipeline = this._boundPipeline;
const boundVertexBuffer = { ...this._boundVertexBuffer };
const boundIndexBuffer = this._boundIndexBuffer;
const boundBindGroup = { ...this._boundBindGroup };
this._clearCache();
const viewport = this._renderer.renderTarget.viewport;
this.renderPassEncoder.setViewport(viewport.x, viewport.y, viewport.width, viewport.height, 0, 1);
this.setPipeline(boundPipeline);
for (const i in boundVertexBuffer) {
this._setVertexBuffer(i, boundVertexBuffer[i]);
}
for (const i in boundBindGroup) {
this.setBindGroup(i, boundBindGroup[i], null);
}
this._setIndexBuffer(boundIndexBuffer);
}
_clearCache() {
for (let i = 0; i < 16; i++) {
this._boundBindGroup[i] = null;
this._boundVertexBuffer[i] = null;
}
this._boundIndexBuffer = null;
this._boundPipeline = null;
}
destroy() {
this._renderer = null;
this._gpu = null;
this._boundBindGroup = null;
this._boundVertexBuffer = null;
this._boundIndexBuffer = null;
this._boundPipeline = null;
}
contextChange(gpu) {
this._gpu = gpu;
}
}
/** @ignore */
GpuEncoderSystem.extension = {
type: [Extensions.ExtensionType.WebGPUSystem],
name: "encoder",
priority: 1
};
exports.GpuEncoderSystem = GpuEncoderSystem;
//# sourceMappingURL=GpuEncoderSystem.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,171 @@
import { ExtensionType } from '../../../extensions/Extensions.mjs';
"use strict";
class GpuEncoderSystem {
constructor(renderer) {
this._boundBindGroup = /* @__PURE__ */ Object.create(null);
this._boundVertexBuffer = /* @__PURE__ */ Object.create(null);
this._renderer = renderer;
}
renderStart() {
this.commandFinished = new Promise((resolve) => {
this._resolveCommandFinished = resolve;
});
this.commandEncoder = this._renderer.gpu.device.createCommandEncoder();
}
beginRenderPass(gpuRenderTarget) {
this.endRenderPass();
this._clearCache();
this.renderPassEncoder = this.commandEncoder.beginRenderPass(gpuRenderTarget.descriptor);
}
endRenderPass() {
if (this.renderPassEncoder) {
this.renderPassEncoder.end();
}
this.renderPassEncoder = null;
}
setViewport(viewport) {
this.renderPassEncoder.setViewport(viewport.x, viewport.y, viewport.width, viewport.height, 0, 1);
}
setPipelineFromGeometryProgramAndState(geometry, program, state, topology) {
const pipeline = this._renderer.pipeline.getPipeline(geometry, program, state, topology);
this.setPipeline(pipeline);
}
setPipeline(pipeline) {
if (this._boundPipeline === pipeline)
return;
this._boundPipeline = pipeline;
this.renderPassEncoder.setPipeline(pipeline);
}
_setVertexBuffer(index, buffer) {
if (this._boundVertexBuffer[index] === buffer)
return;
this._boundVertexBuffer[index] = buffer;
this.renderPassEncoder.setVertexBuffer(index, this._renderer.buffer.updateBuffer(buffer));
}
_setIndexBuffer(buffer) {
if (this._boundIndexBuffer === buffer)
return;
this._boundIndexBuffer = buffer;
const indexFormat = buffer.data.BYTES_PER_ELEMENT === 2 ? "uint16" : "uint32";
this.renderPassEncoder.setIndexBuffer(this._renderer.buffer.updateBuffer(buffer), indexFormat);
}
resetBindGroup(index) {
this._boundBindGroup[index] = null;
}
setBindGroup(index, bindGroup, program) {
if (this._boundBindGroup[index] === bindGroup)
return;
this._boundBindGroup[index] = bindGroup;
bindGroup._touch(this._renderer.textureGC.count);
const gpuBindGroup = this._renderer.bindGroup.getBindGroup(bindGroup, program, index);
this.renderPassEncoder.setBindGroup(index, gpuBindGroup);
}
setGeometry(geometry, program) {
const buffersToBind = this._renderer.pipeline.getBufferNamesToBind(geometry, program);
for (const i in buffersToBind) {
this._setVertexBuffer(i, geometry.attributes[buffersToBind[i]].buffer);
}
if (geometry.indexBuffer) {
this._setIndexBuffer(geometry.indexBuffer);
}
}
_setShaderBindGroups(shader, skipSync) {
for (const i in shader.groups) {
const bindGroup = shader.groups[i];
if (!skipSync) {
this._syncBindGroup(bindGroup);
}
this.setBindGroup(i, bindGroup, shader.gpuProgram);
}
}
_syncBindGroup(bindGroup) {
for (const j in bindGroup.resources) {
const resource = bindGroup.resources[j];
if (resource.isUniformGroup) {
this._renderer.ubo.updateUniformGroup(resource);
}
}
}
draw(options) {
const { geometry, shader, state, topology, size, start, instanceCount, skipSync } = options;
this.setPipelineFromGeometryProgramAndState(geometry, shader.gpuProgram, state, topology);
this.setGeometry(geometry, shader.gpuProgram);
this._setShaderBindGroups(shader, skipSync);
if (geometry.indexBuffer) {
this.renderPassEncoder.drawIndexed(
size || geometry.indexBuffer.data.length,
instanceCount || geometry.instanceCount,
start || 0
);
} else {
this.renderPassEncoder.draw(size || geometry.getSize(), instanceCount || geometry.instanceCount, start || 0);
}
}
finishRenderPass() {
if (this.renderPassEncoder) {
this.renderPassEncoder.end();
this.renderPassEncoder = null;
}
}
postrender() {
this.finishRenderPass();
this._gpu.device.queue.submit([this.commandEncoder.finish()]);
this._resolveCommandFinished();
this.commandEncoder = null;
}
// restores a render pass if finishRenderPass was called
// not optimised as really used for debugging!
// used when we want to stop drawing and log a texture..
restoreRenderPass() {
const descriptor = this._renderer.renderTarget.adaptor.getDescriptor(
this._renderer.renderTarget.renderTarget,
false,
[0, 0, 0, 1]
);
this.renderPassEncoder = this.commandEncoder.beginRenderPass(descriptor);
const boundPipeline = this._boundPipeline;
const boundVertexBuffer = { ...this._boundVertexBuffer };
const boundIndexBuffer = this._boundIndexBuffer;
const boundBindGroup = { ...this._boundBindGroup };
this._clearCache();
const viewport = this._renderer.renderTarget.viewport;
this.renderPassEncoder.setViewport(viewport.x, viewport.y, viewport.width, viewport.height, 0, 1);
this.setPipeline(boundPipeline);
for (const i in boundVertexBuffer) {
this._setVertexBuffer(i, boundVertexBuffer[i]);
}
for (const i in boundBindGroup) {
this.setBindGroup(i, boundBindGroup[i], null);
}
this._setIndexBuffer(boundIndexBuffer);
}
_clearCache() {
for (let i = 0; i < 16; i++) {
this._boundBindGroup[i] = null;
this._boundVertexBuffer[i] = null;
}
this._boundIndexBuffer = null;
this._boundPipeline = null;
}
destroy() {
this._renderer = null;
this._gpu = null;
this._boundBindGroup = null;
this._boundVertexBuffer = null;
this._boundIndexBuffer = null;
this._boundPipeline = null;
}
contextChange(gpu) {
this._gpu = gpu;
}
}
/** @ignore */
GpuEncoderSystem.extension = {
type: [ExtensionType.WebGPUSystem],
name: "encoder",
priority: 1
};
export { GpuEncoderSystem };
//# sourceMappingURL=GpuEncoderSystem.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,23 @@
import { ExtensionType } from '../../../extensions/Extensions';
import { STENCIL_MODES } from '../shared/state/const';
import type { RenderTarget } from '../shared/renderTarget/RenderTarget';
import type { System } from '../shared/system/System';
import type { WebGPURenderer } from './WebGPURenderer';
/**
* This manages the stencil buffer. Used primarily for masking
* @memberof rendering
*/
export declare class GpuStencilSystem implements System {
/** @ignore */
static extension: {
readonly type: readonly [ExtensionType.WebGPUSystem];
readonly name: "stencil";
};
private readonly _renderer;
private _renderTargetStencilState;
private _activeRenderTarget;
constructor(renderer: WebGPURenderer);
protected onRenderTargetChange(renderTarget: RenderTarget): void;
setStencilMode(stencilMode: STENCIL_MODES, stencilReference: number): void;
destroy(): void;
}

View File

@@ -0,0 +1,48 @@
'use strict';
var Extensions = require('../../../extensions/Extensions.js');
var _const = require('../shared/state/const.js');
"use strict";
class GpuStencilSystem {
constructor(renderer) {
this._renderTargetStencilState = /* @__PURE__ */ Object.create(null);
this._renderer = renderer;
renderer.renderTarget.onRenderTargetChange.add(this);
}
onRenderTargetChange(renderTarget) {
let stencilState = this._renderTargetStencilState[renderTarget.uid];
if (!stencilState) {
stencilState = this._renderTargetStencilState[renderTarget.uid] = {
stencilMode: _const.STENCIL_MODES.DISABLED,
stencilReference: 0
};
}
this._activeRenderTarget = renderTarget;
this.setStencilMode(stencilState.stencilMode, stencilState.stencilReference);
}
setStencilMode(stencilMode, stencilReference) {
const stencilState = this._renderTargetStencilState[this._activeRenderTarget.uid];
stencilState.stencilMode = stencilMode;
stencilState.stencilReference = stencilReference;
const renderer = this._renderer;
renderer.pipeline.setStencilMode(stencilMode);
renderer.encoder.renderPassEncoder.setStencilReference(stencilReference);
}
destroy() {
this._renderer.renderTarget.onRenderTargetChange.remove(this);
this._renderer = null;
this._activeRenderTarget = null;
this._renderTargetStencilState = null;
}
}
/** @ignore */
GpuStencilSystem.extension = {
type: [
Extensions.ExtensionType.WebGPUSystem
],
name: "stencil"
};
exports.GpuStencilSystem = GpuStencilSystem;
//# sourceMappingURL=GpuStencilSystem.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"GpuStencilSystem.js","sources":["../../../../src/rendering/renderers/gpu/GpuStencilSystem.ts"],"sourcesContent":["import { ExtensionType } from '../../../extensions/Extensions';\nimport { STENCIL_MODES } from '../shared/state/const';\n\nimport type { RenderTarget } from '../shared/renderTarget/RenderTarget';\nimport type { System } from '../shared/system/System';\nimport type { WebGPURenderer } from './WebGPURenderer';\n\n/**\n * This manages the stencil buffer. Used primarily for masking\n * @memberof rendering\n */\nexport class GpuStencilSystem implements System\n{\n /** @ignore */\n public static extension = {\n type: [\n ExtensionType.WebGPUSystem,\n ],\n name: 'stencil',\n } as const;\n\n private readonly _renderer: WebGPURenderer;\n\n private _renderTargetStencilState: Record<number, {\n stencilMode: STENCIL_MODES;\n stencilReference: number;\n }> = Object.create(null);\n\n private _activeRenderTarget: RenderTarget;\n\n constructor(renderer: WebGPURenderer)\n {\n this._renderer = renderer;\n\n renderer.renderTarget.onRenderTargetChange.add(this);\n }\n\n protected onRenderTargetChange(renderTarget: RenderTarget)\n {\n let stencilState = this._renderTargetStencilState[renderTarget.uid];\n\n if (!stencilState)\n {\n stencilState = this._renderTargetStencilState[renderTarget.uid] = {\n stencilMode: STENCIL_MODES.DISABLED,\n stencilReference: 0,\n };\n }\n\n this._activeRenderTarget = renderTarget;\n\n this.setStencilMode(stencilState.stencilMode, stencilState.stencilReference);\n }\n\n public setStencilMode(stencilMode: STENCIL_MODES, stencilReference: number)\n {\n const stencilState = this._renderTargetStencilState[this._activeRenderTarget.uid];\n\n stencilState.stencilMode = stencilMode;\n stencilState.stencilReference = stencilReference;\n\n const renderer = this._renderer;\n\n renderer.pipeline.setStencilMode(stencilMode);\n renderer.encoder.renderPassEncoder.setStencilReference(stencilReference);\n }\n\n public destroy()\n {\n this._renderer.renderTarget.onRenderTargetChange.remove(this);\n\n (this._renderer as null) = null;\n\n this._activeRenderTarget = null;\n this._renderTargetStencilState = null;\n }\n}\n"],"names":["STENCIL_MODES","ExtensionType"],"mappings":";;;;;;AAWO,MAAM,gBACb,CAAA;AAAA,EAkBI,YAAY,QACZ,EAAA;AARA,IAAQ,IAAA,CAAA,yBAAA,mBAGI,MAAA,CAAA,MAAA,CAAO,IAAI,CAAA,CAAA;AAMnB,IAAA,IAAA,CAAK,SAAY,GAAA,QAAA,CAAA;AAEjB,IAAS,QAAA,CAAA,YAAA,CAAa,oBAAqB,CAAA,GAAA,CAAI,IAAI,CAAA,CAAA;AAAA,GACvD;AAAA,EAEU,qBAAqB,YAC/B,EAAA;AACI,IAAA,IAAI,YAAe,GAAA,IAAA,CAAK,yBAA0B,CAAA,YAAA,CAAa,GAAG,CAAA,CAAA;AAElE,IAAA,IAAI,CAAC,YACL,EAAA;AACI,MAAA,YAAA,GAAe,IAAK,CAAA,yBAAA,CAA0B,YAAa,CAAA,GAAG,CAAI,GAAA;AAAA,QAC9D,aAAaA,oBAAc,CAAA,QAAA;AAAA,QAC3B,gBAAkB,EAAA,CAAA;AAAA,OACtB,CAAA;AAAA,KACJ;AAEA,IAAA,IAAA,CAAK,mBAAsB,GAAA,YAAA,CAAA;AAE3B,IAAA,IAAA,CAAK,cAAe,CAAA,YAAA,CAAa,WAAa,EAAA,YAAA,CAAa,gBAAgB,CAAA,CAAA;AAAA,GAC/E;AAAA,EAEO,cAAA,CAAe,aAA4B,gBAClD,EAAA;AACI,IAAA,MAAM,YAAe,GAAA,IAAA,CAAK,yBAA0B,CAAA,IAAA,CAAK,oBAAoB,GAAG,CAAA,CAAA;AAEhF,IAAA,YAAA,CAAa,WAAc,GAAA,WAAA,CAAA;AAC3B,IAAA,YAAA,CAAa,gBAAmB,GAAA,gBAAA,CAAA;AAEhC,IAAA,MAAM,WAAW,IAAK,CAAA,SAAA,CAAA;AAEtB,IAAS,QAAA,CAAA,QAAA,CAAS,eAAe,WAAW,CAAA,CAAA;AAC5C,IAAS,QAAA,CAAA,OAAA,CAAQ,iBAAkB,CAAA,mBAAA,CAAoB,gBAAgB,CAAA,CAAA;AAAA,GAC3E;AAAA,EAEO,OACP,GAAA;AACI,IAAA,IAAA,CAAK,SAAU,CAAA,YAAA,CAAa,oBAAqB,CAAA,MAAA,CAAO,IAAI,CAAA,CAAA;AAE5D,IAAC,KAAK,SAAqB,GAAA,IAAA,CAAA;AAE3B,IAAA,IAAA,CAAK,mBAAsB,GAAA,IAAA,CAAA;AAC3B,IAAA,IAAA,CAAK,yBAA4B,GAAA,IAAA,CAAA;AAAA,GACrC;AACJ,CAAA;AAAA;AAjEa,gBAAA,CAGK,SAAY,GAAA;AAAA,EACtB,IAAM,EAAA;AAAA,IACFC,wBAAc,CAAA,YAAA;AAAA,GAClB;AAAA,EACA,IAAM,EAAA,SAAA;AACV,CAAA;;;;"}

View File

@@ -0,0 +1,46 @@
import { ExtensionType } from '../../../extensions/Extensions.mjs';
import { STENCIL_MODES } from '../shared/state/const.mjs';
"use strict";
class GpuStencilSystem {
constructor(renderer) {
this._renderTargetStencilState = /* @__PURE__ */ Object.create(null);
this._renderer = renderer;
renderer.renderTarget.onRenderTargetChange.add(this);
}
onRenderTargetChange(renderTarget) {
let stencilState = this._renderTargetStencilState[renderTarget.uid];
if (!stencilState) {
stencilState = this._renderTargetStencilState[renderTarget.uid] = {
stencilMode: STENCIL_MODES.DISABLED,
stencilReference: 0
};
}
this._activeRenderTarget = renderTarget;
this.setStencilMode(stencilState.stencilMode, stencilState.stencilReference);
}
setStencilMode(stencilMode, stencilReference) {
const stencilState = this._renderTargetStencilState[this._activeRenderTarget.uid];
stencilState.stencilMode = stencilMode;
stencilState.stencilReference = stencilReference;
const renderer = this._renderer;
renderer.pipeline.setStencilMode(stencilMode);
renderer.encoder.renderPassEncoder.setStencilReference(stencilReference);
}
destroy() {
this._renderer.renderTarget.onRenderTargetChange.remove(this);
this._renderer = null;
this._activeRenderTarget = null;
this._renderTargetStencilState = null;
}
}
/** @ignore */
GpuStencilSystem.extension = {
type: [
ExtensionType.WebGPUSystem
],
name: "stencil"
};
export { GpuStencilSystem };
//# sourceMappingURL=GpuStencilSystem.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"GpuStencilSystem.mjs","sources":["../../../../src/rendering/renderers/gpu/GpuStencilSystem.ts"],"sourcesContent":["import { ExtensionType } from '../../../extensions/Extensions';\nimport { STENCIL_MODES } from '../shared/state/const';\n\nimport type { RenderTarget } from '../shared/renderTarget/RenderTarget';\nimport type { System } from '../shared/system/System';\nimport type { WebGPURenderer } from './WebGPURenderer';\n\n/**\n * This manages the stencil buffer. Used primarily for masking\n * @memberof rendering\n */\nexport class GpuStencilSystem implements System\n{\n /** @ignore */\n public static extension = {\n type: [\n ExtensionType.WebGPUSystem,\n ],\n name: 'stencil',\n } as const;\n\n private readonly _renderer: WebGPURenderer;\n\n private _renderTargetStencilState: Record<number, {\n stencilMode: STENCIL_MODES;\n stencilReference: number;\n }> = Object.create(null);\n\n private _activeRenderTarget: RenderTarget;\n\n constructor(renderer: WebGPURenderer)\n {\n this._renderer = renderer;\n\n renderer.renderTarget.onRenderTargetChange.add(this);\n }\n\n protected onRenderTargetChange(renderTarget: RenderTarget)\n {\n let stencilState = this._renderTargetStencilState[renderTarget.uid];\n\n if (!stencilState)\n {\n stencilState = this._renderTargetStencilState[renderTarget.uid] = {\n stencilMode: STENCIL_MODES.DISABLED,\n stencilReference: 0,\n };\n }\n\n this._activeRenderTarget = renderTarget;\n\n this.setStencilMode(stencilState.stencilMode, stencilState.stencilReference);\n }\n\n public setStencilMode(stencilMode: STENCIL_MODES, stencilReference: number)\n {\n const stencilState = this._renderTargetStencilState[this._activeRenderTarget.uid];\n\n stencilState.stencilMode = stencilMode;\n stencilState.stencilReference = stencilReference;\n\n const renderer = this._renderer;\n\n renderer.pipeline.setStencilMode(stencilMode);\n renderer.encoder.renderPassEncoder.setStencilReference(stencilReference);\n }\n\n public destroy()\n {\n this._renderer.renderTarget.onRenderTargetChange.remove(this);\n\n (this._renderer as null) = null;\n\n this._activeRenderTarget = null;\n this._renderTargetStencilState = null;\n }\n}\n"],"names":[],"mappings":";;;;AAWO,MAAM,gBACb,CAAA;AAAA,EAkBI,YAAY,QACZ,EAAA;AARA,IAAQ,IAAA,CAAA,yBAAA,mBAGI,MAAA,CAAA,MAAA,CAAO,IAAI,CAAA,CAAA;AAMnB,IAAA,IAAA,CAAK,SAAY,GAAA,QAAA,CAAA;AAEjB,IAAS,QAAA,CAAA,YAAA,CAAa,oBAAqB,CAAA,GAAA,CAAI,IAAI,CAAA,CAAA;AAAA,GACvD;AAAA,EAEU,qBAAqB,YAC/B,EAAA;AACI,IAAA,IAAI,YAAe,GAAA,IAAA,CAAK,yBAA0B,CAAA,YAAA,CAAa,GAAG,CAAA,CAAA;AAElE,IAAA,IAAI,CAAC,YACL,EAAA;AACI,MAAA,YAAA,GAAe,IAAK,CAAA,yBAAA,CAA0B,YAAa,CAAA,GAAG,CAAI,GAAA;AAAA,QAC9D,aAAa,aAAc,CAAA,QAAA;AAAA,QAC3B,gBAAkB,EAAA,CAAA;AAAA,OACtB,CAAA;AAAA,KACJ;AAEA,IAAA,IAAA,CAAK,mBAAsB,GAAA,YAAA,CAAA;AAE3B,IAAA,IAAA,CAAK,cAAe,CAAA,YAAA,CAAa,WAAa,EAAA,YAAA,CAAa,gBAAgB,CAAA,CAAA;AAAA,GAC/E;AAAA,EAEO,cAAA,CAAe,aAA4B,gBAClD,EAAA;AACI,IAAA,MAAM,YAAe,GAAA,IAAA,CAAK,yBAA0B,CAAA,IAAA,CAAK,oBAAoB,GAAG,CAAA,CAAA;AAEhF,IAAA,YAAA,CAAa,WAAc,GAAA,WAAA,CAAA;AAC3B,IAAA,YAAA,CAAa,gBAAmB,GAAA,gBAAA,CAAA;AAEhC,IAAA,MAAM,WAAW,IAAK,CAAA,SAAA,CAAA;AAEtB,IAAS,QAAA,CAAA,QAAA,CAAS,eAAe,WAAW,CAAA,CAAA;AAC5C,IAAS,QAAA,CAAA,OAAA,CAAQ,iBAAkB,CAAA,mBAAA,CAAoB,gBAAgB,CAAA,CAAA;AAAA,GAC3E;AAAA,EAEO,OACP,GAAA;AACI,IAAA,IAAA,CAAK,SAAU,CAAA,YAAA,CAAa,oBAAqB,CAAA,MAAA,CAAO,IAAI,CAAA,CAAA;AAE5D,IAAC,KAAK,SAAqB,GAAA,IAAA,CAAA;AAE3B,IAAA,IAAA,CAAK,mBAAsB,GAAA,IAAA,CAAA;AAC3B,IAAA,IAAA,CAAK,yBAA4B,GAAA,IAAA,CAAA;AAAA,GACrC;AACJ,CAAA;AAAA;AAjEa,gBAAA,CAGK,SAAY,GAAA;AAAA,EACtB,IAAM,EAAA;AAAA,IACF,aAAc,CAAA,YAAA;AAAA,GAClB;AAAA,EACA,IAAM,EAAA,SAAA;AACV,CAAA;;;;"}

View File

@@ -0,0 +1,14 @@
import { ExtensionType } from '../../../extensions/Extensions';
import { UboSystem } from '../shared/shader/UboSystem';
/**
* System plugin to the renderer to manage uniform buffers. With a WGSL twist!
* @memberof rendering
*/
export declare class GpuUboSystem extends UboSystem {
/** @ignore */
static extension: {
readonly type: readonly [ExtensionType.WebGPUSystem];
readonly name: "ubo";
};
constructor();
}

View File

@@ -0,0 +1,24 @@
'use strict';
var Extensions = require('../../../extensions/Extensions.js');
var UboSystem = require('../shared/shader/UboSystem.js');
var createUboElementsWGSL = require('./shader/utils/createUboElementsWGSL.js');
var createUboSyncFunctionWGSL = require('./shader/utils/createUboSyncFunctionWGSL.js');
"use strict";
class GpuUboSystem extends UboSystem.UboSystem {
constructor() {
super({
createUboElements: createUboElementsWGSL.createUboElementsWGSL,
generateUboSync: createUboSyncFunctionWGSL.createUboSyncFunctionWGSL
});
}
}
/** @ignore */
GpuUboSystem.extension = {
type: [Extensions.ExtensionType.WebGPUSystem],
name: "ubo"
};
exports.GpuUboSystem = GpuUboSystem;
//# sourceMappingURL=GpuUboSystem.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"GpuUboSystem.js","sources":["../../../../src/rendering/renderers/gpu/GpuUboSystem.ts"],"sourcesContent":["import { ExtensionType } from '../../../extensions/Extensions';\nimport { UboSystem } from '../shared/shader/UboSystem';\nimport { createUboElementsWGSL } from './shader/utils/createUboElementsWGSL';\nimport { createUboSyncFunctionWGSL } from './shader/utils/createUboSyncFunctionWGSL';\n\n/**\n * System plugin to the renderer to manage uniform buffers. With a WGSL twist!\n * @memberof rendering\n */\nexport class GpuUboSystem extends UboSystem\n{\n /** @ignore */\n public static extension = {\n type: [ExtensionType.WebGPUSystem],\n name: 'ubo',\n } as const;\n\n constructor()\n {\n super({\n createUboElements: createUboElementsWGSL,\n generateUboSync: createUboSyncFunctionWGSL,\n });\n }\n}\n"],"names":["UboSystem","createUboElementsWGSL","createUboSyncFunctionWGSL","ExtensionType"],"mappings":";;;;;;;;AASO,MAAM,qBAAqBA,mBAClC,CAAA;AAAA,EAOI,WACA,GAAA;AACI,IAAM,KAAA,CAAA;AAAA,MACF,iBAAmB,EAAAC,2CAAA;AAAA,MACnB,eAAiB,EAAAC,mDAAA;AAAA,KACpB,CAAA,CAAA;AAAA,GACL;AACJ,CAAA;AAAA;AAfa,YAAA,CAGK,SAAY,GAAA;AAAA,EACtB,IAAA,EAAM,CAACC,wBAAA,CAAc,YAAY,CAAA;AAAA,EACjC,IAAM,EAAA,KAAA;AACV,CAAA;;;;"}

View File

@@ -0,0 +1,22 @@
import { ExtensionType } from '../../../extensions/Extensions.mjs';
import { UboSystem } from '../shared/shader/UboSystem.mjs';
import { createUboElementsWGSL } from './shader/utils/createUboElementsWGSL.mjs';
import { createUboSyncFunctionWGSL } from './shader/utils/createUboSyncFunctionWGSL.mjs';
"use strict";
class GpuUboSystem extends UboSystem {
constructor() {
super({
createUboElements: createUboElementsWGSL,
generateUboSync: createUboSyncFunctionWGSL
});
}
}
/** @ignore */
GpuUboSystem.extension = {
type: [ExtensionType.WebGPUSystem],
name: "ubo"
};
export { GpuUboSystem };
//# sourceMappingURL=GpuUboSystem.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"GpuUboSystem.mjs","sources":["../../../../src/rendering/renderers/gpu/GpuUboSystem.ts"],"sourcesContent":["import { ExtensionType } from '../../../extensions/Extensions';\nimport { UboSystem } from '../shared/shader/UboSystem';\nimport { createUboElementsWGSL } from './shader/utils/createUboElementsWGSL';\nimport { createUboSyncFunctionWGSL } from './shader/utils/createUboSyncFunctionWGSL';\n\n/**\n * System plugin to the renderer to manage uniform buffers. With a WGSL twist!\n * @memberof rendering\n */\nexport class GpuUboSystem extends UboSystem\n{\n /** @ignore */\n public static extension = {\n type: [ExtensionType.WebGPUSystem],\n name: 'ubo',\n } as const;\n\n constructor()\n {\n super({\n createUboElements: createUboElementsWGSL,\n generateUboSync: createUboSyncFunctionWGSL,\n });\n }\n}\n"],"names":[],"mappings":";;;;;;AASO,MAAM,qBAAqB,SAClC,CAAA;AAAA,EAOI,WACA,GAAA;AACI,IAAM,KAAA,CAAA;AAAA,MACF,iBAAmB,EAAA,qBAAA;AAAA,MACnB,eAAiB,EAAA,yBAAA;AAAA,KACpB,CAAA,CAAA;AAAA,GACL;AACJ,CAAA;AAAA;AAfa,YAAA,CAGK,SAAY,GAAA;AAAA,EACtB,IAAA,EAAM,CAAC,aAAA,CAAc,YAAY,CAAA;AAAA,EACjC,IAAM,EAAA,KAAA;AACV,CAAA;;;;"}

View File

@@ -0,0 +1,29 @@
import { ExtensionType } from '../../../extensions/Extensions';
import { BufferResource } from '../shared/buffer/BufferResource';
import { BindGroup } from './shader/BindGroup';
import type { UniformGroup } from '../shared/shader/UniformGroup';
import type { WebGPURenderer } from './WebGPURenderer';
export declare class GpuUniformBatchPipe {
/** @ignore */
static extension: {
readonly type: readonly [ExtensionType.WebGPUPipes];
readonly name: "uniformBatch";
};
private _renderer;
private _bindGroupHash;
private readonly _batchBuffer;
private _buffers;
private _bindGroups;
private _bufferResources;
constructor(renderer: WebGPURenderer);
renderEnd(): void;
private _resetBindGroups;
getUniformBindGroup(group: UniformGroup<any>, duplicate: boolean): BindGroup;
getUboResource(group: UniformGroup<any>): BufferResource;
getArrayBindGroup(data: Float32Array): BindGroup;
getArrayBufferResource(data: Float32Array): BufferResource;
private _getBufferResource;
private _getBindGroup;
private _uploadBindGroups;
destroy(): void;
}

View File

@@ -0,0 +1,135 @@
'use strict';
var Extensions = require('../../../extensions/Extensions.js');
var Buffer = require('../shared/buffer/Buffer.js');
var BufferResource = require('../shared/buffer/BufferResource.js');
var _const = require('../shared/buffer/const.js');
var UboBatch = require('./buffer/UboBatch.js');
var BindGroup = require('./shader/BindGroup.js');
"use strict";
const minUniformOffsetAlignment = 128;
class GpuUniformBatchPipe {
constructor(renderer) {
this._bindGroupHash = /* @__PURE__ */ Object.create(null);
// number of buffers..
this._buffers = [];
this._bindGroups = [];
this._bufferResources = [];
this._renderer = renderer;
this._batchBuffer = new UboBatch.UboBatch({ minUniformOffsetAlignment });
const totalBuffers = 256 / minUniformOffsetAlignment;
for (let i = 0; i < totalBuffers; i++) {
let usage = _const.BufferUsage.UNIFORM | _const.BufferUsage.COPY_DST;
if (i === 0)
usage |= _const.BufferUsage.COPY_SRC;
this._buffers.push(new Buffer.Buffer({
data: this._batchBuffer.data,
usage
}));
}
}
renderEnd() {
this._uploadBindGroups();
this._resetBindGroups();
}
_resetBindGroups() {
for (const i in this._bindGroupHash) {
this._bindGroupHash[i] = null;
}
this._batchBuffer.clear();
}
// just works for single bind groups for now
getUniformBindGroup(group, duplicate) {
if (!duplicate && this._bindGroupHash[group.uid]) {
return this._bindGroupHash[group.uid];
}
this._renderer.ubo.ensureUniformGroup(group);
const data = group.buffer.data;
const offset = this._batchBuffer.addEmptyGroup(data.length);
this._renderer.ubo.syncUniformGroup(group, this._batchBuffer.data, offset / 4);
this._bindGroupHash[group.uid] = this._getBindGroup(offset / minUniformOffsetAlignment);
return this._bindGroupHash[group.uid];
}
getUboResource(group) {
this._renderer.ubo.updateUniformGroup(group);
const data = group.buffer.data;
const offset = this._batchBuffer.addGroup(data);
return this._getBufferResource(offset / minUniformOffsetAlignment);
}
getArrayBindGroup(data) {
const offset = this._batchBuffer.addGroup(data);
return this._getBindGroup(offset / minUniformOffsetAlignment);
}
getArrayBufferResource(data) {
const offset = this._batchBuffer.addGroup(data);
const index = offset / minUniformOffsetAlignment;
return this._getBufferResource(index);
}
_getBufferResource(index) {
if (!this._bufferResources[index]) {
const buffer = this._buffers[index % 2];
this._bufferResources[index] = new BufferResource.BufferResource({
buffer,
offset: (index / 2 | 0) * 256,
size: minUniformOffsetAlignment
});
}
return this._bufferResources[index];
}
_getBindGroup(index) {
if (!this._bindGroups[index]) {
const bindGroup = new BindGroup.BindGroup({
0: this._getBufferResource(index)
});
this._bindGroups[index] = bindGroup;
}
return this._bindGroups[index];
}
_uploadBindGroups() {
const bufferSystem = this._renderer.buffer;
const firstBuffer = this._buffers[0];
firstBuffer.update(this._batchBuffer.byteIndex);
bufferSystem.updateBuffer(firstBuffer);
const commandEncoder = this._renderer.gpu.device.createCommandEncoder();
for (let i = 1; i < this._buffers.length; i++) {
const buffer = this._buffers[i];
commandEncoder.copyBufferToBuffer(
bufferSystem.getGPUBuffer(firstBuffer),
minUniformOffsetAlignment,
bufferSystem.getGPUBuffer(buffer),
0,
this._batchBuffer.byteIndex
);
}
this._renderer.gpu.device.queue.submit([commandEncoder.finish()]);
}
destroy() {
for (let i = 0; i < this._bindGroups.length; i++) {
this._bindGroups[i].destroy();
}
this._bindGroups = null;
this._bindGroupHash = null;
for (let i = 0; i < this._buffers.length; i++) {
this._buffers[i].destroy();
}
this._buffers = null;
for (let i = 0; i < this._bufferResources.length; i++) {
this._bufferResources[i].destroy();
}
this._bufferResources = null;
this._batchBuffer.destroy();
this._bindGroupHash = null;
this._renderer = null;
}
}
/** @ignore */
GpuUniformBatchPipe.extension = {
type: [
Extensions.ExtensionType.WebGPUPipes
],
name: "uniformBatch"
};
exports.GpuUniformBatchPipe = GpuUniformBatchPipe;
//# sourceMappingURL=GpuUniformBatchPipe.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,133 @@
import { ExtensionType } from '../../../extensions/Extensions.mjs';
import { Buffer } from '../shared/buffer/Buffer.mjs';
import { BufferResource } from '../shared/buffer/BufferResource.mjs';
import { BufferUsage } from '../shared/buffer/const.mjs';
import { UboBatch } from './buffer/UboBatch.mjs';
import { BindGroup } from './shader/BindGroup.mjs';
"use strict";
const minUniformOffsetAlignment = 128;
class GpuUniformBatchPipe {
constructor(renderer) {
this._bindGroupHash = /* @__PURE__ */ Object.create(null);
// number of buffers..
this._buffers = [];
this._bindGroups = [];
this._bufferResources = [];
this._renderer = renderer;
this._batchBuffer = new UboBatch({ minUniformOffsetAlignment });
const totalBuffers = 256 / minUniformOffsetAlignment;
for (let i = 0; i < totalBuffers; i++) {
let usage = BufferUsage.UNIFORM | BufferUsage.COPY_DST;
if (i === 0)
usage |= BufferUsage.COPY_SRC;
this._buffers.push(new Buffer({
data: this._batchBuffer.data,
usage
}));
}
}
renderEnd() {
this._uploadBindGroups();
this._resetBindGroups();
}
_resetBindGroups() {
for (const i in this._bindGroupHash) {
this._bindGroupHash[i] = null;
}
this._batchBuffer.clear();
}
// just works for single bind groups for now
getUniformBindGroup(group, duplicate) {
if (!duplicate && this._bindGroupHash[group.uid]) {
return this._bindGroupHash[group.uid];
}
this._renderer.ubo.ensureUniformGroup(group);
const data = group.buffer.data;
const offset = this._batchBuffer.addEmptyGroup(data.length);
this._renderer.ubo.syncUniformGroup(group, this._batchBuffer.data, offset / 4);
this._bindGroupHash[group.uid] = this._getBindGroup(offset / minUniformOffsetAlignment);
return this._bindGroupHash[group.uid];
}
getUboResource(group) {
this._renderer.ubo.updateUniformGroup(group);
const data = group.buffer.data;
const offset = this._batchBuffer.addGroup(data);
return this._getBufferResource(offset / minUniformOffsetAlignment);
}
getArrayBindGroup(data) {
const offset = this._batchBuffer.addGroup(data);
return this._getBindGroup(offset / minUniformOffsetAlignment);
}
getArrayBufferResource(data) {
const offset = this._batchBuffer.addGroup(data);
const index = offset / minUniformOffsetAlignment;
return this._getBufferResource(index);
}
_getBufferResource(index) {
if (!this._bufferResources[index]) {
const buffer = this._buffers[index % 2];
this._bufferResources[index] = new BufferResource({
buffer,
offset: (index / 2 | 0) * 256,
size: minUniformOffsetAlignment
});
}
return this._bufferResources[index];
}
_getBindGroup(index) {
if (!this._bindGroups[index]) {
const bindGroup = new BindGroup({
0: this._getBufferResource(index)
});
this._bindGroups[index] = bindGroup;
}
return this._bindGroups[index];
}
_uploadBindGroups() {
const bufferSystem = this._renderer.buffer;
const firstBuffer = this._buffers[0];
firstBuffer.update(this._batchBuffer.byteIndex);
bufferSystem.updateBuffer(firstBuffer);
const commandEncoder = this._renderer.gpu.device.createCommandEncoder();
for (let i = 1; i < this._buffers.length; i++) {
const buffer = this._buffers[i];
commandEncoder.copyBufferToBuffer(
bufferSystem.getGPUBuffer(firstBuffer),
minUniformOffsetAlignment,
bufferSystem.getGPUBuffer(buffer),
0,
this._batchBuffer.byteIndex
);
}
this._renderer.gpu.device.queue.submit([commandEncoder.finish()]);
}
destroy() {
for (let i = 0; i < this._bindGroups.length; i++) {
this._bindGroups[i].destroy();
}
this._bindGroups = null;
this._bindGroupHash = null;
for (let i = 0; i < this._buffers.length; i++) {
this._buffers[i].destroy();
}
this._buffers = null;
for (let i = 0; i < this._bufferResources.length; i++) {
this._bufferResources[i].destroy();
}
this._bufferResources = null;
this._batchBuffer.destroy();
this._bindGroupHash = null;
this._renderer = null;
}
}
/** @ignore */
GpuUniformBatchPipe.extension = {
type: [
ExtensionType.WebGPUPipes
],
name: "uniformBatch"
};
export { GpuUniformBatchPipe };
//# sourceMappingURL=GpuUniformBatchPipe.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,93 @@
import { AbstractRenderer } from '../shared/system/AbstractRenderer';
import { BindGroupSystem } from './BindGroupSystem';
import { GpuBufferSystem } from './buffer/GpuBufferSystem';
import { GpuColorMaskSystem } from './GpuColorMaskSystem';
import { type GPU, GpuDeviceSystem } from './GpuDeviceSystem';
import { GpuEncoderSystem } from './GpuEncoderSystem';
import { GpuStencilSystem } from './GpuStencilSystem';
import { GpuUboSystem } from './GpuUboSystem';
import { GpuUniformBatchPipe } from './GpuUniformBatchPipe';
import { PipelineSystem } from './pipeline/PipelineSystem';
import { GpuRenderTargetSystem } from './renderTarget/GpuRenderTargetSystem';
import { GpuShaderSystem } from './shader/GpuShaderSystem';
import { GpuStateSystem } from './state/GpuStateSystem';
import { GpuTextureSystem } from './texture/GpuTextureSystem';
import type { ICanvas } from '../../../environment/canvas/ICanvas';
import type { SharedRendererOptions } from '../shared/system/SharedSystems';
import type { ExtractRendererOptions, ExtractSystemTypes } from '../shared/system/utils/typeUtils';
declare const DefaultWebGPUSystems: (typeof import("../..").BackgroundSystem | typeof import("../..").GenerateTextureSystem | typeof import("../..").GlobalUniformSystem | typeof import("../..").HelloSystem | typeof import("../..").ViewSystem | typeof import("../../..").RenderGroupSystem | typeof import("../..").TextureGCSystem | typeof import("../..").ExtractSystem | typeof import("../../..").RendererInitHook | typeof import("../..").RenderableGCSystem | typeof import("../..").SchedulerSystem | typeof GpuUboSystem | typeof GpuEncoderSystem | typeof GpuDeviceSystem | typeof GpuBufferSystem | typeof GpuTextureSystem | typeof GpuRenderTargetSystem | typeof GpuShaderSystem | typeof GpuStateSystem | typeof PipelineSystem | typeof GpuColorMaskSystem | typeof GpuStencilSystem | typeof BindGroupSystem)[];
declare const DefaultWebGPUPipes: (typeof import("../..").BlendModePipe | typeof import("../..").BatcherPipe | typeof import("../../..").SpritePipe | typeof import("../../..").RenderGroupPipe | typeof import("../..").AlphaMaskPipe | typeof import("../..").StencilMaskPipe | typeof import("../..").ColorMaskPipe | typeof import("../../..").CustomRenderPipe | typeof GpuUniformBatchPipe)[];
type WebGPUSystems = ExtractSystemTypes<typeof DefaultWebGPUSystems> & PixiMixins.RendererSystems & PixiMixins.WebGPUSystems;
export type WebGPUPipes = ExtractSystemTypes<typeof DefaultWebGPUPipes> & PixiMixins.RendererPipes & PixiMixins.WebGPUPipes;
/**
* Options for WebGPURenderer.
* @memberof rendering
*/
export interface WebGPUOptions extends SharedRendererOptions, ExtractRendererOptions<typeof DefaultWebGPUSystems>, PixiMixins.WebGPUOptions {
}
export interface WebGPURenderer<T extends ICanvas = HTMLCanvasElement> extends AbstractRenderer<WebGPUPipes, WebGPUOptions, T>, WebGPUSystems {
}
/**
* The WebGPU PixiJS Renderer. This renderer allows you to use the next-generation graphics API, WebGPU.
* ```ts
* // Create a new renderer
* const renderer = new WebGPURenderer();
* await renderer.init();
*
* // Add the renderer to the stage
* document.body.appendChild(renderer.canvas);
*
* // Create a new stage
* const stage = new Container();
*
* // Render the stage
* renderer.render(stage);
* ```
*
* You can use {@link rendering.autoDetectRenderer} to create a renderer that will automatically detect the best
* renderer for the environment.
* ```ts
* // Create a new renderer
* const renderer = await rendering.autoDetectRenderer();
* ```
*
* The renderer is composed of systems that manage specific tasks. The following systems are added by default
* whenever you create a WebGPU renderer:
*
* | WebGPU Core Systems | Systems that are specific to the WebGL renderer |
* | ---------------------------------------- | ----------------------------------------------------------------------------- |
* | {@link rendering.GpuUboSystem} | This manages WebGPU uniform buffer objects feature for shaders |
* | {@link rendering.GpuEncoderSystem} | This manages the WebGPU command encoder |
* | {@link rendering.GpuDeviceSystem} | This manages the WebGPU Device and its extensions |
* | {@link rendering.GpuBufferSystem} | This manages buffers and their GPU resources, keeps everything in sync |
* | {@link rendering.GpuTextureSystem} | This manages textures and their GPU resources, keeps everything in sync |
* | {@link rendering.GpuRenderTargetSystem} | This manages what we render too. For example the screen, or another texture |
* | {@link rendering.GpuShaderSystem} | This manages shaders, programs that run on the GPU to output lovely pixels |
* | {@link rendering.GpuStateSystem} | This manages the state of the WebGPU Pipelines. eg the various flags that can be set blend modes / depthTesting etc |
* | {@link rendering.PipelineSystem} | This manages the WebGPU pipelines, used for rendering |
* | {@link rendering.GpuColorMaskSystem} | This manages the color mask. Used for color masking |
* | {@link rendering.GpuStencilSystem} | This manages the stencil buffer. Used primarily for masking |
* | {@link rendering.BindGroupSystem} | This manages the WebGPU bind groups. this is how data is bound to a shader when rendering |
*
* The breadth of the API surface provided by the renderer is contained within these systems.
* @memberof rendering
* @property {rendering.GpuUboSystem} ubo - UboSystem instance.
* @property {rendering.GpuEncoderSystem} encoder - EncoderSystem instance.
* @property {rendering.GpuDeviceSystem} device - DeviceSystem instance.
* @property {rendering.GpuBufferSystem} buffer - BufferSystem instance.
* @property {rendering.GpuTextureSystem} texture - TextureSystem instance.
* @property {rendering.GpuRenderTargetSystem} renderTarget - RenderTargetSystem instance.
* @property {rendering.GpuShaderSystem} shader - ShaderSystem instance.
* @property {rendering.GpuStateSystem} state - StateSystem instance.
* @property {rendering.PipelineSystem} pipeline - PipelineSystem instance.
* @property {rendering.GpuColorMaskSystem} colorMask - ColorMaskSystem instance.
* @property {rendering.GpuStencilSystem} stencil - StencilSystem instance.
* @property {rendering.BindGroupSystem} bindGroup - BindGroupSystem instance.
* @extends rendering.AbstractRenderer
*/
export declare class WebGPURenderer<T extends ICanvas = HTMLCanvasElement> extends AbstractRenderer<WebGPUPipes, WebGPUOptions, T> implements WebGPUSystems {
/** The WebGPU Device. */
gpu: GPU;
constructor();
}
export {};

View File

@@ -0,0 +1,63 @@
'use strict';
var Extensions = require('../../../extensions/Extensions.js');
var GpuGraphicsAdaptor = require('../../../scene/graphics/gpu/GpuGraphicsAdaptor.js');
var GpuMeshAdapter = require('../../../scene/mesh/gpu/GpuMeshAdapter.js');
var GpuBatchAdaptor = require('../../batcher/gpu/GpuBatchAdaptor.js');
var AbstractRenderer = require('../shared/system/AbstractRenderer.js');
var SharedSystems = require('../shared/system/SharedSystems.js');
var types = require('../types.js');
var BindGroupSystem = require('./BindGroupSystem.js');
var GpuBufferSystem = require('./buffer/GpuBufferSystem.js');
var GpuColorMaskSystem = require('./GpuColorMaskSystem.js');
var GpuDeviceSystem = require('./GpuDeviceSystem.js');
var GpuEncoderSystem = require('./GpuEncoderSystem.js');
var GpuStencilSystem = require('./GpuStencilSystem.js');
var GpuUboSystem = require('./GpuUboSystem.js');
var GpuUniformBatchPipe = require('./GpuUniformBatchPipe.js');
var PipelineSystem = require('./pipeline/PipelineSystem.js');
var GpuRenderTargetSystem = require('./renderTarget/GpuRenderTargetSystem.js');
var GpuShaderSystem = require('./shader/GpuShaderSystem.js');
var GpuStateSystem = require('./state/GpuStateSystem.js');
var GpuTextureSystem = require('./texture/GpuTextureSystem.js');
"use strict";
const DefaultWebGPUSystems = [
...SharedSystems.SharedSystems,
GpuUboSystem.GpuUboSystem,
GpuEncoderSystem.GpuEncoderSystem,
GpuDeviceSystem.GpuDeviceSystem,
GpuBufferSystem.GpuBufferSystem,
GpuTextureSystem.GpuTextureSystem,
GpuRenderTargetSystem.GpuRenderTargetSystem,
GpuShaderSystem.GpuShaderSystem,
GpuStateSystem.GpuStateSystem,
PipelineSystem.PipelineSystem,
GpuColorMaskSystem.GpuColorMaskSystem,
GpuStencilSystem.GpuStencilSystem,
BindGroupSystem.BindGroupSystem
];
const DefaultWebGPUPipes = [...SharedSystems.SharedRenderPipes, GpuUniformBatchPipe.GpuUniformBatchPipe];
const DefaultWebGPUAdapters = [GpuBatchAdaptor.GpuBatchAdaptor, GpuMeshAdapter.GpuMeshAdapter, GpuGraphicsAdaptor.GpuGraphicsAdaptor];
const systems = [];
const renderPipes = [];
const renderPipeAdaptors = [];
Extensions.extensions.handleByNamedList(Extensions.ExtensionType.WebGPUSystem, systems);
Extensions.extensions.handleByNamedList(Extensions.ExtensionType.WebGPUPipes, renderPipes);
Extensions.extensions.handleByNamedList(Extensions.ExtensionType.WebGPUPipesAdaptor, renderPipeAdaptors);
Extensions.extensions.add(...DefaultWebGPUSystems, ...DefaultWebGPUPipes, ...DefaultWebGPUAdapters);
class WebGPURenderer extends AbstractRenderer.AbstractRenderer {
constructor() {
const systemConfig = {
name: "webgpu",
type: types.RendererType.WEBGPU,
systems,
renderPipes,
renderPipeAdaptors
};
super(systemConfig);
}
}
exports.WebGPURenderer = WebGPURenderer;
//# sourceMappingURL=WebGPURenderer.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,61 @@
import { extensions, ExtensionType } from '../../../extensions/Extensions.mjs';
import { GpuGraphicsAdaptor } from '../../../scene/graphics/gpu/GpuGraphicsAdaptor.mjs';
import { GpuMeshAdapter } from '../../../scene/mesh/gpu/GpuMeshAdapter.mjs';
import { GpuBatchAdaptor } from '../../batcher/gpu/GpuBatchAdaptor.mjs';
import { AbstractRenderer } from '../shared/system/AbstractRenderer.mjs';
import { SharedSystems, SharedRenderPipes } from '../shared/system/SharedSystems.mjs';
import { RendererType } from '../types.mjs';
import { BindGroupSystem } from './BindGroupSystem.mjs';
import { GpuBufferSystem } from './buffer/GpuBufferSystem.mjs';
import { GpuColorMaskSystem } from './GpuColorMaskSystem.mjs';
import { GpuDeviceSystem } from './GpuDeviceSystem.mjs';
import { GpuEncoderSystem } from './GpuEncoderSystem.mjs';
import { GpuStencilSystem } from './GpuStencilSystem.mjs';
import { GpuUboSystem } from './GpuUboSystem.mjs';
import { GpuUniformBatchPipe } from './GpuUniformBatchPipe.mjs';
import { PipelineSystem } from './pipeline/PipelineSystem.mjs';
import { GpuRenderTargetSystem } from './renderTarget/GpuRenderTargetSystem.mjs';
import { GpuShaderSystem } from './shader/GpuShaderSystem.mjs';
import { GpuStateSystem } from './state/GpuStateSystem.mjs';
import { GpuTextureSystem } from './texture/GpuTextureSystem.mjs';
"use strict";
const DefaultWebGPUSystems = [
...SharedSystems,
GpuUboSystem,
GpuEncoderSystem,
GpuDeviceSystem,
GpuBufferSystem,
GpuTextureSystem,
GpuRenderTargetSystem,
GpuShaderSystem,
GpuStateSystem,
PipelineSystem,
GpuColorMaskSystem,
GpuStencilSystem,
BindGroupSystem
];
const DefaultWebGPUPipes = [...SharedRenderPipes, GpuUniformBatchPipe];
const DefaultWebGPUAdapters = [GpuBatchAdaptor, GpuMeshAdapter, GpuGraphicsAdaptor];
const systems = [];
const renderPipes = [];
const renderPipeAdaptors = [];
extensions.handleByNamedList(ExtensionType.WebGPUSystem, systems);
extensions.handleByNamedList(ExtensionType.WebGPUPipes, renderPipes);
extensions.handleByNamedList(ExtensionType.WebGPUPipesAdaptor, renderPipeAdaptors);
extensions.add(...DefaultWebGPUSystems, ...DefaultWebGPUPipes, ...DefaultWebGPUAdapters);
class WebGPURenderer extends AbstractRenderer {
constructor() {
const systemConfig = {
name: "webgpu",
type: RendererType.WEBGPU,
systems,
renderPipes,
renderPipeAdaptors
};
super(systemConfig);
}
}
export { WebGPURenderer };
//# sourceMappingURL=WebGPURenderer.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,34 @@
/// <reference types="@webgpu/types" />
import { ExtensionType } from '../../../../extensions/Extensions';
import type { Buffer } from '../../shared/buffer/Buffer';
import type { System } from '../../shared/system/System';
import type { GPU } from '../GpuDeviceSystem';
/**
* System plugin to the renderer to manage buffers.
* @memberof rendering
*/
export declare class GpuBufferSystem implements System {
/** @ignore */
static extension: {
readonly type: readonly [ExtensionType.WebGPUSystem];
readonly name: "buffer";
};
protected CONTEXT_UID: number;
private _gpuBuffers;
private readonly _managedBuffers;
private _gpu;
protected contextChange(gpu: GPU): void;
getGPUBuffer(buffer: Buffer): GPUBuffer;
updateBuffer(buffer: Buffer): GPUBuffer;
/** dispose all WebGL resources of all managed buffers */
destroyAll(): void;
createGPUBuffer(buffer: Buffer): GPUBuffer;
protected onBufferChange(buffer: Buffer): void;
/**
* Disposes buffer
* @param buffer - buffer with data
*/
protected onBufferDestroy(buffer: Buffer): void;
destroy(): void;
private _destroyBuffer;
}

View File

@@ -0,0 +1,94 @@
'use strict';
var Extensions = require('../../../../extensions/Extensions.js');
var fastCopy = require('../../shared/buffer/utils/fastCopy.js');
"use strict";
class GpuBufferSystem {
constructor() {
this._gpuBuffers = /* @__PURE__ */ Object.create(null);
this._managedBuffers = [];
}
contextChange(gpu) {
this._gpu = gpu;
}
getGPUBuffer(buffer) {
return this._gpuBuffers[buffer.uid] || this.createGPUBuffer(buffer);
}
updateBuffer(buffer) {
const gpuBuffer = this._gpuBuffers[buffer.uid] || this.createGPUBuffer(buffer);
const data = buffer.data;
if (buffer._updateID && data) {
buffer._updateID = 0;
this._gpu.device.queue.writeBuffer(
gpuBuffer,
0,
data.buffer,
0,
// round to the nearest 4 bytes
(buffer._updateSize || data.byteLength) + 3 & ~3
);
}
return gpuBuffer;
}
/** dispose all WebGL resources of all managed buffers */
destroyAll() {
for (const id in this._gpuBuffers) {
this._gpuBuffers[id].destroy();
}
this._gpuBuffers = {};
}
createGPUBuffer(buffer) {
if (!this._gpuBuffers[buffer.uid]) {
buffer.on("update", this.updateBuffer, this);
buffer.on("change", this.onBufferChange, this);
buffer.on("destroy", this.onBufferDestroy, this);
this._managedBuffers.push(buffer);
}
const gpuBuffer = this._gpu.device.createBuffer(buffer.descriptor);
buffer._updateID = 0;
if (buffer.data) {
fastCopy.fastCopy(buffer.data.buffer, gpuBuffer.getMappedRange());
gpuBuffer.unmap();
}
this._gpuBuffers[buffer.uid] = gpuBuffer;
return gpuBuffer;
}
onBufferChange(buffer) {
const gpuBuffer = this._gpuBuffers[buffer.uid];
gpuBuffer.destroy();
buffer._updateID = 0;
this._gpuBuffers[buffer.uid] = this.createGPUBuffer(buffer);
}
/**
* Disposes buffer
* @param buffer - buffer with data
*/
onBufferDestroy(buffer) {
this._managedBuffers.splice(this._managedBuffers.indexOf(buffer), 1);
this._destroyBuffer(buffer);
}
destroy() {
this._managedBuffers.forEach((buffer) => this._destroyBuffer(buffer));
this._managedBuffers = null;
this._gpuBuffers = null;
}
_destroyBuffer(buffer) {
const gpuBuffer = this._gpuBuffers[buffer.uid];
gpuBuffer.destroy();
buffer.off("update", this.updateBuffer, this);
buffer.off("change", this.onBufferChange, this);
buffer.off("destroy", this.onBufferDestroy, this);
this._gpuBuffers[buffer.uid] = null;
}
}
/** @ignore */
GpuBufferSystem.extension = {
type: [
Extensions.ExtensionType.WebGPUSystem
],
name: "buffer"
};
exports.GpuBufferSystem = GpuBufferSystem;
//# sourceMappingURL=GpuBufferSystem.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,92 @@
import { ExtensionType } from '../../../../extensions/Extensions.mjs';
import { fastCopy } from '../../shared/buffer/utils/fastCopy.mjs';
"use strict";
class GpuBufferSystem {
constructor() {
this._gpuBuffers = /* @__PURE__ */ Object.create(null);
this._managedBuffers = [];
}
contextChange(gpu) {
this._gpu = gpu;
}
getGPUBuffer(buffer) {
return this._gpuBuffers[buffer.uid] || this.createGPUBuffer(buffer);
}
updateBuffer(buffer) {
const gpuBuffer = this._gpuBuffers[buffer.uid] || this.createGPUBuffer(buffer);
const data = buffer.data;
if (buffer._updateID && data) {
buffer._updateID = 0;
this._gpu.device.queue.writeBuffer(
gpuBuffer,
0,
data.buffer,
0,
// round to the nearest 4 bytes
(buffer._updateSize || data.byteLength) + 3 & ~3
);
}
return gpuBuffer;
}
/** dispose all WebGL resources of all managed buffers */
destroyAll() {
for (const id in this._gpuBuffers) {
this._gpuBuffers[id].destroy();
}
this._gpuBuffers = {};
}
createGPUBuffer(buffer) {
if (!this._gpuBuffers[buffer.uid]) {
buffer.on("update", this.updateBuffer, this);
buffer.on("change", this.onBufferChange, this);
buffer.on("destroy", this.onBufferDestroy, this);
this._managedBuffers.push(buffer);
}
const gpuBuffer = this._gpu.device.createBuffer(buffer.descriptor);
buffer._updateID = 0;
if (buffer.data) {
fastCopy(buffer.data.buffer, gpuBuffer.getMappedRange());
gpuBuffer.unmap();
}
this._gpuBuffers[buffer.uid] = gpuBuffer;
return gpuBuffer;
}
onBufferChange(buffer) {
const gpuBuffer = this._gpuBuffers[buffer.uid];
gpuBuffer.destroy();
buffer._updateID = 0;
this._gpuBuffers[buffer.uid] = this.createGPUBuffer(buffer);
}
/**
* Disposes buffer
* @param buffer - buffer with data
*/
onBufferDestroy(buffer) {
this._managedBuffers.splice(this._managedBuffers.indexOf(buffer), 1);
this._destroyBuffer(buffer);
}
destroy() {
this._managedBuffers.forEach((buffer) => this._destroyBuffer(buffer));
this._managedBuffers = null;
this._gpuBuffers = null;
}
_destroyBuffer(buffer) {
const gpuBuffer = this._gpuBuffers[buffer.uid];
gpuBuffer.destroy();
buffer.off("update", this.updateBuffer, this);
buffer.off("change", this.onBufferChange, this);
buffer.off("destroy", this.onBufferDestroy, this);
this._gpuBuffers[buffer.uid] = null;
}
}
/** @ignore */
GpuBufferSystem.extension = {
type: [
ExtensionType.WebGPUSystem
],
name: "buffer"
};
export { GpuBufferSystem };
//# sourceMappingURL=GpuBufferSystem.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,3 @@
import { Buffer } from '../../shared/buffer/Buffer';
import type { WebGPURenderer } from '../WebGPURenderer';
export declare function GpuReadBuffer(buffer: Buffer, renderer: WebGPURenderer): void;

View File

@@ -0,0 +1,39 @@
'use strict';
var Buffer = require('../../shared/buffer/Buffer.js');
var _const = require('../../shared/buffer/const.js');
"use strict";
function GpuReadBuffer(buffer, renderer) {
const bufferSize = buffer.descriptor.size;
const device = renderer.gpu.device;
const stagingBuffer = new Buffer.Buffer({
data: new Float32Array(24e5),
usage: _const.BufferUsage.MAP_READ | _const.BufferUsage.COPY_DST
});
const stagingGPUBuffer = renderer.buffer.createGPUBuffer(stagingBuffer);
const commandEncoder = device.createCommandEncoder();
commandEncoder.copyBufferToBuffer(
renderer.buffer.getGPUBuffer(buffer),
0,
// Source offset
stagingGPUBuffer,
0,
// Destination offset
bufferSize
);
device.queue.submit([commandEncoder.finish()]);
void stagingGPUBuffer.mapAsync(
GPUMapMode.READ,
0,
// Offset
bufferSize
// Length
).then(() => {
stagingGPUBuffer.getMappedRange(0, bufferSize);
stagingGPUBuffer.unmap();
});
}
exports.GpuReadBuffer = GpuReadBuffer;
//# sourceMappingURL=GpuReadBuffer.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"GpuReadBuffer.js","sources":["../../../../../src/rendering/renderers/gpu/buffer/GpuReadBuffer.ts"],"sourcesContent":["import { Buffer } from '../../shared/buffer/Buffer';\nimport { BufferUsage } from '../../shared/buffer/const';\n\nimport type { WebGPURenderer } from '../WebGPURenderer';\n\nexport function GpuReadBuffer(buffer: Buffer, renderer: WebGPURenderer)\n{\n const bufferSize = buffer.descriptor.size;\n\n const device = renderer.gpu.device;\n\n const stagingBuffer = new Buffer({\n data: new Float32Array(2400000),\n usage: BufferUsage.MAP_READ | BufferUsage.COPY_DST,\n });\n\n const stagingGPUBuffer = renderer.buffer.createGPUBuffer(stagingBuffer);\n\n const commandEncoder = device.createCommandEncoder();\n\n commandEncoder.copyBufferToBuffer(\n renderer.buffer.getGPUBuffer(buffer),\n 0, // Source offset\n stagingGPUBuffer,\n 0, // Destination offset\n bufferSize,\n );\n\n device.queue.submit([commandEncoder.finish()]);\n\n void stagingGPUBuffer.mapAsync(\n GPUMapMode.READ,\n 0, // Offset\n bufferSize, // Length\n ).then(() =>\n {\n stagingGPUBuffer.getMappedRange(0, bufferSize);\n stagingGPUBuffer.unmap();\n });\n}\n"],"names":["Buffer","BufferUsage"],"mappings":";;;;;;AAKgB,SAAA,aAAA,CAAc,QAAgB,QAC9C,EAAA;AACI,EAAM,MAAA,UAAA,GAAa,OAAO,UAAW,CAAA,IAAA,CAAA;AAErC,EAAM,MAAA,MAAA,GAAS,SAAS,GAAI,CAAA,MAAA,CAAA;AAE5B,EAAM,MAAA,aAAA,GAAgB,IAAIA,aAAO,CAAA;AAAA,IAC7B,IAAA,EAAM,IAAI,YAAA,CAAa,IAAO,CAAA;AAAA,IAC9B,KAAA,EAAOC,kBAAY,CAAA,QAAA,GAAWA,kBAAY,CAAA,QAAA;AAAA,GAC7C,CAAA,CAAA;AAED,EAAA,MAAM,gBAAmB,GAAA,QAAA,CAAS,MAAO,CAAA,eAAA,CAAgB,aAAa,CAAA,CAAA;AAEtE,EAAM,MAAA,cAAA,GAAiB,OAAO,oBAAqB,EAAA,CAAA;AAEnD,EAAe,cAAA,CAAA,kBAAA;AAAA,IACX,QAAA,CAAS,MAAO,CAAA,YAAA,CAAa,MAAM,CAAA;AAAA,IACnC,CAAA;AAAA;AAAA,IACA,gBAAA;AAAA,IACA,CAAA;AAAA;AAAA,IACA,UAAA;AAAA,GACJ,CAAA;AAEA,EAAA,MAAA,CAAO,MAAM,MAAO,CAAA,CAAC,cAAe,CAAA,MAAA,EAAQ,CAAC,CAAA,CAAA;AAE7C,EAAA,KAAK,gBAAiB,CAAA,QAAA;AAAA,IAClB,UAAW,CAAA,IAAA;AAAA,IACX,CAAA;AAAA;AAAA,IACA,UAAA;AAAA;AAAA,GACJ,CAAE,KAAK,MACP;AACI,IAAiB,gBAAA,CAAA,cAAA,CAAe,GAAG,UAAU,CAAA,CAAA;AAC7C,IAAA,gBAAA,CAAiB,KAAM,EAAA,CAAA;AAAA,GAC1B,CAAA,CAAA;AACL;;;;"}

View File

@@ -0,0 +1,37 @@
import { Buffer } from '../../shared/buffer/Buffer.mjs';
import { BufferUsage } from '../../shared/buffer/const.mjs';
"use strict";
function GpuReadBuffer(buffer, renderer) {
const bufferSize = buffer.descriptor.size;
const device = renderer.gpu.device;
const stagingBuffer = new Buffer({
data: new Float32Array(24e5),
usage: BufferUsage.MAP_READ | BufferUsage.COPY_DST
});
const stagingGPUBuffer = renderer.buffer.createGPUBuffer(stagingBuffer);
const commandEncoder = device.createCommandEncoder();
commandEncoder.copyBufferToBuffer(
renderer.buffer.getGPUBuffer(buffer),
0,
// Source offset
stagingGPUBuffer,
0,
// Destination offset
bufferSize
);
device.queue.submit([commandEncoder.finish()]);
void stagingGPUBuffer.mapAsync(
GPUMapMode.READ,
0,
// Offset
bufferSize
// Length
).then(() => {
stagingGPUBuffer.getMappedRange(0, bufferSize);
stagingGPUBuffer.unmap();
});
}
export { GpuReadBuffer };
//# sourceMappingURL=GpuReadBuffer.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"GpuReadBuffer.mjs","sources":["../../../../../src/rendering/renderers/gpu/buffer/GpuReadBuffer.ts"],"sourcesContent":["import { Buffer } from '../../shared/buffer/Buffer';\nimport { BufferUsage } from '../../shared/buffer/const';\n\nimport type { WebGPURenderer } from '../WebGPURenderer';\n\nexport function GpuReadBuffer(buffer: Buffer, renderer: WebGPURenderer)\n{\n const bufferSize = buffer.descriptor.size;\n\n const device = renderer.gpu.device;\n\n const stagingBuffer = new Buffer({\n data: new Float32Array(2400000),\n usage: BufferUsage.MAP_READ | BufferUsage.COPY_DST,\n });\n\n const stagingGPUBuffer = renderer.buffer.createGPUBuffer(stagingBuffer);\n\n const commandEncoder = device.createCommandEncoder();\n\n commandEncoder.copyBufferToBuffer(\n renderer.buffer.getGPUBuffer(buffer),\n 0, // Source offset\n stagingGPUBuffer,\n 0, // Destination offset\n bufferSize,\n );\n\n device.queue.submit([commandEncoder.finish()]);\n\n void stagingGPUBuffer.mapAsync(\n GPUMapMode.READ,\n 0, // Offset\n bufferSize, // Length\n ).then(() =>\n {\n stagingGPUBuffer.getMappedRange(0, bufferSize);\n stagingGPUBuffer.unmap();\n });\n}\n"],"names":[],"mappings":";;;;AAKgB,SAAA,aAAA,CAAc,QAAgB,QAC9C,EAAA;AACI,EAAM,MAAA,UAAA,GAAa,OAAO,UAAW,CAAA,IAAA,CAAA;AAErC,EAAM,MAAA,MAAA,GAAS,SAAS,GAAI,CAAA,MAAA,CAAA;AAE5B,EAAM,MAAA,aAAA,GAAgB,IAAI,MAAO,CAAA;AAAA,IAC7B,IAAA,EAAM,IAAI,YAAA,CAAa,IAAO,CAAA;AAAA,IAC9B,KAAA,EAAO,WAAY,CAAA,QAAA,GAAW,WAAY,CAAA,QAAA;AAAA,GAC7C,CAAA,CAAA;AAED,EAAA,MAAM,gBAAmB,GAAA,QAAA,CAAS,MAAO,CAAA,eAAA,CAAgB,aAAa,CAAA,CAAA;AAEtE,EAAM,MAAA,cAAA,GAAiB,OAAO,oBAAqB,EAAA,CAAA;AAEnD,EAAe,cAAA,CAAA,kBAAA;AAAA,IACX,QAAA,CAAS,MAAO,CAAA,YAAA,CAAa,MAAM,CAAA;AAAA,IACnC,CAAA;AAAA;AAAA,IACA,gBAAA;AAAA,IACA,CAAA;AAAA;AAAA,IACA,UAAA;AAAA,GACJ,CAAA;AAEA,EAAA,MAAA,CAAO,MAAM,MAAO,CAAA,CAAC,cAAe,CAAA,MAAA,EAAQ,CAAC,CAAA,CAAA;AAE7C,EAAA,KAAK,gBAAiB,CAAA,QAAA;AAAA,IAClB,UAAW,CAAA,IAAA;AAAA,IACX,CAAA;AAAA;AAAA,IACA,UAAA;AAAA;AAAA,GACJ,CAAE,KAAK,MACP;AACI,IAAiB,gBAAA,CAAA,cAAA,CAAe,GAAG,UAAU,CAAA,CAAA;AAC7C,IAAA,gBAAA,CAAiB,KAAM,EAAA,CAAA;AAAA,GAC1B,CAAA,CAAA;AACL;;;;"}

View File

@@ -0,0 +1,13 @@
export declare class UboBatch {
private _buffer;
data: Float32Array;
private readonly _minUniformOffsetAlignment;
byteIndex: number;
constructor({ minUniformOffsetAlignment }: {
minUniformOffsetAlignment: number;
});
clear(): void;
addEmptyGroup(size: number): number;
addGroup(array: Float32Array): number;
destroy(): void;
}

View File

@@ -0,0 +1,42 @@
'use strict';
"use strict";
class UboBatch {
constructor({ minUniformOffsetAlignment }) {
this._minUniformOffsetAlignment = 256;
this.byteIndex = 0;
this._minUniformOffsetAlignment = minUniformOffsetAlignment;
this.data = new Float32Array(65535);
}
clear() {
this.byteIndex = 0;
}
addEmptyGroup(size) {
if (size > this._minUniformOffsetAlignment / 4) {
throw new Error(`UniformBufferBatch: array is too large: ${size * 4}`);
}
const start = this.byteIndex;
let newSize = start + size * 4;
newSize = Math.ceil(newSize / this._minUniformOffsetAlignment) * this._minUniformOffsetAlignment;
if (newSize > this.data.length * 4) {
throw new Error("UniformBufferBatch: ubo batch got too big");
}
this.byteIndex = newSize;
return start;
}
addGroup(array) {
const offset = this.addEmptyGroup(array.length);
for (let i = 0; i < array.length; i++) {
this.data[offset / 4 + i] = array[i];
}
return offset;
}
destroy() {
this._buffer.destroy();
this._buffer = null;
this.data = null;
}
}
exports.UboBatch = UboBatch;
//# sourceMappingURL=UboBatch.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"UboBatch.js","sources":["../../../../../src/rendering/renderers/gpu/buffer/UboBatch.ts"],"sourcesContent":["import type { Buffer } from '../../shared/buffer/Buffer';\n\nexport class UboBatch\n{\n private _buffer: Buffer;\n public data: Float32Array;\n private readonly _minUniformOffsetAlignment: number = 256;\n\n public byteIndex = 0;\n\n constructor({ minUniformOffsetAlignment }: {minUniformOffsetAlignment: number})\n {\n this._minUniformOffsetAlignment = minUniformOffsetAlignment;\n this.data = new Float32Array(65535);\n }\n\n public clear(): void\n {\n this.byteIndex = 0;\n }\n\n public addEmptyGroup(size: number): number\n {\n // update the buffer.. only float32 for now!\n if (size > this._minUniformOffsetAlignment / 4)\n {\n throw new Error(`UniformBufferBatch: array is too large: ${size * 4}`);\n }\n\n const start = this.byteIndex;\n\n let newSize = start + (size * 4);\n\n newSize = Math.ceil(newSize / this._minUniformOffsetAlignment) * this._minUniformOffsetAlignment;\n\n if (newSize > this.data.length * 4)\n {\n // TODO push a new buffer\n throw new Error('UniformBufferBatch: ubo batch got too big');\n }\n\n this.byteIndex = newSize;\n\n return start;\n }\n\n public addGroup(array: Float32Array): number\n {\n const offset = this.addEmptyGroup(array.length);\n\n for (let i = 0; i < array.length; i++)\n {\n this.data[(offset / 4) + i] = array[i];\n }\n\n return offset;\n }\n\n public destroy()\n {\n this._buffer.destroy();\n this._buffer = null;\n\n this.data = null;\n }\n}\n"],"names":[],"mappings":";;;AAEO,MAAM,QACb,CAAA;AAAA,EAOI,WAAA,CAAY,EAAE,yBAAA,EACd,EAAA;AALA,IAAA,IAAA,CAAiB,0BAAqC,GAAA,GAAA,CAAA;AAEtD,IAAA,IAAA,CAAO,SAAY,GAAA,CAAA,CAAA;AAIf,IAAA,IAAA,CAAK,0BAA6B,GAAA,yBAAA,CAAA;AAClC,IAAK,IAAA,CAAA,IAAA,GAAO,IAAI,YAAA,CAAa,KAAK,CAAA,CAAA;AAAA,GACtC;AAAA,EAEO,KACP,GAAA;AACI,IAAA,IAAA,CAAK,SAAY,GAAA,CAAA,CAAA;AAAA,GACrB;AAAA,EAEO,cAAc,IACrB,EAAA;AAEI,IAAI,IAAA,IAAA,GAAO,IAAK,CAAA,0BAAA,GAA6B,CAC7C,EAAA;AACI,MAAA,MAAM,IAAI,KAAA,CAAM,CAA2C,wCAAA,EAAA,IAAA,GAAO,CAAC,CAAE,CAAA,CAAA,CAAA;AAAA,KACzE;AAEA,IAAA,MAAM,QAAQ,IAAK,CAAA,SAAA,CAAA;AAEnB,IAAI,IAAA,OAAA,GAAU,QAAS,IAAO,GAAA,CAAA,CAAA;AAE9B,IAAA,OAAA,GAAU,KAAK,IAAK,CAAA,OAAA,GAAU,IAAK,CAAA,0BAA0B,IAAI,IAAK,CAAA,0BAAA,CAAA;AAEtE,IAAA,IAAI,OAAU,GAAA,IAAA,CAAK,IAAK,CAAA,MAAA,GAAS,CACjC,EAAA;AAEI,MAAM,MAAA,IAAI,MAAM,2CAA2C,CAAA,CAAA;AAAA,KAC/D;AAEA,IAAA,IAAA,CAAK,SAAY,GAAA,OAAA,CAAA;AAEjB,IAAO,OAAA,KAAA,CAAA;AAAA,GACX;AAAA,EAEO,SAAS,KAChB,EAAA;AACI,IAAA,MAAM,MAAS,GAAA,IAAA,CAAK,aAAc,CAAA,KAAA,CAAM,MAAM,CAAA,CAAA;AAE9C,IAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,KAAA,CAAM,QAAQ,CAClC,EAAA,EAAA;AACI,MAAA,IAAA,CAAK,KAAM,MAAS,GAAA,CAAA,GAAK,CAAC,CAAA,GAAI,MAAM,CAAC,CAAA,CAAA;AAAA,KACzC;AAEA,IAAO,OAAA,MAAA,CAAA;AAAA,GACX;AAAA,EAEO,OACP,GAAA;AACI,IAAA,IAAA,CAAK,QAAQ,OAAQ,EAAA,CAAA;AACrB,IAAA,IAAA,CAAK,OAAU,GAAA,IAAA,CAAA;AAEf,IAAA,IAAA,CAAK,IAAO,GAAA,IAAA,CAAA;AAAA,GAChB;AACJ;;;;"}

View File

@@ -0,0 +1,40 @@
"use strict";
class UboBatch {
constructor({ minUniformOffsetAlignment }) {
this._minUniformOffsetAlignment = 256;
this.byteIndex = 0;
this._minUniformOffsetAlignment = minUniformOffsetAlignment;
this.data = new Float32Array(65535);
}
clear() {
this.byteIndex = 0;
}
addEmptyGroup(size) {
if (size > this._minUniformOffsetAlignment / 4) {
throw new Error(`UniformBufferBatch: array is too large: ${size * 4}`);
}
const start = this.byteIndex;
let newSize = start + size * 4;
newSize = Math.ceil(newSize / this._minUniformOffsetAlignment) * this._minUniformOffsetAlignment;
if (newSize > this.data.length * 4) {
throw new Error("UniformBufferBatch: ubo batch got too big");
}
this.byteIndex = newSize;
return start;
}
addGroup(array) {
const offset = this.addEmptyGroup(array.length);
for (let i = 0; i < array.length; i++) {
this.data[offset / 4 + i] = array[i];
}
return offset;
}
destroy() {
this._buffer.destroy();
this._buffer = null;
this.data = null;
}
}
export { UboBatch };
//# sourceMappingURL=UboBatch.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"UboBatch.mjs","sources":["../../../../../src/rendering/renderers/gpu/buffer/UboBatch.ts"],"sourcesContent":["import type { Buffer } from '../../shared/buffer/Buffer';\n\nexport class UboBatch\n{\n private _buffer: Buffer;\n public data: Float32Array;\n private readonly _minUniformOffsetAlignment: number = 256;\n\n public byteIndex = 0;\n\n constructor({ minUniformOffsetAlignment }: {minUniformOffsetAlignment: number})\n {\n this._minUniformOffsetAlignment = minUniformOffsetAlignment;\n this.data = new Float32Array(65535);\n }\n\n public clear(): void\n {\n this.byteIndex = 0;\n }\n\n public addEmptyGroup(size: number): number\n {\n // update the buffer.. only float32 for now!\n if (size > this._minUniformOffsetAlignment / 4)\n {\n throw new Error(`UniformBufferBatch: array is too large: ${size * 4}`);\n }\n\n const start = this.byteIndex;\n\n let newSize = start + (size * 4);\n\n newSize = Math.ceil(newSize / this._minUniformOffsetAlignment) * this._minUniformOffsetAlignment;\n\n if (newSize > this.data.length * 4)\n {\n // TODO push a new buffer\n throw new Error('UniformBufferBatch: ubo batch got too big');\n }\n\n this.byteIndex = newSize;\n\n return start;\n }\n\n public addGroup(array: Float32Array): number\n {\n const offset = this.addEmptyGroup(array.length);\n\n for (let i = 0; i < array.length; i++)\n {\n this.data[(offset / 4) + i] = array[i];\n }\n\n return offset;\n }\n\n public destroy()\n {\n this._buffer.destroy();\n this._buffer = null;\n\n this.data = null;\n }\n}\n"],"names":[],"mappings":";AAEO,MAAM,QACb,CAAA;AAAA,EAOI,WAAA,CAAY,EAAE,yBAAA,EACd,EAAA;AALA,IAAA,IAAA,CAAiB,0BAAqC,GAAA,GAAA,CAAA;AAEtD,IAAA,IAAA,CAAO,SAAY,GAAA,CAAA,CAAA;AAIf,IAAA,IAAA,CAAK,0BAA6B,GAAA,yBAAA,CAAA;AAClC,IAAK,IAAA,CAAA,IAAA,GAAO,IAAI,YAAA,CAAa,KAAK,CAAA,CAAA;AAAA,GACtC;AAAA,EAEO,KACP,GAAA;AACI,IAAA,IAAA,CAAK,SAAY,GAAA,CAAA,CAAA;AAAA,GACrB;AAAA,EAEO,cAAc,IACrB,EAAA;AAEI,IAAI,IAAA,IAAA,GAAO,IAAK,CAAA,0BAAA,GAA6B,CAC7C,EAAA;AACI,MAAA,MAAM,IAAI,KAAA,CAAM,CAA2C,wCAAA,EAAA,IAAA,GAAO,CAAC,CAAE,CAAA,CAAA,CAAA;AAAA,KACzE;AAEA,IAAA,MAAM,QAAQ,IAAK,CAAA,SAAA,CAAA;AAEnB,IAAI,IAAA,OAAA,GAAU,QAAS,IAAO,GAAA,CAAA,CAAA;AAE9B,IAAA,OAAA,GAAU,KAAK,IAAK,CAAA,OAAA,GAAU,IAAK,CAAA,0BAA0B,IAAI,IAAK,CAAA,0BAAA,CAAA;AAEtE,IAAA,IAAI,OAAU,GAAA,IAAA,CAAK,IAAK,CAAA,MAAA,GAAS,CACjC,EAAA;AAEI,MAAM,MAAA,IAAI,MAAM,2CAA2C,CAAA,CAAA;AAAA,KAC/D;AAEA,IAAA,IAAA,CAAK,SAAY,GAAA,OAAA,CAAA;AAEjB,IAAO,OAAA,KAAA,CAAA;AAAA,GACX;AAAA,EAEO,SAAS,KAChB,EAAA;AACI,IAAA,MAAM,MAAS,GAAA,IAAA,CAAK,aAAc,CAAA,KAAA,CAAM,MAAM,CAAA,CAAA;AAE9C,IAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,KAAA,CAAM,QAAQ,CAClC,EAAA,EAAA;AACI,MAAA,IAAA,CAAK,KAAM,MAAS,GAAA,CAAA,GAAK,CAAC,CAAA,GAAI,MAAM,CAAC,CAAA,CAAA;AAAA,KACzC;AAEA,IAAO,OAAA,MAAA,CAAA;AAAA,GACX;AAAA,EAEO,OACP,GAAA;AACI,IAAA,IAAA,CAAK,QAAQ,OAAQ,EAAA,CAAA;AACrB,IAAA,IAAA,CAAK,OAAU,GAAA,IAAA,CAAA;AAEf,IAAA,IAAA,CAAK,IAAO,GAAA,IAAA,CAAA;AAAA,GAChB;AACJ;;;;"}

View File

@@ -0,0 +1,72 @@
/// <reference types="@webgpu/types" />
import { ExtensionType } from '../../../../extensions/Extensions';
import { STENCIL_MODES } from '../../shared/state/const';
import type { Topology } from '../../shared/geometry/const';
import type { Geometry } from '../../shared/geometry/Geometry';
import type { State } from '../../shared/state/State';
import type { System } from '../../shared/system/System';
import type { GPU } from '../GpuDeviceSystem';
import type { GpuRenderTarget } from '../renderTarget/GpuRenderTarget';
import type { GpuProgram } from '../shader/GpuProgram';
import type { WebGPURenderer } from '../WebGPURenderer';
/**
* A system that creates and manages the GPU pipelines.
*
* Caching Mechanism: At its core, the system employs a two-tiered caching strategy to minimize
* the redundant creation of GPU pipelines (or "pipes"). This strategy is based on generating unique
* keys that represent the state of the graphics settings and the specific requirements of the
* item being rendered. By caching these pipelines, subsequent draw calls with identical configurations
* can reuse existing pipelines instead of generating new ones.
*
* State Management: The system differentiates between "global" state properties (like color masks
* and stencil masks, which do not change frequently) and properties that may vary between draw calls
* (such as geometry, shaders, and blend modes). Unique keys are generated for both these categories
* using getStateKey for global state and getGraphicsStateKey for draw-specific settings. These keys are
* then then used to caching the pipe. The next time we need a pipe we can check
* the cache by first looking at the state cache and then the pipe cache.
* @memberof rendering
*/
export declare class PipelineSystem implements System {
/** @ignore */
static extension: {
readonly type: readonly [ExtensionType.WebGPUSystem];
readonly name: "pipeline";
};
private readonly _renderer;
protected CONTEXT_UID: number;
private _moduleCache;
private _bufferLayoutsCache;
private readonly _bindingNamesCache;
private _pipeCache;
private readonly _pipeStateCaches;
private _gpu;
private _stencilState;
private _stencilMode;
private _colorMask;
private _multisampleCount;
private _depthStencilAttachment;
constructor(renderer: WebGPURenderer);
protected contextChange(gpu: GPU): void;
setMultisampleCount(multisampleCount: number): void;
setRenderTarget(renderTarget: GpuRenderTarget): void;
setColorMask(colorMask: number): void;
setStencilMode(stencilMode: STENCIL_MODES): void;
setPipeline(geometry: Geometry, program: GpuProgram, state: State, passEncoder: GPURenderPassEncoder): void;
getPipeline(geometry: Geometry, program: GpuProgram, state: State, topology?: Topology): GPURenderPipeline;
private _createPipeline;
private _getModule;
private _createModule;
private _generateBufferKey;
private _generateAttributeLocationsKey;
/**
* Returns a hash of buffer names mapped to bind locations.
* This is used to bind the correct buffer to the correct location in the shader.
* @param geometry - The geometry where to get the buffer names
* @param program - The program where to get the buffer names
* @returns An object of buffer names mapped to the bind location.
*/
getBufferNamesToBind(geometry: Geometry, program: GpuProgram): Record<string, string>;
private _createVertexBufferLayouts;
private _updatePipeHash;
destroy(): void;
}

View File

@@ -0,0 +1,251 @@
'use strict';
var Extensions = require('../../../../extensions/Extensions.js');
var warn = require('../../../../utils/logging/warn.js');
var ensureAttributes = require('../../gl/shader/program/ensureAttributes.js');
var _const = require('../../shared/state/const.js');
var createIdFromString = require('../../shared/utils/createIdFromString.js');
var GpuStencilModesToPixi = require('../state/GpuStencilModesToPixi.js');
"use strict";
const topologyStringToId = {
"point-list": 0,
"line-list": 1,
"line-strip": 2,
"triangle-list": 3,
"triangle-strip": 4
};
function getGraphicsStateKey(geometryLayout, shaderKey, state, blendMode, topology) {
return geometryLayout << 24 | shaderKey << 16 | state << 10 | blendMode << 5 | topology;
}
function getGlobalStateKey(stencilStateId, multiSampleCount, colorMask, renderTarget) {
return colorMask << 6 | stencilStateId << 3 | renderTarget << 1 | multiSampleCount;
}
class PipelineSystem {
constructor(renderer) {
this._moduleCache = /* @__PURE__ */ Object.create(null);
this._bufferLayoutsCache = /* @__PURE__ */ Object.create(null);
this._bindingNamesCache = /* @__PURE__ */ Object.create(null);
this._pipeCache = /* @__PURE__ */ Object.create(null);
this._pipeStateCaches = /* @__PURE__ */ Object.create(null);
this._colorMask = 15;
this._multisampleCount = 1;
this._renderer = renderer;
}
contextChange(gpu) {
this._gpu = gpu;
this.setStencilMode(_const.STENCIL_MODES.DISABLED);
this._updatePipeHash();
}
setMultisampleCount(multisampleCount) {
if (this._multisampleCount === multisampleCount)
return;
this._multisampleCount = multisampleCount;
this._updatePipeHash();
}
setRenderTarget(renderTarget) {
this._multisampleCount = renderTarget.msaaSamples;
this._depthStencilAttachment = renderTarget.descriptor.depthStencilAttachment ? 1 : 0;
this._updatePipeHash();
}
setColorMask(colorMask) {
if (this._colorMask === colorMask)
return;
this._colorMask = colorMask;
this._updatePipeHash();
}
setStencilMode(stencilMode) {
if (this._stencilMode === stencilMode)
return;
this._stencilMode = stencilMode;
this._stencilState = GpuStencilModesToPixi.GpuStencilModesToPixi[stencilMode];
this._updatePipeHash();
}
setPipeline(geometry, program, state, passEncoder) {
const pipeline = this.getPipeline(geometry, program, state);
passEncoder.setPipeline(pipeline);
}
getPipeline(geometry, program, state, topology) {
if (!geometry._layoutKey) {
ensureAttributes.ensureAttributes(geometry, program.attributeData);
this._generateBufferKey(geometry);
}
topology = topology || geometry.topology;
const key = getGraphicsStateKey(
geometry._layoutKey,
program._layoutKey,
state.data,
state._blendModeId,
topologyStringToId[topology]
);
if (this._pipeCache[key])
return this._pipeCache[key];
this._pipeCache[key] = this._createPipeline(geometry, program, state, topology);
return this._pipeCache[key];
}
_createPipeline(geometry, program, state, topology) {
const device = this._gpu.device;
const buffers = this._createVertexBufferLayouts(geometry, program);
const blendModes = this._renderer.state.getColorTargets(state);
blendModes[0].writeMask = this._stencilMode === _const.STENCIL_MODES.RENDERING_MASK_ADD ? 0 : this._colorMask;
const layout = this._renderer.shader.getProgramData(program).pipeline;
const descriptor = {
// TODO later check if its helpful to create..
// layout,
vertex: {
module: this._getModule(program.vertex.source),
entryPoint: program.vertex.entryPoint,
// geometry..
buffers
},
fragment: {
module: this._getModule(program.fragment.source),
entryPoint: program.fragment.entryPoint,
targets: blendModes
},
primitive: {
topology,
cullMode: state.cullMode
},
layout,
multisample: {
count: this._multisampleCount
},
// depthStencil,
label: `PIXI Pipeline`
};
if (this._depthStencilAttachment) {
descriptor.depthStencil = {
...this._stencilState,
format: "depth24plus-stencil8",
depthWriteEnabled: state.depthTest,
depthCompare: state.depthTest ? "less" : "always"
};
}
const pipeline = device.createRenderPipeline(descriptor);
return pipeline;
}
_getModule(code) {
return this._moduleCache[code] || this._createModule(code);
}
_createModule(code) {
const device = this._gpu.device;
this._moduleCache[code] = device.createShaderModule({
code
});
return this._moduleCache[code];
}
_generateBufferKey(geometry) {
const keyGen = [];
let index = 0;
const attributeKeys = Object.keys(geometry.attributes).sort();
for (let i = 0; i < attributeKeys.length; i++) {
const attribute = geometry.attributes[attributeKeys[i]];
keyGen[index++] = attribute.offset;
keyGen[index++] = attribute.format;
keyGen[index++] = attribute.stride;
keyGen[index++] = attribute.instance;
}
const stringKey = keyGen.join("|");
geometry._layoutKey = createIdFromString.createIdFromString(stringKey, "geometry");
return geometry._layoutKey;
}
_generateAttributeLocationsKey(program) {
const keyGen = [];
let index = 0;
const attributeKeys = Object.keys(program.attributeData).sort();
for (let i = 0; i < attributeKeys.length; i++) {
const attribute = program.attributeData[attributeKeys[i]];
keyGen[index++] = attribute.location;
}
const stringKey = keyGen.join("|");
program._attributeLocationsKey = createIdFromString.createIdFromString(stringKey, "programAttributes");
return program._attributeLocationsKey;
}
/**
* Returns a hash of buffer names mapped to bind locations.
* This is used to bind the correct buffer to the correct location in the shader.
* @param geometry - The geometry where to get the buffer names
* @param program - The program where to get the buffer names
* @returns An object of buffer names mapped to the bind location.
*/
getBufferNamesToBind(geometry, program) {
const key = geometry._layoutKey << 16 | program._attributeLocationsKey;
if (this._bindingNamesCache[key])
return this._bindingNamesCache[key];
const data = this._createVertexBufferLayouts(geometry, program);
const bufferNamesToBind = /* @__PURE__ */ Object.create(null);
const attributeData = program.attributeData;
for (let i = 0; i < data.length; i++) {
for (const j in attributeData) {
if (attributeData[j].location === i) {
bufferNamesToBind[i] = j;
break;
}
}
}
this._bindingNamesCache[key] = bufferNamesToBind;
return bufferNamesToBind;
}
_createVertexBufferLayouts(geometry, program) {
if (!program._attributeLocationsKey)
this._generateAttributeLocationsKey(program);
const key = geometry._layoutKey << 16 | program._attributeLocationsKey;
if (this._bufferLayoutsCache[key]) {
return this._bufferLayoutsCache[key];
}
const vertexBuffersLayout = [];
geometry.buffers.forEach((buffer) => {
const bufferEntry = {
arrayStride: 0,
stepMode: "vertex",
attributes: []
};
const bufferEntryAttributes = bufferEntry.attributes;
for (const i in program.attributeData) {
const attribute = geometry.attributes[i];
if ((attribute.divisor ?? 1) !== 1) {
warn.warn(`Attribute ${i} has an invalid divisor value of '${attribute.divisor}'. WebGPU only supports a divisor value of 1`);
}
if (attribute.buffer === buffer) {
bufferEntry.arrayStride = attribute.stride;
bufferEntry.stepMode = attribute.instance ? "instance" : "vertex";
bufferEntryAttributes.push({
shaderLocation: program.attributeData[i].location,
offset: attribute.offset,
format: attribute.format
});
}
}
if (bufferEntryAttributes.length) {
vertexBuffersLayout.push(bufferEntry);
}
});
this._bufferLayoutsCache[key] = vertexBuffersLayout;
return vertexBuffersLayout;
}
_updatePipeHash() {
const key = getGlobalStateKey(
this._stencilMode,
this._multisampleCount,
this._colorMask,
this._depthStencilAttachment
);
if (!this._pipeStateCaches[key]) {
this._pipeStateCaches[key] = /* @__PURE__ */ Object.create(null);
}
this._pipeCache = this._pipeStateCaches[key];
}
destroy() {
this._renderer = null;
this._bufferLayoutsCache = null;
}
}
/** @ignore */
PipelineSystem.extension = {
type: [Extensions.ExtensionType.WebGPUSystem],
name: "pipeline"
};
exports.PipelineSystem = PipelineSystem;
//# sourceMappingURL=PipelineSystem.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,249 @@
import { ExtensionType } from '../../../../extensions/Extensions.mjs';
import { warn } from '../../../../utils/logging/warn.mjs';
import { ensureAttributes } from '../../gl/shader/program/ensureAttributes.mjs';
import { STENCIL_MODES } from '../../shared/state/const.mjs';
import { createIdFromString } from '../../shared/utils/createIdFromString.mjs';
import { GpuStencilModesToPixi } from '../state/GpuStencilModesToPixi.mjs';
"use strict";
const topologyStringToId = {
"point-list": 0,
"line-list": 1,
"line-strip": 2,
"triangle-list": 3,
"triangle-strip": 4
};
function getGraphicsStateKey(geometryLayout, shaderKey, state, blendMode, topology) {
return geometryLayout << 24 | shaderKey << 16 | state << 10 | blendMode << 5 | topology;
}
function getGlobalStateKey(stencilStateId, multiSampleCount, colorMask, renderTarget) {
return colorMask << 6 | stencilStateId << 3 | renderTarget << 1 | multiSampleCount;
}
class PipelineSystem {
constructor(renderer) {
this._moduleCache = /* @__PURE__ */ Object.create(null);
this._bufferLayoutsCache = /* @__PURE__ */ Object.create(null);
this._bindingNamesCache = /* @__PURE__ */ Object.create(null);
this._pipeCache = /* @__PURE__ */ Object.create(null);
this._pipeStateCaches = /* @__PURE__ */ Object.create(null);
this._colorMask = 15;
this._multisampleCount = 1;
this._renderer = renderer;
}
contextChange(gpu) {
this._gpu = gpu;
this.setStencilMode(STENCIL_MODES.DISABLED);
this._updatePipeHash();
}
setMultisampleCount(multisampleCount) {
if (this._multisampleCount === multisampleCount)
return;
this._multisampleCount = multisampleCount;
this._updatePipeHash();
}
setRenderTarget(renderTarget) {
this._multisampleCount = renderTarget.msaaSamples;
this._depthStencilAttachment = renderTarget.descriptor.depthStencilAttachment ? 1 : 0;
this._updatePipeHash();
}
setColorMask(colorMask) {
if (this._colorMask === colorMask)
return;
this._colorMask = colorMask;
this._updatePipeHash();
}
setStencilMode(stencilMode) {
if (this._stencilMode === stencilMode)
return;
this._stencilMode = stencilMode;
this._stencilState = GpuStencilModesToPixi[stencilMode];
this._updatePipeHash();
}
setPipeline(geometry, program, state, passEncoder) {
const pipeline = this.getPipeline(geometry, program, state);
passEncoder.setPipeline(pipeline);
}
getPipeline(geometry, program, state, topology) {
if (!geometry._layoutKey) {
ensureAttributes(geometry, program.attributeData);
this._generateBufferKey(geometry);
}
topology = topology || geometry.topology;
const key = getGraphicsStateKey(
geometry._layoutKey,
program._layoutKey,
state.data,
state._blendModeId,
topologyStringToId[topology]
);
if (this._pipeCache[key])
return this._pipeCache[key];
this._pipeCache[key] = this._createPipeline(geometry, program, state, topology);
return this._pipeCache[key];
}
_createPipeline(geometry, program, state, topology) {
const device = this._gpu.device;
const buffers = this._createVertexBufferLayouts(geometry, program);
const blendModes = this._renderer.state.getColorTargets(state);
blendModes[0].writeMask = this._stencilMode === STENCIL_MODES.RENDERING_MASK_ADD ? 0 : this._colorMask;
const layout = this._renderer.shader.getProgramData(program).pipeline;
const descriptor = {
// TODO later check if its helpful to create..
// layout,
vertex: {
module: this._getModule(program.vertex.source),
entryPoint: program.vertex.entryPoint,
// geometry..
buffers
},
fragment: {
module: this._getModule(program.fragment.source),
entryPoint: program.fragment.entryPoint,
targets: blendModes
},
primitive: {
topology,
cullMode: state.cullMode
},
layout,
multisample: {
count: this._multisampleCount
},
// depthStencil,
label: `PIXI Pipeline`
};
if (this._depthStencilAttachment) {
descriptor.depthStencil = {
...this._stencilState,
format: "depth24plus-stencil8",
depthWriteEnabled: state.depthTest,
depthCompare: state.depthTest ? "less" : "always"
};
}
const pipeline = device.createRenderPipeline(descriptor);
return pipeline;
}
_getModule(code) {
return this._moduleCache[code] || this._createModule(code);
}
_createModule(code) {
const device = this._gpu.device;
this._moduleCache[code] = device.createShaderModule({
code
});
return this._moduleCache[code];
}
_generateBufferKey(geometry) {
const keyGen = [];
let index = 0;
const attributeKeys = Object.keys(geometry.attributes).sort();
for (let i = 0; i < attributeKeys.length; i++) {
const attribute = geometry.attributes[attributeKeys[i]];
keyGen[index++] = attribute.offset;
keyGen[index++] = attribute.format;
keyGen[index++] = attribute.stride;
keyGen[index++] = attribute.instance;
}
const stringKey = keyGen.join("|");
geometry._layoutKey = createIdFromString(stringKey, "geometry");
return geometry._layoutKey;
}
_generateAttributeLocationsKey(program) {
const keyGen = [];
let index = 0;
const attributeKeys = Object.keys(program.attributeData).sort();
for (let i = 0; i < attributeKeys.length; i++) {
const attribute = program.attributeData[attributeKeys[i]];
keyGen[index++] = attribute.location;
}
const stringKey = keyGen.join("|");
program._attributeLocationsKey = createIdFromString(stringKey, "programAttributes");
return program._attributeLocationsKey;
}
/**
* Returns a hash of buffer names mapped to bind locations.
* This is used to bind the correct buffer to the correct location in the shader.
* @param geometry - The geometry where to get the buffer names
* @param program - The program where to get the buffer names
* @returns An object of buffer names mapped to the bind location.
*/
getBufferNamesToBind(geometry, program) {
const key = geometry._layoutKey << 16 | program._attributeLocationsKey;
if (this._bindingNamesCache[key])
return this._bindingNamesCache[key];
const data = this._createVertexBufferLayouts(geometry, program);
const bufferNamesToBind = /* @__PURE__ */ Object.create(null);
const attributeData = program.attributeData;
for (let i = 0; i < data.length; i++) {
for (const j in attributeData) {
if (attributeData[j].location === i) {
bufferNamesToBind[i] = j;
break;
}
}
}
this._bindingNamesCache[key] = bufferNamesToBind;
return bufferNamesToBind;
}
_createVertexBufferLayouts(geometry, program) {
if (!program._attributeLocationsKey)
this._generateAttributeLocationsKey(program);
const key = geometry._layoutKey << 16 | program._attributeLocationsKey;
if (this._bufferLayoutsCache[key]) {
return this._bufferLayoutsCache[key];
}
const vertexBuffersLayout = [];
geometry.buffers.forEach((buffer) => {
const bufferEntry = {
arrayStride: 0,
stepMode: "vertex",
attributes: []
};
const bufferEntryAttributes = bufferEntry.attributes;
for (const i in program.attributeData) {
const attribute = geometry.attributes[i];
if ((attribute.divisor ?? 1) !== 1) {
warn(`Attribute ${i} has an invalid divisor value of '${attribute.divisor}'. WebGPU only supports a divisor value of 1`);
}
if (attribute.buffer === buffer) {
bufferEntry.arrayStride = attribute.stride;
bufferEntry.stepMode = attribute.instance ? "instance" : "vertex";
bufferEntryAttributes.push({
shaderLocation: program.attributeData[i].location,
offset: attribute.offset,
format: attribute.format
});
}
}
if (bufferEntryAttributes.length) {
vertexBuffersLayout.push(bufferEntry);
}
});
this._bufferLayoutsCache[key] = vertexBuffersLayout;
return vertexBuffersLayout;
}
_updatePipeHash() {
const key = getGlobalStateKey(
this._stencilMode,
this._multisampleCount,
this._colorMask,
this._depthStencilAttachment
);
if (!this._pipeStateCaches[key]) {
this._pipeStateCaches[key] = /* @__PURE__ */ Object.create(null);
}
this._pipeCache = this._pipeStateCaches[key];
}
destroy() {
this._renderer = null;
this._bufferLayoutsCache = null;
}
}
/** @ignore */
PipelineSystem.extension = {
type: [ExtensionType.WebGPUSystem],
name: "pipeline"
};
export { PipelineSystem };
//# sourceMappingURL=PipelineSystem.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,16 @@
/// <reference types="@webgpu/types" />
import type { TextureSource } from '../../shared/texture/sources/TextureSource';
/**
* A class which holds the canvas contexts and textures for a render target.
* @memberof rendering
* @ignore
*/
export declare class GpuRenderTarget {
contexts: GPUCanvasContext[];
msaaTextures: TextureSource[];
msaa: boolean;
msaaSamples: number;
width: number;
height: number;
descriptor: GPURenderPassDescriptor;
}

View File

@@ -0,0 +1,13 @@
'use strict';
"use strict";
class GpuRenderTarget {
constructor() {
this.contexts = [];
this.msaaTextures = [];
this.msaaSamples = 1;
}
}
exports.GpuRenderTarget = GpuRenderTarget;
//# sourceMappingURL=GpuRenderTarget.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"GpuRenderTarget.js","sources":["../../../../../src/rendering/renderers/gpu/renderTarget/GpuRenderTarget.ts"],"sourcesContent":["import type { TextureSource } from '../../shared/texture/sources/TextureSource';\n\n/**\n * A class which holds the canvas contexts and textures for a render target.\n * @memberof rendering\n * @ignore\n */\nexport class GpuRenderTarget\n{\n public contexts: GPUCanvasContext[] = [];\n public msaaTextures: TextureSource[] = [];\n public msaa: boolean;\n public msaaSamples = 1;\n public width: number;\n public height: number;\n public descriptor: GPURenderPassDescriptor;\n}\n"],"names":[],"mappings":";;;AAOO,MAAM,eACb,CAAA;AAAA,EADO,WAAA,GAAA;AAEH,IAAA,IAAA,CAAO,WAA+B,EAAC,CAAA;AACvC,IAAA,IAAA,CAAO,eAAgC,EAAC,CAAA;AAExC,IAAA,IAAA,CAAO,WAAc,GAAA,CAAA,CAAA;AAAA,GAAA;AAIzB;;;;"}

View File

@@ -0,0 +1,11 @@
"use strict";
class GpuRenderTarget {
constructor() {
this.contexts = [];
this.msaaTextures = [];
this.msaaSamples = 1;
}
}
export { GpuRenderTarget };
//# sourceMappingURL=GpuRenderTarget.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"GpuRenderTarget.mjs","sources":["../../../../../src/rendering/renderers/gpu/renderTarget/GpuRenderTarget.ts"],"sourcesContent":["import type { TextureSource } from '../../shared/texture/sources/TextureSource';\n\n/**\n * A class which holds the canvas contexts and textures for a render target.\n * @memberof rendering\n * @ignore\n */\nexport class GpuRenderTarget\n{\n public contexts: GPUCanvasContext[] = [];\n public msaaTextures: TextureSource[] = [];\n public msaa: boolean;\n public msaaSamples = 1;\n public width: number;\n public height: number;\n public descriptor: GPURenderPassDescriptor;\n}\n"],"names":[],"mappings":";AAOO,MAAM,eACb,CAAA;AAAA,EADO,WAAA,GAAA;AAEH,IAAA,IAAA,CAAO,WAA+B,EAAC,CAAA;AACvC,IAAA,IAAA,CAAO,eAAgC,EAAC,CAAA;AAExC,IAAA,IAAA,CAAO,WAAc,GAAA,CAAA,CAAA;AAAA,GAAA;AAIzB;;;;"}

View File

@@ -0,0 +1,46 @@
/// <reference types="@webgpu/types" />
import { TextureSource } from '../../shared/texture/sources/TextureSource';
import { GpuRenderTarget } from './GpuRenderTarget';
import type { RgbaArray } from '../../../../color/Color';
import type { Rectangle } from '../../../../maths/shapes/Rectangle';
import type { CLEAR_OR_BOOL } from '../../gl/const';
import type { RenderTarget } from '../../shared/renderTarget/RenderTarget';
import type { RenderTargetAdaptor, RenderTargetSystem } from '../../shared/renderTarget/RenderTargetSystem';
import type { Texture } from '../../shared/texture/Texture';
import type { WebGPURenderer } from '../WebGPURenderer';
/**
* The WebGPU adaptor for the render target system. Allows the Render Target System to
* be used with the WebGPU renderer
* @memberof rendering
* @ignore
*/
export declare class GpuRenderTargetAdaptor implements RenderTargetAdaptor<GpuRenderTarget> {
private _renderTargetSystem;
private _renderer;
init(renderer: WebGPURenderer, renderTargetSystem: RenderTargetSystem<GpuRenderTarget>): void;
copyToTexture(sourceRenderSurfaceTexture: RenderTarget, destinationTexture: Texture, originSrc: {
x: number;
y: number;
}, size: {
width: number;
height: number;
}, originDest: {
x: number;
y: number;
}): Texture<TextureSource<any>>;
startRenderPass(renderTarget: RenderTarget, clear?: CLEAR_OR_BOOL, clearColor?: RgbaArray, viewport?: Rectangle): void;
finishRenderPass(): void;
/**
* returns the gpu texture for the first color texture in the render target
* mainly used by the filter manager to get copy the texture for blending
* @param renderTarget
* @returns a gpu texture
*/
private _getGpuColorTexture;
getDescriptor(renderTarget: RenderTarget, clear: CLEAR_OR_BOOL, clearValue: RgbaArray): GPURenderPassDescriptor;
clear(renderTarget: RenderTarget, clear?: CLEAR_OR_BOOL, clearColor?: RgbaArray, viewport?: Rectangle): void;
initGpuRenderTarget(renderTarget: RenderTarget): GpuRenderTarget;
destroyGpuRenderTarget(gpuRenderTarget: GpuRenderTarget): void;
ensureDepthStencilTexture(renderTarget: RenderTarget): void;
resizeGpuRenderTarget(renderTarget: RenderTarget): void;
}

View File

@@ -0,0 +1,214 @@
'use strict';
var _const = require('../../gl/const.js');
var CanvasSource = require('../../shared/texture/sources/CanvasSource.js');
var TextureSource = require('../../shared/texture/sources/TextureSource.js');
var GpuRenderTarget = require('./GpuRenderTarget.js');
"use strict";
class GpuRenderTargetAdaptor {
init(renderer, renderTargetSystem) {
this._renderer = renderer;
this._renderTargetSystem = renderTargetSystem;
}
copyToTexture(sourceRenderSurfaceTexture, destinationTexture, originSrc, size, originDest) {
const renderer = this._renderer;
const baseGpuTexture = this._getGpuColorTexture(
sourceRenderSurfaceTexture
);
const backGpuTexture = renderer.texture.getGpuSource(
destinationTexture.source
);
renderer.encoder.commandEncoder.copyTextureToTexture(
{
texture: baseGpuTexture,
origin: originSrc
},
{
texture: backGpuTexture,
origin: originDest
},
size
);
return destinationTexture;
}
startRenderPass(renderTarget, clear = true, clearColor, viewport) {
const renderTargetSystem = this._renderTargetSystem;
const gpuRenderTarget = renderTargetSystem.getGpuRenderTarget(renderTarget);
const descriptor = this.getDescriptor(renderTarget, clear, clearColor);
gpuRenderTarget.descriptor = descriptor;
this._renderer.pipeline.setRenderTarget(gpuRenderTarget);
this._renderer.encoder.beginRenderPass(gpuRenderTarget);
this._renderer.encoder.setViewport(viewport);
}
finishRenderPass() {
this._renderer.encoder.endRenderPass();
}
/**
* returns the gpu texture for the first color texture in the render target
* mainly used by the filter manager to get copy the texture for blending
* @param renderTarget
* @returns a gpu texture
*/
_getGpuColorTexture(renderTarget) {
const gpuRenderTarget = this._renderTargetSystem.getGpuRenderTarget(renderTarget);
if (gpuRenderTarget.contexts[0]) {
return gpuRenderTarget.contexts[0].getCurrentTexture();
}
return this._renderer.texture.getGpuSource(
renderTarget.colorTextures[0].source
);
}
getDescriptor(renderTarget, clear, clearValue) {
if (typeof clear === "boolean") {
clear = clear ? _const.CLEAR.ALL : _const.CLEAR.NONE;
}
const renderTargetSystem = this._renderTargetSystem;
const gpuRenderTarget = renderTargetSystem.getGpuRenderTarget(renderTarget);
const colorAttachments = renderTarget.colorTextures.map(
(texture, i) => {
const context = gpuRenderTarget.contexts[i];
let view;
let resolveTarget;
if (context) {
const currentTexture = context.getCurrentTexture();
const canvasTextureView = currentTexture.createView();
view = canvasTextureView;
} else {
view = this._renderer.texture.getGpuSource(texture).createView({
mipLevelCount: 1
});
}
if (gpuRenderTarget.msaaTextures[i]) {
resolveTarget = view;
view = this._renderer.texture.getTextureView(
gpuRenderTarget.msaaTextures[i]
);
}
const loadOp = clear & _const.CLEAR.COLOR ? "clear" : "load";
clearValue ?? (clearValue = renderTargetSystem.defaultClearColor);
return {
view,
resolveTarget,
clearValue,
storeOp: "store",
loadOp
};
}
);
let depthStencilAttachment;
if ((renderTarget.stencil || renderTarget.depth) && !renderTarget.depthStencilTexture) {
renderTarget.ensureDepthStencilTexture();
renderTarget.depthStencilTexture.source.sampleCount = gpuRenderTarget.msaa ? 4 : 1;
}
if (renderTarget.depthStencilTexture) {
const stencilLoadOp = clear & _const.CLEAR.STENCIL ? "clear" : "load";
const depthLoadOp = clear & _const.CLEAR.DEPTH ? "clear" : "load";
depthStencilAttachment = {
view: this._renderer.texture.getGpuSource(renderTarget.depthStencilTexture.source).createView(),
stencilStoreOp: "store",
stencilLoadOp,
depthClearValue: 1,
depthLoadOp,
depthStoreOp: "store"
};
}
const descriptor = {
colorAttachments,
depthStencilAttachment
};
return descriptor;
}
clear(renderTarget, clear = true, clearColor, viewport) {
if (!clear)
return;
const { gpu, encoder } = this._renderer;
const device = gpu.device;
const standAlone = encoder.commandEncoder === null;
if (standAlone) {
const commandEncoder = device.createCommandEncoder();
const renderPassDescriptor = this.getDescriptor(renderTarget, clear, clearColor);
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.setViewport(viewport.x, viewport.y, viewport.width, viewport.height, 0, 1);
passEncoder.end();
const gpuCommands = commandEncoder.finish();
device.queue.submit([gpuCommands]);
} else {
this.startRenderPass(renderTarget, clear, clearColor, viewport);
}
}
initGpuRenderTarget(renderTarget) {
renderTarget.isRoot = true;
const gpuRenderTarget = new GpuRenderTarget.GpuRenderTarget();
renderTarget.colorTextures.forEach((colorTexture, i) => {
if (CanvasSource.CanvasSource.test(colorTexture.resource)) {
const context = colorTexture.resource.getContext(
"webgpu"
);
const alphaMode = colorTexture.transparent ? "premultiplied" : "opaque";
try {
context.configure({
device: this._renderer.gpu.device,
// eslint-disable-next-line max-len
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,
format: "bgra8unorm",
alphaMode
});
} catch (e) {
console.error(e);
}
gpuRenderTarget.contexts[i] = context;
}
gpuRenderTarget.msaa = colorTexture.source.antialias;
if (colorTexture.source.antialias) {
const msaaTexture = new TextureSource.TextureSource({
width: 0,
height: 0,
sampleCount: 4
});
gpuRenderTarget.msaaTextures[i] = msaaTexture;
}
});
if (gpuRenderTarget.msaa) {
gpuRenderTarget.msaaSamples = 4;
if (renderTarget.depthStencilTexture) {
renderTarget.depthStencilTexture.source.sampleCount = 4;
}
}
return gpuRenderTarget;
}
destroyGpuRenderTarget(gpuRenderTarget) {
gpuRenderTarget.contexts.forEach((context) => {
context.unconfigure();
});
gpuRenderTarget.msaaTextures.forEach((texture) => {
texture.destroy();
});
gpuRenderTarget.msaaTextures.length = 0;
gpuRenderTarget.contexts.length = 0;
}
ensureDepthStencilTexture(renderTarget) {
const gpuRenderTarget = this._renderTargetSystem.getGpuRenderTarget(renderTarget);
if (renderTarget.depthStencilTexture && gpuRenderTarget.msaa) {
renderTarget.depthStencilTexture.source.sampleCount = 4;
}
}
resizeGpuRenderTarget(renderTarget) {
const gpuRenderTarget = this._renderTargetSystem.getGpuRenderTarget(renderTarget);
gpuRenderTarget.width = renderTarget.width;
gpuRenderTarget.height = renderTarget.height;
if (gpuRenderTarget.msaa) {
renderTarget.colorTextures.forEach((colorTexture, i) => {
const msaaTexture = gpuRenderTarget.msaaTextures[i];
msaaTexture?.resize(
colorTexture.source.width,
colorTexture.source.height,
colorTexture.source._resolution
);
});
}
}
}
exports.GpuRenderTargetAdaptor = GpuRenderTargetAdaptor;
//# sourceMappingURL=GpuRenderTargetAdaptor.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,212 @@
import { CLEAR } from '../../gl/const.mjs';
import { CanvasSource } from '../../shared/texture/sources/CanvasSource.mjs';
import { TextureSource } from '../../shared/texture/sources/TextureSource.mjs';
import { GpuRenderTarget } from './GpuRenderTarget.mjs';
"use strict";
class GpuRenderTargetAdaptor {
init(renderer, renderTargetSystem) {
this._renderer = renderer;
this._renderTargetSystem = renderTargetSystem;
}
copyToTexture(sourceRenderSurfaceTexture, destinationTexture, originSrc, size, originDest) {
const renderer = this._renderer;
const baseGpuTexture = this._getGpuColorTexture(
sourceRenderSurfaceTexture
);
const backGpuTexture = renderer.texture.getGpuSource(
destinationTexture.source
);
renderer.encoder.commandEncoder.copyTextureToTexture(
{
texture: baseGpuTexture,
origin: originSrc
},
{
texture: backGpuTexture,
origin: originDest
},
size
);
return destinationTexture;
}
startRenderPass(renderTarget, clear = true, clearColor, viewport) {
const renderTargetSystem = this._renderTargetSystem;
const gpuRenderTarget = renderTargetSystem.getGpuRenderTarget(renderTarget);
const descriptor = this.getDescriptor(renderTarget, clear, clearColor);
gpuRenderTarget.descriptor = descriptor;
this._renderer.pipeline.setRenderTarget(gpuRenderTarget);
this._renderer.encoder.beginRenderPass(gpuRenderTarget);
this._renderer.encoder.setViewport(viewport);
}
finishRenderPass() {
this._renderer.encoder.endRenderPass();
}
/**
* returns the gpu texture for the first color texture in the render target
* mainly used by the filter manager to get copy the texture for blending
* @param renderTarget
* @returns a gpu texture
*/
_getGpuColorTexture(renderTarget) {
const gpuRenderTarget = this._renderTargetSystem.getGpuRenderTarget(renderTarget);
if (gpuRenderTarget.contexts[0]) {
return gpuRenderTarget.contexts[0].getCurrentTexture();
}
return this._renderer.texture.getGpuSource(
renderTarget.colorTextures[0].source
);
}
getDescriptor(renderTarget, clear, clearValue) {
if (typeof clear === "boolean") {
clear = clear ? CLEAR.ALL : CLEAR.NONE;
}
const renderTargetSystem = this._renderTargetSystem;
const gpuRenderTarget = renderTargetSystem.getGpuRenderTarget(renderTarget);
const colorAttachments = renderTarget.colorTextures.map(
(texture, i) => {
const context = gpuRenderTarget.contexts[i];
let view;
let resolveTarget;
if (context) {
const currentTexture = context.getCurrentTexture();
const canvasTextureView = currentTexture.createView();
view = canvasTextureView;
} else {
view = this._renderer.texture.getGpuSource(texture).createView({
mipLevelCount: 1
});
}
if (gpuRenderTarget.msaaTextures[i]) {
resolveTarget = view;
view = this._renderer.texture.getTextureView(
gpuRenderTarget.msaaTextures[i]
);
}
const loadOp = clear & CLEAR.COLOR ? "clear" : "load";
clearValue ?? (clearValue = renderTargetSystem.defaultClearColor);
return {
view,
resolveTarget,
clearValue,
storeOp: "store",
loadOp
};
}
);
let depthStencilAttachment;
if ((renderTarget.stencil || renderTarget.depth) && !renderTarget.depthStencilTexture) {
renderTarget.ensureDepthStencilTexture();
renderTarget.depthStencilTexture.source.sampleCount = gpuRenderTarget.msaa ? 4 : 1;
}
if (renderTarget.depthStencilTexture) {
const stencilLoadOp = clear & CLEAR.STENCIL ? "clear" : "load";
const depthLoadOp = clear & CLEAR.DEPTH ? "clear" : "load";
depthStencilAttachment = {
view: this._renderer.texture.getGpuSource(renderTarget.depthStencilTexture.source).createView(),
stencilStoreOp: "store",
stencilLoadOp,
depthClearValue: 1,
depthLoadOp,
depthStoreOp: "store"
};
}
const descriptor = {
colorAttachments,
depthStencilAttachment
};
return descriptor;
}
clear(renderTarget, clear = true, clearColor, viewport) {
if (!clear)
return;
const { gpu, encoder } = this._renderer;
const device = gpu.device;
const standAlone = encoder.commandEncoder === null;
if (standAlone) {
const commandEncoder = device.createCommandEncoder();
const renderPassDescriptor = this.getDescriptor(renderTarget, clear, clearColor);
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.setViewport(viewport.x, viewport.y, viewport.width, viewport.height, 0, 1);
passEncoder.end();
const gpuCommands = commandEncoder.finish();
device.queue.submit([gpuCommands]);
} else {
this.startRenderPass(renderTarget, clear, clearColor, viewport);
}
}
initGpuRenderTarget(renderTarget) {
renderTarget.isRoot = true;
const gpuRenderTarget = new GpuRenderTarget();
renderTarget.colorTextures.forEach((colorTexture, i) => {
if (CanvasSource.test(colorTexture.resource)) {
const context = colorTexture.resource.getContext(
"webgpu"
);
const alphaMode = colorTexture.transparent ? "premultiplied" : "opaque";
try {
context.configure({
device: this._renderer.gpu.device,
// eslint-disable-next-line max-len
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,
format: "bgra8unorm",
alphaMode
});
} catch (e) {
console.error(e);
}
gpuRenderTarget.contexts[i] = context;
}
gpuRenderTarget.msaa = colorTexture.source.antialias;
if (colorTexture.source.antialias) {
const msaaTexture = new TextureSource({
width: 0,
height: 0,
sampleCount: 4
});
gpuRenderTarget.msaaTextures[i] = msaaTexture;
}
});
if (gpuRenderTarget.msaa) {
gpuRenderTarget.msaaSamples = 4;
if (renderTarget.depthStencilTexture) {
renderTarget.depthStencilTexture.source.sampleCount = 4;
}
}
return gpuRenderTarget;
}
destroyGpuRenderTarget(gpuRenderTarget) {
gpuRenderTarget.contexts.forEach((context) => {
context.unconfigure();
});
gpuRenderTarget.msaaTextures.forEach((texture) => {
texture.destroy();
});
gpuRenderTarget.msaaTextures.length = 0;
gpuRenderTarget.contexts.length = 0;
}
ensureDepthStencilTexture(renderTarget) {
const gpuRenderTarget = this._renderTargetSystem.getGpuRenderTarget(renderTarget);
if (renderTarget.depthStencilTexture && gpuRenderTarget.msaa) {
renderTarget.depthStencilTexture.source.sampleCount = 4;
}
}
resizeGpuRenderTarget(renderTarget) {
const gpuRenderTarget = this._renderTargetSystem.getGpuRenderTarget(renderTarget);
gpuRenderTarget.width = renderTarget.width;
gpuRenderTarget.height = renderTarget.height;
if (gpuRenderTarget.msaa) {
renderTarget.colorTextures.forEach((colorTexture, i) => {
const msaaTexture = gpuRenderTarget.msaaTextures[i];
msaaTexture?.resize(
colorTexture.source.width,
colorTexture.source.height,
colorTexture.source._resolution
);
});
}
}
}
export { GpuRenderTargetAdaptor };
//# sourceMappingURL=GpuRenderTargetAdaptor.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,18 @@
import { ExtensionType } from '../../../../extensions/Extensions';
import { RenderTargetSystem } from '../../shared/renderTarget/RenderTargetSystem';
import { GpuRenderTargetAdaptor } from './GpuRenderTargetAdaptor';
import type { WebGPURenderer } from '../WebGPURenderer';
import type { GpuRenderTarget } from './GpuRenderTarget';
/**
* The WebGL adaptor for the render target system. Allows the Render Target System to be used with the WebGl renderer
* @memberof rendering
*/
export declare class GpuRenderTargetSystem extends RenderTargetSystem<GpuRenderTarget> {
/** @ignore */
static extension: {
readonly type: readonly [ExtensionType.WebGPUSystem];
readonly name: "renderTarget";
};
adaptor: GpuRenderTargetAdaptor;
constructor(renderer: WebGPURenderer);
}

View File

@@ -0,0 +1,22 @@
'use strict';
var Extensions = require('../../../../extensions/Extensions.js');
var RenderTargetSystem = require('../../shared/renderTarget/RenderTargetSystem.js');
var GpuRenderTargetAdaptor = require('./GpuRenderTargetAdaptor.js');
"use strict";
class GpuRenderTargetSystem extends RenderTargetSystem.RenderTargetSystem {
constructor(renderer) {
super(renderer);
this.adaptor = new GpuRenderTargetAdaptor.GpuRenderTargetAdaptor();
this.adaptor.init(renderer, this);
}
}
/** @ignore */
GpuRenderTargetSystem.extension = {
type: [Extensions.ExtensionType.WebGPUSystem],
name: "renderTarget"
};
exports.GpuRenderTargetSystem = GpuRenderTargetSystem;
//# sourceMappingURL=GpuRenderTargetSystem.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"GpuRenderTargetSystem.js","sources":["../../../../../src/rendering/renderers/gpu/renderTarget/GpuRenderTargetSystem.ts"],"sourcesContent":["import { ExtensionType } from '../../../../extensions/Extensions';\nimport { RenderTargetSystem } from '../../shared/renderTarget/RenderTargetSystem';\nimport { GpuRenderTargetAdaptor } from './GpuRenderTargetAdaptor';\n\nimport type { WebGPURenderer } from '../WebGPURenderer';\nimport type { GpuRenderTarget } from './GpuRenderTarget';\n\n/**\n * The WebGL adaptor for the render target system. Allows the Render Target System to be used with the WebGl renderer\n * @memberof rendering\n */\nexport class GpuRenderTargetSystem extends RenderTargetSystem<GpuRenderTarget>\n{\n /** @ignore */\n public static extension = {\n type: [ExtensionType.WebGPUSystem],\n name: 'renderTarget',\n } as const;\n\n public adaptor = new GpuRenderTargetAdaptor();\n\n constructor(renderer: WebGPURenderer)\n {\n super(renderer);\n\n this.adaptor.init(renderer, this);\n }\n}\n"],"names":["RenderTargetSystem","GpuRenderTargetAdaptor","ExtensionType"],"mappings":";;;;;;;AAWO,MAAM,8BAA8BA,qCAC3C,CAAA;AAAA,EASI,YAAY,QACZ,EAAA;AACI,IAAA,KAAA,CAAM,QAAQ,CAAA,CAAA;AAJlB,IAAO,IAAA,CAAA,OAAA,GAAU,IAAIC,6CAAuB,EAAA,CAAA;AAMxC,IAAK,IAAA,CAAA,OAAA,CAAQ,IAAK,CAAA,QAAA,EAAU,IAAI,CAAA,CAAA;AAAA,GACpC;AACJ,CAAA;AAAA;AAhBa,qBAAA,CAGK,SAAY,GAAA;AAAA,EACtB,IAAA,EAAM,CAACC,wBAAA,CAAc,YAAY,CAAA;AAAA,EACjC,IAAM,EAAA,cAAA;AACV,CAAA;;;;"}

View File

@@ -0,0 +1,20 @@
import { ExtensionType } from '../../../../extensions/Extensions.mjs';
import { RenderTargetSystem } from '../../shared/renderTarget/RenderTargetSystem.mjs';
import { GpuRenderTargetAdaptor } from './GpuRenderTargetAdaptor.mjs';
"use strict";
class GpuRenderTargetSystem extends RenderTargetSystem {
constructor(renderer) {
super(renderer);
this.adaptor = new GpuRenderTargetAdaptor();
this.adaptor.init(renderer, this);
}
}
/** @ignore */
GpuRenderTargetSystem.extension = {
type: [ExtensionType.WebGPUSystem],
name: "renderTarget"
};
export { GpuRenderTargetSystem };
//# sourceMappingURL=GpuRenderTargetSystem.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"GpuRenderTargetSystem.mjs","sources":["../../../../../src/rendering/renderers/gpu/renderTarget/GpuRenderTargetSystem.ts"],"sourcesContent":["import { ExtensionType } from '../../../../extensions/Extensions';\nimport { RenderTargetSystem } from '../../shared/renderTarget/RenderTargetSystem';\nimport { GpuRenderTargetAdaptor } from './GpuRenderTargetAdaptor';\n\nimport type { WebGPURenderer } from '../WebGPURenderer';\nimport type { GpuRenderTarget } from './GpuRenderTarget';\n\n/**\n * The WebGL adaptor for the render target system. Allows the Render Target System to be used with the WebGl renderer\n * @memberof rendering\n */\nexport class GpuRenderTargetSystem extends RenderTargetSystem<GpuRenderTarget>\n{\n /** @ignore */\n public static extension = {\n type: [ExtensionType.WebGPUSystem],\n name: 'renderTarget',\n } as const;\n\n public adaptor = new GpuRenderTargetAdaptor();\n\n constructor(renderer: WebGPURenderer)\n {\n super(renderer);\n\n this.adaptor.init(renderer, this);\n }\n}\n"],"names":[],"mappings":";;;;;AAWO,MAAM,8BAA8B,kBAC3C,CAAA;AAAA,EASI,YAAY,QACZ,EAAA;AACI,IAAA,KAAA,CAAM,QAAQ,CAAA,CAAA;AAJlB,IAAO,IAAA,CAAA,OAAA,GAAU,IAAI,sBAAuB,EAAA,CAAA;AAMxC,IAAK,IAAA,CAAA,OAAA,CAAQ,IAAK,CAAA,QAAA,EAAU,IAAI,CAAA,CAAA;AAAA,GACpC;AACJ,CAAA;AAAA;AAhBa,qBAAA,CAGK,SAAY,GAAA;AAAA,EACtB,IAAA,EAAM,CAAC,aAAA,CAAc,YAAY,CAAA;AAAA,EACjC,IAAM,EAAA,cAAA;AACV,CAAA;;;;"}

View File

@@ -0,0 +1,2 @@
import type { Matrix } from '../../../../maths/matrix/Matrix';
export declare function calculateProjection(pm: Matrix, x: number, y: number, width: number, height: number, flipY: boolean): Matrix;

View File

@@ -0,0 +1,15 @@
'use strict';
"use strict";
function calculateProjection(pm, x, y, width, height, flipY) {
const sign = flipY ? 1 : -1;
pm.identity();
pm.a = 1 / width * 2;
pm.d = sign * (1 / height * 2);
pm.tx = -1 - x * pm.a;
pm.ty = -sign - y * pm.d;
return pm;
}
exports.calculateProjection = calculateProjection;
//# sourceMappingURL=calculateProjection.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"calculateProjection.js","sources":["../../../../../src/rendering/renderers/gpu/renderTarget/calculateProjection.ts"],"sourcesContent":["import type { Matrix } from '../../../../maths/matrix/Matrix';\n\nexport function calculateProjection(\n pm: Matrix,\n x: number,\n y: number,\n width: number,\n height: number,\n flipY: boolean\n): Matrix\n{\n const sign = flipY ? 1 : -1;\n\n pm.identity();\n\n pm.a = (1 / width * 2);\n pm.d = sign * (1 / height * 2);\n\n pm.tx = -1 - (x * pm.a);\n pm.ty = -sign - (y * pm.d);\n\n return pm;\n}\n"],"names":[],"mappings":";;;AAEO,SAAS,oBACZ,EACA,EAAA,CAAA,EACA,CACA,EAAA,KAAA,EACA,QACA,KAEJ,EAAA;AACI,EAAM,MAAA,IAAA,GAAO,QAAQ,CAAI,GAAA,CAAA,CAAA,CAAA;AAEzB,EAAA,EAAA,CAAG,QAAS,EAAA,CAAA;AAEZ,EAAG,EAAA,CAAA,CAAA,GAAK,IAAI,KAAQ,GAAA,CAAA,CAAA;AACpB,EAAG,EAAA,CAAA,CAAA,GAAI,IAAQ,IAAA,CAAA,GAAI,MAAS,GAAA,CAAA,CAAA,CAAA;AAE5B,EAAG,EAAA,CAAA,EAAA,GAAK,CAAM,CAAA,GAAA,CAAA,GAAI,EAAG,CAAA,CAAA,CAAA;AACrB,EAAA,EAAA,CAAG,EAAK,GAAA,CAAC,IAAQ,GAAA,CAAA,GAAI,EAAG,CAAA,CAAA,CAAA;AAExB,EAAO,OAAA,EAAA,CAAA;AACX;;;;"}

View File

@@ -0,0 +1,13 @@
"use strict";
function calculateProjection(pm, x, y, width, height, flipY) {
const sign = flipY ? 1 : -1;
pm.identity();
pm.a = 1 / width * 2;
pm.d = sign * (1 / height * 2);
pm.tx = -1 - x * pm.a;
pm.ty = -sign - y * pm.d;
return pm;
}
export { calculateProjection };
//# sourceMappingURL=calculateProjection.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"calculateProjection.mjs","sources":["../../../../../src/rendering/renderers/gpu/renderTarget/calculateProjection.ts"],"sourcesContent":["import type { Matrix } from '../../../../maths/matrix/Matrix';\n\nexport function calculateProjection(\n pm: Matrix,\n x: number,\n y: number,\n width: number,\n height: number,\n flipY: boolean\n): Matrix\n{\n const sign = flipY ? 1 : -1;\n\n pm.identity();\n\n pm.a = (1 / width * 2);\n pm.d = sign * (1 / height * 2);\n\n pm.tx = -1 - (x * pm.a);\n pm.ty = -sign - (y * pm.d);\n\n return pm;\n}\n"],"names":[],"mappings":";AAEO,SAAS,oBACZ,EACA,EAAA,CAAA,EACA,CACA,EAAA,KAAA,EACA,QACA,KAEJ,EAAA;AACI,EAAM,MAAA,IAAA,GAAO,QAAQ,CAAI,GAAA,CAAA,CAAA,CAAA;AAEzB,EAAA,EAAA,CAAG,QAAS,EAAA,CAAA;AAEZ,EAAG,EAAA,CAAA,CAAA,GAAK,IAAI,KAAQ,GAAA,CAAA,CAAA;AACpB,EAAG,EAAA,CAAA,CAAA,GAAI,IAAQ,IAAA,CAAA,GAAI,MAAS,GAAA,CAAA,CAAA,CAAA;AAE5B,EAAG,EAAA,CAAA,EAAA,GAAK,CAAM,CAAA,GAAA,CAAA,GAAI,EAAG,CAAA,CAAA,CAAA;AACrB,EAAA,EAAA,CAAG,EAAK,GAAA,CAAC,IAAQ,GAAA,CAAA,GAAI,EAAG,CAAA,CAAA,CAAA;AAExB,EAAO,OAAA,EAAA,CAAA;AACX;;;;"}

View File

@@ -0,0 +1,75 @@
import type { BindResource } from './BindResource';
/**
* A bind group is a collection of resources that are bound together for use by a shader.
* They are essentially a wrapper for the WebGPU BindGroup class. But with the added bonus
* that WebGL can also work with them.
* @see https://gpuweb.github.io/gpuweb/#dictdef-gpubindgroupdescriptor
* @example
* // Create a bind group with a single texture and sampler
* const bindGroup = new BindGroup({
* uTexture: texture.source,
* uTexture: texture.style,
* });
*
* Bind groups resources must implement the {@link BindResource} interface.
* The following resources are supported:
* - {@link TextureSource}
* - {@link TextureStyle}
* - {@link Buffer}
* - {@link BufferResource}
* - {@link UniformGroup}
*
* The keys in the bind group must correspond to the names of the resources in the GPU program.
*
* This bind group class will also watch for changes in its resources ensuring that the changes
* are reflected in the WebGPU BindGroup.
* @memberof rendering
*/
export declare class BindGroup {
/** The resources that are bound together for use by a shader. */
resources: Record<string, BindResource>;
/**
* a key used internally to match it up to a WebGPU Bindgroup
* @internal
* @ignore
*/
_key: string;
private _dirty;
/**
* Create a new instance eof the Bind Group.
* @param resources - The resources that are bound together for use by a shader.
*/
constructor(resources?: Record<string, BindResource>);
/**
* Updates the key if its flagged as dirty. This is used internally to
* match this bind group to a WebGPU BindGroup.
* @internal
* @ignore
*/
_updateKey(): void;
/**
* Set a resource at a given index. this function will
* ensure that listeners will be removed from the current resource
* and added to the new resource.
* @param resource - The resource to set.
* @param index - The index to set the resource at.
*/
setResource(resource: BindResource, index: number): void;
/**
* Returns the resource at the current specified index.
* @param index - The index of the resource to get.
* @returns - The resource at the specified index.
*/
getResource(index: number): BindResource;
/**
* Used internally to 'touch' each resource, to ensure that the GC
* knows that all resources in this bind group are still being used.
* @param tick - The current tick.
* @internal
* @ignore
*/
_touch(tick: number): void;
/** Destroys this bind group and removes all listeners. */
destroy(): void;
protected onResourceChange(resource: BindResource): void;
}

View File

@@ -0,0 +1,101 @@
'use strict';
"use strict";
class BindGroup {
/**
* Create a new instance eof the Bind Group.
* @param resources - The resources that are bound together for use by a shader.
*/
constructor(resources) {
/** The resources that are bound together for use by a shader. */
this.resources = /* @__PURE__ */ Object.create(null);
this._dirty = true;
let index = 0;
for (const i in resources) {
const resource = resources[i];
this.setResource(resource, index++);
}
this._updateKey();
}
/**
* Updates the key if its flagged as dirty. This is used internally to
* match this bind group to a WebGPU BindGroup.
* @internal
* @ignore
*/
_updateKey() {
if (!this._dirty)
return;
this._dirty = false;
const keyParts = [];
let index = 0;
for (const i in this.resources) {
keyParts[index++] = this.resources[i]._resourceId;
}
this._key = keyParts.join("|");
}
/**
* Set a resource at a given index. this function will
* ensure that listeners will be removed from the current resource
* and added to the new resource.
* @param resource - The resource to set.
* @param index - The index to set the resource at.
*/
setResource(resource, index) {
const currentResource = this.resources[index];
if (resource === currentResource)
return;
if (currentResource) {
resource.off?.("change", this.onResourceChange, this);
}
resource.on?.("change", this.onResourceChange, this);
this.resources[index] = resource;
this._dirty = true;
}
/**
* Returns the resource at the current specified index.
* @param index - The index of the resource to get.
* @returns - The resource at the specified index.
*/
getResource(index) {
return this.resources[index];
}
/**
* Used internally to 'touch' each resource, to ensure that the GC
* knows that all resources in this bind group are still being used.
* @param tick - The current tick.
* @internal
* @ignore
*/
_touch(tick) {
const resources = this.resources;
for (const i in resources) {
resources[i]._touched = tick;
}
}
/** Destroys this bind group and removes all listeners. */
destroy() {
const resources = this.resources;
for (const i in resources) {
const resource = resources[i];
resource.off?.("change", this.onResourceChange, this);
}
this.resources = null;
}
onResourceChange(resource) {
this._dirty = true;
if (resource.destroyed) {
const resources = this.resources;
for (const i in resources) {
if (resources[i] === resource) {
resources[i] = null;
}
}
} else {
this._updateKey();
}
}
}
exports.BindGroup = BindGroup;
//# sourceMappingURL=BindGroup.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,99 @@
"use strict";
class BindGroup {
/**
* Create a new instance eof the Bind Group.
* @param resources - The resources that are bound together for use by a shader.
*/
constructor(resources) {
/** The resources that are bound together for use by a shader. */
this.resources = /* @__PURE__ */ Object.create(null);
this._dirty = true;
let index = 0;
for (const i in resources) {
const resource = resources[i];
this.setResource(resource, index++);
}
this._updateKey();
}
/**
* Updates the key if its flagged as dirty. This is used internally to
* match this bind group to a WebGPU BindGroup.
* @internal
* @ignore
*/
_updateKey() {
if (!this._dirty)
return;
this._dirty = false;
const keyParts = [];
let index = 0;
for (const i in this.resources) {
keyParts[index++] = this.resources[i]._resourceId;
}
this._key = keyParts.join("|");
}
/**
* Set a resource at a given index. this function will
* ensure that listeners will be removed from the current resource
* and added to the new resource.
* @param resource - The resource to set.
* @param index - The index to set the resource at.
*/
setResource(resource, index) {
const currentResource = this.resources[index];
if (resource === currentResource)
return;
if (currentResource) {
resource.off?.("change", this.onResourceChange, this);
}
resource.on?.("change", this.onResourceChange, this);
this.resources[index] = resource;
this._dirty = true;
}
/**
* Returns the resource at the current specified index.
* @param index - The index of the resource to get.
* @returns - The resource at the specified index.
*/
getResource(index) {
return this.resources[index];
}
/**
* Used internally to 'touch' each resource, to ensure that the GC
* knows that all resources in this bind group are still being used.
* @param tick - The current tick.
* @internal
* @ignore
*/
_touch(tick) {
const resources = this.resources;
for (const i in resources) {
resources[i]._touched = tick;
}
}
/** Destroys this bind group and removes all listeners. */
destroy() {
const resources = this.resources;
for (const i in resources) {
const resource = resources[i];
resource.off?.("change", this.onResourceChange, this);
}
this.resources = null;
}
onResourceChange(resource) {
this._dirty = true;
if (resource.destroyed) {
const resources = this.resources;
for (const i in resources) {
if (resources[i] === resource) {
resources[i] = null;
}
}
} else {
this._updateKey();
}
}
}
export { BindGroup };
//# sourceMappingURL=BindGroup.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,33 @@
import type { BindGroup } from './BindGroup';
/**
* an interface that allows a resource to be bound to the gpu in a bind group
* @memberof rendering
*/
export interface BindResource {
/**
* The type of resource this is
* @ignore
*/
_resourceType: string;
/**
* Unique id for this resource this can change and is used to link the gpu
* @ignore
*/
_resourceId: number;
_touched: number;
/**
* a boolean that indicates if the resource has been destroyed.
* If true, the resource should not be used and any bind groups
* that will release any references to this resource.
* @ignore
*/
destroyed: boolean;
/**
* event dispatch whenever the underlying resource needs to change
* this could be a texture or buffer that has been resized.
* This is important as it allows the renderer to know that it needs to rebind the resource
*/
on?(event: 'change', listenerFunction: (resource: BindResource) => void, listener: BindGroup): void;
/** @todo */
off?(event: 'change', listenerFunction: (resource: BindResource) => void, listener: BindGroup): void;
}

View File

@@ -0,0 +1,4 @@
'use strict';
"use strict";
//# sourceMappingURL=BindResource.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BindResource.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}

View File

@@ -0,0 +1,2 @@
"use strict";
//# sourceMappingURL=BindResource.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BindResource.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}

View File

@@ -0,0 +1,148 @@
/// <reference types="@webgpu/types" />
import type { ExtractedAttributeData } from '../../gl/shader/program/extractAttributesFromGlProgram';
import type { StructsAndGroups } from './utils/extractStructAndGroups';
/**
* a WebGPU descriptions of how the program is laid out
* @see https://gpuweb.github.io/gpuweb/#gpupipelinelayout
* @memberof rendering
*/
export type ProgramPipelineLayoutDescription = GPUBindGroupLayoutEntry[][];
/**
* a map the maps names of uniforms to group indexes
* @memberof rendering
*/
export type ProgramLayout = Record<string, number>[];
/**
* the program source
* @memberof rendering
*/
export interface ProgramSource {
/** The wgsl source code of the shader. */
source: string;
/** The main function to run in this shader */
entryPoint?: string;
}
/**
* The options for the gpu program
* @memberof rendering
*/
export interface GpuProgramOptions {
/**
* the name of the program, this is added to the label of the GPU Program created
* under the hood. Makes it much easier to debug!
*/
name?: string;
/** The fragment glsl shader source. */
fragment?: ProgramSource;
/** The vertex glsl shader source. */
vertex?: ProgramSource;
/** The layout of the program. If not provided, it will be generated from the shader sources. */
layout?: ProgramLayout;
/** The gpu layout of the program. If not provided, it will be generated from the shader sources. */
gpuLayout?: ProgramPipelineLayoutDescription;
}
/**
* A wrapper for a WebGPU Program, specifically designed for the WebGPU renderer.
* This class facilitates the creation and management of shader code that integrates with the WebGPU pipeline.
*
* To leverage the full capabilities of this class, familiarity with WGSL shaders is recommended.
* @see https://gpuweb.github.io/gpuweb/#index
* @example
*
* // Create a new program
* const program = new GpuProgram({
* vertex: {
* source: '...',
* entryPoint: 'main',
* },
* fragment:{
* source: '...',
* entryPoint: 'main',
* },
* });
*
*
* Note: Both fragment and vertex shader sources can coexist within a single WGSL source file
* this can make things a bit simpler.
*
* For optimal usage and best performance, it help to reuse programs whenever possible.
* The {@link GpuProgram.from} helper function is designed for this purpose, utilizing an
* internal cache to efficiently manage and retrieve program instances.
* By leveraging this function, you can significantly reduce overhead and enhance the performance of your rendering pipeline.
*
* An important distinction between WebGL and WebGPU regarding program data retrieval:
* While WebGL allows extraction of program information directly from its compiled state,
* WebGPU does not offer such a capability. Therefore, in the context of WebGPU, we're required
* to manually extract the program layout information from the source code itself.
* @memberof rendering
*/
export declare class GpuProgram {
/** The fragment glsl shader source. */
readonly fragment?: ProgramSource;
/** The vertex glsl shader source */
readonly vertex?: ProgramSource;
/**
* Mapping of uniform names to group indexes for organizing shader program uniforms.
* Automatically generated from shader sources if not provided.
* @example
* // Assuming a shader with two uniforms, `u_time` and `u_resolution`, grouped respectively:
* [
* { "u_time": 0 },
* { "u_resolution": 1 }
* ]
*/
readonly layout: ProgramLayout;
/**
* Configuration for the WebGPU bind group layouts, detailing resource organization for the shader.
* Generated from shader sources if not explicitly provided.
* @example
* // Assuming a shader program that requires two bind groups:
* [
* // First bind group layout entries
* [{ binding: 0, visibility: GPUShaderStage.VERTEX, type: "uniform-buffer" }],
* // Second bind group layout entries
* [{ binding: 1, visibility: GPUShaderStage.FRAGMENT, type: "sampler" },
* { binding: 2, visibility: GPUShaderStage.FRAGMENT, type: "sampled-texture" }]
* ]
*/
readonly gpuLayout: ProgramPipelineLayoutDescription;
/**
* @internal
* @ignore
*/
_layoutKey: number;
/**
* @internal
* @ignore
*/
_attributeLocationsKey: number;
/** the structs and groups extracted from the shader sources */
readonly structsAndGroups: StructsAndGroups;
/**
* the name of the program, this is added to the label of the GPU Program created under the hood.
* Makes it much easier to debug!
*/
readonly name: string;
private _attributeData;
/** if true, the program will automatically assign global uniforms to group[0] */
autoAssignGlobalUniforms: boolean;
/** if true, the program will automatically assign local uniforms to group[1] */
autoAssignLocalUniforms: boolean;
/**
* Create a new GpuProgram
* @param options - The options for the gpu program
*/
constructor(options: GpuProgramOptions);
private _generateProgramKey;
get attributeData(): Record<string, ExtractedAttributeData>;
/** destroys the program */
destroy(): void;
/**
* Helper function that creates a program for a given source.
* It will check the program cache if the program has already been created.
* If it has that one will be returned, if not a new one will be created and cached.
* @param options - The options for the program.
* @returns A program using the same source
*/
static from(options: GpuProgramOptions): GpuProgram;
}

View File

@@ -0,0 +1,81 @@
'use strict';
var createIdFromString = require('../../shared/utils/createIdFromString.js');
var extractAttributesFromGpuProgram = require('./utils/extractAttributesFromGpuProgram.js');
var extractStructAndGroups = require('./utils/extractStructAndGroups.js');
var generateGpuLayoutGroups = require('./utils/generateGpuLayoutGroups.js');
var generateLayoutHash = require('./utils/generateLayoutHash.js');
var removeStructAndGroupDuplicates = require('./utils/removeStructAndGroupDuplicates.js');
"use strict";
const programCache = /* @__PURE__ */ Object.create(null);
class GpuProgram {
/**
* Create a new GpuProgram
* @param options - The options for the gpu program
*/
constructor(options) {
/**
* @internal
* @ignore
*/
this._layoutKey = 0;
/**
* @internal
* @ignore
*/
this._attributeLocationsKey = 0;
const { fragment, vertex, layout, gpuLayout, name } = options;
this.name = name;
this.fragment = fragment;
this.vertex = vertex;
if (fragment.source === vertex.source) {
const structsAndGroups = extractStructAndGroups.extractStructAndGroups(fragment.source);
this.structsAndGroups = structsAndGroups;
} else {
const vertexStructsAndGroups = extractStructAndGroups.extractStructAndGroups(vertex.source);
const fragmentStructsAndGroups = extractStructAndGroups.extractStructAndGroups(fragment.source);
this.structsAndGroups = removeStructAndGroupDuplicates.removeStructAndGroupDuplicates(vertexStructsAndGroups, fragmentStructsAndGroups);
}
this.layout = layout ?? generateLayoutHash.generateLayoutHash(this.structsAndGroups);
this.gpuLayout = gpuLayout ?? generateGpuLayoutGroups.generateGpuLayoutGroups(this.structsAndGroups);
this.autoAssignGlobalUniforms = !!(this.layout[0]?.globalUniforms !== void 0);
this.autoAssignLocalUniforms = !!(this.layout[1]?.localUniforms !== void 0);
this._generateProgramKey();
}
// TODO maker this pure
_generateProgramKey() {
const { vertex, fragment } = this;
const bigKey = vertex.source + fragment.source + vertex.entryPoint + fragment.entryPoint;
this._layoutKey = createIdFromString.createIdFromString(bigKey, "program");
}
get attributeData() {
this._attributeData ?? (this._attributeData = extractAttributesFromGpuProgram.extractAttributesFromGpuProgram(this.vertex));
return this._attributeData;
}
/** destroys the program */
destroy() {
this.gpuLayout = null;
this.layout = null;
this.structsAndGroups = null;
this.fragment = null;
this.vertex = null;
}
/**
* Helper function that creates a program for a given source.
* It will check the program cache if the program has already been created.
* If it has that one will be returned, if not a new one will be created and cached.
* @param options - The options for the program.
* @returns A program using the same source
*/
static from(options) {
const key = `${options.vertex.source}:${options.fragment.source}:${options.fragment.entryPoint}:${options.vertex.entryPoint}`;
if (!programCache[key]) {
programCache[key] = new GpuProgram(options);
}
return programCache[key];
}
}
exports.GpuProgram = GpuProgram;
//# sourceMappingURL=GpuProgram.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,79 @@
import { createIdFromString } from '../../shared/utils/createIdFromString.mjs';
import { extractAttributesFromGpuProgram } from './utils/extractAttributesFromGpuProgram.mjs';
import { extractStructAndGroups } from './utils/extractStructAndGroups.mjs';
import { generateGpuLayoutGroups } from './utils/generateGpuLayoutGroups.mjs';
import { generateLayoutHash } from './utils/generateLayoutHash.mjs';
import { removeStructAndGroupDuplicates } from './utils/removeStructAndGroupDuplicates.mjs';
"use strict";
const programCache = /* @__PURE__ */ Object.create(null);
class GpuProgram {
/**
* Create a new GpuProgram
* @param options - The options for the gpu program
*/
constructor(options) {
/**
* @internal
* @ignore
*/
this._layoutKey = 0;
/**
* @internal
* @ignore
*/
this._attributeLocationsKey = 0;
const { fragment, vertex, layout, gpuLayout, name } = options;
this.name = name;
this.fragment = fragment;
this.vertex = vertex;
if (fragment.source === vertex.source) {
const structsAndGroups = extractStructAndGroups(fragment.source);
this.structsAndGroups = structsAndGroups;
} else {
const vertexStructsAndGroups = extractStructAndGroups(vertex.source);
const fragmentStructsAndGroups = extractStructAndGroups(fragment.source);
this.structsAndGroups = removeStructAndGroupDuplicates(vertexStructsAndGroups, fragmentStructsAndGroups);
}
this.layout = layout ?? generateLayoutHash(this.structsAndGroups);
this.gpuLayout = gpuLayout ?? generateGpuLayoutGroups(this.structsAndGroups);
this.autoAssignGlobalUniforms = !!(this.layout[0]?.globalUniforms !== void 0);
this.autoAssignLocalUniforms = !!(this.layout[1]?.localUniforms !== void 0);
this._generateProgramKey();
}
// TODO maker this pure
_generateProgramKey() {
const { vertex, fragment } = this;
const bigKey = vertex.source + fragment.source + vertex.entryPoint + fragment.entryPoint;
this._layoutKey = createIdFromString(bigKey, "program");
}
get attributeData() {
this._attributeData ?? (this._attributeData = extractAttributesFromGpuProgram(this.vertex));
return this._attributeData;
}
/** destroys the program */
destroy() {
this.gpuLayout = null;
this.layout = null;
this.structsAndGroups = null;
this.fragment = null;
this.vertex = null;
}
/**
* Helper function that creates a program for a given source.
* It will check the program cache if the program has already been created.
* If it has that one will be returned, if not a new one will be created and cached.
* @param options - The options for the program.
* @returns A program using the same source
*/
static from(options) {
const key = `${options.vertex.source}:${options.fragment.source}:${options.fragment.entryPoint}:${options.vertex.entryPoint}`;
if (!programCache[key]) {
programCache[key] = new GpuProgram(options);
}
return programCache[key];
}
}
export { GpuProgram };
//# sourceMappingURL=GpuProgram.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,27 @@
/// <reference types="@webgpu/types" />
import { ExtensionType } from '../../../../extensions/Extensions';
import type { ShaderSystem } from '../../shared/shader/ShaderSystem';
import type { GPU } from '../GpuDeviceSystem';
import type { GpuProgram } from './GpuProgram';
export interface GPUProgramData {
bindGroups: GPUBindGroupLayout[];
pipeline: GPUPipelineLayout;
}
/**
* A system that manages the rendering of GpuPrograms.
* @memberof rendering
*/
export declare class GpuShaderSystem implements ShaderSystem {
/** @ignore */
static extension: {
readonly type: readonly [ExtensionType.WebGPUSystem];
readonly name: "shader";
};
maxTextures: number;
private _gpu;
private readonly _gpuProgramData;
protected contextChange(gpu: GPU): void;
getProgramData(program: GpuProgram): GPUProgramData;
private _createGPUProgramData;
destroy(): void;
}

View File

@@ -0,0 +1,41 @@
'use strict';
var Extensions = require('../../../../extensions/Extensions.js');
"use strict";
class GpuShaderSystem {
constructor() {
this._gpuProgramData = /* @__PURE__ */ Object.create(null);
}
contextChange(gpu) {
this._gpu = gpu;
this.maxTextures = gpu.device.limits.maxSampledTexturesPerShaderStage;
}
getProgramData(program) {
return this._gpuProgramData[program._layoutKey] || this._createGPUProgramData(program);
}
_createGPUProgramData(program) {
const device = this._gpu.device;
const bindGroups = program.gpuLayout.map((group) => device.createBindGroupLayout({ entries: group }));
const pipelineLayoutDesc = { bindGroupLayouts: bindGroups };
this._gpuProgramData[program._layoutKey] = {
bindGroups,
pipeline: device.createPipelineLayout(pipelineLayoutDesc)
};
return this._gpuProgramData[program._layoutKey];
}
destroy() {
this._gpu = null;
this._gpuProgramData = null;
}
}
/** @ignore */
GpuShaderSystem.extension = {
type: [
Extensions.ExtensionType.WebGPUSystem
],
name: "shader"
};
exports.GpuShaderSystem = GpuShaderSystem;
//# sourceMappingURL=GpuShaderSystem.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"GpuShaderSystem.js","sources":["../../../../../src/rendering/renderers/gpu/shader/GpuShaderSystem.ts"],"sourcesContent":["import { ExtensionType } from '../../../../extensions/Extensions';\n\nimport type { ShaderSystem } from '../../shared/shader/ShaderSystem';\nimport type { GPU } from '../GpuDeviceSystem';\nimport type { GpuProgram } from './GpuProgram';\n\nexport interface GPUProgramData\n{\n bindGroups: GPUBindGroupLayout[]\n pipeline: GPUPipelineLayout\n}\n\n/**\n * A system that manages the rendering of GpuPrograms.\n * @memberof rendering\n */\nexport class GpuShaderSystem implements ShaderSystem\n{\n /** @ignore */\n public static extension = {\n type: [\n ExtensionType.WebGPUSystem,\n ],\n name: 'shader',\n } as const;\n\n public maxTextures: number;\n\n private _gpu: GPU;\n\n private readonly _gpuProgramData: Record<number, GPUProgramData> = Object.create(null);\n\n protected contextChange(gpu: GPU): void\n {\n this._gpu = gpu;\n\n this.maxTextures = gpu.device.limits.maxSampledTexturesPerShaderStage;\n }\n\n public getProgramData(program: GpuProgram)\n {\n return this._gpuProgramData[program._layoutKey] || this._createGPUProgramData(program);\n }\n\n private _createGPUProgramData(program: GpuProgram)\n {\n const device = this._gpu.device;\n\n const bindGroups = program.gpuLayout.map((group) => device.createBindGroupLayout({ entries: group }));\n\n const pipelineLayoutDesc = { bindGroupLayouts: bindGroups };\n\n this._gpuProgramData[program._layoutKey] = {\n bindGroups,\n pipeline: device.createPipelineLayout(pipelineLayoutDesc),\n };\n\n // generally we avoid having to make this automatically\n // keeping this for a reminder, if any issues popup\n // program._gpuLayout = {\n // bindGroups: null,\n // pipeline: 'auto',\n // };\n\n return this._gpuProgramData[program._layoutKey];\n }\n\n public destroy(): void\n {\n // TODO destroy the _gpuProgramData\n this._gpu = null;\n (this._gpuProgramData as null) = null;\n }\n}\n"],"names":["ExtensionType"],"mappings":";;;;;AAgBO,MAAM,eACb,CAAA;AAAA,EADO,WAAA,GAAA;AAcH,IAAiB,IAAA,CAAA,eAAA,mBAAyD,MAAA,CAAA,MAAA,CAAO,IAAI,CAAA,CAAA;AAAA,GAAA;AAAA,EAE3E,cAAc,GACxB,EAAA;AACI,IAAA,IAAA,CAAK,IAAO,GAAA,GAAA,CAAA;AAEZ,IAAK,IAAA,CAAA,WAAA,GAAc,GAAI,CAAA,MAAA,CAAO,MAAO,CAAA,gCAAA,CAAA;AAAA,GACzC;AAAA,EAEO,eAAe,OACtB,EAAA;AACI,IAAA,OAAO,KAAK,eAAgB,CAAA,OAAA,CAAQ,UAAU,CAAK,IAAA,IAAA,CAAK,sBAAsB,OAAO,CAAA,CAAA;AAAA,GACzF;AAAA,EAEQ,sBAAsB,OAC9B,EAAA;AACI,IAAM,MAAA,MAAA,GAAS,KAAK,IAAK,CAAA,MAAA,CAAA;AAEzB,IAAA,MAAM,UAAa,GAAA,OAAA,CAAQ,SAAU,CAAA,GAAA,CAAI,CAAC,KAAA,KAAU,MAAO,CAAA,qBAAA,CAAsB,EAAE,OAAA,EAAS,KAAM,EAAC,CAAC,CAAA,CAAA;AAEpG,IAAM,MAAA,kBAAA,GAAqB,EAAE,gBAAA,EAAkB,UAAW,EAAA,CAAA;AAE1D,IAAK,IAAA,CAAA,eAAA,CAAgB,OAAQ,CAAA,UAAU,CAAI,GAAA;AAAA,MACvC,UAAA;AAAA,MACA,QAAA,EAAU,MAAO,CAAA,oBAAA,CAAqB,kBAAkB,CAAA;AAAA,KAC5D,CAAA;AASA,IAAO,OAAA,IAAA,CAAK,eAAgB,CAAA,OAAA,CAAQ,UAAU,CAAA,CAAA;AAAA,GAClD;AAAA,EAEO,OACP,GAAA;AAEI,IAAA,IAAA,CAAK,IAAO,GAAA,IAAA,CAAA;AACZ,IAAC,KAAK,eAA2B,GAAA,IAAA,CAAA;AAAA,GACrC;AACJ,CAAA;AAAA;AAzDa,eAAA,CAGK,SAAY,GAAA;AAAA,EACtB,IAAM,EAAA;AAAA,IACFA,wBAAc,CAAA,YAAA;AAAA,GAClB;AAAA,EACA,IAAM,EAAA,QAAA;AACV,CAAA;;;;"}

View File

@@ -0,0 +1,39 @@
import { ExtensionType } from '../../../../extensions/Extensions.mjs';
"use strict";
class GpuShaderSystem {
constructor() {
this._gpuProgramData = /* @__PURE__ */ Object.create(null);
}
contextChange(gpu) {
this._gpu = gpu;
this.maxTextures = gpu.device.limits.maxSampledTexturesPerShaderStage;
}
getProgramData(program) {
return this._gpuProgramData[program._layoutKey] || this._createGPUProgramData(program);
}
_createGPUProgramData(program) {
const device = this._gpu.device;
const bindGroups = program.gpuLayout.map((group) => device.createBindGroupLayout({ entries: group }));
const pipelineLayoutDesc = { bindGroupLayouts: bindGroups };
this._gpuProgramData[program._layoutKey] = {
bindGroups,
pipeline: device.createPipelineLayout(pipelineLayoutDesc)
};
return this._gpuProgramData[program._layoutKey];
}
destroy() {
this._gpu = null;
this._gpuProgramData = null;
}
}
/** @ignore */
GpuShaderSystem.extension = {
type: [
ExtensionType.WebGPUSystem
],
name: "shader"
};
export { GpuShaderSystem };
//# sourceMappingURL=GpuShaderSystem.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"GpuShaderSystem.mjs","sources":["../../../../../src/rendering/renderers/gpu/shader/GpuShaderSystem.ts"],"sourcesContent":["import { ExtensionType } from '../../../../extensions/Extensions';\n\nimport type { ShaderSystem } from '../../shared/shader/ShaderSystem';\nimport type { GPU } from '../GpuDeviceSystem';\nimport type { GpuProgram } from './GpuProgram';\n\nexport interface GPUProgramData\n{\n bindGroups: GPUBindGroupLayout[]\n pipeline: GPUPipelineLayout\n}\n\n/**\n * A system that manages the rendering of GpuPrograms.\n * @memberof rendering\n */\nexport class GpuShaderSystem implements ShaderSystem\n{\n /** @ignore */\n public static extension = {\n type: [\n ExtensionType.WebGPUSystem,\n ],\n name: 'shader',\n } as const;\n\n public maxTextures: number;\n\n private _gpu: GPU;\n\n private readonly _gpuProgramData: Record<number, GPUProgramData> = Object.create(null);\n\n protected contextChange(gpu: GPU): void\n {\n this._gpu = gpu;\n\n this.maxTextures = gpu.device.limits.maxSampledTexturesPerShaderStage;\n }\n\n public getProgramData(program: GpuProgram)\n {\n return this._gpuProgramData[program._layoutKey] || this._createGPUProgramData(program);\n }\n\n private _createGPUProgramData(program: GpuProgram)\n {\n const device = this._gpu.device;\n\n const bindGroups = program.gpuLayout.map((group) => device.createBindGroupLayout({ entries: group }));\n\n const pipelineLayoutDesc = { bindGroupLayouts: bindGroups };\n\n this._gpuProgramData[program._layoutKey] = {\n bindGroups,\n pipeline: device.createPipelineLayout(pipelineLayoutDesc),\n };\n\n // generally we avoid having to make this automatically\n // keeping this for a reminder, if any issues popup\n // program._gpuLayout = {\n // bindGroups: null,\n // pipeline: 'auto',\n // };\n\n return this._gpuProgramData[program._layoutKey];\n }\n\n public destroy(): void\n {\n // TODO destroy the _gpuProgramData\n this._gpu = null;\n (this._gpuProgramData as null) = null;\n }\n}\n"],"names":[],"mappings":";;;AAgBO,MAAM,eACb,CAAA;AAAA,EADO,WAAA,GAAA;AAcH,IAAiB,IAAA,CAAA,eAAA,mBAAyD,MAAA,CAAA,MAAA,CAAO,IAAI,CAAA,CAAA;AAAA,GAAA;AAAA,EAE3E,cAAc,GACxB,EAAA;AACI,IAAA,IAAA,CAAK,IAAO,GAAA,GAAA,CAAA;AAEZ,IAAK,IAAA,CAAA,WAAA,GAAc,GAAI,CAAA,MAAA,CAAO,MAAO,CAAA,gCAAA,CAAA;AAAA,GACzC;AAAA,EAEO,eAAe,OACtB,EAAA;AACI,IAAA,OAAO,KAAK,eAAgB,CAAA,OAAA,CAAQ,UAAU,CAAK,IAAA,IAAA,CAAK,sBAAsB,OAAO,CAAA,CAAA;AAAA,GACzF;AAAA,EAEQ,sBAAsB,OAC9B,EAAA;AACI,IAAM,MAAA,MAAA,GAAS,KAAK,IAAK,CAAA,MAAA,CAAA;AAEzB,IAAA,MAAM,UAAa,GAAA,OAAA,CAAQ,SAAU,CAAA,GAAA,CAAI,CAAC,KAAA,KAAU,MAAO,CAAA,qBAAA,CAAsB,EAAE,OAAA,EAAS,KAAM,EAAC,CAAC,CAAA,CAAA;AAEpG,IAAM,MAAA,kBAAA,GAAqB,EAAE,gBAAA,EAAkB,UAAW,EAAA,CAAA;AAE1D,IAAK,IAAA,CAAA,eAAA,CAAgB,OAAQ,CAAA,UAAU,CAAI,GAAA;AAAA,MACvC,UAAA;AAAA,MACA,QAAA,EAAU,MAAO,CAAA,oBAAA,CAAqB,kBAAkB,CAAA;AAAA,KAC5D,CAAA;AASA,IAAO,OAAA,IAAA,CAAK,eAAgB,CAAA,OAAA,CAAQ,UAAU,CAAA,CAAA;AAAA,GAClD;AAAA,EAEO,OACP,GAAA;AAEI,IAAA,IAAA,CAAK,IAAO,GAAA,IAAA,CAAA;AACZ,IAAC,KAAK,eAA2B,GAAA,IAAA,CAAA;AAAA,GACrC;AACJ,CAAA;AAAA;AAzDa,eAAA,CAGK,SAAY,GAAA;AAAA,EACtB,IAAM,EAAA;AAAA,IACF,aAAc,CAAA,YAAA;AAAA,GAClB;AAAA,EACA,IAAM,EAAA,QAAA;AACV,CAAA;;;;"}

Some files were not shown because too many files have changed in this diff Show More