diff --git a/src/caches/getGPUBindGroup.ts b/src/caches/getGPUBindGroup.ts index d5624e4b4c9eea8cbfac3d534d890521cc11694a..743b819e33c02ebe8c617a83e3dde8aff8cb935f 100644 --- a/src/caches/getGPUBindGroup.ts +++ b/src/caches/getGPUBindGroup.ts @@ -4,15 +4,17 @@ import { IGPUBindGroupDescriptor, IGPUBufferBinding, IGPUExternalTexture } from import { IGPUSampler } from "../data/IGPUSampler"; import { IGPUTextureFromContext } from "../data/IGPUTexture"; import { IGPUTextureView } from "../data/IGPUTextureView"; +import { GPUTextureView_destroy } from "../eventnames"; import { getGPUBindGroupLayout } from "./getGPUBindGroupLayout"; import { getGPUBufferBinding } from "./getGPUBufferBinding"; import { getGPUExternalTexture } from "./getGPUExternalTexture"; import { getGPUSampler } from "./getGPUSampler"; import { getGPUTextureView } from "./getGPUTextureView"; -import { GPUTextureView_destroy } from "../eventnames"; export function getGPUBindGroup(device: GPUDevice, bindGroup: IGPUBindGroupDescriptor) { + const bindGroupMap: WeakMap = device["_bindGroupMap"] = device["_bindGroupMap"] || new WeakMap(); + let gBindGroup = bindGroupMap.get(bindGroup); if (gBindGroup) return gBindGroup; @@ -103,5 +105,3 @@ export function getGPUBindGroup(device: GPUDevice, bindGroup: IGPUBindGroupDescr return gBindGroup; } - -const bindGroupMap = new WeakMap(); diff --git a/src/caches/getGPUComputePipeline.ts b/src/caches/getGPUComputePipeline.ts index a2003a6b8d1ac7a775a01f7fdf0776d9d076e948..d52b27eee8c6a03c637432f8aa2532ee18af0148 100644 --- a/src/caches/getGPUComputePipeline.ts +++ b/src/caches/getGPUComputePipeline.ts @@ -4,6 +4,8 @@ import { getGPUShaderModule } from "./getGPUShaderModule"; export function getGPUComputePipeline(device: GPUDevice, descriptor: IGPUComputePipeline) { + const computePipelineMap: WeakMap = device["_computePipelineMap"] = device["_computePipelineMap"] || new WeakMap(); + let pipeline = computePipelineMap.get(descriptor); if (pipeline) return pipeline; @@ -21,4 +23,3 @@ export function getGPUComputePipeline(device: GPUDevice, descriptor: IGPUCompute return pipeline; } -const computePipelineMap = new WeakMap(); diff --git a/src/caches/getGPURenderPassDescriptor.ts b/src/caches/getGPURenderPassDescriptor.ts index b8cc512eb4e2f9d6642265297da8121e85bb9e1d..440fef3e32ddd7238ada36b42eb188114058c94c 100644 --- a/src/caches/getGPURenderPassDescriptor.ts +++ b/src/caches/getGPURenderPassDescriptor.ts @@ -1,9 +1,11 @@ +import { anyEmitter } from "@feng3d/event"; import { watcher } from "@feng3d/watcher"; import { IGPURenderPassColorAttachment } from "../data/IGPURenderPassColorAttachment"; import { IGPURenderPassDepthStencilAttachment } from "../data/IGPURenderPassDepthStencilAttachment"; import { IGPURenderPassDescriptor } from "../data/IGPURenderPassDescriptor"; import { IGPUTexture, IGPUTextureBase, IGPUTextureFromContext } from "../data/IGPUTexture"; import { IGPUTextureView } from "../data/IGPUTextureView"; +import { IGPUTexture_resize } from "../eventnames"; import { getGPUTextureFormat } from "./getGPUTextureFormat"; import { getGPUTextureSize } from "./getGPUTextureSize"; import { getGPUTextureView } from "./getGPUTextureView"; @@ -17,48 +19,89 @@ import { getGPUTextureView } from "./getGPUTextureView"; */ export function getGPURenderPassDescriptor(device: GPUDevice, descriptor: IGPURenderPassDescriptor): GPURenderPassDescriptor { + const renderPassDescriptorMap: Map = device["_RenderPassDescriptorMap"] = device["_RenderPassDescriptorMap"] || new Map(); + let renderPassDescriptor = renderPassDescriptorMap.get(descriptor); + if (renderPassDescriptor) + { + // 执行更新函数。 + (renderPassDescriptor["_updates"] as Function[]).forEach((v) => v()); + return renderPassDescriptor; + } + + renderPassDescriptor = { colorAttachments: [], }; + renderPassDescriptorMap.set(descriptor, renderPassDescriptor); + + const _updates: Function[] = renderPassDescriptor["_updates"] = []; + descriptor = getIGPURenderPassDescriptor(descriptor); - const renderPassDescriptor: GPURenderPassDescriptor = { - colorAttachments: [], - }; if (descriptor.colorAttachments) { descriptor.colorAttachments.forEach((v, i) => { if (!v) return; - const view = getGPUTextureView(device, v.view); + const { clearValue, loadOp, storeOp } = v; - let resolveTarget: GPUTextureView; - if (v.resolveTarget) - { - resolveTarget = getGPUTextureView(device, v.resolveTarget); - } - const loadOp = v.loadOp; - const storeOp = v.storeOp; const attachment: GPURenderPassColorAttachment = { ...v, - view, - resolveTarget, + view: undefined, + resolveTarget: undefined, + clearValue, loadOp, storeOp, }; + const updateView = () => + { + attachment.view = getGPUTextureView(device, v.view); + }; + updateView(); + + // + if ((v.view.texture as IGPUTextureFromContext).context) + { + _updates.push(updateView); + } + anyEmitter.on(v.view.texture, IGPUTexture_resize, updateView); + + // + if (v.resolveTarget) + { + const updateResolveTarget = () => + { + attachment.resolveTarget = getGPUTextureView(device, v.resolveTarget); + }; + updateResolveTarget(); + // + if ((v.resolveTarget?.texture as IGPUTextureFromContext)?.context) + { + _updates.push(updateResolveTarget); + } + anyEmitter.on(v.resolveTarget.texture, IGPUTexture_resize, updateResolveTarget); + } + + // renderPassDescriptor.colorAttachments[i] = attachment; }); } if (descriptor.depthStencilAttachment) { - const depthStencilAttachment = descriptor.depthStencilAttachment; - - const view = getGPUTextureView(device, depthStencilAttachment.view); + const v = descriptor.depthStencilAttachment; renderPassDescriptor.depthStencilAttachment = { - ...depthStencilAttachment, - view, + ...v, + view: undefined, }; + + const updateView = () => + { + renderPassDescriptor.depthStencilAttachment.view = getGPUTextureView(device, v.view); + }; + updateView(); + + anyEmitter.on(v.view.texture, IGPUTexture_resize, updateView); } return renderPassDescriptor; @@ -73,38 +116,37 @@ export function getGPURenderPassDescriptor(device: GPUDevice, descriptor: IGPURe function getIGPURenderPassDescriptor(renderPass: IGPURenderPassDescriptor) { let iGPURenderPass = renderPassMap.get(renderPass); - if (!iGPURenderPass) - { - // 更新渲染通道附件尺寸,使得附件上纹理尺寸一致。 - updateAttachmentSize(renderPass); + if (iGPURenderPass) return iGPURenderPass; - // 获取颜色附件完整描述列表。 - const colorAttachments = getIGPURenderPassColorAttachments(renderPass.colorAttachments, renderPass.multisample); + // 更新渲染通道附件尺寸,使得附件上纹理尺寸一致。 + updateAttachmentSize(renderPass); - // 获取深度模板附件 - const depthStencilAttachment = getIGPURenderPassDepthStencilAttachment(renderPass.depthStencilAttachment, renderPass.attachmentSize, renderPass.multisample); + // 获取颜色附件完整描述列表。 + const colorAttachments = getIGPURenderPassColorAttachments(renderPass.colorAttachments, renderPass.multisample); - // 附件尺寸变化时,渲染通道描述失效。 - const watchProperty = { attachmentSize: { width: 0, height: 0 } }; // 被监听的属性 - watcher.watchobject(renderPass, watchProperty, () => - { - // 更新所有纹理描述中的尺寸 - updateAttachmentSize(renderPass); - // 更新所有纹理尺寸 - const iGPURenderPass = renderPassMap.get(renderPass); - // 由于深度纹理与多重采样纹理可能是引擎自动生成的,这部分纹理需要更新。 - updateIGPURenderPassAttachmentSize(iGPURenderPass, renderPass.attachmentSize); - }); + // 获取深度模板附件 + const depthStencilAttachment = getIGPURenderPassDepthStencilAttachment(renderPass.depthStencilAttachment, renderPass.attachmentSize, renderPass.multisample); - // - iGPURenderPass = { - ...renderPass, - colorAttachments, - depthStencilAttachment, - }; + // 附件尺寸变化时,渲染通道描述失效。 + const watchProperty = { attachmentSize: { width: 0, height: 0 } }; // 被监听的属性 + watcher.watchobject(renderPass, watchProperty, () => + { + // 更新所有纹理描述中的尺寸 + updateAttachmentSize(renderPass); + // 更新所有纹理尺寸 + const iGPURenderPass = renderPassMap.get(renderPass); + // 由于深度纹理与多重采样纹理可能是引擎自动生成的,这部分纹理需要更新。 + updateIGPURenderPassAttachmentSize(iGPURenderPass, renderPass.attachmentSize); + }); - renderPassMap.set(renderPass, iGPURenderPass); - } + // + iGPURenderPass = { + ...renderPass, + colorAttachments, + depthStencilAttachment, + }; + + renderPassMap.set(renderPass, iGPURenderPass); return iGPURenderPass; } @@ -275,43 +317,42 @@ const multisampleTextureMap = new WeakMap(); function getIGPURenderPassDepthStencilAttachment(depthStencilAttachment: IGPURenderPassDepthStencilAttachment, attachmentSize: { width: number, height: number }, multisample: number) { let gpuDepthStencilAttachment: IGPURenderPassDepthStencilAttachment; - if (depthStencilAttachment) - { - let view = depthStencilAttachment.view; - if (!view) - { - view = { - texture: { - label: `自动生成的深度纹理`, - size: [attachmentSize.width, attachmentSize.height], - format: "depth24plus", - usage: GPUTextureUsage.RENDER_ATTACHMENT, - } - }; - } + if (!depthStencilAttachment) return undefined; - let resolveTarget = depthStencilAttachment.resolveTarget; - if (multisample && !resolveTarget) - { - resolveTarget = view; - view = getMultisampleTextureView(view.texture, multisample); - } - - const depthClearValue = depthStencilAttachment.depthClearValue; - const depthLoadOp = depthStencilAttachment.depthLoadOp; - const depthStoreOp = depthStencilAttachment.depthStoreOp; - - // - gpuDepthStencilAttachment = { - ...depthStencilAttachment, - view, - resolveTarget, - depthClearValue, - depthLoadOp, - depthStoreOp, + let view = depthStencilAttachment.view; + if (!view) + { + view = { + texture: { + label: `自动生成的深度纹理`, + size: [attachmentSize.width, attachmentSize.height], + format: "depth24plus", + usage: GPUTextureUsage.RENDER_ATTACHMENT, + } }; } + let resolveTarget = depthStencilAttachment.resolveTarget; + if (multisample && !resolveTarget) + { + resolveTarget = view; + view = getMultisampleTextureView(view.texture, multisample); + } + + const depthClearValue = depthStencilAttachment.depthClearValue; + const depthLoadOp = depthStencilAttachment.depthLoadOp; + const depthStoreOp = depthStencilAttachment.depthStoreOp; + + // + gpuDepthStencilAttachment = { + ...depthStencilAttachment, + view, + resolveTarget, + depthClearValue, + depthLoadOp, + depthStoreOp, + }; + return gpuDepthStencilAttachment; } @@ -371,7 +412,7 @@ function updateAttachmentSize(renderPass: IGPURenderPassDescriptor) * @param texture 纹理描述。 * @param attachmentSize 附件尺寸。 */ -function setITextureSize(texture: IGPUTexture, attachmentSize: {width: number, height: number}) +function setITextureSize(texture: IGPUTexture, attachmentSize: { width: number, height: number }) { if ((texture as IGPUTextureFromContext).context) { diff --git a/src/caches/getGPUTexture.ts b/src/caches/getGPUTexture.ts index 3a73fec414eaaa0ad4f24510022eb7d4b3b1fcea..61c9db84e1113552a727af3c830fc611631c04be 100644 --- a/src/caches/getGPUTexture.ts +++ b/src/caches/getGPUTexture.ts @@ -1,9 +1,9 @@ import { anyEmitter } from "@feng3d/event"; import { watcher } from "@feng3d/watcher"; import { IGPUTexture, IGPUTextureBase, IGPUTextureFromContext } from "../data/IGPUTexture"; +import { GPUTexture_destroy, IGPUTexture_resize } from "../eventnames"; import { generateMipmap } from "../utils/generate-mipmap"; import { getGPUCanvasContext } from "./getGPUCanvasContext"; -import { GPUTexture_destroy } from "../eventnames"; /** * 获取GPU纹理 {@link GPUTexture} 。 @@ -16,10 +16,7 @@ export function getGPUTexture(device: GPUDevice, texture: IGPUTexture, autoCreat { const textureMap: Map = device["textureMap"] = device["textureMap"] || new Map(); let gpuTexture = textureMap.get(texture); - if (gpuTexture) - { - return gpuTexture; - } + if (gpuTexture) return gpuTexture; if ((texture as IGPUTextureFromContext).context) { @@ -120,6 +117,8 @@ export function getGPUTexture(device: GPUDevice, texture: IGPUTexture, autoCreat } gpuTexture.destroy(); + // + anyEmitter.emit(texture, IGPUTexture_resize); }; watcher.watch(iGPUTextureBase, "size", resize); diff --git a/src/caches/getIGPUComputePipeline.ts b/src/caches/getIGPUComputePipeline.ts index 47b881ba005052589af0135fb7e3d387a3f11363..edc0254995f0281ea72277784f6259c7c220899f 100644 --- a/src/caches/getIGPUComputePipeline.ts +++ b/src/caches/getIGPUComputePipeline.ts @@ -1,5 +1,5 @@ import { FunctionInfo } from "wgsl_reflect"; -import { IGPUComputePipeline, IGPUProgrammableStage } from "../data/IGPUComputeObject"; +import { IGPUComputePipeline, IGPUComputeStage, IGPUProgrammableStage } from "../data/IGPUComputeObject"; import { getIGPUPipelineLayout } from "./getIGPUPipelineLayout"; import { getWGSLReflectInfo } from "./getWGSLReflectInfo"; @@ -39,7 +39,7 @@ const computePipelineMap = new Map(); * @param computeStage 计算阶段描述。 * @returns 计算阶段完整描述。 */ -function getIGPUComputeStage(computeStage: IGPUProgrammableStage) +function getIGPUComputeStage(computeStage: IGPUComputeStage) { const reflect = getWGSLReflectInfo(computeStage.code); let compute: FunctionInfo; diff --git a/src/eventnames.ts b/src/eventnames.ts index bbdee6012ad9e5bc6643793e1014199eab41cd5c..9eed9cba434099239a2f238db50bcad28298ada3 100644 --- a/src/eventnames.ts +++ b/src/eventnames.ts @@ -10,3 +10,4 @@ export const GPUTextureView_destroy = "GPUTextureView_destroy"; export const GPUQueue_submit = "GPUQueue_submit"; +export const IGPUTexture_resize = "IGPUTexture_resize"; \ No newline at end of file diff --git a/src/runs/runBindGroup.ts b/src/runs/runBindGroup.ts index bce95ae486956fafcd665392e6cde390aab66bed..ca71e5fa06d3e7a6ad54daf6451215d9adc4ecec 100644 --- a/src/runs/runBindGroup.ts +++ b/src/runs/runBindGroup.ts @@ -6,16 +6,13 @@ import { IGPUBindGroupEntry, IGPUBufferBinding } from "../data/IGPUBindGroupDesc import { IGPUBindingResources } from "../data/IGPUBindingResources"; import { IGPUComputePipeline } from "../data/IGPUComputeObject"; import { IGPURenderPipeline, IGPUSetBindGroup } from "../data/IGPURenderObject"; -import { IGPUPipelineLayoutDescriptor } from "../internal/IGPUPipelineLayoutDescriptor"; import { ChainMap } from "../utils/ChainMap"; import { getIGPUBuffer } from "./getIGPUIndexBuffer"; export function runBindGroup(device: GPUDevice, passEncoder: GPUBindingCommandsMixin, pipeline: IGPUComputePipeline | IGPURenderPipeline, bindingResources: IGPUBindingResources) { - const gpuPipelineLayout = getIGPUPipelineLayout(pipeline); - // 计算 bindGroups - const setBindGroups = getIGPUSetBindGroups(gpuPipelineLayout, bindingResources); + const setBindGroups = getIGPUSetBindGroups(pipeline, bindingResources); setBindGroups?.forEach((setBindGroup, index) => { @@ -24,14 +21,17 @@ export function runBindGroup(device: GPUDevice, passEncoder: GPUBindingCommandsM }); } -function getIGPUSetBindGroups(layout: IGPUPipelineLayoutDescriptor, bindingResources: IGPUBindingResources) +function getIGPUSetBindGroups(pipeline: IGPUComputePipeline | IGPURenderPipeline, bindingResources: IGPUBindingResources) { // - let gpuSetBindGroups = bindGroupsMap.get([layout, bindingResources]); + let gpuSetBindGroups = bindGroupsMap.get([pipeline, bindingResources]); if (gpuSetBindGroups) return gpuSetBindGroups; gpuSetBindGroups = []; + bindGroupsMap.set([pipeline, bindingResources], gpuSetBindGroups); + // + const layout = getIGPUPipelineLayout(pipeline); layout.bindGroupLayouts.forEach((bindGroupLayout, group) => { const entries: IGPUBindGroupEntry[] = []; @@ -84,12 +84,10 @@ function getIGPUSetBindGroups(layout: IGPUPipelineLayoutDescriptor, bindingResou }); }); - bindGroupsMap.set([layout, bindingResources], gpuSetBindGroups); - return gpuSetBindGroups; } -const bindGroupsMap = new ChainMap<[IGPUPipelineLayoutDescriptor, IGPUBindingResources], IGPUSetBindGroup[]>(); +const bindGroupsMap = new ChainMap<[IGPUComputePipeline | IGPURenderPipeline, IGPUBindingResources], IGPUSetBindGroup[]>(); /** *