playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
154 lines (148 loc) • 5.2 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
import { Shader } from "../shader.js";
import { SHADERLANGUAGE_WGSL } from "../constants.js";
import { Debug, DebugHelper } from "../../../core/debug.js";
import { DebugGraphics } from "../debug-graphics.js";
class WebgpuResolver {
constructor(device) {
/** @type {WebgpuGraphicsDevice} */
__publicField(this, "device");
/**
* Cache of render pipelines for each texture format, to avoid their per frame creation.
*
* @type {Map<GPUTextureFormat, GPURenderPipeline>}
* @private
*/
__publicField(this, "pipelineCache", /* @__PURE__ */ new Map());
this.device = device;
const code = `
var<private> pos : array<vec2f, 4> = array<vec2f, 4>(
vec2(-1.0, 1.0), vec2(1.0, 1.0), vec2(-1.0, -1.0), vec2(1.0, -1.0)
);
struct VertexOutput {
position : vec4f,
};
fn vertexMain( vertexIndex : u32) -> VertexOutput {
var output : VertexOutput;
output.position = vec4f(pos[vertexIndex], 0, 1);
return output;
}
var img : texture_depth_multisampled_2d;
fn fragmentMain( fragColor: vec4f) -> vec4f {
// load th depth value from sample index 0
var depth = textureLoad(img, vec2i(fragColor.xy), 0u);
return vec4f(depth, 0.0, 0.0, 0.0);
}
`;
this.shader = new Shader(device, {
name: "WebGPUResolverDepthShader",
shaderLanguage: SHADERLANGUAGE_WGSL,
vshader: code,
fshader: code
});
}
destroy() {
this.shader.destroy();
this.shader = null;
this.pipelineCache = null;
}
/**
* @param {GPUTextureFormat} format - Texture format.
* @returns {GPURenderPipeline} Pipeline for the given format.
* @private
*/
getPipeline(format) {
let pipeline = this.pipelineCache.get(format);
if (!pipeline) {
pipeline = this.createPipeline(format);
this.pipelineCache.set(format, pipeline);
}
return pipeline;
}
/**
* @param {GPUTextureFormat} format - Texture format.
* @returns {GPURenderPipeline} Pipeline for the given format.
* @private
*/
createPipeline(format) {
const webgpuShader = this.shader.impl;
const pipeline = this.device.wgpu.createRenderPipeline({
layout: "auto",
vertex: {
module: webgpuShader.getVertexShaderModule(),
entryPoint: webgpuShader.vertexEntryPoint
},
fragment: {
module: webgpuShader.getFragmentShaderModule(),
entryPoint: webgpuShader.fragmentEntryPoint,
targets: [{
format
}]
},
primitive: {
topology: "triangle-strip"
}
});
DebugHelper.setLabel(pipeline, `RenderPipeline-DepthResolver-${format}`);
return pipeline;
}
/**
* @param {GPUCommandEncoder} commandEncoder - Command encoder to use for the resolve.
* @param {GPUTexture} sourceTexture - Source multi-sampled depth texture to resolve.
* @param {GPUTexture} destinationTexture - Destination depth texture to resolve to.
* @private
*/
resolveDepth(commandEncoder, sourceTexture, destinationTexture) {
Debug.assert(sourceTexture.sampleCount > 1);
Debug.assert(destinationTexture.sampleCount === 1);
Debug.assert(sourceTexture.depthOrArrayLayers === destinationTexture.depthOrArrayLayers);
const device = this.device;
const wgpu = device.wgpu;
const pipeline = this.getPipeline(destinationTexture.format);
DebugGraphics.pushGpuMarker(device, "DEPTH_RESOLVE-RENDERER");
const numFaces = sourceTexture.depthOrArrayLayers;
for (let face = 0; face < numFaces; face++) {
const srcView = sourceTexture.createView({
dimension: "2d",
aspect: "depth-only",
baseMipLevel: 0,
mipLevelCount: 1,
baseArrayLayer: face
});
const dstView = destinationTexture.createView({
dimension: "2d",
baseMipLevel: 0,
mipLevelCount: 1,
baseArrayLayer: face
});
const passEncoder = commandEncoder.beginRenderPass({
colorAttachments: [{
view: dstView,
loadOp: "clear",
storeOp: "store"
}]
});
DebugHelper.setLabel(passEncoder, "DepthResolve-PassEncoder");
const bindGroup = wgpu.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [{
binding: 0,
resource: srcView
}]
});
passEncoder.setPipeline(pipeline);
passEncoder.setBindGroup(0, bindGroup);
passEncoder.draw(4);
passEncoder.end();
}
DebugGraphics.popGpuMarker(device);
device.pipeline = null;
}
}
export {
WebgpuResolver
};