UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

154 lines (148 loc) 5.2 kB
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 { @builtin(position) position : vec4f, }; @vertex fn vertexMain(@builtin(vertex_index) vertexIndex : u32) -> VertexOutput { var output : VertexOutput; output.position = vec4f(pos[vertexIndex], 0, 1); return output; } @group(0) @binding(0) var img : texture_depth_multisampled_2d; @fragment fn fragmentMain(@builtin(position) fragColor: vec4f) -> @location(0) 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 };