diff --git a/cocos/gfx/base/define.ts b/cocos/gfx/base/define.ts index 235e0880c8e..b74a9a3a720 100644 --- a/cocos/gfx/base/define.ts +++ b/cocos/gfx/base/define.ts @@ -979,6 +979,15 @@ export class Viewport { this.maxDepth = info.maxDepth; return this; } + + public reset (): void { + this.left = 0; + this.top = 0; + this.width = 0; + this.height = 0; + this.minDepth = 0; + this.maxDepth = 1; + } } export class Color { @@ -1006,6 +1015,13 @@ export class Color { this.w = w; return this; } + + public reset (): void { + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 0; + } } export class BindingMappingInfo { @@ -1756,6 +1772,10 @@ export class DescriptorSetLayoutInfo { deepCopy(this.bindings, info.bindings, DescriptorSetLayoutBinding); return this; } + + reset (): void { + this.bindings.length = 0; + } } export class DescriptorSetInfo { diff --git a/cocos/rendering/custom/compiler.ts b/cocos/rendering/custom/compiler.ts index da170462e25..5b77997b8c7 100644 --- a/cocos/rendering/custom/compiler.ts +++ b/cocos/rendering/custom/compiler.ts @@ -30,7 +30,8 @@ import { LayoutGraphData } from './layout-graph'; import { BasicPipeline } from './pipeline'; import { Blit, ClearView, ComputePass, ComputeSubpass, CopyPass, Dispatch, FormatView, ManagedBuffer, ManagedResource, ManagedTexture, MovePass, RasterPass, RasterSubpass, RaytracePass, RenderGraph, RenderGraphVisitor, RasterView, ComputeView, - RenderQueue, RenderSwapchain, ResolvePass, ResourceGraph, ResourceGraphVisitor, SceneData, SubresourceView } from './render-graph'; + RenderQueue, RenderSwapchain, ResolvePass, ResourceGraph, ResourceGraphVisitor, SceneData, SubresourceView, + PersistentBuffer, PersistentTexture } from './render-graph'; import { AccessType, ResourceResidency, SceneFlags } from './types'; import { hashCombineNum, hashCombineStr } from './define'; @@ -342,7 +343,8 @@ class ResourceVisitor implements ResourceGraphVisitor { managed (value: ManagedResource): void { this.dependency(); } - persistentBuffer (value: Buffer): void { + persistentBuffer (value: PersistentBuffer): void { + // noop } dependency (): void { @@ -354,7 +356,7 @@ class ResourceVisitor implements ResourceGraphVisitor { depthFirstSearch(this._passManagerVis.graphView, this._passManagerVis, this._passManagerVis.colorMap); } - persistentTexture (value: Texture): void { + persistentTexture (value: PersistentTexture): void { this.dependency(); } framebuffer (value: Framebuffer): void { @@ -364,8 +366,10 @@ class ResourceVisitor implements ResourceGraphVisitor { this.dependency(); } formatView (value: FormatView): void { + // noop } subresourceView (value: SubresourceView): void { + // noop } } diff --git a/cocos/rendering/custom/define.ts b/cocos/rendering/custom/define.ts index b131e820357..173c93da99a 100644 --- a/cocos/rendering/custom/define.ts +++ b/cocos/rendering/custom/define.ts @@ -755,8 +755,10 @@ export function buildReflectionProbePass ( probeCamera.clearStencil, probeCamera.clearFlag, ); - const passBuilder = probePass.addQueue(QueueHint.RENDER_OPAQUE); - passBuilder.addSceneOfCamera(camera, new LightInfo(), SceneFlags.REFLECTION_PROBE); + const passBuilder = probePass.addQueue(QueueHint.RENDER_OPAQUE, 'reflect-map'); + const lightInfo = new LightInfo(); + lightInfo.probe = probe; + passBuilder.addSceneOfCamera(camera, lightInfo, SceneFlags.REFLECTION_PROBE | SceneFlags.OPAQUE_OBJECT); updateCameraUBO(passBuilder as unknown as any, probeCamera, ppl); } diff --git a/cocos/rendering/custom/executor.ts b/cocos/rendering/custom/executor.ts index e855f90ce53..c2b3bd61379 100644 --- a/cocos/rendering/custom/executor.ts +++ b/cocos/rendering/custom/executor.ts @@ -28,7 +28,7 @@ * ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! ========================= */ /* eslint-disable max-len */ -import { getPhaseID, InstancedBuffer, PipelineStateManager } from '..'; +import { getPhaseID, PipelineStateManager } from '..'; import { assert, cclegacy, RecyclePool } from '../../core'; import intersect from '../../core/geometry/intersect'; import { Sphere } from '../../core/geometry/sphere'; @@ -47,6 +47,7 @@ import { DescriptorSetInfo, Device, deviceManager, + DispatchInfo, Format, Framebuffer, FramebufferInfo, @@ -55,11 +56,12 @@ import { InputAssemblerInfo, LoadOp, MemoryUsageBit, + PipelineBindPoint, PipelineState, + PipelineStateInfo, Rect, RenderPass, RenderPassInfo, - Shader, StoreOp, SurfaceTransform, Swapchain, @@ -72,11 +74,10 @@ import { import { legacyCC } from '../../core/global-exports'; import { Vec3 } from '../../core/math/vec3'; import { Vec4 } from '../../core/math/vec4'; -import { Pass } from '../../render-scene'; import { Camera } from '../../render-scene/scene/camera'; import { ShadowType } from '../../render-scene/scene/shadows'; import { Root } from '../../root'; -import { IRenderPass, isEnableEffect, SetIndex, UBODeferredLight, UBOForwardLight, UBOLocal } from '../define'; +import { IRenderPass, SetIndex, UBODeferredLight, UBOForwardLight, UBOLocal } from '../define'; import { PipelineSceneData } from '../pipeline-scene-data'; import { PipelineInputAssemblerData } from '../render-pipeline'; import { DescriptorSetData, LayoutGraphData, PipelineLayoutData, RenderPhaseData, RenderStageData } from './layout-graph'; @@ -95,6 +96,8 @@ import { ManagedResource, ManagedTexture, MovePass, + PersistentBuffer, + PersistentTexture, RasterPass, RasterSubpass, RasterView, @@ -113,6 +116,7 @@ import { SubresourceView, } from './render-graph'; import { + AccessType, AttachmentType, QueueHint, ResourceDimension, @@ -128,6 +132,7 @@ import { RenderAdditiveLightQueue } from '../render-additive-light-queue'; import { DefaultVisitor, depthFirstSearch, ReferenceGraphView } from './graph'; import { VectorGraphColorMap } from './effect'; import { + bool, getDescriptorSetDataFromLayout, getDescriptorSetDataFromLayoutId, getRenderArea, @@ -137,32 +142,74 @@ import { } from './define'; import { RenderReflectionProbeQueue } from '../render-reflection-probe-queue'; import { SceneCulling } from './scene-culling'; +import { Pass } from '../../render-scene'; class ResourceVisitor implements ResourceGraphVisitor { name: string; constructor (resName = '') { this.name = resName; + if (context) { + const ppl = context.pipeline as any; + ppl.resourceUses.push(resName); + } } set resName (value: string) { this.name = value; } - createDeviceTex (value: Texture | Framebuffer | ManagedResource | RenderSwapchain): void { - const deviceTex = new DeviceTexture(this.name, value); - context.deviceTextures.set(this.name, deviceTex); + checkTexture (name: string): boolean { + const dTex = context.deviceTextures.get(name)!; + const resID = context.resourceGraph.vertex(this.name); + const desc = context.resourceGraph.getDesc(resID); + let res = false; + if (dTex.texture) { + res = dTex.texture.width === desc.width && dTex.texture.height === desc.height; + } else if (dTex.swapchain) { + res = dTex.swapchain.width === desc.width && dTex.swapchain.height === desc.height; + } + return res; + } + createDeviceTex (value: PersistentTexture | Framebuffer | ManagedResource | RenderSwapchain): void { + if (!context.deviceTextures.get(this.name)) { + const deviceTex = new DeviceTexture(this.name, value); + context.deviceTextures.set(this.name, deviceTex); + } else if (!this.checkTexture(this.name)) { + const dTex = context.deviceTextures.get(this.name)!; + dTex.texture?.destroy(); + const deviceTex = new DeviceTexture(this.name, value); + context.deviceTextures.set(this.name, deviceTex); + } + } + checkBuffer (name: string): boolean { + const dBuf = context.deviceBuffers.get(name)!; + const resID = context.resourceGraph.vertex(this.name); + const desc = context.resourceGraph.getDesc(resID); + return dBuf.buffer!.size >= desc.width; + } + createDeviceBuf (value: ManagedBuffer | PersistentBuffer): void { + const mount: boolean = !!context.deviceBuffers.get(this.name); + if (!mount) { + const deviceBuf = new DeviceBuffer(this.name, value); + context.deviceBuffers.set(this.name, deviceBuf); + } else if (!this.checkBuffer(this.name)) { + const dBuf = context.deviceBuffers.get(this.name)!; + dBuf.buffer?.destroy(); + const deviceBuf = new DeviceBuffer(this.name, value); + context.deviceBuffers.set(this.name, deviceBuf); + } } managed (value: ManagedResource): void { this.createDeviceTex(value); } managedBuffer (value: ManagedBuffer): void { - // noop + this.createDeviceBuf(value); } managedTexture (value: ManagedTexture): void { // noop } - persistentBuffer (value: Buffer): void { - // noop + persistentBuffer (value: PersistentBuffer): void { + this.createDeviceBuf(value); } - persistentTexture (value: Texture): void { + persistentTexture (value: PersistentTexture): void { this.createDeviceTex(value); } framebuffer (value: Framebuffer): void { @@ -172,10 +219,10 @@ class ResourceVisitor implements ResourceGraphVisitor { this.createDeviceTex(value); } formatView (value: FormatView): void { - // noop + // do nothing } subresourceView (value: SubresourceView): void { - // noop + // do nothing } } @@ -199,26 +246,11 @@ class DeviceTexture extends DeviceResource { get description (): ResourceDesc | null { return this._desc; } get trait (): ResourceTraits | null { return this._trait; } get swapchain (): Swapchain | null { return this._swapchain; } - private _setDesc (desc: ResourceDesc): void { - if (!this._desc) { - this._desc = new ResourceDesc(); - } - this._desc.alignment = desc.alignment; - this._desc.depthOrArraySize = desc.depthOrArraySize; - this._desc.dimension = desc.dimension; - this._desc.flags = desc.flags; - this._desc.format = desc.format; - this._desc.height = desc.height; - this._desc.mipLevels = desc.mipLevels; - this._desc.sampleCount = desc.sampleCount; - this._desc.textureFlags = desc.textureFlags; - this._desc.width = desc.width; - } - constructor (name: string, tex: Texture | Framebuffer | RenderSwapchain | ManagedResource) { + constructor (name: string, tex: PersistentTexture | Framebuffer | RenderSwapchain | ManagedResource) { super(name); const resGraph = context.resourceGraph; const verID = resGraph.vertex(name); - this._setDesc(resGraph.getDesc(verID)); + this._desc = resGraph.getDesc(verID); this._trait = resGraph.getTraits(verID); if (tex instanceof Texture) { this._texture = tex; @@ -233,7 +265,7 @@ class DeviceTexture extends DeviceResource { return; } - const info = this._desc!; + const info = this._desc; let type = TextureType.TEX2D; switch (info.dimension) { @@ -287,8 +319,35 @@ function isShadowMap (graphScene: GraphScene): boolean | null { } class DeviceBuffer extends DeviceResource { - constructor (name: string) { + private _buffer: Buffer | null; + + get buffer (): Buffer | null { + return this._buffer; + } + + constructor (name: string, buffer: ManagedBuffer | PersistentBuffer) { super(name); + const resGraph = context.resourceGraph; + const verID = resGraph.vertex(name); + const desc = resGraph.getDesc(verID); + const bufferInfo = new BufferInfo(); + bufferInfo.size = desc.width; + bufferInfo.memUsage = MemoryUsageBit.DEVICE; + + if (desc.flags & ResourceFlags.INDIRECT) bufferInfo.usage |= BufferUsageBit.INDIRECT; + if (desc.flags & ResourceFlags.UNIFORM) bufferInfo.usage |= BufferUsageBit.UNIFORM; + if (desc.flags & ResourceFlags.STORAGE) bufferInfo.usage |= BufferUsageBit.STORAGE; + if (desc.flags & ResourceFlags.TRANSFER_SRC) bufferInfo.usage |= BufferUsageBit.TRANSFER_SRC; + if (desc.flags & ResourceFlags.TRANSFER_DST) bufferInfo.usage |= BufferUsageBit.TRANSFER_DST; + + this._buffer = context.device.createBuffer(bufferInfo); + } + + release (): void { + if (this._buffer) { + this._buffer.destroy(); + this._buffer = null; + } } } @@ -447,19 +506,73 @@ class BlitDesc { const deferredLitsBufView = context.blit.deferredLitsBufView; this._lightBufferData = context.blit.lightBufferData; this._lightBufferData.fill(0); - // const binding = isEnableEffect() ? getDescBindingFromName('CCForwardLight') : UBOForwardLight.BINDING; this._stageDesc.bindBuffer(UBOForwardLight.BINDING, deferredLitsBufView); } this._stageDesc.bindBuffer(UBOLocal.BINDING, context.blit.emptyLocalUBO); } } +class DeviceComputeQueue { + private _devicePass: DeviceComputePass | undefined; + private _hint: QueueHint = QueueHint.NONE; + private _phaseID: number = getPhaseID('default'); + private _renderPhase: RenderPhaseData | null = null; + private _descSetData: DescriptorSetData | null = null; + private _layoutID = -1; + private _isUpdateUBO = false; + private _isUploadInstance = false; + private _isUploadBatched = false; + private _queueId = -1; + init (devicePass: DeviceComputePass, renderQueue: RenderQueue, id: number): void { + this.reset(); + this.queueHint = renderQueue.hint; + this.queueId = id; + this._devicePass = devicePass; + this._phaseID = cclegacy.rendering.getPhaseID(devicePass.passID, context.renderGraph.getLayout(id)); + } + get phaseID (): number { return this._phaseID; } + set layoutID (value: number) { + this._layoutID = value; + const layoutGraph = context.layoutGraph; + this._renderPhase = layoutGraph.tryGetRenderPhase(value); + const layout = layoutGraph.getLayout(value); + this._descSetData = layout.descriptorSets.get(UpdateFrequency.PER_PHASE)!; + } + get layoutID (): number { return this._layoutID; } + get descSetData (): DescriptorSetData | null { return this._descSetData; } + get renderPhase (): RenderPhaseData | null { return this._renderPhase; } + set queueId (val) { this._queueId = val; } + get queueId (): number { return this._queueId; } + set isUpdateUBO (update: boolean) { this._isUpdateUBO = update; } + get isUpdateUBO (): boolean { return this._isUpdateUBO; } + set isUploadInstance (value: boolean) { this._isUploadInstance = value; } + get isUploadInstance (): boolean { return this._isUploadInstance; } + set isUploadBatched (value: boolean) { this._isUploadBatched = value; } + get isUploadBatched (): boolean { return this._isUploadBatched; } + + reset (): void { + this._isUpdateUBO = false; + this._isUploadInstance = false; + this._isUploadBatched = false; + } + set queueHint (value: QueueHint) { this._hint = value; } + get queueHint (): QueueHint { return this._hint; } + get devicePass (): DeviceComputePass { return this._devicePass!; } + + record (): void { + if (this._descSetData && this._descSetData.descriptorSet) { + context.commandBuffer + .bindDescriptorSet(SetIndex.COUNT, this._descSetData.descriptorSet); + } + } +} + class DeviceRenderQueue { private _preSceneTasks: DevicePreSceneTask[] = []; private _sceneTasks: DeviceSceneTask[] = []; private _postSceneTasks: DevicePostSceneTask[] = []; private _devicePass: DeviceRenderPass | undefined; - private _hint: QueueHint = QueueHint.NONE; + private _hint: QueueHint = QueueHint.NONE; private _graphQueue!: RenderQueue; private _phaseID: number = getPhaseID('default'); private _renderPhase: RenderPhaseData | null = null; @@ -522,7 +635,7 @@ class DeviceRenderQueue { } addSceneTask (scene: GraphScene): void { if (!this._transversal) { - this._transversal = new DeviceSceneTransversal(this, context.pipelineSceneData, scene); + this._transversal = new DeviceSceneTransversal(this, context.pipelineSceneData, scene); } this._transversal.graphScene = scene; this._preSceneTasks.push(this._transversal.preRenderPass(this._sceneVisitor)); @@ -604,7 +717,10 @@ class RenderPassLayoutInfo { // find resource const deviceTex = context.deviceTextures.get(this._inputName); const gfxTex = deviceTex?.texture; - if (!gfxTex) { + + const deviceBuf = context.deviceBuffers.get(this._inputName); + const gfxBuf = deviceBuf?.buffer; + if (!gfxTex && !gfxBuf) { throw Error(`Could not find texture with resource name ${this._inputName}`); } const resId = context.resourceGraph.vertex(this._inputName); @@ -617,9 +733,20 @@ class RenderPassLayoutInfo { for (const block of layoutData.descriptorSetLayoutData.descriptorBlocks) { for (let i = 0; i !== block.descriptors.length; ++i) { if (descriptorID === block.descriptors[i].descriptorID) { - layoutDesc.bindTexture(block.offset + i, gfxTex); - const renderData = context.renderGraph.getData(this._vertID); - layoutDesc.bindSampler(block.offset + i, renderData.samplers.get(descriptorID) || context.device.getSampler(samplerInfo)); + if (gfxTex) { + layoutDesc.bindTexture(block.offset + i, gfxTex); + const renderData = context.renderGraph.getData(this._vertID); + layoutDesc.bindSampler(block.offset + i, renderData.samplers.get(descriptorID) || context.device.getSampler(samplerInfo)); + } else { + const desc = context.resourceGraph.getDesc(resId); + if (desc.flags & ResourceFlags.STORAGE) { + const access = input[1][0].accessType !== AccessType.READ ? AccessFlagBit.COMPUTE_SHADER_WRITE + : AccessFlagBit.COMPUTE_SHADER_READ_OTHER; + (layoutDesc as any).bindBuffer(block.offset + i, gfxBuf!, 0, access); + } else { + layoutDesc.bindBuffer(block.offset + i, gfxBuf!); + } + } if (!this._descriptorSet) this._descriptorSet = layoutDesc; continue; } @@ -794,15 +921,10 @@ class DeviceRenderPass { const currTex = device.createTexture(new TextureInfo()); colorTexs.push(currTex); } - // if (!depthTex && !swapchain && !framebuffer) { - // depthTex = device.createTexture(new TextureInfo( - // TextureType.TEX2D, - // TextureUsageBit.DEPTH_STENCIL_ATTACHMENT | TextureUsageBit.SAMPLED, - // Format.DEPTH_STENCIL, - // colorTexs[0].width, - // colorTexs[0].height, - // )); - // } + const depth = swapchain ? swapchain.depthStencilTexture : depthTex; + if (!depth) { + depthStencilAttachment.format = Format.UNKNOWN; + } this._renderPass = device.createRenderPass(new RenderPassInfo(colors, depthStencilAttachment)); this._framebuffer = framebuffer || device.createFramebuffer(new FramebufferInfo( this._renderPass, @@ -829,6 +951,7 @@ class DeviceRenderPass { } addQueue (queue: DeviceRenderQueue): void { this._deviceQueues.push(queue); } prePass (): void { + context.descriptorSet = getDescriptorSetDataFromLayout(this.layoutName)!.descriptorSet; for (const queue of this._deviceQueues) { queue.preRecord(); } @@ -881,7 +1004,7 @@ class DeviceRenderPass { ia, ); const descData = getDescriptorSetDataFromLayoutId(pass.passID)!; - mergeSrcToTargetDesc(descData.descriptorSet, context.pipeline.descriptorSet, true); + mergeSrcToTargetDesc(descData.descriptorSet, context.descriptorSet, true); profilerViewport.width = rect.width; profilerViewport.height = rect.height; cmdBuff.setViewport(profilerViewport); @@ -918,7 +1041,7 @@ class DeviceRenderPass { ); cmdBuff.bindDescriptorSet( SetIndex.GLOBAL, - context.pipeline.descriptorSet, + context.descriptorSet!, ); for (const queue of this._deviceQueues) { queue.record(); @@ -930,7 +1053,6 @@ class DeviceRenderPass { } postPass (): void { - // this.submitMap.clear(); for (const queue of this._deviceQueues) { queue.postRecord(); } @@ -1010,6 +1132,135 @@ class DeviceRenderPass { } } +class ComputePassInfo { + protected _id!: number; + protected _pass!: ComputePass; + get id (): number { return this._id; } + get pass (): ComputePass { return this._pass; } + private _copyPass (pass: ComputePass): void { + const computePass = this._pass || new ComputePass(); + for (const val of pass.computeViews) { + const currComputeViews = val[1]; + const currComputeKey = val[0]; + const computeViews: ComputeView[] = computePass.computeViews.get(currComputeKey) || []; + if (computeViews.length) computeViews.length = currComputeViews.length; + let idx = 0; + for (const currComputeView of currComputeViews) { + const computeView = computeViews[idx] || new ComputeView(); + computeView.name = currComputeView.name; + computeView.accessType = currComputeView.accessType; + computeView.clearFlags = currComputeView.clearFlags; + computeView.clearValue.x = currComputeView.clearValue.x; + computeView.clearValue.y = currComputeView.clearValue.y; + computeView.clearValue.z = currComputeView.clearValue.z; + computeView.clearValue.w = currComputeView.clearValue.w; + computeView.clearValueType = currComputeView.clearValueType; + computeViews[idx] = computeView; + idx++; + } + computePass.computeViews.set(currComputeKey, computeViews); + } + this._pass = computePass; + } + applyInfo (id: number, pass: ComputePass): void { + this._id = id; + this._copyPass(pass); + } +} + +class DeviceComputePass { + protected _deviceQueues: DeviceComputeQueue[] = []; + protected _passID: number; + protected _layoutName: string; + protected _viewport: Viewport | null = null; + private _computeInfo: ComputePassInfo; + private _layout: RenderPassLayoutInfo | null = null; + constructor (passInfo: ComputePassInfo) { + this._computeInfo = passInfo; + this._layoutName = context.renderGraph.getLayout(passInfo.id); + this._passID = cclegacy.rendering.getPassID(this._layoutName); + + for (const cv of passInfo.pass.computeViews) { + let resTex = context.deviceTextures.get(cv[0]); + if (!resTex) { + this.visitResource(cv[0]); + resTex = context.deviceTextures.get(cv[0])!; + } + this._applyRenderLayout(cv); + } + // update the layout descriptorSet + if (this.renderLayout && this.renderLayout.descriptorSet) { + this.renderLayout.descriptorSet.update(); + } + } + get layoutName (): string { return this._layoutName; } + get passID (): number { return this._passID; } + get renderLayout (): RenderPassLayoutInfo | null { return this._layout; } + + get deviceQueues (): DeviceComputeQueue[] { return this._deviceQueues; } + get computePassInfo (): ComputePassInfo { return this._computeInfo; } + visitResource (resName: string): void { + const resourceGraph = context.resourceGraph; + const vertId = resourceGraph.vertex(resName); + resourceVisitor.resName = resName; + resourceGraph.visitVertex(resourceVisitor, vertId); + } + addQueue (queue: DeviceComputeQueue): void { this._deviceQueues.push(queue); } + prePass (): void { + // noop + } + protected _applyRenderLayout (input: [string, ComputeView[]]): void { + const stageName = context.renderGraph.getLayout(this._computeInfo.id); + if (stageName) { + const layoutGraph = context.layoutGraph; + const stageId = layoutGraph.locateChild(layoutGraph.nullVertex(), stageName); + if (stageId !== 0xFFFFFFFF) { + this._layout = new RenderPassLayoutInfo(stageId, this._computeInfo.id, input); + } + } + } + getGlobalDescData (): DescriptorSetData { + const stageId = context.layoutGraph.locateChild(context.layoutGraph.nullVertex(), 'default'); + assert(stageId !== 0xFFFFFFFF); + const layout = context.layoutGraph.getLayout(stageId); + const layoutData = layout.descriptorSets.get(UpdateFrequency.PER_PASS)!; + return layoutData; + } + + // record common buffer + record (): void { + const cmdBuff = context.commandBuffer; + + cmdBuff.bindDescriptorSet( + SetIndex.GLOBAL, + context.descriptorSet!, + ); + for (const queue of this._deviceQueues) { + queue.record(); + } + const renderData = context.renderGraph.getData(this._computeInfo.id); + updateGlobalDescBinding(renderData, context.renderGraph.getLayout(this._computeInfo.id)); + } + + postPass (): void { + // noop + } + resetResource (id: number, pass: ComputePass): void { + this._computeInfo.applyInfo(id, pass); + this._layoutName = context.renderGraph.getLayout(id); + this._passID = cclegacy.rendering.getPassID(this._layoutName); + this._deviceQueues.length = 0; + const colTextures: Texture[] = []; + for (const cv of this._computeInfo.pass.computeViews) { + this._applyRenderLayout(cv); + } + // update the layout descriptorSet + if (this.renderLayout && this.renderLayout.descriptorSet) { + this.renderLayout.descriptorSet.update(); + } + } +} + class DeviceSceneTransversal extends WebSceneTransversal { protected _currentQueue: DeviceRenderQueue; protected _graphScene: GraphScene; @@ -1138,13 +1389,8 @@ class DevicePreSceneTask extends WebSceneTask { if (this.graphScene.blit) { this._currentQueue.blitDesc!.update(); } - // if (isShadowMap(this.graphScene)) { - - // } - // this._uploadInstanceBuffers(); } } - const sceneViewport = new Viewport(); class DeviceSceneTask extends WebSceneTask { protected _currentQueue: DeviceRenderQueue; @@ -1173,10 +1419,27 @@ class DeviceSceneTask extends WebSceneTask { } get graphScene (): GraphScene { return this._graphScene; } public start (): void { - // noop + // do nothing } protected _recordUI (): void { + const devicePass = this._currentQueue.devicePass; + const rasterId = devicePass.rasterPassInfo.id; + const passRenderData = context.renderGraph.getData(rasterId); + // CCGlobal + this._updateGlobal(passRenderData); + // CCCamera, CCShadow, CCCSM + const queueId = this._currentQueue.queueId; + const queueRenderData = context.renderGraph.getData(queueId)!; + this._updateGlobal(queueRenderData); + + const layoutName = context.renderGraph.getLayout(rasterId); + const descSetData = getDescriptorSetDataFromLayout(layoutName); + if (context.descriptorSet) { + mergeSrcToTargetDesc(descSetData!.descriptorSet, context.descriptorSet, true); + } + this._currentQueue.isUpdateUBO = true; + const batches = this.camera!.scene!.batches; for (let i = 0; i < batches.length; i++) { const batch = batches[i]; @@ -1204,17 +1467,6 @@ class DeviceSceneTask extends WebSceneTask { } } - protected _recordReflectionProbe (): void { - const submitMap = context.submitMap; - const currSubmitInfo = submitMap.get(this.camera!)!.get(this._currentQueue.phaseID)!; - currSubmitInfo.reflectionProbe?.recordCommandBuffer( - context.device, - this._renderPass, - - context.commandBuffer, - ); - } - private _clearExtBlitDesc (desc, extResId: number[]): void { const toGpuDesc = desc.gpuDescriptorSet; for (let i = 0; i < extResId.length; i++) { @@ -1240,7 +1492,7 @@ class DeviceSceneTask extends WebSceneTask { const shader = pass.getShaderVariant(); const devicePass = this._currentQueue.devicePass; const screenIa: InputAssembler = this._currentQueue.blitDesc!.screenQuad!.quadIA!; - const globalDesc = context.pipeline.descriptorSet; + const globalDesc = context.descriptorSet; let pso: PipelineState | null = null; if (pass !== null && shader !== null && screenIa !== null) { pso = PipelineStateManager.getOrCreatePipelineState( @@ -1285,7 +1537,7 @@ class DeviceSceneTask extends WebSceneTask { const layoutName = context.renderGraph.getLayout(rasterId); const descSetData = getDescriptorSetDataFromLayout(layoutName); - mergeSrcToTargetDesc(descSetData!.descriptorSet, context.pipeline.descriptorSet, true); + mergeSrcToTargetDesc(descSetData!.descriptorSet, context.descriptorSet, true); this._currentQueue.isUpdateUBO = true; } @@ -1329,7 +1581,7 @@ class DeviceSceneTask extends WebSceneTask { return; } const renderQueueDesc = sceneCulling.sceneQueryIndex.get(this.graphScene.sceneID)!; - const renderQueue = sceneCulling.renderQueues[renderQueueDesc.renderQueueTarget]; + const renderQueue = sceneCulling.renderQueues[renderQueueDesc.renderQueueTarget]; const graphSceneData = this.graphScene.scene!; renderQueue.opaqueQueue.recordCommandBuffer(deviceManager.gfxDevice, this._renderPass, context.commandBuffer); renderQueue.opaqueInstancingQueue.recordCommandBuffer(this._renderPass, context.commandBuffer); @@ -1337,12 +1589,13 @@ class DeviceSceneTask extends WebSceneTask { this._recordAdditiveLights(); this.visitor.bindDescriptorSet( SetIndex.GLOBAL, - context.pipeline.descriptorSet, + context.descriptorSet!, ); } renderQueue.transparentInstancingQueue.recordCommandBuffer(this._renderPass, context.commandBuffer); renderQueue.transparentQueue.recordCommandBuffer(deviceManager.gfxDevice, this._renderPass, context.commandBuffer); + if (bool(graphSceneData.flags & SceneFlags.REFLECTION_PROBE)) renderQueue.probeQueue.removeMacro(); if (graphSceneData.flags & SceneFlags.GEOMETRY) { this.camera!.geometryRenderer?.render( devicePass.renderPass, @@ -1353,19 +1606,18 @@ class DeviceSceneTask extends WebSceneTask { if (graphSceneData.flags & SceneFlags.UI) { this._recordUI(); } - if (graphSceneData.flags & SceneFlags.REFLECTION_PROBE) { - this._recordReflectionProbe(); - } } } -class DevicePostSceneTask extends WebSceneTask {} +class DevicePostSceneTask extends WebSceneTask { } class ExecutorPools { constructor (context: ExecutorContext) { this.deviceQueuePool = new RecyclePool((): DeviceRenderQueue => new DeviceRenderQueue(), 16); + this.computeQueuePool = new RecyclePool((): DeviceComputeQueue => new DeviceComputeQueue(), 16); this.graphScenePool = new RecyclePool((): GraphScene => new GraphScene(), 16); this.rasterPassInfoPool = new RecyclePool((): RasterPassInfo => new RasterPassInfo(), 16); + this.computePassInfoPool = new RecyclePool((): ComputePassInfo => new ComputePassInfo(), 16); this.reflectionProbe = new RecyclePool((): RenderReflectionProbeQueue => new RenderReflectionProbeQueue(context.pipeline), 8); this.passPool = new RecyclePool((): { priority: number; hash: number; depth: number; shaderId: number; subModel: any; passIdx: number; } => ({ priority: 0, @@ -1376,15 +1628,12 @@ class ExecutorPools { passIdx: 0, }), 64); } - addPassInfo (): IRenderPass { - return this.passPool.add(); - } - resetPassInfo (): void { - this.passPool.reset(); - } addDeviceQueue (): DeviceRenderQueue { return this.deviceQueuePool.add(); } + addComputeQueue (): DeviceComputeQueue { + return this.computeQueuePool.add(); + } addGraphScene (): GraphScene { return this.graphScenePool.add(); } @@ -1394,17 +1643,23 @@ class ExecutorPools { addRasterPassInfo (): RasterPassInfo { return this.rasterPassInfoPool.add(); } + addComputePassInfo (): ComputePassInfo { + return this.computePassInfoPool.add(); + } reset (): void { this.deviceQueuePool.reset(); + this.computeQueuePool.reset(); this.graphScenePool.reset(); this.reflectionProbe.reset(); - this.resetPassInfo(); + this.computePassInfoPool.reset(); } readonly deviceQueuePool: RecyclePool; + readonly computeQueuePool: RecyclePool; readonly graphScenePool: RecyclePool; readonly reflectionProbe: RecyclePool; readonly passPool: RecyclePool; readonly rasterPassInfoPool: RecyclePool; + readonly computePassInfoPool: RecyclePool; } const vbData = new Float32Array(4 * 4); @@ -1489,8 +1744,8 @@ class BlitInfo { let maxY = (renderArea.y + renderArea.height) / this._context.height; if (this._context.root.device.capabilities.screenSpaceSignY > 0) { const temp = maxY; - maxY = minY; - minY = temp; + maxY = minY; + minY = temp; } let n = 0; switch (surfaceTransform) { @@ -1547,7 +1802,7 @@ class BlitInfo { } // create index buffer - const ibStride = Uint8Array.BYTES_PER_ELEMENT; + const ibStride = Uint16Array.BYTES_PER_ELEMENT; const ibSize = ibStride * 6; const quadIB: Buffer = device.createBuffer(new BufferInfo( @@ -1561,11 +1816,11 @@ class BlitInfo { return inputAssemblerData; } - const indices = new Uint8Array(6); + const indices = new Uint16Array(6); indices[0] = 0; indices[1] = 1; indices[2] = 2; indices[3] = 1; indices[4] = 3; indices[5] = 2; - quadIB.update(indices); + quadIB.update(indices.buffer); // create input assembler @@ -1596,6 +1851,7 @@ class ExecutorContext { layoutGraph: LayoutGraphData, width: number, height: number, + descriptorSet = null, ) { this.pipeline = pipeline; this.device = device; @@ -1612,6 +1868,7 @@ class ExecutorContext { this.pools = new ExecutorPools(this); this.blit = new BlitInfo(this); this.culling = new SceneCulling(); + this.descriptorSet = descriptorSet; } reset (): void { this.culling.clear(); @@ -1633,6 +1890,7 @@ class ExecutorContext { readonly resourceGraph: ResourceGraph; readonly devicePasses: Map = new Map(); readonly deviceTextures: Map = new Map(); + readonly deviceBuffers: Map = new Map(); readonly layoutGraph: LayoutGraphData; readonly root: Root; readonly ubo: PipelineUBO; @@ -1645,6 +1903,7 @@ class ExecutorContext { width: number; height: number; cullCamera; + descriptorSet: DescriptorSet | null; } export class Executor { @@ -1694,6 +1953,26 @@ export class Executor { deviceTexs.get(name)!.release(); deviceTexs.delete(name); } + + const deletesBuff: string[] = []; + const deviceBuffs = context.deviceBuffers; + for (const [name, dBuff] of deviceBuffs) { + const resId = context.resourceGraph.vertex(name); + const trait = context.resourceGraph.getTraits(resId); + if (!resourceUses.includes(name)) { + switch (trait.residency) { + case ResourceResidency.MANAGED: + deletesBuff.push(name); + break; + default: + } + } + } + for (const name of deletesBuff) { + deviceBuffs.get(name)!.release(); + deviceBuffs.delete(name); + } + resourceUses.length = 0; } execute (rg: RenderGraph): void { @@ -1716,6 +1995,11 @@ export class Executor { v.release(); } context.deviceTextures.clear(); + + for (const [k, v] of context.deviceBuffers) { + v.release(); + } + context.deviceBuffers.clear(); } readonly _context: ExecutorContext; private _visitor: RenderVisitor | undefined; @@ -1725,8 +2009,9 @@ class BaseRenderVisitor { public queueID = 0xFFFFFFFF; public sceneID = 0xFFFFFFFF; public passID = 0xFFFFFFFF; - public currPass: DeviceRenderPass | undefined; - public currQueue: DeviceRenderQueue | undefined; + public dispatchID = 0xFFFFFFFF; + public currPass: DeviceRenderPass | DeviceComputePass | undefined; + public currQueue: DeviceRenderQueue |DeviceComputeQueue | undefined; public rg: RenderGraph; constructor () { this.rg = context.renderGraph; @@ -1734,6 +2019,12 @@ class BaseRenderVisitor { protected _isRasterPass (u: number): boolean { return !!context.renderGraph.tryGetRasterPass(u); } + protected isComputePass (u: number): boolean { + return !!context.renderGraph.tryGetCompute(u); + } + protected isDispatch (u: number): boolean { + return !!context.renderGraph.tryGetDispatch(u); + } protected _isQueue (u: number): boolean { return !!context.renderGraph.tryGetQueue(u); } @@ -1744,7 +2035,17 @@ class BaseRenderVisitor { return !!context.renderGraph.tryGetBlit(u); } applyID (id: number): void { - if (this._isRasterPass(id)) { this.passID = id; } else if (this._isQueue(id)) { this.queueID = id; } else if (this._isScene(id) || this._isBlit(id)) { this.sceneID = id; } + if (this._isRasterPass(id)) { + this.passID = id; + } else if (this._isQueue(id)) { + this.queueID = id; + } else if (this._isScene(id) || this._isBlit(id)) { + this.sceneID = id; + } else if (this.isComputePass(id)) { + this.passID = id; + } else if (this.isDispatch(id)) { + this.dispatchID = id; + } } } @@ -1773,32 +2074,59 @@ class PreRenderVisitor extends BaseRenderVisitor implements RenderGraphVisitor { } } rasterSubpass (value: RasterSubpass): void { - // noop + // do nothing } computeSubpass (value: ComputeSubpass): void { - // noop - } - compute (value: ComputePass): void { - // noop + // do nothing } resolve (value: ResolvePass): void { - // noop - } - copy (value: CopyPass): void { - // noop + // do nothing } move (value: MovePass): void { - // noop + // do nothing } raytrace (value: RaytracePass): void { - // noop + // do nothing + } + compute (pass: ComputePass): void { + if (!this.rg.getValid(this.passID)) return; + const devicePasses = context.devicePasses; + const computeInfo = new ComputePassInfo(); + computeInfo.applyInfo(this.passID, pass); + this.currPass = new DeviceComputePass(computeInfo); + + this.currPass.prePass(); + this.currPass.record(); + this.currPass.postPass(); + } + copy (value: CopyPass): void { + if (value.uploadPairs.length) { + for (const upload of value.uploadPairs) { + const resBuffers = context.deviceBuffers; + const resourceGraph = context.resourceGraph; + const vertId = resourceGraph.vertex(upload.target); + resourceVisitor.resName = upload.target; + resourceGraph.visitVertex(resourceVisitor, vertId); + + const gfxBuffer = resBuffers.get(upload.target); + context.device.commandBuffer.updateBuffer(gfxBuffer!.buffer!, upload.source, upload.source.byteLength); + } + } } queue (value: RenderQueue): void { if (!this.rg.getValid(this.queueID)) return; - const deviceQueue = context.pools.addDeviceQueue(); - deviceQueue.init(this.currPass!, value, this.queueID); - this.currQueue = deviceQueue; - this.currPass!.addQueue(deviceQueue); + let deviceQueue: DeviceComputeQueue | DeviceRenderQueue; + if ('rasterPassInfo' in this.currPass!) { + deviceQueue = context.pools.addDeviceQueue(); + deviceQueue.init(this.currPass, value, this.queueID); + this.currQueue = deviceQueue; + this.currPass.addQueue(deviceQueue); + } else { + deviceQueue = context.pools.addComputeQueue(); + deviceQueue.init(this.currPass!, value, this.queueID); + this.currQueue = deviceQueue; + this.currPass!.addQueue(deviceQueue); + } const layoutName = this.rg.getLayout(this.queueID); if (layoutName) { const layoutGraph = context.layoutGraph; @@ -1810,18 +2138,46 @@ class PreRenderVisitor extends BaseRenderVisitor implements RenderGraphVisitor { } scene (value: SceneData): void { if (!this.rg.getValid(this.sceneID)) return; + const renderQueue = this.currQueue as DeviceRenderQueue; const graphScene = context.pools.addGraphScene(); graphScene.init(value, null, this.sceneID); - this.currQueue!.addSceneTask(graphScene); + renderQueue.addSceneTask(graphScene); } blit (value: Blit): void { if (!this.rg.getValid(this.sceneID)) return; + const renderQueue = this.currQueue as DeviceRenderQueue; const graphScene = context.pools.addGraphScene(); graphScene.init(null, value, -1); - this.currQueue!.addSceneTask(graphScene); + renderQueue.addSceneTask(graphScene); } dispatch (value: Dispatch): void { - // noop + let pso: PipelineState | null = null; + const devicePass = this.currPass as DeviceComputePass; + const pass = value.material?.passes[value.passID]; + pass?.update(); + const shader = pass?.getShaderVariant(); + + if (pass !== null && shader !== null) { + const psoInfo = new PipelineStateInfo( + shader, + pass?.pipelineLayout, + ); + psoInfo.bindPoint = PipelineBindPoint.COMPUTE; + pso = deviceManager.gfxDevice.createPipelineState(psoInfo); + } + const cmdBuff = context.commandBuffer; + if (pso) { + cmdBuff.bindPipelineState(pso); + const layoutStage = devicePass.renderLayout; + const layoutDesc = layoutStage!.descriptorSet!; + const extResId: number[] = []; + cmdBuff.bindDescriptorSet(SetIndex.GLOBAL, layoutDesc); + } + + const gx = value.threadGroupCountX; + const gy = value.threadGroupCountY; + const gz = value.threadGroupCountZ; + (cmdBuff as any).dispatch(new DispatchInfo(gx, gy, gz)); } } @@ -1846,25 +2202,25 @@ class PostRenderVisitor extends BaseRenderVisitor implements RenderGraphVisitor this.currPass.postPass(); } rasterSubpass (value: RasterSubpass): void { - // noop + // do nothing } computeSubpass (value: ComputeSubpass): void { - // noop + // do nothing } resolve (value: ResolvePass): void { - // noop + // do nothing } compute (value: ComputePass): void { - // noop + // do nothing } copy (value: CopyPass): void { - // noop + // do nothing } move (value: MovePass): void { - // noop + // do nothing } raytrace (value: RaytracePass): void { - // noop + // do nothing } queue (value: RenderQueue): void { // collect scene results @@ -1873,10 +2229,10 @@ class PostRenderVisitor extends BaseRenderVisitor implements RenderGraphVisitor // scene command list finished } blit (value: Blit): void { - // noop + // do nothing } dispatch (value: Dispatch): void { - // noop + // do nothing } } diff --git a/cocos/rendering/custom/layout-graph.ts b/cocos/rendering/custom/layout-graph.ts index 9ec1346ce68..4e8d25991dd 100644 --- a/cocos/rendering/custom/layout-graph.ts +++ b/cocos/rendering/custom/layout-graph.ts @@ -30,15 +30,22 @@ /* eslint-disable max-len */ import { AddressableGraph, AdjI, AdjacencyGraph, BidirectionalGraph, ComponentGraph, ED, InEI, MutableGraph, MutableReferenceGraph, NamedGraph, OutE, OutEI, PolymorphicGraph, PropertyGraph, PropertyMap, ReferenceGraph, VertexListGraph, directional, findRelative, getPath, parallel, reindexEdgeList, traversal } from './graph'; import { DescriptorSet, DescriptorSetLayout, DescriptorSetLayoutInfo, PipelineLayout, ShaderStageFlagBit, Type, UniformBlock } from '../../gfx'; -import { DescriptorBlock, saveDescriptorBlock, loadDescriptorBlock, DescriptorBlockIndex, saveDescriptorBlockIndex, loadDescriptorBlockIndex, DescriptorTypeOrder, UpdateFrequency } from './types'; +import { DescriptorBlock, saveDescriptorBlock, loadDescriptorBlock, DescriptorBlockIndex, saveDescriptorBlockIndex, loadDescriptorBlockIndex, DescriptorTypeOrder, UpdateFrequency, RenderCommonObjectPool } from './types'; import { OutputArchive, InputArchive } from './archive'; import { saveUniformBlock, loadUniformBlock, saveDescriptorSetLayoutInfo, loadDescriptorSetLayoutInfo } from './serialization'; +import { RecyclePool } from '../../core/memop'; export class DescriptorDB { + reset (): void { + this.blocks.clear(); + } readonly blocks: Map = new Map(); } export class RenderPhase { + reset (): void { + this.shaders.clear(); + } readonly shaders: Set = new Set(); } @@ -587,6 +594,12 @@ export class UniformData { this.uniformType = uniformType; this.offset = offset; } + reset (uniformID = 0xFFFFFFFF, uniformType: Type = Type.UNKNOWN, offset = 0): void { + this.uniformID = uniformID; + this.uniformType = uniformType; + this.offset = offset; + this.size = 0; + } uniformID: number; uniformType: Type; offset: number; @@ -594,6 +607,10 @@ export class UniformData { } export class UniformBlockData { + reset (): void { + this.bufferSize = 0; + this.uniforms.length = 0; + } bufferSize = 0; readonly uniforms: UniformData[] = []; } @@ -604,6 +621,11 @@ export class DescriptorData { this.type = type; this.count = count; } + reset (descriptorID = 0, type: Type = Type.UNKNOWN, count = 1): void { + this.descriptorID = descriptorID; + this.type = type; + this.count = count; + } descriptorID: number; type: Type; count: number; @@ -615,6 +637,13 @@ export class DescriptorBlockData { this.visibility = visibility; this.capacity = capacity; } + reset (type: DescriptorTypeOrder = DescriptorTypeOrder.UNIFORM_BUFFER, visibility: ShaderStageFlagBit = ShaderStageFlagBit.NONE, capacity = 0): void { + this.type = type; + this.visibility = visibility; + this.offset = 0; + this.capacity = capacity; + this.descriptors.length = 0; + } type: DescriptorTypeOrder; visibility: ShaderStageFlagBit; offset = 0; @@ -636,6 +665,18 @@ export class DescriptorSetLayoutData { this.uniformBlocks = uniformBlocks; this.bindingMap = bindingMap; } + reset ( + slot = 0xFFFFFFFF, + capacity = 0, + ): void { + this.slot = slot; + this.capacity = capacity; + this.uniformBlockCapacity = 0; + this.samplerTextureCapacity = 0; + this.descriptorBlocks.length = 0; + this.uniformBlocks.clear(); + this.bindingMap.clear(); + } slot: number; capacity: number; uniformBlockCapacity = 0; @@ -651,6 +692,12 @@ export class DescriptorSetData { this.descriptorSetLayout = descriptorSetLayout; this.descriptorSet = descriptorSet; } + reset (descriptorSetLayout: DescriptorSetLayout | null = null, descriptorSet: DescriptorSet | null = null): void { + this.descriptorSetLayoutData.reset(); + this.descriptorSetLayoutInfo.reset(); + this.descriptorSetLayout = descriptorSetLayout; + this.descriptorSet = descriptorSet; + } readonly descriptorSetLayoutData: DescriptorSetLayoutData; readonly descriptorSetLayoutInfo: DescriptorSetLayoutInfo = new DescriptorSetLayoutInfo(); /*refcount*/ descriptorSetLayout: DescriptorSetLayout | null; @@ -658,36 +705,65 @@ export class DescriptorSetData { } export class PipelineLayoutData { + reset (): void { + this.descriptorSets.clear(); + } readonly descriptorSets: Map = new Map(); } export class ShaderBindingData { + reset (): void { + this.descriptorBindings.clear(); + } readonly descriptorBindings: Map = new Map(); } export class ShaderLayoutData { + reset (): void { + this.layoutData.clear(); + this.bindingData.clear(); + } readonly layoutData: Map = new Map(); readonly bindingData: Map = new Map(); } export class TechniqueData { + reset (): void { + this.passes.length = 0; + } readonly passes: ShaderLayoutData[] = []; } export class EffectData { + reset (): void { + this.techniques.clear(); + } readonly techniques: Map = new Map(); } export class ShaderProgramData { + reset (): void { + this.layout.reset(); + this.pipelineLayout = null; + } readonly layout: PipelineLayoutData = new PipelineLayoutData(); /*refcount*/ pipelineLayout: PipelineLayout | null = null; } export class RenderStageData { + reset (): void { + this.descriptorVisibility.clear(); + } readonly descriptorVisibility: Map = new Map(); } export class RenderPhaseData { + reset (): void { + this.rootSignature = ''; + this.shaderPrograms.length = 0; + this.shaderIndex.clear(); + this.pipelineLayout = null; + } rootSignature = ''; readonly shaderPrograms: ShaderProgramData[] = []; readonly shaderIndex: Map = new Map(); @@ -1260,10 +1336,222 @@ export class LayoutGraphData implements BidirectionalGraph constantMacros = ''; } +export class LayoutGraphObjectPoolSettings { + constructor (batchSize: number) { + this.descriptorDBBatchSize = batchSize; + this.renderPhaseBatchSize = batchSize; + this.layoutGraphBatchSize = batchSize; + this.uniformDataBatchSize = batchSize; + this.uniformBlockDataBatchSize = batchSize; + this.descriptorDataBatchSize = batchSize; + this.descriptorBlockDataBatchSize = batchSize; + this.descriptorSetLayoutDataBatchSize = batchSize; + this.descriptorSetDataBatchSize = batchSize; + this.pipelineLayoutDataBatchSize = batchSize; + this.shaderBindingDataBatchSize = batchSize; + this.shaderLayoutDataBatchSize = batchSize; + this.techniqueDataBatchSize = batchSize; + this.effectDataBatchSize = batchSize; + this.shaderProgramDataBatchSize = batchSize; + this.renderStageDataBatchSize = batchSize; + this.renderPhaseDataBatchSize = batchSize; + this.layoutGraphDataBatchSize = batchSize; + } + descriptorDBBatchSize = 16; + renderPhaseBatchSize = 16; + layoutGraphBatchSize = 16; + uniformDataBatchSize = 16; + uniformBlockDataBatchSize = 16; + descriptorDataBatchSize = 16; + descriptorBlockDataBatchSize = 16; + descriptorSetLayoutDataBatchSize = 16; + descriptorSetDataBatchSize = 16; + pipelineLayoutDataBatchSize = 16; + shaderBindingDataBatchSize = 16; + shaderLayoutDataBatchSize = 16; + techniqueDataBatchSize = 16; + effectDataBatchSize = 16; + shaderProgramDataBatchSize = 16; + renderStageDataBatchSize = 16; + renderPhaseDataBatchSize = 16; + layoutGraphDataBatchSize = 16; +} + +export class LayoutGraphObjectPool { + constructor (settings: LayoutGraphObjectPoolSettings, renderCommon: RenderCommonObjectPool) { + this.renderCommon = renderCommon; + this._descriptorDB = new RecyclePool(() => new DescriptorDB(), settings.descriptorDBBatchSize); + this._renderPhase = new RecyclePool(() => new RenderPhase(), settings.renderPhaseBatchSize); + this._layoutGraph = new RecyclePool(() => new LayoutGraph(), settings.layoutGraphBatchSize); + this._uniformData = new RecyclePool(() => new UniformData(), settings.uniformDataBatchSize); + this._uniformBlockData = new RecyclePool(() => new UniformBlockData(), settings.uniformBlockDataBatchSize); + this._descriptorData = new RecyclePool(() => new DescriptorData(), settings.descriptorDataBatchSize); + this._descriptorBlockData = new RecyclePool(() => new DescriptorBlockData(), settings.descriptorBlockDataBatchSize); + this._descriptorSetLayoutData = new RecyclePool(() => new DescriptorSetLayoutData(), settings.descriptorSetLayoutDataBatchSize); + this._descriptorSetData = new RecyclePool(() => new DescriptorSetData(), settings.descriptorSetDataBatchSize); + this._pipelineLayoutData = new RecyclePool(() => new PipelineLayoutData(), settings.pipelineLayoutDataBatchSize); + this._shaderBindingData = new RecyclePool(() => new ShaderBindingData(), settings.shaderBindingDataBatchSize); + this._shaderLayoutData = new RecyclePool(() => new ShaderLayoutData(), settings.shaderLayoutDataBatchSize); + this._techniqueData = new RecyclePool(() => new TechniqueData(), settings.techniqueDataBatchSize); + this._effectData = new RecyclePool(() => new EffectData(), settings.effectDataBatchSize); + this._shaderProgramData = new RecyclePool(() => new ShaderProgramData(), settings.shaderProgramDataBatchSize); + this._renderStageData = new RecyclePool(() => new RenderStageData(), settings.renderStageDataBatchSize); + this._renderPhaseData = new RecyclePool(() => new RenderPhaseData(), settings.renderPhaseDataBatchSize); + this._layoutGraphData = new RecyclePool(() => new LayoutGraphData(), settings.layoutGraphDataBatchSize); + } + reset (): void { + this._descriptorDB.reset(); + this._renderPhase.reset(); + this._layoutGraph.reset(); + this._uniformData.reset(); + this._uniformBlockData.reset(); + this._descriptorData.reset(); + this._descriptorBlockData.reset(); + this._descriptorSetLayoutData.reset(); + this._descriptorSetData.reset(); + this._pipelineLayoutData.reset(); + this._shaderBindingData.reset(); + this._shaderLayoutData.reset(); + this._techniqueData.reset(); + this._effectData.reset(); + this._shaderProgramData.reset(); + this._renderStageData.reset(); + this._renderPhaseData.reset(); + this._layoutGraphData.reset(); + } + createDescriptorDB (): DescriptorDB { + const v = this._descriptorDB.add(); + v.reset(); + return v; + } + createRenderPhase (): RenderPhase { + const v = this._renderPhase.add(); + v.reset(); + return v; + } + createLayoutGraph (): LayoutGraph { + const v = this._layoutGraph.add(); + v.clear(); + return v; + } + createUniformData ( + uniformID = 0xFFFFFFFF, + uniformType: Type = Type.UNKNOWN, + offset = 0, + ): UniformData { + const v = this._uniformData.add(); + v.reset(uniformID, uniformType, offset); + return v; + } + createUniformBlockData (): UniformBlockData { + const v = this._uniformBlockData.add(); + v.reset(); + return v; + } + createDescriptorData ( + descriptorID = 0, + type: Type = Type.UNKNOWN, + count = 1, + ): DescriptorData { + const v = this._descriptorData.add(); + v.reset(descriptorID, type, count); + return v; + } + createDescriptorBlockData ( + type: DescriptorTypeOrder = DescriptorTypeOrder.UNIFORM_BUFFER, + visibility: ShaderStageFlagBit = ShaderStageFlagBit.NONE, + capacity = 0, + ): DescriptorBlockData { + const v = this._descriptorBlockData.add(); + v.reset(type, visibility, capacity); + return v; + } + createDescriptorSetLayoutData ( + slot = 0xFFFFFFFF, + capacity = 0, + ): DescriptorSetLayoutData { + const v = this._descriptorSetLayoutData.add(); + v.reset(slot, capacity); + return v; + } + createDescriptorSetData ( + descriptorSetLayout: DescriptorSetLayout | null = null, + descriptorSet: DescriptorSet | null = null, + ): DescriptorSetData { + const v = this._descriptorSetData.add(); + v.reset(descriptorSetLayout, descriptorSet); + return v; + } + createPipelineLayoutData (): PipelineLayoutData { + const v = this._pipelineLayoutData.add(); + v.reset(); + return v; + } + createShaderBindingData (): ShaderBindingData { + const v = this._shaderBindingData.add(); + v.reset(); + return v; + } + createShaderLayoutData (): ShaderLayoutData { + const v = this._shaderLayoutData.add(); + v.reset(); + return v; + } + createTechniqueData (): TechniqueData { + const v = this._techniqueData.add(); + v.reset(); + return v; + } + createEffectData (): EffectData { + const v = this._effectData.add(); + v.reset(); + return v; + } + createShaderProgramData (): ShaderProgramData { + const v = this._shaderProgramData.add(); + v.reset(); + return v; + } + createRenderStageData (): RenderStageData { + const v = this._renderStageData.add(); + v.reset(); + return v; + } + createRenderPhaseData (): RenderPhaseData { + const v = this._renderPhaseData.add(); + v.reset(); + return v; + } + createLayoutGraphData (): LayoutGraphData { + const v = this._layoutGraphData.add(); + v.clear(); + return v; + } + public readonly renderCommon: RenderCommonObjectPool; + private readonly _descriptorDB: RecyclePool; + private readonly _renderPhase: RecyclePool; + private readonly _layoutGraph: RecyclePool; + private readonly _uniformData: RecyclePool; + private readonly _uniformBlockData: RecyclePool; + private readonly _descriptorData: RecyclePool; + private readonly _descriptorBlockData: RecyclePool; + private readonly _descriptorSetLayoutData: RecyclePool; + private readonly _descriptorSetData: RecyclePool; + private readonly _pipelineLayoutData: RecyclePool; + private readonly _shaderBindingData: RecyclePool; + private readonly _shaderLayoutData: RecyclePool; + private readonly _techniqueData: RecyclePool; + private readonly _effectData: RecyclePool; + private readonly _shaderProgramData: RecyclePool; + private readonly _renderStageData: RecyclePool; + private readonly _renderPhaseData: RecyclePool; + private readonly _layoutGraphData: RecyclePool; +} + export function saveDescriptorDB (ar: OutputArchive, v: DescriptorDB): void { ar.writeNumber(v.blocks.size); // Map for (const [k1, v1] of v.blocks) { - saveDescriptorBlockIndex(ar, JSON.parse(k1)); + saveDescriptorBlockIndex(ar, JSON.parse(k1) as DescriptorBlockIndex); saveDescriptorBlock(ar, v1); } } diff --git a/cocos/rendering/custom/pipeline.ts b/cocos/rendering/custom/pipeline.ts index 87172d5f715..e97d787ff1f 100644 --- a/cocos/rendering/custom/pipeline.ts +++ b/cocos/rendering/custom/pipeline.ts @@ -385,8 +385,18 @@ export interface Setter extends RenderNode { setBuiltinSpotLightConstants (light: SpotLight, camera: Camera): void; setBuiltinPointLightConstants (light: PointLight, camera: Camera): void; setBuiltinRangedDirectionalLightConstants (light: RangedDirectionalLight, camera: Camera): void; - setBuiltinDirectionalLightViewConstants (light: DirectionalLight, level?: number): void; - setBuiltinSpotLightViewConstants (light: SpotLight): void; + setBuiltinDirectionalLightFrustumConstants ( + camera: Camera, + light: DirectionalLight, + csmLevel?: number): void; + setBuiltinSpotLightFrustumConstants (light: SpotLight): void; +} + +export interface SceneBuilder extends Setter { + useLightFrustum ( + light: Light, + csmLevel?: number, + optCamera?: Camera): void; } /** @@ -413,16 +423,7 @@ export interface RenderQueueBuilder extends Setter { addScene ( camera: Camera, sceneFlags: SceneFlags, - light?: Light | null): void; - addSceneCulledByDirectionalLight ( - camera: Camera, - sceneFlags: SceneFlags, - light: DirectionalLight, - level: number): void; - addSceneCulledBySpotLight ( - camera: Camera, - sceneFlags: SceneFlags, - light: SpotLight): void; + light?: Light): SceneBuilder; /** * @en Render a full-screen quad. * @zh 渲染全屏四边形 @@ -515,7 +516,7 @@ export interface BasicRenderPassBuilder extends Setter { addTexture ( name: string, slotName: string, - sampler?: Sampler | null, + sampler?: Sampler, plane?: number): void; /** * @en Add render queue. @@ -689,14 +690,15 @@ export interface BasicPipeline extends PipelineRuntime { size: number, flags: ResourceFlags, residency: ResourceResidency): number; - updateBuffer ( + updateBuffer (name: string, size: number): void; + addExternalTexture ( name: string, - size: number): void; - addExternalTexture (name: string, texture: Texture, flags: ResourceFlags): number; + texture: Texture, + flags: ResourceFlags): number; updateExternalTexture (name: string, texture: Texture): void; addTexture ( name: string, - textureType: TextureType, + type: TextureType, format: Format, width: number, height: number, @@ -809,10 +811,11 @@ export interface BasicPipeline extends PipelineRuntime { * @param copyPairs @en Array of copy source and target @zh 拷贝来源与目标的数组 */ addCopyPass (copyPairs: CopyPair[]): void; + addBuiltinReflectionProbePass (camera: Camera): void; /** * @engineInternal */ - getDescriptorSetLayout (shaderName: string, freq: UpdateFrequency): DescriptorSetLayout | null; + getDescriptorSetLayout (shaderName: string, freq: UpdateFrequency): DescriptorSetLayout | undefined; } /** @@ -875,7 +878,7 @@ export interface RenderSubpassBuilder extends Setter { addTexture ( name: string, slotName: string, - sampler?: Sampler | null, + sampler?: Sampler, plane?: number): void; /** * @en Add storage buffer. @@ -1019,7 +1022,7 @@ export interface ComputeSubpassBuilder extends Setter { addTexture ( name: string, slotName: string, - sampler?: Sampler | null, + sampler?: Sampler, plane?: number): void; /** * @en Add storage buffer. @@ -1175,7 +1178,7 @@ export interface ComputePassBuilder extends Setter { addTexture ( name: string, slotName: string, - sampler?: Sampler | null, + sampler?: Sampler, plane?: number): void; /** * @en Add storage buffer. @@ -1389,7 +1392,7 @@ export interface Pipeline extends BasicPipeline { addBuiltinGpuCullingPass ( camera: Camera, hzbName?: string, - light?: Light | null): void; + light?: Light): void; addBuiltinHzbGenerationPass (sourceDepthStencilName: string, targetHzbName: string): void; /** * @experimental @@ -1423,8 +1426,7 @@ export interface PipelineBuilder { * @param pipeline @en Current render pipeline @zh 当前管线 */ setup (cameras: Camera[], pipeline: BasicPipeline): void; - - onGlobalPipelineStateChanged?(): void; + onGlobalPipelineStateChanged? (): void; } /** diff --git a/cocos/rendering/custom/private.ts b/cocos/rendering/custom/private.ts index 62e2393c627..b4cae1f5d17 100644 --- a/cocos/rendering/custom/private.ts +++ b/cocos/rendering/custom/private.ts @@ -64,7 +64,7 @@ export interface ProgramLibrary { phaseID: number, name: string, defines: MacroRecord, - key?: string | null): ProgramProxy | null; + key?: string): ProgramProxy | null; getBlockSizes (phaseID: number, programName: string): number[]; getHandleMap (phaseID: number, programName: string): Record; getProgramID (phaseID: number, programName: string): number; diff --git a/cocos/rendering/custom/render-graph.ts b/cocos/rendering/custom/render-graph.ts index fa3f241f839..135d22cd640 100644 --- a/cocos/rendering/custom/render-graph.ts +++ b/cocos/rendering/custom/render-graph.ts @@ -31,10 +31,12 @@ import { AdjI, AdjacencyGraph, BidirectionalGraph, ComponentGraph, ED, InEI, MutableGraph, MutableReferenceGraph, NamedGraph, OutE, OutEI, PolymorphicGraph, PropertyGraph, PropertyMap, ReferenceGraph, UuidGraph, VertexListGraph, directional, parallel, reindexEdgeList, traversal } from './graph'; import { Material } from '../../asset/assets'; import { Camera } from '../../render-scene/scene/camera'; -import { AccessFlagBit, Buffer, ClearFlagBit, Color, Format, Framebuffer, LoadOp, RenderPass, SampleCount, Sampler, SamplerInfo, ShaderStageFlagBit, StoreOp, Swapchain, Texture, TextureFlagBit, Viewport, TextureType } from '../../gfx'; -import { AccessType, AttachmentType, ClearValueType, CopyPair, LightInfo, MovePair, QueueHint, ResolvePair, ResourceDimension, ResourceFlags, ResourceResidency, SceneFlags, UploadPair } from './types'; +import { AccessFlagBit, Buffer, ClearFlagBit, Color, Format, Framebuffer, LoadOp, RenderPass, SampleCount, Sampler, SamplerInfo, ShaderStageFlagBit, StoreOp, Swapchain, Texture, TextureFlagBit, TextureType, Viewport } from '../../gfx'; +import { AccessType, AttachmentType, ClearValueType, CopyPair, LightInfo, MovePair, QueueHint, ResolvePair, ResourceDimension, ResourceFlags, ResourceResidency, SceneFlags, UploadPair, RenderCommonObjectPool } from './types'; import { RenderScene } from '../../render-scene/core/render-scene'; import { RenderWindow } from '../../render-scene/core/render-window'; +import { Light } from '../../render-scene/scene'; +import { RecyclePool } from '../../core/memop'; export class ClearValue { constructor (x = 0, y = 0, z = 0, w = 0) { @@ -43,6 +45,12 @@ export class ClearValue { this.z = z; this.w = w; } + reset (x = 0, y = 0, z = 0, w = 0): void { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } x: number; y: number; z: number; @@ -69,6 +77,26 @@ export class RasterView { this.clearColor = clearColor; this.shaderStageFlags = shaderStageFlags; } + reset ( + slotName = '', + accessType: AccessType = AccessType.WRITE, + attachmentType: AttachmentType = AttachmentType.RENDER_TARGET, + loadOp: LoadOp = LoadOp.LOAD, + storeOp: StoreOp = StoreOp.STORE, + clearFlags: ClearFlagBit = ClearFlagBit.ALL, + shaderStageFlags: ShaderStageFlagBit = ShaderStageFlagBit.NONE, + ): void { + this.slotName = slotName; + this.slotName1 = ''; + this.accessType = accessType; + this.attachmentType = attachmentType; + this.loadOp = loadOp; + this.storeOp = storeOp; + this.clearFlags = clearFlags; + this.clearColor.reset(); + this.slotID = 0; + this.shaderStageFlags = shaderStageFlags; + } slotName: string; slotName1 = ''; accessType: AccessType; @@ -97,6 +125,21 @@ export class ComputeView { this.clearValue = clearValue; this.shaderStageFlags = shaderStageFlags; } + reset ( + name = '', + accessType: AccessType = AccessType.READ, + clearFlags: ClearFlagBit = ClearFlagBit.NONE, + clearValueType: ClearValueType = ClearValueType.NONE, + shaderStageFlags: ShaderStageFlagBit = ShaderStageFlagBit.NONE, + ): void { + this.name = name; + this.accessType = accessType; + this.plane = 0; + this.clearFlags = clearFlags; + this.clearValueType = clearValueType; + this.clearValue.reset(); + this.shaderStageFlags = shaderStageFlags; + } name: string; accessType: AccessType; plane = 0; @@ -107,6 +150,19 @@ export class ComputeView { } export class ResourceDesc { + reset (): void { + this.dimension = ResourceDimension.BUFFER; + this.alignment = 0; + this.width = 0; + this.height = 0; + this.depthOrArraySize = 0; + this.mipLevels = 0; + this.format = Format.UNKNOWN; + this.sampleCount = SampleCount.X1; + this.textureFlags = TextureFlagBit.NONE; + this.flags = ResourceFlags.NONE; + this.viewType = TextureType.TEX2D; + } dimension: ResourceDimension = ResourceDimension.BUFFER; alignment = 0; width = 0; @@ -124,6 +180,9 @@ export class ResourceTraits { constructor (residency: ResourceResidency = ResourceResidency.MANAGED) { this.residency = residency; } + reset (residency: ResourceResidency = ResourceResidency.MANAGED): void { + this.residency = residency; + } residency: ResourceResidency; } @@ -131,6 +190,13 @@ export class RenderSwapchain { constructor (swapchain: Swapchain | null = null) { this.swapchain = swapchain; } + reset (swapchain: Swapchain | null = null): void { + this.swapchain = swapchain; + this.renderWindow = null; + this.currentID = 0; + this.numBackBuffers = 0; + this.generation = 0xFFFFFFFF; + } /*pointer*/ swapchain: Swapchain | null; /*pointer*/ renderWindow: RenderWindow | null = null; currentID = 0; @@ -139,6 +205,9 @@ export class RenderSwapchain { } export class ResourceStates { + reset (): void { + this.states = AccessFlagBit.NONE; + } states: AccessFlagBit = AccessFlagBit.NONE; } @@ -146,6 +215,22 @@ export class ManagedBuffer { constructor (buffer: Buffer | null = null) { this.buffer = buffer; } + reset (buffer: Buffer | null = null): void { + this.buffer = buffer; + this.fenceValue = 0; + } + /*refcount*/ buffer: Buffer | null; + fenceValue = 0; +} + +export class PersistentBuffer { + constructor (buffer: Buffer | null = null) { + this.buffer = buffer; + } + reset (buffer: Buffer | null = null): void { + this.buffer = buffer; + this.fenceValue = 0; + } /*refcount*/ buffer: Buffer | null; fenceValue = 0; } @@ -154,15 +239,39 @@ export class ManagedTexture { constructor (texture: Texture | null = null) { this.texture = texture; } + reset (texture: Texture | null = null): void { + this.texture = texture; + this.fenceValue = 0; + } + /*refcount*/ texture: Texture | null; + fenceValue = 0; +} + +export class PersistentTexture { + constructor (texture: Texture | null = null) { + this.texture = texture; + } + reset (texture: Texture | null = null): void { + this.texture = texture; + this.fenceValue = 0; + } /*refcount*/ texture: Texture | null; fenceValue = 0; } export class ManagedResource { + reset (): void { + this.unused = 0; + } unused = 0; } export class Subpass { + reset (): void { + this.rasterViews.clear(); + this.computeViews.clear(); + this.resolvePairs.length = 0; + } readonly rasterViews: Map = new Map(); readonly computeViews: Map = new Map(); readonly resolvePairs: ResolvePair[] = []; @@ -470,10 +579,20 @@ export class SubpassGraph implements BidirectionalGraph } export class RasterSubpass { - constructor (subpassID: number, count: number, quality: number) { + constructor (subpassID = 0xFFFFFFFF, count = 1, quality = 0) { + this.subpassID = subpassID; + this.count = count; + this.quality = quality; + } + reset (subpassID = 0xFFFFFFFF, count = 1, quality = 0): void { + this.rasterViews.clear(); + this.computeViews.clear(); + this.resolvePairs.length = 0; + this.viewport.reset(); this.subpassID = subpassID; this.count = count; this.quality = quality; + this.showStatistics = false; } readonly rasterViews: Map = new Map(); readonly computeViews: Map = new Map(); @@ -486,7 +605,12 @@ export class RasterSubpass { } export class ComputeSubpass { - constructor (subpassID: number) { + constructor (subpassID = 0xFFFFFFFF) { + this.subpassID = subpassID; + } + reset (subpassID = 0xFFFFFFFF): void { + this.rasterViews.clear(); + this.computeViews.clear(); this.subpassID = subpassID; } readonly rasterViews: Map = new Map(); @@ -495,6 +619,22 @@ export class ComputeSubpass { } export class RasterPass { + reset (): void { + this.rasterViews.clear(); + this.computeViews.clear(); + this.attachmentIndexMap.clear(); + this.textures.clear(); + this.subpassGraph.clear(); + this.width = 0; + this.height = 0; + this.count = 1; + this.quality = 0; + this.viewport.reset(); + this.versionName = ''; + this.version = 0; + this.hashValue = 0; + this.showStatistics = false; + } readonly rasterViews: Map = new Map(); readonly computeViews: Map = new Map(); readonly attachmentIndexMap: Map = new Map(); @@ -512,22 +652,42 @@ export class RasterPass { } export class PersistentRenderPassAndFramebuffer { - constructor (renderPass: RenderPass, framebuffer: Framebuffer) { + constructor (renderPass: RenderPass | null = null, framebuffer: Framebuffer | null = null) { this.renderPass = renderPass; this.framebuffer = framebuffer; } - /*refcount*/ renderPass: RenderPass; - /*refcount*/ framebuffer: Framebuffer; + reset (renderPass: RenderPass | null = null, framebuffer: Framebuffer | null = null): void { + this.renderPass = renderPass; + this.framebuffer = framebuffer; + this.clearColors.length = 0; + this.clearDepth = 0; + this.clearStencil = 0; + } + /*refcount*/ renderPass: RenderPass | null; + /*refcount*/ framebuffer: Framebuffer | null; readonly clearColors: Color[] = []; clearDepth = 0; clearStencil = 0; } export class FormatView { + reset (): void { + this.format = Format.UNKNOWN; + } format: Format = Format.UNKNOWN; } export class SubresourceView { + reset (): void { + this.textureView = null; + this.format = Format.UNKNOWN; + this.indexOrFirstMipLevel = 0; + this.numMipLevels = 0; + this.firstArraySlice = 0; + this.numArraySlices = 0; + this.firstPlane = 0; + this.numPlanes = 0; + } /*refcount*/ textureView: Texture | null = null; format: Format = Format.UNKNOWN; indexOrFirstMipLevel = 0; @@ -573,8 +733,8 @@ export interface ResourceGraphValueType { [ResourceGraphValue.Managed]: ManagedResource [ResourceGraphValue.ManagedBuffer]: ManagedBuffer [ResourceGraphValue.ManagedTexture]: ManagedTexture - [ResourceGraphValue.PersistentBuffer]: Buffer - [ResourceGraphValue.PersistentTexture]: Texture + [ResourceGraphValue.PersistentBuffer]: PersistentBuffer + [ResourceGraphValue.PersistentTexture]: PersistentTexture [ResourceGraphValue.Framebuffer]: Framebuffer [ResourceGraphValue.Swapchain]: RenderSwapchain [ResourceGraphValue.FormatView]: FormatView @@ -585,8 +745,8 @@ export interface ResourceGraphVisitor { managed(value: ManagedResource): unknown; managedBuffer(value: ManagedBuffer): unknown; managedTexture(value: ManagedTexture): unknown; - persistentBuffer(value: Buffer): unknown; - persistentTexture(value: Texture): unknown; + persistentBuffer(value: PersistentBuffer): unknown; + persistentTexture(value: PersistentTexture): unknown; framebuffer(value: Framebuffer): unknown; swapchain(value: RenderSwapchain): unknown; formatView(value: FormatView): unknown; @@ -596,8 +756,8 @@ export interface ResourceGraphVisitor { export type ResourceGraphObject = ManagedResource | ManagedBuffer | ManagedTexture -| Buffer -| Texture +| PersistentBuffer +| PersistentTexture | Framebuffer | RenderSwapchain | FormatView @@ -1046,9 +1206,9 @@ export class ResourceGraph implements BidirectionalGraph case ResourceGraphValue.ManagedTexture: return visitor.managedTexture(vert._object as ManagedTexture); case ResourceGraphValue.PersistentBuffer: - return visitor.persistentBuffer(vert._object as Buffer); + return visitor.persistentBuffer(vert._object as PersistentBuffer); case ResourceGraphValue.PersistentTexture: - return visitor.persistentTexture(vert._object as Texture); + return visitor.persistentTexture(vert._object as PersistentTexture); case ResourceGraphValue.Framebuffer: return visitor.framebuffer(vert._object as Framebuffer); case ResourceGraphValue.Swapchain: @@ -1082,16 +1242,16 @@ export class ResourceGraph implements BidirectionalGraph throw Error('value id not match'); } } - getPersistentBuffer (v: number): Buffer { + getPersistentBuffer (v: number): PersistentBuffer { if (this._vertices[v]._id === ResourceGraphValue.PersistentBuffer) { - return this._vertices[v]._object as Buffer; + return this._vertices[v]._object as PersistentBuffer; } else { throw Error('value id not match'); } } - getPersistentTexture (v: number): Texture { + getPersistentTexture (v: number): PersistentTexture { if (this._vertices[v]._id === ResourceGraphValue.PersistentTexture) { - return this._vertices[v]._object as Texture; + return this._vertices[v]._object as PersistentTexture; } else { throw Error('value id not match'); } @@ -1145,16 +1305,16 @@ export class ResourceGraph implements BidirectionalGraph return null; } } - tryGetPersistentBuffer (v: number): Buffer | null { + tryGetPersistentBuffer (v: number): PersistentBuffer | null { if (this._vertices[v]._id === ResourceGraphValue.PersistentBuffer) { - return this._vertices[v]._object as Buffer; + return this._vertices[v]._object as PersistentBuffer; } else { return null; } } - tryGetPersistentTexture (v: number): Texture | null { + tryGetPersistentTexture (v: number): PersistentTexture | null { if (this._vertices[v]._id === ResourceGraphValue.PersistentTexture) { - return this._vertices[v]._object as Texture; + return this._vertices[v]._object as PersistentTexture; } else { return null; } @@ -1290,24 +1450,41 @@ export class ResourceGraph implements BidirectionalGraph } export class ComputePass { + reset (): void { + this.computeViews.clear(); + this.textures.clear(); + } readonly computeViews: Map = new Map(); readonly textures: Map = new Map(); } export class ResolvePass { + reset (): void { + this.resolvePairs.length = 0; + } readonly resolvePairs: ResolvePair[] = []; } export class CopyPass { + reset (): void { + this.copyPairs.length = 0; + this.uploadPairs.length = 0; + } readonly copyPairs: CopyPair[] = []; readonly uploadPairs: UploadPair[] = []; } export class MovePass { + reset (): void { + this.movePairs.length = 0; + } readonly movePairs: MovePair[] = []; } export class RaytracePass { + reset (): void { + this.computeViews.clear(); + } readonly computeViews: Map = new Map(); } @@ -1317,6 +1494,11 @@ export class ClearView { this.clearFlags = clearFlags; this.clearColor = clearColor; } + reset (slotName = '', clearFlags: ClearFlagBit = ClearFlagBit.ALL): void { + this.slotName = slotName; + this.clearFlags = clearFlags; + this.clearColor.reset(); + } slotName: string; clearFlags: ClearFlagBit; readonly clearColor: Color; @@ -1327,31 +1509,68 @@ export class RenderQueue { this.hint = hint; this.phaseID = phaseID; } + reset (hint: QueueHint = QueueHint.RENDER_OPAQUE, phaseID = 0xFFFFFFFF): void { + this.hint = hint; + this.phaseID = phaseID; + this.viewport = null; + } hint: QueueHint; phaseID: number; viewport: Viewport | null = null; } +export enum CullingFlags { + NONE = 0, + CAMERA_FRUSTUM = 0x1, + LIGHT_FRUSTUM = 0x2, + LIGHT_BOUNDS = 0x4, +} + export class SceneData { - constructor (scene: RenderScene | null = null, camera: Camera | null = null, flags: SceneFlags = SceneFlags.NONE, light: LightInfo = new LightInfo()) { + constructor ( + scene: RenderScene | null = null, + camera: Camera | null = null, + flags: SceneFlags = SceneFlags.NONE, + light: LightInfo = new LightInfo(), + cullingFlags: CullingFlags = CullingFlags.CAMERA_FRUSTUM, + shadingLight: Light | null = null, + ) { this.scene = scene; this.camera = camera; this.light = light; this.flags = flags; + this.cullingFlags = cullingFlags; + this.shadingLight = shadingLight; + } + reset ( + scene: RenderScene | null = null, + camera: Camera | null = null, + flags: SceneFlags = SceneFlags.NONE, + cullingFlags: CullingFlags = CullingFlags.CAMERA_FRUSTUM, + shadingLight: Light | null = null, + ): void { + this.scene = scene; + this.camera = camera; + this.light.reset(); + this.flags = flags; + this.cullingFlags = cullingFlags; + this.shadingLight = shadingLight; } /*pointer*/ scene: RenderScene | null; /*pointer*/ camera: Camera | null; readonly light: LightInfo; flags: SceneFlags; + cullingFlags: CullingFlags; + /*refcount*/ shadingLight: Light | null; } export class Dispatch { constructor ( - material: Material | null, - passID: number, - threadGroupCountX: number, - threadGroupCountY: number, - threadGroupCountZ: number, + material: Material | null = null, + passID = 0, + threadGroupCountX = 0, + threadGroupCountY = 0, + threadGroupCountZ = 0, ) { this.material = material; this.passID = passID; @@ -1359,6 +1578,19 @@ export class Dispatch { this.threadGroupCountY = threadGroupCountY; this.threadGroupCountZ = threadGroupCountZ; } + reset ( + material: Material | null = null, + passID = 0, + threadGroupCountX = 0, + threadGroupCountY = 0, + threadGroupCountZ = 0, + ): void { + this.material = material; + this.passID = passID; + this.threadGroupCountX = threadGroupCountX; + this.threadGroupCountY = threadGroupCountY; + this.threadGroupCountZ = threadGroupCountZ; + } /*refcount*/ material: Material | null; passID: number; threadGroupCountX: number; @@ -1367,7 +1599,13 @@ export class Dispatch { } export class Blit { - constructor (material: Material | null, passID: number, sceneFlags: SceneFlags, camera: Camera | null) { + constructor (material: Material | null = null, passID = 0, sceneFlags: SceneFlags = SceneFlags.NONE, camera: Camera | null = null) { + this.material = material; + this.passID = passID; + this.sceneFlags = sceneFlags; + this.camera = camera; + } + reset (material: Material | null = null, passID = 0, sceneFlags: SceneFlags = SceneFlags.NONE, camera: Camera | null = null): void { this.material = material; this.passID = passID; this.sceneFlags = sceneFlags; @@ -1380,6 +1618,13 @@ export class Blit { } export class RenderData { + reset (): void { + this.constants.clear(); + this.buffers.clear(); + this.textures.clear(); + this.samplers.clear(); + this.custom = ''; + } readonly constants: Map = new Map(); readonly buffers: Map = new Map(); readonly textures: Map = new Map(); @@ -2270,3 +2515,410 @@ export class RenderGraph implements BidirectionalGraph readonly index: Map = new Map(); readonly sortedVertices: number[] = []; } + +export class RenderGraphObjectPoolSettings { + constructor (batchSize: number) { + this.clearValueBatchSize = batchSize; + this.rasterViewBatchSize = batchSize; + this.computeViewBatchSize = batchSize; + this.resourceDescBatchSize = batchSize; + this.resourceTraitsBatchSize = batchSize; + this.renderSwapchainBatchSize = batchSize; + this.resourceStatesBatchSize = batchSize; + this.managedBufferBatchSize = batchSize; + this.persistentBufferBatchSize = batchSize; + this.managedTextureBatchSize = batchSize; + this.persistentTextureBatchSize = batchSize; + this.managedResourceBatchSize = batchSize; + this.subpassBatchSize = batchSize; + this.subpassGraphBatchSize = batchSize; + this.rasterSubpassBatchSize = batchSize; + this.computeSubpassBatchSize = batchSize; + this.rasterPassBatchSize = batchSize; + this.persistentRenderPassAndFramebufferBatchSize = batchSize; + this.formatViewBatchSize = batchSize; + this.subresourceViewBatchSize = batchSize; + this.resourceGraphBatchSize = batchSize; + this.computePassBatchSize = batchSize; + this.resolvePassBatchSize = batchSize; + this.copyPassBatchSize = batchSize; + this.movePassBatchSize = batchSize; + this.raytracePassBatchSize = batchSize; + this.clearViewBatchSize = batchSize; + this.renderQueueBatchSize = batchSize; + this.sceneDataBatchSize = batchSize; + this.dispatchBatchSize = batchSize; + this.blitBatchSize = batchSize; + this.renderDataBatchSize = batchSize; + this.renderGraphBatchSize = batchSize; + } + clearValueBatchSize = 16; + rasterViewBatchSize = 16; + computeViewBatchSize = 16; + resourceDescBatchSize = 16; + resourceTraitsBatchSize = 16; + renderSwapchainBatchSize = 16; + resourceStatesBatchSize = 16; + managedBufferBatchSize = 16; + persistentBufferBatchSize = 16; + managedTextureBatchSize = 16; + persistentTextureBatchSize = 16; + managedResourceBatchSize = 16; + subpassBatchSize = 16; + subpassGraphBatchSize = 16; + rasterSubpassBatchSize = 16; + computeSubpassBatchSize = 16; + rasterPassBatchSize = 16; + persistentRenderPassAndFramebufferBatchSize = 16; + formatViewBatchSize = 16; + subresourceViewBatchSize = 16; + resourceGraphBatchSize = 16; + computePassBatchSize = 16; + resolvePassBatchSize = 16; + copyPassBatchSize = 16; + movePassBatchSize = 16; + raytracePassBatchSize = 16; + clearViewBatchSize = 16; + renderQueueBatchSize = 16; + sceneDataBatchSize = 16; + dispatchBatchSize = 16; + blitBatchSize = 16; + renderDataBatchSize = 16; + renderGraphBatchSize = 16; +} + +export class RenderGraphObjectPool { + constructor (settings: RenderGraphObjectPoolSettings, renderCommon: RenderCommonObjectPool) { + this.renderCommon = renderCommon; + this._clearValue = new RecyclePool(() => new ClearValue(), settings.clearValueBatchSize); + this._rasterView = new RecyclePool(() => new RasterView(), settings.rasterViewBatchSize); + this._computeView = new RecyclePool(() => new ComputeView(), settings.computeViewBatchSize); + this._resourceDesc = new RecyclePool(() => new ResourceDesc(), settings.resourceDescBatchSize); + this._resourceTraits = new RecyclePool(() => new ResourceTraits(), settings.resourceTraitsBatchSize); + this._renderSwapchain = new RecyclePool(() => new RenderSwapchain(), settings.renderSwapchainBatchSize); + this._resourceStates = new RecyclePool(() => new ResourceStates(), settings.resourceStatesBatchSize); + this._managedBuffer = new RecyclePool(() => new ManagedBuffer(), settings.managedBufferBatchSize); + this._persistentBuffer = new RecyclePool(() => new PersistentBuffer(), settings.persistentBufferBatchSize); + this._managedTexture = new RecyclePool(() => new ManagedTexture(), settings.managedTextureBatchSize); + this._persistentTexture = new RecyclePool(() => new PersistentTexture(), settings.persistentTextureBatchSize); + this._managedResource = new RecyclePool(() => new ManagedResource(), settings.managedResourceBatchSize); + this._subpass = new RecyclePool(() => new Subpass(), settings.subpassBatchSize); + this._subpassGraph = new RecyclePool(() => new SubpassGraph(), settings.subpassGraphBatchSize); + this._rasterSubpass = new RecyclePool(() => new RasterSubpass(), settings.rasterSubpassBatchSize); + this._computeSubpass = new RecyclePool(() => new ComputeSubpass(), settings.computeSubpassBatchSize); + this._rasterPass = new RecyclePool(() => new RasterPass(), settings.rasterPassBatchSize); + this._persistentRenderPassAndFramebuffer = new RecyclePool(() => new PersistentRenderPassAndFramebuffer(), settings.persistentRenderPassAndFramebufferBatchSize); + this._formatView = new RecyclePool(() => new FormatView(), settings.formatViewBatchSize); + this._subresourceView = new RecyclePool(() => new SubresourceView(), settings.subresourceViewBatchSize); + this._resourceGraph = new RecyclePool(() => new ResourceGraph(), settings.resourceGraphBatchSize); + this._computePass = new RecyclePool(() => new ComputePass(), settings.computePassBatchSize); + this._resolvePass = new RecyclePool(() => new ResolvePass(), settings.resolvePassBatchSize); + this._copyPass = new RecyclePool(() => new CopyPass(), settings.copyPassBatchSize); + this._movePass = new RecyclePool(() => new MovePass(), settings.movePassBatchSize); + this._raytracePass = new RecyclePool(() => new RaytracePass(), settings.raytracePassBatchSize); + this._clearView = new RecyclePool(() => new ClearView(), settings.clearViewBatchSize); + this._renderQueue = new RecyclePool(() => new RenderQueue(), settings.renderQueueBatchSize); + this._sceneData = new RecyclePool(() => new SceneData(), settings.sceneDataBatchSize); + this._dispatch = new RecyclePool(() => new Dispatch(), settings.dispatchBatchSize); + this._blit = new RecyclePool(() => new Blit(), settings.blitBatchSize); + this._renderData = new RecyclePool(() => new RenderData(), settings.renderDataBatchSize); + this._renderGraph = new RecyclePool(() => new RenderGraph(), settings.renderGraphBatchSize); + } + reset (): void { + this._clearValue.reset(); + this._rasterView.reset(); + this._computeView.reset(); + this._resourceDesc.reset(); + this._resourceTraits.reset(); + this._renderSwapchain.reset(); + this._resourceStates.reset(); + this._managedBuffer.reset(); + this._persistentBuffer.reset(); + this._managedTexture.reset(); + this._persistentTexture.reset(); + this._managedResource.reset(); + this._subpass.reset(); + this._subpassGraph.reset(); + this._rasterSubpass.reset(); + this._computeSubpass.reset(); + this._rasterPass.reset(); + this._persistentRenderPassAndFramebuffer.reset(); + this._formatView.reset(); + this._subresourceView.reset(); + this._resourceGraph.reset(); + this._computePass.reset(); + this._resolvePass.reset(); + this._copyPass.reset(); + this._movePass.reset(); + this._raytracePass.reset(); + this._clearView.reset(); + this._renderQueue.reset(); + this._sceneData.reset(); + this._dispatch.reset(); + this._blit.reset(); + this._renderData.reset(); + this._renderGraph.reset(); + } + createClearValue ( + x = 0, + y = 0, + z = 0, + w = 0, + ): ClearValue { + const v = this._clearValue.add(); + v.reset(x, y, z, w); + return v; + } + createRasterView ( + slotName = '', + accessType: AccessType = AccessType.WRITE, + attachmentType: AttachmentType = AttachmentType.RENDER_TARGET, + loadOp: LoadOp = LoadOp.LOAD, + storeOp: StoreOp = StoreOp.STORE, + clearFlags: ClearFlagBit = ClearFlagBit.ALL, + shaderStageFlags: ShaderStageFlagBit = ShaderStageFlagBit.NONE, + ): RasterView { + const v = this._rasterView.add(); + v.reset(slotName, accessType, attachmentType, loadOp, storeOp, clearFlags, shaderStageFlags); + return v; + } + createComputeView ( + name = '', + accessType: AccessType = AccessType.READ, + clearFlags: ClearFlagBit = ClearFlagBit.NONE, + clearValueType: ClearValueType = ClearValueType.NONE, + shaderStageFlags: ShaderStageFlagBit = ShaderStageFlagBit.NONE, + ): ComputeView { + const v = this._computeView.add(); + v.reset(name, accessType, clearFlags, clearValueType, shaderStageFlags); + return v; + } + createResourceDesc (): ResourceDesc { + const v = this._resourceDesc.add(); + v.reset(); + return v; + } + createResourceTraits ( + residency: ResourceResidency = ResourceResidency.MANAGED, + ): ResourceTraits { + const v = this._resourceTraits.add(); + v.reset(residency); + return v; + } + createRenderSwapchain ( + swapchain: Swapchain | null = null, + ): RenderSwapchain { + const v = this._renderSwapchain.add(); + v.reset(swapchain); + return v; + } + createResourceStates (): ResourceStates { + const v = this._resourceStates.add(); + v.reset(); + return v; + } + createManagedBuffer ( + buffer: Buffer | null = null, + ): ManagedBuffer { + const v = this._managedBuffer.add(); + v.reset(buffer); + return v; + } + createPersistentBuffer ( + buffer: Buffer | null = null, + ): PersistentBuffer { + const v = this._persistentBuffer.add(); + v.reset(buffer); + return v; + } + createManagedTexture ( + texture: Texture | null = null, + ): ManagedTexture { + const v = this._managedTexture.add(); + v.reset(texture); + return v; + } + createPersistentTexture ( + texture: Texture | null = null, + ): PersistentTexture { + const v = this._persistentTexture.add(); + v.reset(texture); + return v; + } + createManagedResource (): ManagedResource { + const v = this._managedResource.add(); + v.reset(); + return v; + } + createSubpass (): Subpass { + const v = this._subpass.add(); + v.reset(); + return v; + } + createSubpassGraph (): SubpassGraph { + const v = this._subpassGraph.add(); + v.clear(); + return v; + } + createRasterSubpass ( + subpassID = 0xFFFFFFFF, + count = 1, + quality = 0, + ): RasterSubpass { + const v = this._rasterSubpass.add(); + v.reset(subpassID, count, quality); + return v; + } + createComputeSubpass ( + subpassID = 0xFFFFFFFF, + ): ComputeSubpass { + const v = this._computeSubpass.add(); + v.reset(subpassID); + return v; + } + createRasterPass (): RasterPass { + const v = this._rasterPass.add(); + v.reset(); + return v; + } + createPersistentRenderPassAndFramebuffer ( + renderPass: RenderPass | null = null, + framebuffer: Framebuffer | null = null, + ): PersistentRenderPassAndFramebuffer { + const v = this._persistentRenderPassAndFramebuffer.add(); + v.reset(renderPass, framebuffer); + return v; + } + createFormatView (): FormatView { + const v = this._formatView.add(); + v.reset(); + return v; + } + createSubresourceView (): SubresourceView { + const v = this._subresourceView.add(); + v.reset(); + return v; + } + createResourceGraph (): ResourceGraph { + const v = this._resourceGraph.add(); + v.clear(); + return v; + } + createComputePass (): ComputePass { + const v = this._computePass.add(); + v.reset(); + return v; + } + createResolvePass (): ResolvePass { + const v = this._resolvePass.add(); + v.reset(); + return v; + } + createCopyPass (): CopyPass { + const v = this._copyPass.add(); + v.reset(); + return v; + } + createMovePass (): MovePass { + const v = this._movePass.add(); + v.reset(); + return v; + } + createRaytracePass (): RaytracePass { + const v = this._raytracePass.add(); + v.reset(); + return v; + } + createClearView ( + slotName = '', + clearFlags: ClearFlagBit = ClearFlagBit.ALL, + ): ClearView { + const v = this._clearView.add(); + v.reset(slotName, clearFlags); + return v; + } + createRenderQueue ( + hint: QueueHint = QueueHint.RENDER_OPAQUE, + phaseID = 0xFFFFFFFF, + ): RenderQueue { + const v = this._renderQueue.add(); + v.reset(hint, phaseID); + return v; + } + createSceneData ( + scene: RenderScene | null = null, + camera: Camera | null = null, + flags: SceneFlags = SceneFlags.NONE, + cullingFlags: CullingFlags = CullingFlags.CAMERA_FRUSTUM, + shadingLight: Light | null = null, + ): SceneData { + const v = this._sceneData.add(); + v.reset(scene, camera, flags, cullingFlags, shadingLight); + return v; + } + createDispatch ( + material: Material | null = null, + passID = 0, + threadGroupCountX = 0, + threadGroupCountY = 0, + threadGroupCountZ = 0, + ): Dispatch { + const v = this._dispatch.add(); + v.reset(material, passID, threadGroupCountX, threadGroupCountY, threadGroupCountZ); + return v; + } + createBlit ( + material: Material | null = null, + passID = 0, + sceneFlags: SceneFlags = SceneFlags.NONE, + camera: Camera | null = null, + ): Blit { + const v = this._blit.add(); + v.reset(material, passID, sceneFlags, camera); + return v; + } + createRenderData (): RenderData { + const v = this._renderData.add(); + v.reset(); + return v; + } + createRenderGraph (): RenderGraph { + const v = this._renderGraph.add(); + v.clear(); + return v; + } + public readonly renderCommon: RenderCommonObjectPool; + private readonly _clearValue: RecyclePool; + private readonly _rasterView: RecyclePool; + private readonly _computeView: RecyclePool; + private readonly _resourceDesc: RecyclePool; + private readonly _resourceTraits: RecyclePool; + private readonly _renderSwapchain: RecyclePool; + private readonly _resourceStates: RecyclePool; + private readonly _managedBuffer: RecyclePool; + private readonly _persistentBuffer: RecyclePool; + private readonly _managedTexture: RecyclePool; + private readonly _persistentTexture: RecyclePool; + private readonly _managedResource: RecyclePool; + private readonly _subpass: RecyclePool; + private readonly _subpassGraph: RecyclePool; + private readonly _rasterSubpass: RecyclePool; + private readonly _computeSubpass: RecyclePool; + private readonly _rasterPass: RecyclePool; + private readonly _persistentRenderPassAndFramebuffer: RecyclePool; + private readonly _formatView: RecyclePool; + private readonly _subresourceView: RecyclePool; + private readonly _resourceGraph: RecyclePool; + private readonly _computePass: RecyclePool; + private readonly _resolvePass: RecyclePool; + private readonly _copyPass: RecyclePool; + private readonly _movePass: RecyclePool; + private readonly _raytracePass: RecyclePool; + private readonly _clearView: RecyclePool; + private readonly _renderQueue: RecyclePool; + private readonly _sceneData: RecyclePool; + private readonly _dispatch: RecyclePool; + private readonly _blit: RecyclePool; + private readonly _renderData: RecyclePool; + private readonly _renderGraph: RecyclePool; +} diff --git a/cocos/rendering/custom/scene-culling.ts b/cocos/rendering/custom/scene-culling.ts index b337a00f6de..8a8e001ab93 100644 --- a/cocos/rendering/custom/scene-culling.ts +++ b/cocos/rendering/custom/scene-culling.ts @@ -1,18 +1,38 @@ -import { Vec3, assert } from '../../core'; +import { Vec3, assert, RecyclePool } from '../../core'; import { Frustum, intersect, AABB } from '../../core/geometry'; import { CommandBuffer } from '../../gfx'; import { BatchingSchemes, Pass, RenderScene } from '../../render-scene'; -import { CSMLevel, Camera, DirectionalLight, Light, LightType, Model, SKYBOX_FLAG, ShadowType, SpotLight } from '../../render-scene/scene'; -import { Node } from '../../scene-graph'; +import { CSMLevel, Camera, DirectionalLight, LightType, Model, ProbeType, + ReflectionProbe, SKYBOX_FLAG, ShadowType, SpotLight } from '../../render-scene/scene'; +import { Layers, Node } from '../../scene-graph'; import { PipelineSceneData } from '../pipeline-scene-data'; import { hashCombineStr, getSubpassOrPassID, bool } from './define'; import { LayoutGraphData } from './layout-graph'; import { RenderGraph, RenderGraphValue, SceneData } from './render-graph'; import { SceneFlags } from './types'; -import { RenderQueue, RenderQueueDesc } from './web-pipeline-types'; +import { RenderQueue, RenderQueueDesc, instancePool } from './web-pipeline-types'; +import { ObjectPool } from './utils'; -function computeCullingKey (camera: Camera | null, light: Light | null, castShadows: boolean, lightLevel: number): number { +const vec3Pool = new ObjectPool(() => new Vec3()); +class CullingPools { + cullingKeyRecycle = new RecyclePool(() => new CullingKey(), 8); + cullingQueriesRecycle = new RecyclePool(() => new CullingQueries(), 8); + renderQueueRecycle = new RecyclePool(() => new RenderQueue(), 8); + renderQueueDescRecycle = new RecyclePool(() => new RenderQueueDesc(), 8); +} +const REFLECTION_PROBE_DEFAULT_MASK = Layers.makeMaskExclude([Layers.BitMask.UI_2D, Layers.BitMask.UI_3D, + Layers.BitMask.GIZMOS, Layers.BitMask.EDITOR, + Layers.BitMask.SCENE_GIZMO, Layers.BitMask.PROFILER]); + +function computeCullingKey ( + sceneData: SceneData, + castShadows: boolean, +): number { let hashCode = 0; + const camera = sceneData.camera; + const light = sceneData.light.light; + const lightLevel = sceneData.light.level; + const reflectProbe = sceneData.light.probe; if (camera) { // camera hashCode = hashCombineStr(`u${camera.node.uuid}`, hashCode); @@ -49,19 +69,22 @@ function computeCullingKey (camera: Camera | null, light: Light | null, castShad } hashCode = hashCombineStr(`cast${castShadows}`, hashCode); hashCode = hashCombineStr(`level${lightLevel}`, hashCode); + if (reflectProbe) { + hashCode = hashCombineStr(`probe${reflectProbe.getProbeId()}`, hashCode); + } return hashCode; } class CullingKey { - camera: Camera | null; - light: Light | null; + sceneData: SceneData | null = null; castShadows = false; - lightLevel = 0xffffffff; - constructor (camera: Camera | null, light: Light | null, castShadows: boolean, lightLevel: number) { - this.camera = camera; - this.light = light; + constructor (sceneData: SceneData | null = null, castShadows: boolean = false) { + this.sceneData = sceneData; + this.castShadows = castShadows; + } + update (sceneData: SceneData, castShadows: boolean): void { + this.sceneData = sceneData; this.castShadows = castShadows; - this.lightLevel = lightLevel; } } @@ -71,6 +94,10 @@ class CullingQueries { // key: hash val culledResultIndex: Map = new Map(); cullingKeyResult: Map = new Map(); + update (): void { + this.culledResultIndex.clear(); + this.cullingKeyResult.clear(); + } } function isNodeVisible (node: Node, visibility: number): boolean { @@ -80,6 +107,11 @@ function isNodeVisible (node: Node, visibility: number): boolean { function isModelVisible (model: Model, visibility: number): boolean { return !!(visibility & model.visFlags); } + +function isReflectProbeMask (model: Model): boolean { + return bool((model.node.layer & REFLECTION_PROBE_DEFAULT_MASK) === model.node.layer || (REFLECTION_PROBE_DEFAULT_MASK & model.visFlags)); +} + const transWorldBounds = new AABB(); function isFrustumVisible (model: Model, frustum: Readonly, castShadow: boolean): boolean { const modelWorldBounds = model.worldBounds; @@ -94,31 +126,48 @@ function isFrustumVisible (model: Model, frustum: Readonly, castShadow: return !intersect.aabbFrustum(transWorldBounds, frustum); } +function isIntersectAABB (lAABB: AABB, rAABB: AABB): boolean { + return !intersect.aabbWithAABB(lAABB, rAABB); +} + function sceneCulling ( - skyboxModelToSkip: Model | null, scene: RenderScene, camera: Camera, camOrLightFrustum: Readonly, castShadow: boolean, + probe: ReflectionProbe | null, + isReflectProbe: boolean, models: Array, ): void { + const skybox = pSceneData.skybox; + const skyboxModel = skybox.model; const visibility = camera.visibility; + const camSkyboxFlag = camera.clearFlag & SKYBOX_FLAG; + if (!castShadow && skybox && skybox.enabled && skyboxModel && camSkyboxFlag) { + models.push(skyboxModel); + } + for (const model of scene.models) { assert(!!model); - if (!model.enabled || model === skyboxModelToSkip || (castShadow && !model.castShadow)) { + if (!model.enabled || !model.node || (castShadow && !model.castShadow)) { continue; } if (scene && scene.isCulledByLod(camera, model)) { continue; } + if (!probe || (probe && probe.probeType === ProbeType.CUBE)) { + if (isNodeVisible(model.node, visibility) + || isModelVisible(model, visibility)) { + const wBounds = model.worldBounds; + // frustum culling + if (wBounds && ((!probe && isFrustumVisible(model, camOrLightFrustum, castShadow)) + || (probe && isIntersectAABB(wBounds, probe.boundingBox!)))) { + continue; + } - if (isNodeVisible(model.node, visibility) - || isModelVisible(model, visibility)) { - // frustum culling - if (isFrustumVisible(model, camOrLightFrustum, castShadow)) { - continue; + models.push(model); } - + } else if (isReflectProbeMask(model)) { models.push(model); } } @@ -138,9 +187,10 @@ function computeSortingDepth (camera: Camera, model: Model): number { let depth = 0; if (model.node) { const node = model.transform; - const tempVec3 = new Vec3(); + const tempVec3 = vec3Pool.acquire(); const position = Vec3.subtract(tempVec3, node.worldPosition, camera.position); depth = position.dot(camera.forward); + vec3Pool.release(tempVec3); } return depth; } @@ -149,17 +199,29 @@ function addRenderObject ( phaseLayoutId: number, isDrawOpaqueOrMask: boolean, isDrawBlend: boolean, + isDrawProbe: boolean, camera: Camera, model: Model, queue: RenderQueue, ): void { + const probeQueue = queue.probeQueue; + if (isDrawProbe) { + probeQueue.applyMacro(model, phaseLayoutId); + } const subModels = model.subModels; const subModelCount = subModels.length; + const skyboxModel = pSceneData.skybox.model; for (let subModelIdx = 0; subModelIdx < subModelCount; ++subModelIdx) { const subModel = subModels[subModelIdx]; const passes = subModel.passes; const passCount = passes.length; + const probePhase = probeQueue.probeMap.includes(subModel); + if (probePhase) phaseLayoutId = probeQueue.defaultId; for (let passIdx = 0; passIdx < passCount; ++passIdx) { + if (model === skyboxModel && !subModelIdx && !passIdx && isDrawOpaqueOrMask) { + queue.opaqueQueue.add(model, computeSortingDepth(camera, model), subModelIdx, passIdx); + continue; + } const pass = passes[passIdx]; // check phase const phaseAllowed = phaseLayoutId === pass.phaseID; @@ -204,21 +266,24 @@ export class SceneCulling { culledResults: Array> = new Array>(); renderQueues: Array = new Array(); sceneQueryIndex: Map = new Map(); + cullingPools = new CullingPools(); // source id numCullingQueries = 0; // target id numRenderQueues = 0; layoutGraph; renderGraph; + resetPool (): void { + this.cullingPools.cullingKeyRecycle.reset(); + this.cullingPools.cullingQueriesRecycle.reset(); + this.cullingPools.renderQueueRecycle.reset(); + this.cullingPools.renderQueueDescRecycle.reset(); + instancePool.reset(); + } clear (): void { + this.resetPool(); this.sceneQueries.clear(); - for (const c of this.culledResults) { - c.length = 0; - } this.culledResults.length = 0; - for (const q of this.renderQueues) { - q.clear(); - } this.renderQueues.length = 0; this.sceneQueryIndex.clear(); this.numCullingQueries = 0; @@ -234,34 +299,44 @@ export class SceneCulling { this.fillRenderQueues(rg, pplSceneData); } - private getOrCreateSceneCullingQuery (sceneData: SceneData): number { + private getOrCreateSceneCullingQuery (sceneId: number): number { + const sceneData: SceneData = this.renderGraph.getScene(sceneId); const scene = sceneData.scene!; let queries = this.sceneQueries.get(scene); if (!queries) { - this.sceneQueries.set(scene, new CullingQueries()); + const cullingQuery = this.cullingPools.cullingQueriesRecycle.add(); + cullingQuery.update(); + this.sceneQueries.set(scene, cullingQuery); queries = this.sceneQueries.get(scene); } - const castShadow = bool(sceneData.flags & SceneFlags.SHADOW_CASTER); - const key = computeCullingKey(sceneData.camera, sceneData.light.light, castShadow, sceneData.light.level); + const castShadow: boolean = bool(sceneData.flags & SceneFlags.SHADOW_CASTER); + const key = computeCullingKey(sceneData, castShadow); const cullNum = queries!.culledResultIndex.get(key); if (cullNum !== undefined) { return cullNum; } - const soureceID = this.numCullingQueries++; + const sourceID = this.numCullingQueries++; if (this.numCullingQueries > this.culledResults.length) { assert(this.numCullingQueries === (this.culledResults.length + 1)); this.culledResults.push([]); } - queries!.culledResultIndex.set(key, soureceID); - queries!.cullingKeyResult.set(key, new CullingKey(sceneData.camera, sceneData.light.light, castShadow, sceneData.light.level)); - return soureceID; + queries!.culledResultIndex.set(key, sourceID); + const cullingKey = this.cullingPools.cullingKeyRecycle.add(); + cullingKey.update( + sceneData, + castShadow, + ); + queries!.cullingKeyResult.set(key, cullingKey); + return sourceID; } private createRenderQueue (sceneFlags: SceneFlags, subpassOrPassLayoutID: number): number { const targetID = this.numRenderQueues++; if (this.numRenderQueues > this.renderQueues.length) { assert(this.numRenderQueues === (this.renderQueues.length + 1)); - this.renderQueues.push(new RenderQueue()); + const renderQueue = this.cullingPools.renderQueueRecycle.add(); + renderQueue.update(); + this.renderQueues.push(renderQueue); } assert(targetID < this.renderQueues.length); const rq = this.renderQueues[targetID]; @@ -280,13 +355,15 @@ export class SceneCulling { assert(!!sceneData.scene); continue; } - const sourceID = this.getOrCreateSceneCullingQuery(sceneData); - const layoutID = getSubpassOrPassID(v, rg, lg); + const sourceID = this.getOrCreateSceneCullingQuery(v); + const layoutID: number = getSubpassOrPassID(v, rg, lg); const targetID = this.createRenderQueue(sceneData.flags, layoutID); const lightType = sceneData.light.light ? sceneData.light.light.type : LightType.UNKNOWN; + const renderQueueDesc = this.cullingPools.renderQueueDescRecycle.add(); + renderQueueDesc.update(sourceID, targetID, lightType); // add render queue to query source - this.sceneQueryIndex.set(v, new RenderQueueDesc(sourceID, targetID, lightType)); + this.sceneQueryIndex.set(v, renderQueueDesc); } } @@ -299,25 +376,38 @@ export class SceneCulling { } } + private _getPhaseIdFromScene (scene: number): number { + const rg: RenderGraph = this.renderGraph; + const renderQueueId = rg.getParent(scene); + assert(rg.holds(RenderGraphValue.Queue, renderQueueId)); + const graphRenderQueue = rg.getQueue(renderQueueId); + return graphRenderQueue.phaseID; + } + private batchCulling (pplSceneData: PipelineSceneData): void { - const skybox = pplSceneData.skybox; - const skyboxModelToSkip = skybox ? skybox.model : null; for (const [scene, queries] of this.sceneQueries) { assert(!!scene); for (const [key, sourceID] of queries.culledResultIndex) { const cullingKey = queries.cullingKeyResult.get(key)!; - assert(!!cullingKey.camera); - assert(cullingKey.camera.scene === scene); - const camera = cullingKey.camera; - const light = cullingKey.light; - const level = cullingKey.lightLevel; + const sceneData = cullingKey.sceneData!; + assert(!!sceneData.camera); + assert(sceneData.camera.scene === scene); + const camera = sceneData.camera; + const light = sceneData.light.light; + const level = sceneData.light.level; const castShadow = cullingKey.castShadows; + const reflectProbe = sceneData.light.probe; assert(sourceID < this.culledResults.length); const models = this.culledResults[sourceID]; + const isReflectProbe = bool(sceneData.flags & SceneFlags.REFLECTION_PROBE); + if (reflectProbe) { + sceneCulling(scene, reflectProbe.camera, reflectProbe.camera.frustum, castShadow, reflectProbe, isReflectProbe, models); + continue; + } if (light) { switch (light.type) { case LightType.SPOT: - sceneCulling(skyboxModelToSkip, scene, camera, (light as SpotLight).frustum, castShadow, models); + sceneCulling(scene, camera, (light as SpotLight).frustum, castShadow, null, isReflectProbe, models); break; case LightType.DIRECTIONAL: { const csmLayers = pplSceneData.csmLayers; @@ -339,29 +429,29 @@ export class SceneCulling { frustum = csmLayers.layers[level].validFrustum; } } - sceneCulling(skyboxModelToSkip, scene, camera, frustum, castShadow, models); + sceneCulling(scene, camera, frustum, castShadow, null, isReflectProbe, models); } break; default: } } else { - sceneCulling(skyboxModelToSkip, scene, camera, camera.frustum, castShadow, models); + sceneCulling(scene, camera, camera.frustum, castShadow, null, isReflectProbe, models); } } } } private fillRenderQueues (rg: RenderGraph, pplSceneData: PipelineSceneData): void { - const skybox = pplSceneData.skybox; for (const [sceneId, desc] of this.sceneQueryIndex) { assert(rg.holds(RenderGraphValue.Scene, sceneId)); const sourceId = desc.culledSource; const targetId = desc.renderQueueTarget; const sceneData = rg.getScene(sceneId); - const isDrawBlend = bool(sceneData.flags & SceneFlags.TRANSPARENT_OBJECT); - const isDrawOpaqueOrMask = bool(sceneData.flags & (SceneFlags.OPAQUE_OBJECT | SceneFlags.CUTOUT_OBJECT)); - const isDrawShadowCaster = bool(sceneData.flags & SceneFlags.SHADOW_CASTER); - if (!isDrawShadowCaster && !isDrawBlend && !isDrawOpaqueOrMask) { + const isDrawBlend: boolean = bool(sceneData.flags & SceneFlags.TRANSPARENT_OBJECT); + const isDrawOpaqueOrMask: boolean = bool(sceneData.flags & (SceneFlags.OPAQUE_OBJECT | SceneFlags.CUTOUT_OBJECT)); + const isDrawShadowCaster: boolean = bool(sceneData.flags & SceneFlags.SHADOW_CASTER); + const isDrawProbe: boolean = bool(sceneData.flags & SceneFlags.REFLECTION_PROBE); + if (!isDrawShadowCaster && !isDrawBlend && !isDrawOpaqueOrMask && !isDrawProbe) { continue; } // render queue info @@ -383,27 +473,13 @@ export class SceneCulling { // skybox const camera = sceneData.camera; assert(!!camera); - if (!bool(sceneData.flags & SceneFlags.SHADOW_CASTER) - && skybox && skybox.enabled - && (camera.clearFlag & SKYBOX_FLAG)) { - assert(!!skybox.model); - const model = skybox.model; - const node = model.node; - let depth = 0; - if (node) { - const tempVec3 = new Vec3(); - Vec3.subtract(tempVec3, node.worldPosition, camera.position); - depth = tempVec3.dot(camera.forward); - } - renderQueue.opaqueQueue.add(model, depth, 0, 0); - } - // fill render queue for (const model of sourceModels) { addRenderObject( phaseLayoutId, isDrawOpaqueOrMask, isDrawBlend, + isDrawProbe, camera, model, renderQueue, diff --git a/cocos/rendering/custom/types.ts b/cocos/rendering/custom/types.ts index bde9ca132f7..577955e8017 100644 --- a/cocos/rendering/custom/types.ts +++ b/cocos/rendering/custom/types.ts @@ -29,9 +29,11 @@ */ /* eslint-disable max-len */ import { ResolveMode, ShaderStageFlagBit, Type, UniformBlock } from '../../gfx'; +import { ReflectionProbe } from '../../render-scene/scene/reflection-probe'; import { Light } from '../../render-scene/scene'; import { OutputArchive, InputArchive } from './archive'; import { saveUniformBlock, loadUniformBlock } from './serialization'; +import { RecyclePool } from '../../core/memop'; export enum UpdateFrequency { PER_INSTANCE, @@ -208,6 +210,7 @@ export enum SceneFlags { DRAW_NON_INSTANCING = 0x1000, REFLECTION_PROBE = 0x2000, GPU_DRIVEN = 0x4000, + NON_BUILTIN = 0x8000, ALL = 0xFFFFFFFF, } @@ -288,12 +291,20 @@ export function getClearValueTypeName (e: ClearValueType): string { } export class LightInfo { - constructor (light: Light | null = null, level = 0, culledByLight = false) { + constructor (light: Light | null = null, level = 0, culledByLight = false, probe: ReflectionProbe | null = null) { this.light = light; + this.probe = probe; + this.level = level; + this.culledByLight = culledByLight; + } + reset (light: Light | null = null, level = 0, culledByLight = false, probe: ReflectionProbe | null = null): void { + this.light = light; + this.probe = probe; this.level = level; this.culledByLight = culledByLight; } /*refcount*/ light: Light | null; + /*pointer*/ probe: ReflectionProbe | null; level: number; culledByLight: boolean; } @@ -339,11 +350,21 @@ export class Descriptor { constructor (type: Type = Type.UNKNOWN) { this.type = type; } + reset (type: Type = Type.UNKNOWN): void { + this.type = type; + this.count = 1; + } type: Type; count = 1; } export class DescriptorBlock { + reset (): void { + this.descriptors.clear(); + this.uniformBlocks.clear(); + this.capacity = 0; + this.count = 0; + } readonly descriptors: Map = new Map(); readonly uniformBlocks: Map = new Map(); capacity = 0; @@ -351,6 +372,14 @@ export class DescriptorBlock { } export class DescriptorBlockFlattened { + reset (): void { + this.descriptorNames.length = 0; + this.uniformBlockNames.length = 0; + this.descriptors.length = 0; + this.uniformBlocks.length = 0; + this.capacity = 0; + this.count = 0; + } readonly descriptorNames: string[] = []; readonly uniformBlockNames: string[] = []; readonly descriptors: Descriptor[] = []; @@ -393,6 +422,19 @@ export class ResolvePair { this.mode = mode; this.mode1 = mode1; } + reset ( + source = '', + target = '', + resolveFlags: ResolveFlags = ResolveFlags.NONE, + mode: ResolveMode = ResolveMode.SAMPLE_ZERO, + mode1: ResolveMode = ResolveMode.SAMPLE_ZERO, + ): void { + this.source = source; + this.target = target; + this.resolveFlags = resolveFlags; + this.mode = mode; + this.mode1 = mode1; + } source: string; target: string; resolveFlags: ResolveFlags; @@ -424,6 +466,29 @@ export class CopyPair { this.targetFirstSlice = targetFirstSlice; this.targetPlaneSlice = targetPlaneSlice; } + reset ( + source = '', + target = '', + mipLevels = 0xFFFFFFFF, + numSlices = 0xFFFFFFFF, + sourceMostDetailedMip = 0, + sourceFirstSlice = 0, + sourcePlaneSlice = 0, + targetMostDetailedMip = 0, + targetFirstSlice = 0, + targetPlaneSlice = 0, + ): void { + this.source = source; + this.target = target; + this.mipLevels = mipLevels; + this.numSlices = numSlices; + this.sourceMostDetailedMip = sourceMostDetailedMip; + this.sourceFirstSlice = sourceFirstSlice; + this.sourcePlaneSlice = sourcePlaneSlice; + this.targetMostDetailedMip = targetMostDetailedMip; + this.targetFirstSlice = targetFirstSlice; + this.targetPlaneSlice = targetPlaneSlice; + } source: string; target: string; mipLevels: number; @@ -454,6 +519,22 @@ export class UploadPair { this.targetFirstSlice = targetFirstSlice; this.targetPlaneSlice = targetPlaneSlice; } + reset ( + target = '', + mipLevels = 0xFFFFFFFF, + numSlices = 0xFFFFFFFF, + targetMostDetailedMip = 0, + targetFirstSlice = 0, + targetPlaneSlice = 0, + ): void { + // source: Uint8Array size unchanged + this.target = target; + this.mipLevels = mipLevels; + this.numSlices = numSlices; + this.targetMostDetailedMip = targetMostDetailedMip; + this.targetFirstSlice = targetFirstSlice; + this.targetPlaneSlice = targetPlaneSlice; + } readonly source: Uint8Array; target: string; mipLevels: number; @@ -481,6 +562,23 @@ export class MovePair { this.targetFirstSlice = targetFirstSlice; this.targetPlaneSlice = targetPlaneSlice; } + reset ( + source = '', + target = '', + mipLevels = 0xFFFFFFFF, + numSlices = 0xFFFFFFFF, + targetMostDetailedMip = 0, + targetFirstSlice = 0, + targetPlaneSlice = 0, + ): void { + this.source = source; + this.target = target; + this.mipLevels = mipLevels; + this.numSlices = numSlices; + this.targetMostDetailedMip = targetMostDetailedMip; + this.targetFirstSlice = targetFirstSlice; + this.targetPlaneSlice = targetPlaneSlice; + } source: string; target: string; mipLevels: number; @@ -491,6 +589,19 @@ export class MovePair { } export class PipelineStatistics { + reset (): void { + this.numRenderPasses = 0; + this.numManagedTextures = 0; + this.totalManagedTextures = 0; + this.numUploadBuffers = 0; + this.numUploadBufferViews = 0; + this.numFreeUploadBuffers = 0; + this.numFreeUploadBufferViews = 0; + this.numDescriptorSets = 0; + this.numFreeDescriptorSets = 0; + this.numInstancingBuffers = 0; + this.numInstancingUniformBlocks = 0; + } numRenderPasses = 0; numManagedTextures = 0; totalManagedTextures = 0; @@ -504,14 +615,175 @@ export class PipelineStatistics { numInstancingUniformBlocks = 0; } +export class RenderCommonObjectPoolSettings { + constructor (batchSize: number) { + this.lightInfoBatchSize = batchSize; + this.descriptorBatchSize = batchSize; + this.descriptorBlockBatchSize = batchSize; + this.descriptorBlockFlattenedBatchSize = batchSize; + this.descriptorBlockIndexBatchSize = batchSize; + this.resolvePairBatchSize = batchSize; + this.copyPairBatchSize = batchSize; + this.uploadPairBatchSize = batchSize; + this.movePairBatchSize = batchSize; + this.pipelineStatisticsBatchSize = batchSize; + } + lightInfoBatchSize = 16; + descriptorBatchSize = 16; + descriptorBlockBatchSize = 16; + descriptorBlockFlattenedBatchSize = 16; + descriptorBlockIndexBatchSize = 16; + resolvePairBatchSize = 16; + copyPairBatchSize = 16; + uploadPairBatchSize = 16; + movePairBatchSize = 16; + pipelineStatisticsBatchSize = 16; +} + +export class RenderCommonObjectPool { + constructor (settings: RenderCommonObjectPoolSettings) { + this._lightInfo = new RecyclePool(() => new LightInfo(), settings.lightInfoBatchSize); + this._descriptor = new RecyclePool(() => new Descriptor(), settings.descriptorBatchSize); + this._descriptorBlock = new RecyclePool(() => new DescriptorBlock(), settings.descriptorBlockBatchSize); + this._descriptorBlockFlattened = new RecyclePool(() => new DescriptorBlockFlattened(), settings.descriptorBlockFlattenedBatchSize); + this._descriptorBlockIndex = new RecyclePool(() => new DescriptorBlockIndex(), settings.descriptorBlockIndexBatchSize); + this._resolvePair = new RecyclePool(() => new ResolvePair(), settings.resolvePairBatchSize); + this._copyPair = new RecyclePool(() => new CopyPair(), settings.copyPairBatchSize); + this._uploadPair = new RecyclePool(() => new UploadPair(), settings.uploadPairBatchSize); + this._movePair = new RecyclePool(() => new MovePair(), settings.movePairBatchSize); + this._pipelineStatistics = new RecyclePool(() => new PipelineStatistics(), settings.pipelineStatisticsBatchSize); + } + reset (): void { + this._lightInfo.reset(); + this._descriptor.reset(); + this._descriptorBlock.reset(); + this._descriptorBlockFlattened.reset(); + this._descriptorBlockIndex.reset(); + this._resolvePair.reset(); + this._copyPair.reset(); + this._uploadPair.reset(); + this._movePair.reset(); + this._pipelineStatistics.reset(); + } + createLightInfo ( + light: Light | null = null, + level = 0, + culledByLight = false, + probe: ReflectionProbe | null = null, + ): LightInfo { + const v = this._lightInfo.add(); + v.reset(light, level, culledByLight, probe); + return v; + } + createDescriptor ( + type: Type = Type.UNKNOWN, + ): Descriptor { + const v = this._descriptor.add(); + v.reset(type); + return v; + } + createDescriptorBlock (): DescriptorBlock { + const v = this._descriptorBlock.add(); + v.reset(); + return v; + } + createDescriptorBlockFlattened (): DescriptorBlockFlattened { + const v = this._descriptorBlockFlattened.add(); + v.reset(); + return v; + } + createDescriptorBlockIndex ( + updateFrequency: UpdateFrequency = UpdateFrequency.PER_INSTANCE, + parameterType: ParameterType = ParameterType.CONSTANTS, + descriptorType: DescriptorTypeOrder = DescriptorTypeOrder.UNIFORM_BUFFER, + visibility: ShaderStageFlagBit = ShaderStageFlagBit.NONE, + ): DescriptorBlockIndex { + const v = this._descriptorBlockIndex.add(); + v.updateFrequency = updateFrequency; + v.parameterType = parameterType; + v.descriptorType = descriptorType; + v.visibility = visibility; + return v; + } + createResolvePair ( + source = '', + target = '', + resolveFlags: ResolveFlags = ResolveFlags.NONE, + mode: ResolveMode = ResolveMode.SAMPLE_ZERO, + mode1: ResolveMode = ResolveMode.SAMPLE_ZERO, + ): ResolvePair { + const v = this._resolvePair.add(); + v.reset(source, target, resolveFlags, mode, mode1); + return v; + } + createCopyPair ( + source = '', + target = '', + mipLevels = 0xFFFFFFFF, + numSlices = 0xFFFFFFFF, + sourceMostDetailedMip = 0, + sourceFirstSlice = 0, + sourcePlaneSlice = 0, + targetMostDetailedMip = 0, + targetFirstSlice = 0, + targetPlaneSlice = 0, + ): CopyPair { + const v = this._copyPair.add(); + v.reset(source, target, mipLevels, numSlices, sourceMostDetailedMip, sourceFirstSlice, sourcePlaneSlice, targetMostDetailedMip, targetFirstSlice, targetPlaneSlice); + return v; + } + createUploadPair ( + target = '', + mipLevels = 0xFFFFFFFF, + numSlices = 0xFFFFFFFF, + targetMostDetailedMip = 0, + targetFirstSlice = 0, + targetPlaneSlice = 0, + ): UploadPair { + const v = this._uploadPair.add(); + v.reset(target, mipLevels, numSlices, targetMostDetailedMip, targetFirstSlice, targetPlaneSlice); + return v; + } + createMovePair ( + source = '', + target = '', + mipLevels = 0xFFFFFFFF, + numSlices = 0xFFFFFFFF, + targetMostDetailedMip = 0, + targetFirstSlice = 0, + targetPlaneSlice = 0, + ): MovePair { + const v = this._movePair.add(); + v.reset(source, target, mipLevels, numSlices, targetMostDetailedMip, targetFirstSlice, targetPlaneSlice); + return v; + } + createPipelineStatistics (): PipelineStatistics { + const v = this._pipelineStatistics.add(); + v.reset(); + return v; + } + private readonly _lightInfo: RecyclePool; + private readonly _descriptor: RecyclePool; + private readonly _descriptorBlock: RecyclePool; + private readonly _descriptorBlockFlattened: RecyclePool; + private readonly _descriptorBlockIndex: RecyclePool; + private readonly _resolvePair: RecyclePool; + private readonly _copyPair: RecyclePool; + private readonly _uploadPair: RecyclePool; + private readonly _movePair: RecyclePool; + private readonly _pipelineStatistics: RecyclePool; +} + export function saveLightInfo (ar: OutputArchive, v: LightInfo): void { // skip, v.light: Light + // skip, v.probe: ReflectionProbe ar.writeNumber(v.level); ar.writeBool(v.culledByLight); } export function loadLightInfo (ar: InputArchive, v: LightInfo): void { // skip, v.light: Light + // skip, v.probe: ReflectionProbe v.level = ar.readNumber(); v.culledByLight = ar.readBool(); } diff --git a/cocos/rendering/custom/utils.ts b/cocos/rendering/custom/utils.ts index 92e985d9731..7654640d022 100644 --- a/cocos/rendering/custom/utils.ts +++ b/cocos/rendering/custom/utils.ts @@ -118,3 +118,33 @@ export function getUBOTypeCount (type: Type): number { return 0; } } + +export class ObjectPool { + // Array to store objects in the pool + private pool: T[] = []; + // Function to create new objects + private createFunction: (...args: U) => T; + + // Constructor, takes a function to create objects as parameter + constructor (createFunction: (...args: U) => T) { + this.createFunction = createFunction; + } + // Get object from the pool, either take from the pool if available or create a new one + acquire (...args: U): T { + if (this.pool.length > 0) { + return this.pool.pop()!; + } + return this.createFunction(...args); + } + // Put the object back into the pool for later reuse + release (obj: T): void { + // Push the object to the end of the pool + if (!this.pool.includes(obj)) { + this.pool.push(obj); + } + } + + create (...args: U): T { + return this.createFunction(...args); + } +} diff --git a/cocos/rendering/custom/web-pipeline-types.ts b/cocos/rendering/custom/web-pipeline-types.ts index c41128cefd4..52b3ecccb7a 100644 --- a/cocos/rendering/custom/web-pipeline-types.ts +++ b/cocos/rendering/custom/web-pipeline-types.ts @@ -1,6 +1,7 @@ +import { RecyclePool, cclegacy } from '../../core'; import { CommandBuffer, DescriptorSet, Device, PipelineState, RenderPass, deviceManager } from '../../gfx'; -import { RenderScene } from '../../render-scene'; -import { Camera, Light, LightType, Model, SubModel } from '../../render-scene/scene'; +import { IMacroPatch } from '../../render-scene'; +import { LightType, Model, SubModel } from '../../render-scene/scene'; import { SetIndex } from '../define'; import { InstancedBuffer } from '../instanced-buffer'; import { PipelineStateManager } from '../pipeline-state-manager'; @@ -29,6 +30,90 @@ export class DrawInstance { this.shaderID = shaderID; this.passIndex = passIndex; } + update ( + subModel: SubModel | null = null, + priority = 0, + hash = 0, + depth = 0, + shaderID = 0, + passIndex = 0, + ): void { + this.subModel = subModel; + this.priority = priority; + this.hash = hash; + this.depth = depth; + this.shaderID = shaderID; + this.passIndex = passIndex; + } +} + +export const instancePool = new RecyclePool(() => new DrawInstance(), 8); + +const CC_USE_RGBE_OUTPUT = 'CC_USE_RGBE_OUTPUT'; +function getLayoutId (passLayout: string, phaseLayout: string): number { + const r = cclegacy.rendering; + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return r.getPhaseID(r.getPassID(passLayout), phaseLayout); +} +function getPassIndexFromLayout (subModel: SubModel, phaseLayoutId: number): number { + const passes = subModel.passes; + for (let k = 0; k < passes.length; k++) { + if ((passes[k].phaseID === phaseLayoutId)) { + return k; + } + } + return -1; +} + +export class ProbeHelperQueue { + probeMap: Array = new Array(); + defaultId: number = getLayoutId('default', 'default'); + removeMacro (): void { + for (const subModel of this.probeMap) { + let patches: IMacroPatch[] = []; + patches = patches.concat(subModel.patches!); + if (!patches.length) continue; + for (let j = 0; j < patches.length; j++) { + const patch = patches[j]; + if (patch.name === CC_USE_RGBE_OUTPUT) { + patches.splice(j, 1); + break; + } + } + subModel.onMacroPatchesStateChanged(patches); + } + } + applyMacro (model: Model, probeLayoutId: number): void { + const subModels = model.subModels; + for (let j = 0; j < subModels.length; j++) { + const subModel: SubModel = subModels[j]; + + //Filter transparent objects + const isTransparent = subModel.passes[0].blendState.targets[0].blend; + if (isTransparent) { + continue; + } + + let passIdx = getPassIndexFromLayout(subModel, probeLayoutId); + let bUseReflectPass = true; + if (passIdx < 0) { + probeLayoutId = this.defaultId; + passIdx = getPassIndexFromLayout(subModel, probeLayoutId); + bUseReflectPass = false; + } + if (passIdx < 0) { continue; } + if (!bUseReflectPass) { + let patches: IMacroPatch[] = []; + patches = patches.concat(subModel.patches!); + const useRGBEPatchs: IMacroPatch[] = [ + { name: CC_USE_RGBE_OUTPUT, value: true }, + ]; + patches = patches.concat(useRGBEPatchs); + subModel.onMacroPatchesStateChanged(patches); + this.probeMap.push(subModel); + } + } + } } export class RenderDrawQueue { @@ -42,8 +127,9 @@ export class RenderDrawQueue { const shaderId = subModel.shaders[passIdx].typedID; const hash = (0 << 30) | (passPriority as number << 16) | (modelPriority as number << 8) | passIdx; const priority = model.priority; - - this.instances.push(new DrawInstance(subModel, priority, hash, depth, shaderId, passIdx)); + const instance = instancePool.add(); + instance.update(subModel, priority, hash, depth, shaderId, passIdx); + this.instances.push(instance); } /** * @en Comparison sorting function. Opaque objects are sorted by priority -> depth front to back -> shader ID. @@ -186,9 +272,19 @@ export class RenderQueueDesc { this.renderQueueTarget = renderQueueTargetIn; this.lightType = lightTypeIn; } + update ( + culledSourceIn = 0xFFFFFFFF, + renderQueueTargetIn = 0xFFFFFFFF, + lightTypeIn: LightType = LightType.UNKNOWN, + ): void { + this.culledSource = culledSourceIn; + this.renderQueueTarget = renderQueueTargetIn; + this.lightType = lightTypeIn; + } } export class RenderQueue { + probeQueue: ProbeHelperQueue = new ProbeHelperQueue(); opaqueQueue: RenderDrawQueue = new RenderDrawQueue(); transparentQueue: RenderDrawQueue = new RenderDrawQueue(); opaqueInstancingQueue: RenderInstancingQueue = new RenderInstancingQueue(); @@ -212,7 +308,8 @@ export class RenderQueue { instances.clear(); } - clear (): void { + update (): void { + this.probeQueue.probeMap.length = 0; this.opaqueQueue.instances.length = 0; this.transparentQueue.instances.length = 0; this._clearInstances(this.opaqueInstancingQueue.batches); diff --git a/cocos/rendering/custom/web-pipeline.ts b/cocos/rendering/custom/web-pipeline.ts index 316e90a2431..9c26269b844 100644 --- a/cocos/rendering/custom/web-pipeline.ts +++ b/cocos/rendering/custom/web-pipeline.ts @@ -24,21 +24,21 @@ /* eslint-disable max-len */ import { systemInfo } from 'pal/system-info'; -import { DEBUG } from 'internal:constants'; -import { Buffer, DescriptorSetLayout, Device, Feature, Format, FormatFeatureBit, Sampler, Swapchain, Texture, ClearFlagBit, DescriptorSet, deviceManager, Viewport, API, CommandBuffer, Type, SamplerInfo, Filter, Address, DescriptorSetInfo, LoadOp, StoreOp, ShaderStageFlagBit, BufferInfo, TextureInfo, TextureType, UniformBlock, ResolveMode, SampleCount, Color } from '../../gfx'; -import { Mat4, Quat, toRadian, Vec2, Vec3, Vec4, assert, macro, cclegacy, IVec4Like, IMat4Like, IVec2Like, Color as CoreColor } from '../../core'; -import { AccessType, AttachmentType, CopyPair, LightInfo, LightingMode, MovePair, QueueHint, ResolvePair, ResourceDimension, ResourceFlags, ResourceResidency, SceneFlags, UpdateFrequency } from './types'; -import { ComputeView, RasterView, Blit, ClearView, ComputePass, CopyPass, Dispatch, ManagedBuffer, ManagedResource, MovePass, RasterPass, RasterSubpass, RenderData, RenderGraph, RenderGraphComponent, RenderGraphValue, RenderQueue, RenderSwapchain, ResourceDesc, ResourceGraph, ResourceGraphValue, ResourceStates, ResourceTraits, SceneData, Subpass } from './render-graph'; -import { ComputePassBuilder, ComputeQueueBuilder, ComputeSubpassBuilder, BasicPipeline, PipelineBuilder, RenderPassBuilder, RenderQueueBuilder, RenderSubpassBuilder, PipelineType, BasicRenderPassBuilder, PipelineCapabilities, BasicMultisampleRenderPassBuilder } from './pipeline'; +import { DEBUG, EDITOR } from 'internal:constants'; +import { Buffer, DescriptorSetLayout, Device, Feature, Format, FormatFeatureBit, Sampler, Swapchain, Texture, ClearFlagBit, DescriptorSet, deviceManager, Viewport, API, CommandBuffer, Type, SamplerInfo, Filter, Address, DescriptorSetInfo, LoadOp, StoreOp, ShaderStageFlagBit, BufferInfo, TextureInfo, TextureType, UniformBlock, ResolveMode, SampleCount, Color, ComparisonFunc } from '../../gfx'; +import { Mat4, Quat, toRadian, Vec2, Vec3, Vec4, assert, macro, cclegacy, IVec4Like, IMat4Like, IVec2Like, Color as CoreColor, RecyclePool } from '../../core'; +import { AccessType, AttachmentType, CopyPair, LightInfo, LightingMode, MovePair, QueueHint, RenderCommonObjectPool, RenderCommonObjectPoolSettings, ResolvePair, ResourceDimension, ResourceFlags, ResourceResidency, SceneFlags, UpdateFrequency, UploadPair } from './types'; +import { ComputePass, CopyPass, MovePass, RasterPass, RasterSubpass, RenderData, RenderGraph, RenderGraphComponent, RenderGraphValue, RenderQueue, RenderSwapchain, ResourceDesc, ResourceGraph, ResourceGraphValue, ResourceStates, ResourceTraits, SceneData, Subpass, PersistentBuffer, RenderGraphObjectPool, RenderGraphObjectPoolSettings, CullingFlags, ManagedResource, ManagedBuffer } from './render-graph'; +import { ComputePassBuilder, ComputeQueueBuilder, BasicPipeline, PipelineBuilder, RenderQueueBuilder, RenderSubpassBuilder, PipelineType, BasicRenderPassBuilder, PipelineCapabilities, BasicMultisampleRenderPassBuilder, Setter, SceneBuilder } from './pipeline'; import { PipelineSceneData } from '../pipeline-scene-data'; -import { Model, Camera, ShadowType, CSMLevel, DirectionalLight, SpotLight, PCFType, Shadows, SphereLight, PointLight, RangedDirectionalLight } from '../../render-scene/scene'; +import { Model, Camera, ShadowType, CSMLevel, DirectionalLight, SpotLight, PCFType, Shadows, SphereLight, PointLight, RangedDirectionalLight, ProbeType } from '../../render-scene/scene'; import { Light, LightType } from '../../render-scene/scene/light'; import { DescriptorSetData, DescriptorSetLayoutData, LayoutGraphData } from './layout-graph'; import { Executor } from './executor'; import { RenderWindow } from '../../render-scene/core/render-window'; import { MacroRecord, RenderScene } from '../../render-scene'; import { GlobalDSManager } from '../global-descriptor-set-manager'; -import { isEnableEffect, supportsR32FloatTexture, supportsRGBA16HalfFloatTexture, UBOSkinning } from '../define'; +import { supportsR32FloatTexture, supportsRGBA16HalfFloatTexture, UBOSkinning } from '../define'; import { OS } from '../../../pal/system-info/enum-type'; import { Compiler } from './compiler'; import { PipelineUBO } from '../pipeline-ubo'; @@ -51,12 +51,14 @@ import { CustomPipelineBuilder } from './custom-pipeline'; import { decideProfilerCamera } from '../pipeline-funcs'; import { DebugViewCompositeType } from '../debug-view'; import { getUBOTypeCount } from './utils'; -import { initGlobalDescBinding } from './define'; +import { buildReflectionProbePass, initGlobalDescBinding } from './define'; import { createGfxDescriptorSetsAndPipelines } from './layout-graph-utils'; import { Root } from '../../root'; import { CSMLayers, CSMShadowLayer } from '../shadow/csm-layers'; import { Scene } from '../../scene-graph'; import { Director } from '../../game'; +import { ReflectionProbeManager } from '../../3d'; +import { legacyCC } from '../../core/global-exports'; const _uboVec = new Vec4(); const _uboVec3 = new Vec3(); @@ -72,12 +74,94 @@ const _samplerPointInfo = new SamplerInfo( Address.CLAMP, Address.CLAMP, ); -export class WebSetter { + +const renderCommonObjectSetting = new RenderCommonObjectPoolSettings(16); +const renderGraphPoolSetting: RenderGraphObjectPoolSettings = new RenderGraphObjectPoolSettings(16); +class PipelinePool { + renderData = new RenderData(); + layoutGraph = new LayoutGraphData(); + rg = new RenderGraph(); + vertId = -1; + sceneData = new SceneData(); + resourceGraph = new ResourceGraph(); + computePass = new ComputePass(); + rasterPass = new RasterPass(); + rasterSubpass = new RasterSubpass(); + renderQueue = new RenderQueue(); + sceneBuilder = new RecyclePool(() => new WebSceneBuilder(this.renderData, this.layoutGraph, this.rg, this.vertId, this.sceneData), 16); + renderPassBuilder = new RecyclePool(() => new WebRenderPassBuilder(this.renderData, this.rg, this.layoutGraph, this.resourceGraph, this.vertId, this.rasterPass, this.getPipelineSceneData()), 16); + computeQueueBuilder = new RecyclePool(() => new WebComputeQueueBuilder(this.renderData, this.rg, this.layoutGraph, this.vertId, this.renderQueue, this.getPipelineSceneData()), 16); + renderQueueBuilder = new RecyclePool(() => new WebRenderQueueBuilder(this.renderData, this.rg, this.layoutGraph, this.vertId, this.renderQueue, this.getPipelineSceneData()), 16); + renderSubpassBuilder = new RecyclePool(() => new WebRenderSubpassBuilder(this.renderData, this.rg, this.layoutGraph, this.vertId, this.rasterSubpass, this.getPipelineSceneData()), 16); + computePassBuilder = new RecyclePool(() => new WebComputePassBuilder(this.renderData, this.rg, this.layoutGraph, this.resourceGraph, this.vertId, this.computePass, this.getPipelineSceneData()), 16); + samplerInfo = new RecyclePool(() => new SamplerInfo(), 16); + color = new RecyclePool(() => new Color(), 16); + renderCommonObjectPool = new RenderCommonObjectPool(renderCommonObjectSetting); + renderGraphPool = new RenderGraphObjectPool(renderGraphPoolSetting, this.renderCommonObjectPool); + viewport = new RecyclePool(() => new Viewport(), 16); + + getPipelineSceneData (): PipelineSceneData { + return (legacyCC.director.root as Root).pipeline.pipelineSceneData; + } + + createColor ( + x: number = 0, + y: number = 0, + z: number = 0, + w: number = 0, + ): Color { + const color = this.color.add(); + color.set(x, y, z, w); + return color; + } + createSamplerInfo ( + minFilter: Filter = Filter.LINEAR, + magFilter: Filter = Filter.LINEAR, + mipFilter: Filter = Filter.NONE, + addressU: Address = Address.WRAP, + addressV: Address = Address.WRAP, + addressW: Address = Address.WRAP, + maxAnisotropy: number = 0, + cmpFunc: ComparisonFunc = ComparisonFunc.ALWAYS, + ): SamplerInfo { + const samplerInfo = this.samplerInfo.add(); + samplerInfo.minFilter = minFilter; + samplerInfo.magFilter = magFilter; + samplerInfo.mipFilter = mipFilter; + samplerInfo.addressU = addressU; + samplerInfo.addressV = addressV; + samplerInfo.addressW = addressW; + samplerInfo.maxAnisotropy = maxAnisotropy; + samplerInfo.cmpFunc = cmpFunc; + return samplerInfo; + } + reset (): void { + this.sceneBuilder.reset(); + this.renderPassBuilder.reset(); + this.computePassBuilder.reset(); + this.computeQueueBuilder.reset(); + this.renderCommonObjectPool.reset(); + this.renderGraphPool.reset(); + this.viewport.reset(); + this.samplerInfo.reset(); + this.color.reset(); + this.renderQueueBuilder.reset(); + this.renderSubpassBuilder.reset(); + } +} +let pipelinePool: PipelinePool; +let renderGraphPool: RenderGraphObjectPool; +export class WebSetter implements Setter { constructor (data: RenderData, lg: LayoutGraphData) { this._data = data; this._lg = lg; } - + get name (): string { + return ''; + } + set name (name: string) { + // noop + } protected _copyToBuffer (target: IVec4Like | Quat | IVec2Like | IMat4Like | number, offset: number, type: Type): void { assert(offset !== -1); const arr = this.getCurrConstant(); @@ -137,10 +221,10 @@ export class WebSetter { } protected _getCurrUniformBlock (): UniformBlock | undefined { - const block: string = this._currBlock; + const block: string = this._currBlock; const nodeId = this._lg.locateChild(0xFFFFFFFF, this._currStage); const ppl = this._lg.getLayout(nodeId); - const layout = ppl.descriptorSets.get(UpdateFrequency.PER_PASS)!.descriptorSetLayoutData; + const layout = ppl.descriptorSets.get(this._currFrequency)!.descriptorSetLayoutData; const nameID: number = this._lg.attributeIndex.get(block)!; return layout.uniformBlocks.get(nameID); } @@ -148,7 +232,7 @@ export class WebSetter { protected _getCurrDescSetLayoutData (): DescriptorSetLayoutData { const nodeId = this._lg.locateChild(0xFFFFFFFF, this._currStage); const ppl = this._lg.getLayout(nodeId); - const layout = ppl.descriptorSets.get(UpdateFrequency.PER_PASS)!.descriptorSetLayoutData; + const layout = ppl.descriptorSets.get(this._currFrequency)!.descriptorSetLayoutData; return layout; } @@ -165,9 +249,10 @@ export class WebSetter { return -1; } - setCurrConstant (block: string, stage = 'default'): boolean { + setCurrConstant (block: string, stage = 'default', frequency: UpdateFrequency = UpdateFrequency.PER_PASS): boolean { this._currBlock = block; this._currStage = stage; + this._currFrequency = frequency; const nameID: number = this._lg.attributeIndex.get(block)!; this._currCount = 0; const currBlock = this._getCurrUniformBlock(); @@ -183,9 +268,10 @@ export class WebSetter { return this._currConstant; } - public addConstant (block: string, stage = 'default'): boolean { + public addConstant (block: string, stage = 'default', frequency: UpdateFrequency = UpdateFrequency.PER_PASS): boolean { this._currBlock = block; this._currStage = stage; + this._currFrequency = frequency; const num = this._lg.attributeIndex.get(block)!; this._currCount = 0; const currBlock = this._getCurrUniformBlock(); @@ -198,7 +284,7 @@ export class WebSetter { value.fill(0); this._data.constants.set(num, value); } - this.setCurrConstant(block); + this.setCurrConstant(block, stage); return true; } public setMat4 (name: string, mat: Mat4, idx = 0): void { @@ -234,6 +320,9 @@ export class WebSetter { public setFloat (name: string, v: number, idx = 0): void { this._applyCurrConstantBuffer(name, v, Type.FLOAT, idx); } + public setArrayBuffer (name: string, arrayBuffer: ArrayBuffer): void { + throw new Error('Method not implemented.'); + } public offsetFloat (v: number, offset: number): void { this._copyToBuffer(v, offset, Type.FLOAT); } @@ -260,32 +349,195 @@ export class WebSetter { const num = this._lg.attributeIndex.get(name)!; this._data.samplers.set(num, sampler); } + + public getParentLayout (): string { + const director = cclegacy.director; + const root = director.root; + const pipeline = root.pipeline as WebPipeline; + const parId = pipeline.renderGraph!.getParent(this._vertID); + const layoutName = pipeline.renderGraph!.getLayout(parId); + return layoutName; + } + + public getCurrentLayout (): string { + const director = cclegacy.director; + const root = director.root; + const pipeline = root.pipeline as WebPipeline; + const layoutName = pipeline.renderGraph!.getLayout(this._vertID); + return layoutName; + } + public setBuiltinCameraConstants (camera: Camera): void { - // TODO + const director = cclegacy.director; + const root = director.root; + const pipeline = root.pipeline as WebPipeline; + const layoutName = this.getParentLayout(); + setCameraUBOValues(this, camera, pipeline.pipelineSceneData, camera.scene, layoutName); } public setBuiltinShadowMapConstants (light: Light, numLevels?: number): void { - // TODO + setShadowUBOView(this, null, this.getParentLayout()); } - public setBuiltinDirectionalLightViewConstants (light: DirectionalLight): void { - // TODO + public setBuiltinDirectionalLightFrustumConstants (camera: Camera, light: DirectionalLight, csmLevel = 0): void { + setShadowUBOLightView(this, camera, light, csmLevel); } - public setBuiltinSpotLightViewConstants (light: SpotLight): void { - // TODO + public setBuiltinSpotLightFrustumConstants (light: SpotLight): void { + setShadowUBOLightView(this, null, light, 0); } public setBuiltinDirectionalLightConstants (light: DirectionalLight, camera: Camera): void { // TODO } public setBuiltinSphereLightConstants (light: SphereLight, camera: Camera): void { - // TODO + const director = cclegacy.director; + const pipeline = (director.root as Root).pipeline; + const sceneData = pipeline.pipelineSceneData; + if (!this.addConstant('CCForwardLight', this.getParentLayout(), UpdateFrequency.PER_BATCH)) return; + uniformOffset = this.getUniformOffset('cc_lightPos', Type.FLOAT4); + if (this.hasUniform(uniformOffset)) { + _uboVec.set(light.position.x, light.position.y, light.position.z, LightType.SPHERE); + this.offsetVec4(_uboVec, uniformOffset); + } + uniformOffset = this.getUniformOffset('cc_lightSizeRangeAngle', Type.FLOAT4); + if (this.hasUniform(uniformOffset)) { + _uboVec.set(light.size, light.range, 0.0, 0.0); + this.offsetVec4(_uboVec, uniformOffset); + } + const isHDR = sceneData.isHDR; + const lightMeterScale = 10000.0; + uniformOffset = this.getUniformOffset('cc_lightColor', Type.FLOAT4); + if (this.hasUniform(uniformOffset)) { + _uboVec.set(light.color.x, light.color.y, light.color.z, 0); + if (light.useColorTemperature) { + const finalColor = light.finalColor; + _uboVec.x = finalColor.x; + _uboVec.y = finalColor.y; + _uboVec.z = finalColor.z; + } + if (isHDR) { + _uboVec.w = (light).luminance * camera.exposure * lightMeterScale; + } else { + _uboVec.w = (light).luminance; + } + this.offsetVec4(_uboVec, uniformOffset); + } } public setBuiltinSpotLightConstants (light: SpotLight, camera: Camera): void { - // TODO + const director = cclegacy.director; + const pipeline = (director.root as Root).pipeline; + const sceneData = pipeline.pipelineSceneData; + + const shadowInfo = sceneData.shadows; + if (!this.addConstant('CCForwardLight', this.getParentLayout(), UpdateFrequency.PER_BATCH)) return; + uniformOffset = this.getUniformOffset('cc_lightPos', Type.FLOAT4); + if (this.hasUniform(uniformOffset)) { + _uboVec.set(light.position.x, light.position.y, light.position.z, LightType.SPOT); + this.offsetVec4(_uboVec, uniformOffset); + } + uniformOffset = this.getUniformOffset('cc_lightSizeRangeAngle', Type.FLOAT4); + if (this.hasUniform(uniformOffset)) { + _uboVec.set(light.size, light.range, light.spotAngle, (shadowInfo.enabled && light.shadowEnabled && shadowInfo.type === ShadowType.ShadowMap) ? 1 : 0); + this.offsetVec4(_uboVec, uniformOffset); + } + uniformOffset = this.getUniformOffset('cc_lightDir', Type.FLOAT4); + if (this.hasUniform(uniformOffset)) { + _uboVec.set(light.direction.x, light.direction.y, light.direction.z, 0); + this.offsetVec4(_uboVec, uniformOffset); + } + const isHDR = sceneData.isHDR; + const lightMeterScale = 10000.0; + uniformOffset = this.getUniformOffset('cc_lightColor', Type.FLOAT4); + if (this.hasUniform(uniformOffset)) { + _uboVec.set(light.color.x, light.color.y, light.color.z, 0); + if (light.useColorTemperature) { + const finalColor = light.finalColor; + _uboVec.x = finalColor.x; + _uboVec.y = finalColor.y; + _uboVec.z = finalColor.z; + } + if (isHDR) { + _uboVec.w = (light).luminance * camera.exposure * lightMeterScale; + } else { + _uboVec.w = (light).luminance; + } + this.offsetVec4(_uboVec, uniformOffset); + } } public setBuiltinPointLightConstants (light: PointLight, camera: Camera): void { - // TODO + const director = cclegacy.director; + const pipeline = (director.root as Root).pipeline; + const sceneData = pipeline.pipelineSceneData; + if (!this.addConstant('CCForwardLight', this.getParentLayout(), UpdateFrequency.PER_BATCH)) return; + uniformOffset = this.getUniformOffset('cc_lightPos', Type.FLOAT4); + if (this.hasUniform(uniformOffset)) { + _uboVec.set(light.position.x, light.position.y, light.position.z, LightType.POINT); + this.offsetVec4(_uboVec, uniformOffset); + } + uniformOffset = this.getUniformOffset('cc_lightSizeRangeAngle', Type.FLOAT4); + if (this.hasUniform(uniformOffset)) { + _uboVec.set(0.0, light.range, 0.0, 0.0); + this.offsetVec4(_uboVec, uniformOffset); + } + const isHDR = sceneData.isHDR; + const lightMeterScale = 10000.0; + uniformOffset = this.getUniformOffset('cc_lightColor', Type.FLOAT4); + if (this.hasUniform(uniformOffset)) { + _uboVec.set(light.color.x, light.color.y, light.color.z, 0); + if (light.useColorTemperature) { + const finalColor = light.finalColor; + _uboVec.x = finalColor.x; + _uboVec.y = finalColor.y; + _uboVec.z = finalColor.z; + } + if (isHDR) { + _uboVec.w = (light).luminance * camera.exposure * lightMeterScale; + } else { + _uboVec.w = (light).luminance; + } + this.offsetVec4(_uboVec, uniformOffset); + } } public setBuiltinRangedDirectionalLightConstants (light: RangedDirectionalLight, camera: Camera): void { - // TODO + const director = cclegacy.director; + const pipeline = (director.root as Root).pipeline; + const sceneData = pipeline.pipelineSceneData; + if (!this.addConstant('CCForwardLight', this.getParentLayout(), UpdateFrequency.PER_BATCH)) return; + uniformOffset = this.getUniformOffset('cc_lightPos', Type.FLOAT4); + if (this.hasUniform(uniformOffset)) { + _uboVec.set(light.position.x, light.position.y, light.position.z, LightType.RANGED_DIRECTIONAL); + this.offsetVec4(_uboVec, uniformOffset); + } + uniformOffset = this.getUniformOffset('cc_lightSizeRangeAngle', Type.FLOAT4); + if (this.hasUniform(uniformOffset)) { + _uboVec.set(light.right.x, light.right.y, light.right.z, 0.0); + this.offsetVec4(_uboVec, uniformOffset); + } + uniformOffset = this.getUniformOffset('cc_lightDir', Type.FLOAT4); + if (this.hasUniform(uniformOffset)) { + _uboVec.set(light.direction.x, light.direction.y, light.direction.z, 0); + this.offsetVec4(_uboVec, uniformOffset); + } + uniformOffset = this.getUniformOffset('cc_lightBoundingSizeVS', Type.FLOAT4); + if (this.hasUniform(uniformOffset)) { + const scale = light.scale; + _uboVec.set(scale.x * 0.5, scale.y * 0.5, scale.z * 0.5, 0); + this.offsetVec4(_uboVec, uniformOffset); + } + const isHDR = sceneData.isHDR; + uniformOffset = this.getUniformOffset('cc_lightColor', Type.FLOAT4); + if (this.hasUniform(uniformOffset)) { + _uboVec.set(light.color.x, light.color.y, light.color.z, 0); + if (light.useColorTemperature) { + const finalColor = light.finalColor; + _uboVec.x = finalColor.x; + _uboVec.y = finalColor.y; + _uboVec.z = finalColor.z; + } + if (isHDR) { + _uboVec.w = light.illuminance * camera.exposure; + } else { + _uboVec.w = light.illuminance; + } + this.offsetVec4(_uboVec, uniformOffset); + } } public hasSampler (name: string): boolean { const id = this._lg.attributeIndex.get(name); @@ -306,19 +558,21 @@ export class WebSetter { } // protected - protected _data: RenderData; + protected _data: RenderData; protected _lg: LayoutGraphData; + protected _vertID: number = -1; protected _currBlock; protected _currStage: string = ''; + protected _currFrequency: UpdateFrequency = UpdateFrequency.PER_PASS; protected _currCount; protected _currConstant: number[] = []; } function setShadowUBOLightView ( setter: WebSetter, - camera: Camera, + camera: Camera | null, light: Light, - level: number, + csmLevel: number, layout = 'default', ): void { const director = cclegacy.director; @@ -339,8 +593,8 @@ function setShadowUBOLightView ( if (shadowInfo.enabled) { if (shadowInfo.type === ShadowType.ShadowMap) { // update CSM layers - if (light && light.node) { - csmLayers.update(sceneData, camera); + if (light && light.node && light.type === LightType.DIRECTIONAL) { + csmLayers.update(sceneData, camera!); } } } @@ -374,7 +628,7 @@ function setShadowUBOLightView ( setter.offsetVec4(_uboVec, uniformOffset); } } else { - const layer = csmLayers.layers[level]; + const layer = csmLayers.layers[csmLevel]; matShadowView = layer.matShadowView; matShadowProj = layer.matShadowProj; matShadowViewProj = layer.matShadowViewProj; @@ -632,6 +886,13 @@ function setShadowUBOView (setter: WebSetter, camera: Camera | null, layout = 'd } } +function setComputeConstants (setter: WebSetter, layoutName: string): void { + const director = cclegacy.director; + const root = director.root; + const pipeline = root.pipeline as WebPipeline; + setter.addConstant('CCConst', layoutName); +} + function setCameraUBOValues ( setter: WebSetter, camera: Readonly | null, @@ -815,7 +1076,7 @@ function setTextureUBOView (setter: WebSetter, camera: Camera | null, cfg: Reado setter.setSampler('cc_spotShadowMap', pipeline.defaultSampler); } if (!setter.hasTexture('cc_spotShadowMap')) { - setter.setTexture('cc_spotShadowMap', pipeline.defaultTexture); + setter.setTexture('cc_spotShadowMap', pipeline.defaultTexture); } } @@ -863,7 +1124,53 @@ function getResourceDimension (type: TextureType): ResourceDimension { return ResourceDimension.TEXTURE2D; } -export class WebRenderQueueBuilder extends WebSetter implements RenderQueueBuilder { +export class WebSceneBuilder extends WebSetter implements SceneBuilder { + constructor ( + data: RenderData, + layoutGraph: LayoutGraphData, + rg: RenderGraph, + sceneId: number, + scene: SceneData, + ) { + super(data, layoutGraph); + this._renderGraph = rg; + this._scene = scene; + this._vertID = sceneId; + } + update ( + data: RenderData, + layoutGraph: LayoutGraphData, + rg: RenderGraph, + sceneId: number, + scene: SceneData, + ): void { + this._data = data; + this._lg = layoutGraph; + this._renderGraph = rg; + this._scene = scene; + this._vertID = sceneId; + } + + useLightFrustum (light: Light, csmLevel = 0, optCamera: Camera | undefined = undefined): void { + this._scene.light.light = light; + this._scene.light.level = csmLevel; + this._scene.light.culledByLight = true; + if (optCamera) { + this._scene.camera = optCamera; + } + if (this._scene.flags & SceneFlags.NON_BUILTIN) { + return; + } + const queueId = this._renderGraph.getParent(this._vertID); + const passId = this._renderGraph.getParent(queueId); + const layoutName = this._renderGraph.getLayout(passId); + setShadowUBOLightView(this, this._scene.camera, light, csmLevel, layoutName); + } + private _renderGraph: RenderGraph; + private _scene: SceneData; +} + +export class WebRenderQueueBuilder extends WebSetter implements RenderQueueBuilder { constructor (data: RenderData, renderGraph: RenderGraph, layoutGraph: LayoutGraphData, vertID: number, queue: RenderQueue, pipeline: PipelineSceneData) { super(data, layoutGraph); this._renderGraph = renderGraph; @@ -871,6 +1178,15 @@ export class WebRenderQueueBuilder extends WebSetter implements RenderQueueBuild this._queue = queue; this._pipeline = pipeline; } + update (data: RenderData, renderGraph: RenderGraph, layoutGraph: LayoutGraphData, vertID: number, queue: RenderQueue, pipeline: PipelineSceneData): void { + this._data = data; + this._lg = layoutGraph; + this._renderGraph = renderGraph; + this._vertID = vertID; + this._queue = queue; + this._pipeline = pipeline; + } + setArrayBuffer (name: string, arrayBuffer: ArrayBuffer): void { throw new Error('Method not implemented.'); } @@ -881,16 +1197,10 @@ export class WebRenderQueueBuilder extends WebSetter implements RenderQueueBuild this._renderGraph.setName(this._vertID, name); } - getLayoutName (): string { - const parId = this._renderGraph.getParent(this._vertID); - const layoutName = isEnableEffect() ? this._renderGraph.getLayout(parId) : 'default'; - return layoutName; - } - addSceneOfCamera (camera: Camera, light: LightInfo, sceneFlags = SceneFlags.NONE, name = 'Camera'): void { - const sceneData = new SceneData(camera.scene, camera, sceneFlags, light); - this._renderGraph.addVertex(RenderGraphValue.Scene, sceneData, name, '', new RenderData(), false, this._vertID); - const layoutName = this.getLayoutName(); + const sceneData = renderGraphPool.createSceneData(camera.scene, camera, sceneFlags, CullingFlags.NONE, light.light); + this._renderGraph.addVertex(RenderGraphValue.Scene, sceneData, name, '', renderGraphPool.createRenderData(), false, this._vertID); + const layoutName = this.getParentLayout(); const scene: Scene = cclegacy.director.getScene(); setCameraUBOValues( this, @@ -907,29 +1217,41 @@ export class WebRenderQueueBuilder extends WebSetter implements RenderQueueBuild setTextureUBOView(this, camera, this._pipeline); initGlobalDescBinding(this._data, layoutName); } - addScene (camera: Camera, sceneFlags = SceneFlags.NONE): void { - const sceneData = new SceneData(camera.scene, camera, sceneFlags); - this._renderGraph.addVertex(RenderGraphValue.Scene, sceneData, 'Scene', '', new RenderData(), false, this._vertID); - } - addSceneCulledByDirectionalLight (camera: Camera, sceneFlags: SceneFlags, light: DirectionalLight, level: number): void { - const sceneData = new SceneData(camera.scene, camera, sceneFlags, new LightInfo(light, level)); - this._renderGraph.addVertex(RenderGraphValue.Scene, sceneData, 'Scene', '', new RenderData(), false, this._vertID); - } - addSceneCulledBySpotLight (camera: Camera, sceneFlags: SceneFlags, light: SpotLight): void { - const sceneData = new SceneData(camera.scene, camera, sceneFlags, new LightInfo(light, 0)); - this._renderGraph.addVertex(RenderGraphValue.Scene, sceneData, 'Scene', '', new RenderData(), false, this._vertID); + addScene (camera: Camera, sceneFlags = SceneFlags.NONE, light: Light | undefined = undefined): SceneBuilder { + const sceneData = renderGraphPool.createSceneData(camera.scene, camera, sceneFlags); + if (light) { + sceneData.light.light = light; + } + const renderData = renderGraphPool.createRenderData(); + const sceneId = this._renderGraph.addVertex(RenderGraphValue.Scene, sceneData, 'Scene', '', renderData, false, this._vertID); + if (!(sceneFlags & SceneFlags.NON_BUILTIN)) { + const layoutName = this.getParentLayout(); + setCameraUBOValues( + this, + camera, + this._pipeline, + camera.scene, + layoutName, + ); + setShadowUBOView(this, camera, layoutName); + setTextureUBOView(this, camera, this._pipeline); + initGlobalDescBinding(this._data, layoutName); + } + const sceneBuilder = pipelinePool.sceneBuilder.add(); + sceneBuilder.update(renderData, this._lg, this._renderGraph, sceneId, sceneData); + return sceneBuilder; } addFullscreenQuad (material: Material, passID: number, sceneFlags = SceneFlags.NONE, name = 'Quad'): void { this._renderGraph.addVertex( RenderGraphValue.Blit, - new Blit(material, passID, sceneFlags, null), + renderGraphPool.createBlit(material, passID, sceneFlags, null), name, '', - new RenderData(), + renderGraphPool.createRenderData(), false, this._vertID, ); - const layoutName = this.getLayoutName(); + const layoutName = this.getParentLayout(); const scene: Scene | null = cclegacy.director.getScene(); setCameraUBOValues( this, @@ -949,14 +1271,14 @@ export class WebRenderQueueBuilder extends WebSetter implements RenderQueueBuild addCameraQuad (camera: Camera, material: Material, passID: number, sceneFlags = SceneFlags.NONE): void { this._renderGraph.addVertex( RenderGraphValue.Blit, - new Blit(material, passID, sceneFlags, camera), + renderGraphPool.createBlit(material, passID, sceneFlags, camera), 'CameraQuad', '', - new RenderData(), + renderGraphPool.createRenderData(), false, this._vertID, ); - const layoutName = this.getLayoutName(); + const layoutName = this.getParentLayout(); const scene: Scene = cclegacy.director.getScene(); setCameraUBOValues( this, @@ -974,24 +1296,26 @@ export class WebRenderQueueBuilder extends WebSetter implements RenderQueueBuild initGlobalDescBinding(this._data, layoutName); } clearRenderTarget (name: string, color: Color = new Color()): void { + const clearView = renderGraphPool.createClearView(name, ClearFlagBit.COLOR); + clearView.clearColor.copy(color); this._renderGraph.addVertex( RenderGraphValue.Clear, - [new ClearView(name, ClearFlagBit.COLOR, color)], + [clearView], 'ClearRenderTarget', '', - new RenderData(), + renderGraphPool.createRenderData(), false, this._vertID, ); } setViewport (viewport: Viewport): void { - this._queue.viewport = new Viewport().copy(viewport); + const currViewport = pipelinePool.viewport.add(); + this._queue.viewport = currViewport.copy(viewport); } addCustomCommand (customBehavior: string): void { throw new Error('Method not implemented.'); } private _renderGraph: RenderGraph; - private _vertID: number; private _queue: RenderQueue; private _pipeline: PipelineSceneData; } @@ -1007,7 +1331,24 @@ export class WebRenderSubpassBuilder extends WebSetter implements RenderSubpassB ) { super(data, layoutGraph); this._renderGraph = renderGraph; - this._layoutGraph = layoutGraph; + this._vertID = vertID; + this._subpass = subpass; + this._pipeline = pipeline; + + const layoutName = this._renderGraph.component(RenderGraphComponent.Layout, this._vertID); + this._layoutID = layoutGraph.locateChild(layoutGraph.nullVertex(), layoutName); + } + update ( + data: RenderData, + renderGraph: RenderGraph, + layoutGraph: LayoutGraphData, + vertID: number, + subpass: RasterSubpass, + pipeline: PipelineSceneData, + ): void { + this._data = data; + this._lg = layoutGraph; + this._renderGraph = renderGraph; this._vertID = vertID; this._subpass = subpass; this._pipeline = pipeline; @@ -1047,15 +1388,16 @@ export class WebRenderSubpassBuilder extends WebSetter implements RenderSubpassB throw new Error('Method not implemented.'); } addQueue (hint: QueueHint = QueueHint.RENDER_OPAQUE, layoutName = 'default'): RenderQueueBuilder { - const layoutId = this._layoutGraph.locateChild(this._layoutID, layoutName); + const layoutId = this._lg.locateChild(this._layoutID, layoutName); if (DEBUG) { assert(layoutId !== 0xFFFFFFFF); } - const queue = new RenderQueue(hint); - queue.phaseID = layoutId; - const data = new RenderData(); + const queue = renderGraphPool.createRenderQueue(hint, layoutId); + const data = renderGraphPool.createRenderData(); const queueID = this._renderGraph.addVertex(RenderGraphValue.Queue, queue, '', layoutName, data, false, this._vertID); - return new WebRenderQueueBuilder(data, this._renderGraph, this._layoutGraph, queueID, queue, this._pipeline); + const queueBuilder = pipelinePool.renderQueueBuilder.add(); + queueBuilder.update(data, this._renderGraph, this._lg, queueID, queue, this._pipeline); + return queueBuilder; } get showStatistics (): boolean { return this._subpass.showStatistics; @@ -1063,28 +1405,35 @@ export class WebRenderSubpassBuilder extends WebSetter implements RenderSubpassB set showStatistics (enable: boolean) { this._subpass.showStatistics = enable; } - - private readonly _renderGraph: RenderGraph; - private readonly _vertID: number; - private readonly _layoutID: number; - private readonly _subpass: RasterSubpass; - private readonly _pipeline: PipelineSceneData; - private readonly _layoutGraph: LayoutGraphData; + private _renderGraph: RenderGraph; + private _layoutID: number; + private _subpass: RasterSubpass; + private _pipeline: PipelineSceneData; } export class WebRenderPassBuilder extends WebSetter implements BasicMultisampleRenderPassBuilder { constructor (data: RenderData, renderGraph: RenderGraph, layoutGraph: LayoutGraphData, resourceGraph: ResourceGraph, vertID: number, pass: RasterPass, pipeline: PipelineSceneData) { super(data, layoutGraph); this._renderGraph = renderGraph; - this._layoutGraph = layoutGraph; this._resourceGraph = resourceGraph; this._vertID = vertID; this._pass = pass; this._pipeline = pipeline; - const layoutName = this._renderGraph.component(RenderGraphComponent.Layout, this._vertID); this._layoutID = layoutGraph.locateChild(layoutGraph.nullVertex(), layoutName); } + update (data: RenderData, renderGraph: RenderGraph, layoutGraph: LayoutGraphData, resourceGraph: ResourceGraph, vertID: number, pass: RasterPass, pipeline: PipelineSceneData): void { + this._renderGraph = renderGraph; + this._lg = layoutGraph; + this._resourceGraph = resourceGraph; + this._vertID = vertID; + this._pass = pass; + this._pipeline = pipeline; + this._data = data; + const layoutName = this._renderGraph.component(RenderGraphComponent.Layout, this._vertID); + this._layoutID = layoutGraph.locateChild(layoutGraph.nullVertex(), layoutName); + } + setCustomShaderStages (name: string, stageFlags: ShaderStageFlagBit): void { throw new Error('Method not implemented.'); } @@ -1109,7 +1458,7 @@ export class WebRenderPassBuilder extends WebSetter implements BasicMultisampleR if (loadOp === LoadOp.LOAD) { clearFlag = ClearFlagBit.NONE; } - const view = new RasterView( + const view = renderGraphPool.createRasterView( '', AccessType.WRITE, @@ -1117,15 +1466,15 @@ export class WebRenderPassBuilder extends WebSetter implements BasicMultisampleR loadOp, storeOp, clearFlag, - clearColor, ); + view.clearColor.copy(clearColor); this._pass.rasterViews.set(name, view); } addDepthStencil (name: string, loadOp = LoadOp.CLEAR, storeOp = StoreOp.STORE, depth = 1, stencil = 0, clearFlag = ClearFlagBit.DEPTH_STENCIL): void { if (DEBUG) { assert(Boolean(name && this._resourceGraph.contains(name))); } - const view = new RasterView( + const view = renderGraphPool.createRasterView( '', AccessType.WRITE, @@ -1133,8 +1482,8 @@ export class WebRenderPassBuilder extends WebSetter implements BasicMultisampleR loadOp, storeOp, clearFlag, - new Color(depth, stencil, 0, 0), ); + view.clearColor.set(depth, stencil, 0, 0); this._pass.rasterViews.set(name, view); } resolveRenderTarget (source: string, target: string): void { @@ -1149,13 +1498,13 @@ export class WebRenderPassBuilder extends WebSetter implements BasicMultisampleR // TODO } private _addComputeResource (name: string, accessType: AccessType, slotName: string): void { - const view = new ComputeView(slotName); + const view = renderGraphPool.createComputeView(slotName); view.accessType = accessType; if (DEBUG) { assert(Boolean(view.name)); assert(Boolean(name && this._resourceGraph.contains(name))); const descriptorName = view.name; - const descriptorID = this._layoutGraph.attributeIndex.get(descriptorName); + const descriptorID = this._lg.attributeIndex.get(descriptorName); assert(descriptorID !== undefined); } if (this._pass.computeViews.has(name)) { @@ -1167,7 +1516,7 @@ export class WebRenderPassBuilder extends WebSetter implements BasicMultisampleR addTexture (name: string, slotName: string, sampler: Sampler | null = null): void { this._addComputeResource(name, AccessType.READ, slotName); if (sampler) { - const descriptorID = this._layoutGraph.attributeIndex.get(slotName)!; + const descriptorID = this._lg.attributeIndex.get(slotName)!; this._data.samplers.set(descriptorID, sampler); } } @@ -1180,64 +1529,66 @@ export class WebRenderPassBuilder extends WebSetter implements BasicMultisampleR addRenderSubpass (layoutName = ''): RenderSubpassBuilder { const name = 'Raster'; const subpassID = this._pass.subpassGraph.numVertices(); - this._pass.subpassGraph.addVertex(name, new Subpass()); - const subpass = new RasterSubpass(subpassID, 1, 0); - const data = new RenderData(); + this._pass.subpassGraph.addVertex(name, renderGraphPool.createSubpass()); + const subpass = renderGraphPool.createRasterSubpass(subpassID, 1, 0); + const data = renderGraphPool.createRenderData(); const vertID = this._renderGraph.addVertex(RenderGraphValue.RasterSubpass, subpass, name, layoutName, data, false); - const result = new WebRenderSubpassBuilder(data, this._renderGraph, this._layoutGraph, vertID, subpass, this._pipeline); + const result = pipelinePool.renderSubpassBuilder.add(); + result.update(data, this._renderGraph, this._lg, vertID, subpass, this._pipeline); return result; } addQueue (hint: QueueHint = QueueHint.RENDER_OPAQUE, layoutName = 'default'): WebRenderQueueBuilder { - const layoutId = this._layoutGraph.locateChild(this._layoutID, layoutName); + const layoutId = this._lg.locateChild(this._layoutID, layoutName); if (DEBUG) { assert(layoutId !== 0xFFFFFFFF); } - const queue = new RenderQueue(hint); - queue.phaseID = layoutId; - const data = new RenderData(); + const queue = renderGraphPool.createRenderQueue(hint, layoutId); + const data = renderGraphPool.createRenderData(); const queueID = this._renderGraph.addVertex(RenderGraphValue.Queue, queue, '', layoutName, data, false, this._vertID); - return new WebRenderQueueBuilder(data, this._renderGraph, this._layoutGraph, queueID, queue, this._pipeline); + const result = pipelinePool.renderQueueBuilder.add(); + result.update(data, this._renderGraph, this._lg, queueID, queue, this._pipeline); + return result; } addFullscreenQuad (material: Material, passID: number, sceneFlags = SceneFlags.NONE, name = 'FullscreenQuad'): void { - const queue = new RenderQueue(QueueHint.RENDER_TRANSPARENT); + const queue = renderGraphPool.createRenderQueue(QueueHint.RENDER_TRANSPARENT); const queueId = this._renderGraph.addVertex( RenderGraphValue.Queue, queue, 'Queue', '', - new RenderData(), + renderGraphPool.createRenderData(), false, this._vertID, ); this._renderGraph.addVertex( RenderGraphValue.Blit, - new Blit(material, passID, sceneFlags, null), + renderGraphPool.createBlit(material, passID, sceneFlags, null), name, '', - new RenderData(), + renderGraphPool.createRenderData(), false, queueId, ); } addCameraQuad (camera: Camera, material: Material, passID: number, sceneFlags: SceneFlags, name = 'CameraQuad'): void { - const queue = new RenderQueue(QueueHint.RENDER_TRANSPARENT); + const queue = renderGraphPool.createRenderQueue(QueueHint.RENDER_TRANSPARENT); const queueId = this._renderGraph.addVertex( RenderGraphValue.Queue, queue, 'Queue', '', - new RenderData(), + renderGraphPool.createRenderData(), false, this._vertID, ); this._renderGraph.addVertex( RenderGraphValue.Blit, - new Blit(material, passID, sceneFlags, camera), + renderGraphPool.createBlit(material, passID, sceneFlags, camera), name, '', - new RenderData(), + renderGraphPool.createRenderData(), false, queueId, ); @@ -1251,13 +1602,11 @@ export class WebRenderPassBuilder extends WebSetter implements BasicMultisampleR set showStatistics (enable: boolean) { this._pass.showStatistics = enable; } - private readonly _renderGraph: RenderGraph; - private readonly _vertID: number; - private readonly _layoutID: number; - private readonly _pass: RasterPass; - private readonly _pipeline: PipelineSceneData; - private readonly _layoutGraph: LayoutGraphData; - private readonly _resourceGraph: ResourceGraph; + private _renderGraph: RenderGraph; + private _layoutID: number; + private _pass: RasterPass; + private _pipeline: PipelineSceneData; + private _resourceGraph: ResourceGraph; } export class WebComputeQueueBuilder extends WebSetter implements ComputeQueueBuilder { @@ -1268,6 +1617,14 @@ export class WebComputeQueueBuilder extends WebSetter implements ComputeQueueBui this._queue = queue; this._pipeline = pipeline; } + update (data: RenderData, renderGraph: RenderGraph, layoutGraph: LayoutGraphData, vertID: number, queue: RenderQueue, pipeline: PipelineSceneData): void { + this._data = data; + this._lg = layoutGraph; + this._renderGraph = renderGraph; + this._vertID = vertID; + this._queue = queue; + this._pipeline = pipeline; + } setArrayBuffer (name: string, arrayBuffer: ArrayBuffer): void { throw new Error('Method not implemented.'); } @@ -1287,29 +1644,39 @@ export class WebComputeQueueBuilder extends WebSetter implements ComputeQueueBui ): void { this._renderGraph.addVertex( RenderGraphValue.Dispatch, - new Dispatch(material, passID, threadGroupCountX, threadGroupCountY, threadGroupCountZ), + renderGraphPool.createDispatch(material, passID, threadGroupCountX, threadGroupCountY, threadGroupCountZ), name, '', - new RenderData(), + renderGraphPool.createRenderData(), false, this._vertID, ); } - private readonly _renderGraph: RenderGraph; - private readonly _vertID: number; - private readonly _queue: RenderQueue; - private readonly _pipeline: PipelineSceneData; + private _renderGraph: RenderGraph; + private _queue: RenderQueue; + private _pipeline: PipelineSceneData; } export class WebComputePassBuilder extends WebSetter implements ComputePassBuilder { constructor (data: RenderData, renderGraph: RenderGraph, layoutGraph: LayoutGraphData, resourceGraph: ResourceGraph, vertID: number, pass: ComputePass, pipeline: PipelineSceneData) { super(data, layoutGraph); this._renderGraph = renderGraph; - this._layoutGraph = layoutGraph; + this._resourceGraph = resourceGraph; + this._vertID = vertID; + this._pass = pass; + this._pipeline = pipeline; + + const layoutName = this._renderGraph.component(RenderGraphComponent.Layout, this._vertID); + this._layoutID = layoutGraph.locateChild(layoutGraph.nullVertex(), layoutName); + } + update (data: RenderData, renderGraph: RenderGraph, layoutGraph: LayoutGraphData, resourceGraph: ResourceGraph, vertID: number, pass: ComputePass, pipeline: PipelineSceneData): void { + this._data = data; + this._renderGraph = renderGraph; + this._lg = layoutGraph; this._resourceGraph = resourceGraph; this._vertID = vertID; this._pass = pass; @@ -1334,7 +1701,7 @@ export class WebComputePassBuilder extends WebSetter implements ComputePassBuild throw new Error('Method not implemented.'); } addStorageBuffer (name: string, accessType: AccessType, slotName: string): void { - throw new Error('Method not implemented.'); + this._addComputeResource(name, accessType, slotName); } addStorageImage (name: string, accessType: AccessType, slotName: string): void { throw new Error('Method not implemented.'); @@ -1343,23 +1710,40 @@ export class WebComputePassBuilder extends WebSetter implements ComputePassBuild throw new Error('Method not implemented.'); } addQueue (layoutName = 'default'): WebComputeQueueBuilder { - const layoutId = this._layoutGraph.locateChild(this._layoutID, layoutName); + const layoutId = this._lg.locateChild(this._layoutID, layoutName); if (DEBUG) { assert(layoutId !== 0xFFFFFFFF); } - const queue = new RenderQueue(); - queue.phaseID = layoutId; - const data = new RenderData(); + const queue = renderGraphPool.createRenderQueue(QueueHint.RENDER_OPAQUE, layoutId); + const data = renderGraphPool.createRenderData(); const queueID = this._renderGraph.addVertex(RenderGraphValue.Queue, queue, '', layoutName, data, false, this._vertID); - return new WebComputeQueueBuilder(data, this._renderGraph, this._layoutGraph, queueID, queue, this._pipeline); + const computeQueueBuilder = pipelinePool.computeQueueBuilder.add(); + computeQueueBuilder.update(data, this._renderGraph, this._lg, queueID, queue, this._pipeline); + return computeQueueBuilder; } - private readonly _renderGraph: RenderGraph; - private readonly _layoutGraph: LayoutGraphData; - private readonly _resourceGraph: ResourceGraph; - private readonly _vertID: number; - private readonly _layoutID: number; - private readonly _pass: ComputePass; - private readonly _pipeline: PipelineSceneData; + + private _addComputeResource (name: string, accessType: AccessType, slotName: string): void { + const view = renderGraphPool.createComputeView(slotName); + view.accessType = accessType; + if (DEBUG) { + assert(Boolean(view.name)); + assert(Boolean(name && this._resourceGraph.contains(name))); + const descriptorName = view.name; + const descriptorID = this._lg.attributeIndex.get(descriptorName); + assert(descriptorID !== undefined); + } + if (this._pass.computeViews.has(name)) { + this._pass.computeViews.get(name)?.push(view); + } else { + this._pass.computeViews.set(name, [view]); + } + } + + private _renderGraph: RenderGraph; + private _resourceGraph: ResourceGraph; + private _layoutID: number; + private _pass: ComputePass; + private _pipeline: PipelineSceneData; } export class WebMovePassBuilder { @@ -1410,7 +1794,7 @@ export class WebCopyPassBuilder { function isManaged (residency: ResourceResidency): boolean { return residency === ResourceResidency.MANAGED - || residency === ResourceResidency.MEMORYLESS; + || residency === ResourceResidency.MEMORYLESS; } export class WebPipeline implements BasicPipeline { @@ -1430,6 +1814,7 @@ export class WebPipeline implements BasicPipeline { throw new Error('Method not implemented.'); } addRenderWindow (name: string, format: Format, width: number, height: number, renderWindow: RenderWindow): number { + // Objects need to be held for a long time, so there is no need to use pool management const desc = new ResourceDesc(); desc.dimension = ResourceDimension.TEXTURE2D; desc.width = width; @@ -1593,6 +1978,31 @@ export class WebPipeline implements BasicPipeline { // TODO: implement resolve pass throw new Error('Method not implemented.'); } + + public addComputePass (passName: string): ComputePassBuilder { + const name = 'Compute'; + const pass = renderGraphPool.createComputePass(); + + const data = renderGraphPool.createRenderData(); + const vertID = this._renderGraph!.addVertex(RenderGraphValue.Compute, pass, name, passName, data, false); + const result = pipelinePool.computePassBuilder.add(); + result.update(data, this._renderGraph!, this._layoutGraph, this._resourceGraph, vertID, pass, this._pipelineSceneData); + setComputeConstants(result, passName); + initGlobalDescBinding(data, passName); + return result; + } + + public addUploadPass (uploadPairs: UploadPair[]): void { + const name = 'UploadPass'; + const pass = renderGraphPool.createCopyPass(); + for (const up of uploadPairs) { + pass.uploadPairs.push(up); + } + + const vertID = this._renderGraph!.addVertex(RenderGraphValue.Copy, pass, name, '', renderGraphPool.createRenderData(), false); + // const result = new WebCopyPassBuilder(this._renderGraph!, vertID, pass); + } + public addCopyPass (copyPairs: CopyPair[]): void { // const renderData = new RenderData(); // const vertID = this._renderGraph!.addVertex( @@ -1612,7 +2022,7 @@ export class WebPipeline implements BasicPipeline { } const resDesc = this.resourceGraph.getDesc(tarVerId); const currRaster = this.addRenderPass(resDesc.width, resDesc.height, 'copy-pass'); - currRaster.addRenderTarget(targetName, LoadOp.CLEAR, StoreOp.STORE, new Color(0, 0, 0, 0)); + currRaster.addRenderTarget(targetName, LoadOp.CLEAR, StoreOp.STORE, pipelinePool.createColor()); currRaster.addTexture(pair.source, 'outputResultMap'); currRaster.addQueue(QueueHint.NONE).addFullscreenQuad(this._copyPassMat, 0, SceneFlags.NONE); } @@ -1621,7 +2031,7 @@ export class WebPipeline implements BasicPipeline { let str = ''; str += `#define CC_DEVICE_SUPPORT_FLOAT_TEXTURE ${this._device.getFormatFeatures(Format.RGBA32F) & (FormatFeatureBit.RENDER_TARGET | FormatFeatureBit.SAMPLED_TEXTURE) ? 1 : 0}\n`; - str += `#define CC_ENABLE_CLUSTERED_LIGHT_CULLING ${clusterEnabled ? 1 : 0}\n`; + // str += `#define CC_ENABLE_CLUSTERED_LIGHT_CULLING ${clusterEnabled ? 1 : 0}\n`; // defined in material str += `#define CC_DEVICE_MAX_VERTEX_UNIFORM_VECTORS ${this._device.capabilities.maxVertexUniformVectors}\n`; str += `#define CC_DEVICE_MAX_FRAGMENT_UNIFORM_VECTORS ${this._device.capabilities.maxFragmentUniformVectors}\n`; str += `#define CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT ${this._device.hasFeature(Feature.INPUT_ATTACHMENT_BENEFIT) ? 1 : 0}\n`; @@ -1679,13 +2089,14 @@ export class WebPipeline implements BasicPipeline { public activate (swapchain: Swapchain): boolean { this._device = deviceManager.gfxDevice; + pipelinePool = new PipelinePool(); + renderGraphPool = pipelinePool.renderGraphPool; createGfxDescriptorSetsAndPipelines(this._device, this._layoutGraph); this._globalDSManager = new GlobalDSManager(this._device); this._globalDescSetData = this.getGlobalDescriptorSetData()!; this._globalDescriptorSetLayout = this._globalDescSetData.descriptorSetLayout; this._globalDescriptorSetInfo = new DescriptorSetInfo(this._globalDescriptorSetLayout!); - this._globalDescriptorSet = isEnableEffect() ? this._device.createDescriptorSet(this._globalDescriptorSetInfo) - : this._globalDescSetData.descriptorSet; + this._globalDescriptorSet = this._device.createDescriptorSet(this._globalDescriptorSetInfo); this._globalDSManager.globalDescriptorSet = this.globalDescriptorSet; this._compileMaterial(); this.setMacroBool('CC_USE_HDR', this._pipelineSceneData.isHDR); @@ -1717,7 +2128,7 @@ export class WebPipeline implements BasicPipeline { this.setMacroInt('CC_DIR_LIGHT_SHADOW_TYPE', 0); // 0: CC_CASCADED_LAYERS_TRANSITION_OFF, 1: CC_CASCADED_LAYERS_TRANSITION_ON - this.setMacroBool('CC_CASCADED_LAYERS_TRANSITION', false); + this.setMacroBool('CC_CASCADED_LAYERS_TRANSITION', false); // enable the deferred pipeline if (this.usesDeferredPipeline) { @@ -1837,6 +2248,7 @@ export class WebPipeline implements BasicPipeline { } beginSetup (): void { if (!this._renderGraph) this._renderGraph = new RenderGraph(); + pipelinePool.reset(); } endSetup (): void { this.compile(); @@ -1851,11 +2263,22 @@ export class WebPipeline implements BasicPipeline { desc.format = format; desc.flags = ResourceFlags.STORAGE; + if (residency === ResourceResidency.PERSISTENT) { + return this._resourceGraph.addVertex( + ResourceGraphValue.PersistentBuffer, + new PersistentBuffer(), + name, + desc, + new ResourceTraits(ResourceResidency.PERSISTENT), + new ResourceStates(), + new SamplerInfo(), + ); + } + return this._resourceGraph.addVertex( ResourceGraphValue.ManagedBuffer, new ManagedBuffer(), name, - desc, new ResourceTraits(residency), new ResourceStates(), @@ -1953,7 +2376,6 @@ export class WebPipeline implements BasicPipeline { // noop } endFrame (): void { - // this._renderGraph = null; this.renderGraph?.clear(); } @@ -2017,6 +2439,27 @@ export class WebPipeline implements BasicPipeline { this.execute(); this.endFrame(); } + addBuiltinReflectionProbePass (camera: Camera): void { + const reflectionProbeManager = cclegacy.internal.reflectionProbeManager as ReflectionProbeManager; + if (!reflectionProbeManager) return; + const probes = reflectionProbeManager.getProbes(); + if (probes.length === 0) return; + for (let i = 0; i < probes.length; i++) { + const probe = probes[i]; + if (probe.needRender) { + if (probes[i].probeType === ProbeType.PLANAR) { + buildReflectionProbePass(camera, this, probe, probe.realtimePlanarTexture!.window!, 0); + } else if (EDITOR) { + for (let faceIdx = 0; faceIdx < probe.bakedCubeTextures.length; faceIdx++) { + probe.updateCameraDir(faceIdx); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + buildReflectionProbePass(camera, this, probe, probe.bakedCubeTextures[faceIdx].window!, faceIdx); + } + probe.needRender = false; + } + } + } + } addRenderPassImpl (width: number, height: number, layoutName: string, count = 1, quality = 0): BasicMultisampleRenderPassBuilder { if (DEBUG) { const stageId = this.layoutGraph.locateChild(this.layoutGraph.nullVertex(), layoutName); @@ -2026,16 +2469,17 @@ export class WebPipeline implements BasicPipeline { assert(Boolean(layout.descriptorSets.get(UpdateFrequency.PER_PASS))); } const name = 'Raster'; - const pass = new RasterPass(); + const pass = renderGraphPool.createRasterPass(); pass.viewport.width = width; pass.viewport.height = height; pass.count = count; pass.quality = quality; - const data = new RenderData(); + const data = renderGraphPool.createRenderData(); const vertID = this._renderGraph!.addVertex(RenderGraphValue.RasterPass, pass, name, layoutName, data, false); - const result = new WebRenderPassBuilder(data, this._renderGraph!, this._layoutGraph, this._resourceGraph, vertID, pass, this._pipelineSceneData); - this._updateRasterPassConstants(result, width, height, isEnableEffect() ? layoutName : 'default'); + const result = pipelinePool.renderPassBuilder.add(); + result.update(data, this._renderGraph!, this._layoutGraph, this._resourceGraph, vertID, pass, this._pipelineSceneData); + this._updateRasterPassConstants(result, width, height, layoutName); initGlobalDescBinding(data, layoutName); return result; } diff --git a/cocos/rendering/custom/web-scene.ts b/cocos/rendering/custom/web-scene.ts index ea0272151da..168d3c0d556 100644 --- a/cocos/rendering/custom/web-scene.ts +++ b/cocos/rendering/custom/web-scene.ts @@ -136,13 +136,13 @@ export class WebSceneTask implements SceneTask { } public start (): void { - this._sceneCulling(); + // do nothing } public join (): void { // for web-pipeline, do nothing } public submit (): void { - + // do nothing } get camera (): scene.Camera | null { return this._camera; } get renderScene (): RenderScene | null { diff --git a/cocos/rendering/forward/forward-stage.ts b/cocos/rendering/forward/forward-stage.ts index 3a486735198..86a6f2dde06 100644 --- a/cocos/rendering/forward/forward-stage.ts +++ b/cocos/rendering/forward/forward-stage.ts @@ -122,6 +122,7 @@ export class ForwardStage extends RenderStage { } public destroy (): void { + // do nothing } public render (camera: Camera): void { @@ -179,8 +180,14 @@ export class ForwardStage extends RenderStage { const framebuffer = camera.window.framebuffer; const renderPass = pipeline.getRenderPass(camera.clearFlag & this._clearFlag, framebuffer); - cmdBuff.beginRenderPass(renderPass, framebuffer, this._renderArea, - colors, camera.clearDepth, camera.clearStencil); + cmdBuff.beginRenderPass( + renderPass, + framebuffer, + this._renderArea, + colors, + camera.clearDepth, + camera.clearStencil, + ); cmdBuff.bindDescriptorSet(SetIndex.GLOBAL, pipeline.descriptorSet); this._renderQueues[0].recordCommandBuffer(device, renderPass, cmdBuff); diff --git a/cocos/rendering/post-process/passes/base-pass.ts b/cocos/rendering/post-process/passes/base-pass.ts index 54fecf11729..8260e67f517 100644 --- a/cocos/rendering/post-process/passes/base-pass.ts +++ b/cocos/rendering/post-process/passes/base-pass.ts @@ -41,14 +41,14 @@ export function disablePostProcessForDebugView (): boolean { return debugView.singleMode as number > 0; } -export function getShadowMapSampler (): Sampler | null { +export function getShadowMapSampler (): Sampler | undefined { if (!_pointSampler) { const director = cclegacy.director; const pipeline = director.root.pipeline; const device = pipeline.device; _pointSampler = device.getSampler(_samplerPointInfo); } - return _pointSampler; + return _pointSampler || undefined; } export abstract class BasePass { diff --git a/cocos/rendering/post-process/passes/forward-final-pass.ts b/cocos/rendering/post-process/passes/forward-final-pass.ts index 1ae8bdead67..8452c212963 100644 --- a/cocos/rendering/post-process/passes/forward-final-pass.ts +++ b/cocos/rendering/post-process/passes/forward-final-pass.ts @@ -1,6 +1,6 @@ import { Vec4 } from '../../../core'; import { ClearFlagBit, Format } from '../../../gfx'; -import { Camera } from '../../../render-scene/scene'; +import { Camera, SKYBOX_FLAG } from '../../../render-scene/scene'; import { getCameraUniqueID } from '../../custom/define'; import { Pipeline } from '../../custom/pipeline'; import { passContext } from '../utils/pass-context'; @@ -17,7 +17,7 @@ export class ForwardFinalPass extends BasePass { return; } - passContext.clearFlag = camera.clearFlag & ClearFlagBit.COLOR; + passContext.clearFlag = camera.clearFlag & ClearFlagBit.COLOR | (camera.clearFlag & SKYBOX_FLAG); Vec4.set(passContext.clearColor, camera.clearColor.x, camera.clearColor.y, camera.clearColor.z, camera.clearColor.w); passContext.material = this.material; diff --git a/cocos/rendering/post-process/passes/forward-pass.ts b/cocos/rendering/post-process/passes/forward-pass.ts index 4fa9f366640..9b4cf87efd0 100644 --- a/cocos/rendering/post-process/passes/forward-pass.ts +++ b/cocos/rendering/post-process/passes/forward-pass.ts @@ -1,7 +1,7 @@ import { Vec4 } from '../../../core'; import { ClearFlagBit, Format } from '../../../gfx'; -import { Camera, ShadowType } from '../../../render-scene/scene'; +import { Camera, ShadowType, SKYBOX_FLAG } from '../../../render-scene/scene'; import { LightInfo, QueueHint, SceneFlags } from '../../custom/types'; import { getCameraUniqueID } from '../../custom/define'; import { Pipeline } from '../../custom/pipeline'; @@ -38,7 +38,7 @@ export class ForwardPass extends BasePass { } public render (camera: Camera, ppl: Pipeline): void { - passContext.clearFlag = ClearFlagBit.COLOR | (camera.clearFlag & ClearFlagBit.DEPTH_STENCIL); + passContext.clearFlag = ClearFlagBit.COLOR | (camera.clearFlag & ClearFlagBit.DEPTH_STENCIL) | (camera.clearFlag & SKYBOX_FLAG); Vec4.set(passContext.clearColor, 0, 0, 0, 0); Vec4.set(passContext.clearDepthColor, camera.clearDepth, camera.clearStencil, 0, 0); diff --git a/cocos/rendering/post-process/post-process-builder.ts b/cocos/rendering/post-process/post-process-builder.ts index eb56eb6baa1..a17ab69a549 100644 --- a/cocos/rendering/post-process/post-process-builder.ts +++ b/cocos/rendering/post-process/post-process-builder.ts @@ -185,7 +185,7 @@ export class PostProcessBuilder implements PipelineBuilder { this.applyPreviewCamera(camera); } - buildReflectionProbePasss(camera, ppl); + ppl.addBuiltinReflectionProbePass(camera); passContext.postProcess = camera.postProcess || globalPP; diff --git a/cocos/rendering/post-process/utils/pass-context.ts b/cocos/rendering/post-process/utils/pass-context.ts index a8d783e92b2..0921cf0b717 100644 --- a/cocos/rendering/post-process/utils/pass-context.ts +++ b/cocos/rendering/post-process/utils/pass-context.ts @@ -3,7 +3,7 @@ import { EDITOR } from 'internal:constants'; import { QueueHint, ResourceResidency, SceneFlags } from '../../custom/types'; import { ClearFlagBit, Color, Format, LoadOp, Rect, StoreOp, Viewport } from '../../../gfx'; import { Pipeline, RenderPassBuilder } from '../../custom/pipeline'; -import { Camera } from '../../../render-scene/scene'; +import { Camera, SKYBOX_FLAG } from '../../../render-scene/scene'; import { Material } from '../../../asset/assets'; import { PostProcess } from '../components'; import { getRenderArea } from '../../custom/define'; @@ -111,7 +111,7 @@ export class PassContext { // return this; // } - addRasterView (name: string, format: Format, offscreen = true, residency?: ResourceResidency): PassContext { + addRasterView (name: string, format: Format, offscreen = true, residency: ResourceResidency = ResourceResidency.MANAGED): PassContext { const ppl = this.ppl; const camera = this.camera; const pass = this.pass; @@ -154,10 +154,11 @@ export class PassContext { const clearFlag = this.clearFlag & ClearFlagBit.COLOR; let loadOp = LoadOp.CLEAR; - if (clearFlag === ClearFlagBit.NONE) { + if (clearFlag === ClearFlagBit.NONE && !(this.clearFlag & SKYBOX_FLAG)) { loadOp = LoadOp.LOAD; + } else if (this.clearFlag & SKYBOX_FLAG) { + clearColor.set(0, 0, 0, 1); } - pass.addRenderTarget(name, loadOp, StoreOp.STORE, clearColor); } return this; diff --git a/cocos/rendering/scene-culling.ts b/cocos/rendering/scene-culling.ts index ca507ed247e..64173902a93 100644 --- a/cocos/rendering/scene-culling.ts +++ b/cocos/rendering/scene-culling.ts @@ -41,7 +41,7 @@ const roPool = new Pool((): IRenderObject => ({ model: null!, dep function getRenderObject (model: Model, camera: Camera): IRenderObject { let depth = 0; if (model.node) { - Vec3.subtract(_tempVec3, model.node.worldPosition, camera.position); + Vec3.subtract(_tempVec3, model.worldBounds ? model.worldBounds.center : model.node.worldPosition, camera.position); depth = Vec3.dot(_tempVec3, camera.forward); } const ro = roPool.alloc(); diff --git a/native/cocos/renderer/pipeline/SceneCulling.cpp b/native/cocos/renderer/pipeline/SceneCulling.cpp index 46babac15dc..d94ad2cb40e 100644 --- a/native/cocos/renderer/pipeline/SceneCulling.cpp +++ b/native/cocos/renderer/pipeline/SceneCulling.cpp @@ -57,7 +57,8 @@ RenderObject genRenderObject(const scene::Model *model, const scene::Camera *cam if (model->getNode()) { const auto *node = model->getTransform(); cc::Vec3 position; - cc::Vec3::subtract(node->getWorldPosition(), camera->getPosition(), &position); + const auto *bounds = model->getWorldBounds(); + Vec3::subtract(bounds ? bounds->center : node->getWorldPosition(), camera->getPosition(), &position); depth = position.dot(camera->getForward()); } diff --git a/native/cocos/renderer/pipeline/custom/FrameGraphDispatcher.cpp b/native/cocos/renderer/pipeline/custom/FrameGraphDispatcher.cpp index 0324502effa..7d2ab654957 100644 --- a/native/cocos/renderer/pipeline/custom/FrameGraphDispatcher.cpp +++ b/native/cocos/renderer/pipeline/custom/FrameGraphDispatcher.cpp @@ -314,12 +314,12 @@ RenderingInfo FrameGraphDispatcher::getRenderPassAndFrameBuffer(RenderGraph::ver CC_EXPECTS(tex.texture); fbInfo.colorTextures.emplace_back(tex.texture); }, - [&](const IntrusivePtr &res) { + [&](const PersistentBuffer &res) { std::ignore = res; CC_EXPECTS(false); }, - [&](const IntrusivePtr &tex) { - fbInfo.colorTextures.emplace_back(tex); + [&](const PersistentTexture &tex) { + fbInfo.colorTextures.emplace_back(tex.texture); }, [&](const IntrusivePtr &fb) { CC_EXPECTS(fb->getColorTextures().size() == 1); @@ -1565,7 +1565,7 @@ gfx::SamplerInfo makePointSamplerInfo() { return gfx::SamplerInfo{gfx::Filter::POINT, gfx::Filter::POINT, gfx::Filter::POINT}; } -SubresourceView makeSubresourceView(const ResourceDesc& srcDesc, const ResourceDesc &targetDesc, const gfx::ResourceRange& range) { +SubresourceView makeSubresourceView(const ResourceDesc &targetDesc, const gfx::ResourceRange& range) { SubresourceView view{}; view.firstArraySlice = range.firstSlice; view.numArraySlices = range.numSlices; @@ -1574,7 +1574,6 @@ SubresourceView makeSubresourceView(const ResourceDesc& srcDesc, const ResourceD view.firstPlane = range.basePlane; view.numPlanes = range.planeCount; view.format = targetDesc.format; - view.viewType = srcDesc.viewType; view.textureView = nullptr; return view; } @@ -1691,7 +1690,6 @@ void subresourceAnalysis(ResourceAccessGraph& rag, ResourceGraph& resg) { auto descResViewID = findVertex(subres, resg); auto targetResID = rag.resourceIndex.at(resName); - const auto &srcDesc = get(ResourceGraph::DescTag{}, resg, descResViewID); const auto &targetName = get(ResourceGraph::NameTag{}, resg, targetResID); const auto &targetDesc = get(ResourceGraph::DescTag{}, resg, targetResID); const auto &srcResourceRange = rag.movedSourceStatus.at(subres).range; @@ -1699,7 +1697,7 @@ void subresourceAnalysis(ResourceAccessGraph& rag, ResourceGraph& resg) { const auto &indexName = concatResName(targetName, subres, rag.resource()); auto subresID = findVertex(indexName, resg); if (subresID == ResourceGraph::null_vertex()) { - const auto &subView = makeSubresourceView(srcDesc, targetDesc, srcResourceRange); + const auto &subView = makeSubresourceView(targetDesc, srcResourceRange); // register to resourcegraph subresID = addVertex( SubresourceViewTag{}, diff --git a/native/cocos/renderer/pipeline/custom/NativeBuiltinUtils.cpp b/native/cocos/renderer/pipeline/custom/NativeBuiltinUtils.cpp index fabf92f5d61..325d2ad31fc 100644 --- a/native/cocos/renderer/pipeline/custom/NativeBuiltinUtils.cpp +++ b/native/cocos/renderer/pipeline/custom/NativeBuiltinUtils.cpp @@ -26,14 +26,18 @@ #include "cocos/application/ApplicationManager.h" #include "cocos/renderer/gfx-base/GFXDef-common.h" #include "cocos/renderer/gfx-base/GFXDevice.h" +#include "cocos/renderer/pipeline/Define.h" #include "cocos/renderer/pipeline/PipelineSceneData.h" #include "cocos/renderer/pipeline/custom/LayoutGraphTypes.h" +#include "cocos/renderer/pipeline/custom/NativePipelineTypes.h" #include "cocos/renderer/pipeline/custom/NativeTypes.h" #include "cocos/renderer/pipeline/custom/NativeUtils.h" #include "cocos/renderer/pipeline/custom/RenderGraphTypes.h" #include "cocos/renderer/pipeline/custom/details/GslUtils.h" #include "cocos/scene/Camera.h" +#include "cocos/scene/DirectionalLight.h" #include "cocos/scene/Fog.h" +#include "cocos/scene/Shadow.h" #include "cocos/scene/Skybox.h" #include "cocos/scene/SpotLight.h" @@ -254,12 +258,12 @@ float getPCFRadius( void setShadowUBOView( gfx::Device &device, const LayoutGraphData &layoutGraph, - const pipeline::PipelineSceneData &sceneData, + const pipeline::PipelineSceneData &pplSceneData, const scene::DirectionalLight &mainLight, RenderData &data) { - const auto &shadowInfo = *sceneData.getShadows(); - const auto &csmLayers = *sceneData.getCSMLayers(); - const auto &csmSupported = sceneData.getCSMSupported(); + const auto &shadowInfo = *pplSceneData.getShadows(); + const auto &csmLayers = *pplSceneData.getCSMLayers(); + const auto &csmSupported = pplSceneData.getCSMSupported(); const auto &packing = pipeline::supportsR32FloatTexture(&device) ? 0.0F : 1.0F; Vec4 vec4ShadowInfo{}; if (shadowInfo.isEnabled()) { @@ -369,12 +373,12 @@ void setShadowUBOView( void setShadowUBOLightView( gfx::Device *device, const LayoutGraphData &layoutGraph, - const pipeline::PipelineSceneData &sceneData, + const pipeline::PipelineSceneData &pplSceneData, + const BuiltinCascadedShadowMap *csm, const scene::Light &light, uint32_t level, RenderData &data) { - const auto &shadowInfo = *sceneData.getShadows(); - const auto &csmLayers = *sceneData.getCSMLayers(); + const auto &shadowInfo = *pplSceneData.getShadows(); const auto &packing = pipeline::supportsR32FloatTexture(device) ? 0.0F : 1.0F; const auto &cap = device->getCapabilities(); Vec4 vec4ShadowInfo{}; @@ -391,29 +395,31 @@ void setShadowUBOLightView( Mat4 matShadowProj; Mat4 matShadowViewProj; scene::CSMLevel levelCount{}; + CC_EXPECTS(csm); if (mainLight.isShadowFixedArea() || mainLight.getCSMLevel() == scene::CSMLevel::LEVEL_1) { - matShadowView = csmLayers.getSpecialLayer()->getMatShadowView(); - matShadowProj = csmLayers.getSpecialLayer()->getMatShadowProj(); - matShadowViewProj = csmLayers.getSpecialLayer()->getMatShadowViewProj(); + matShadowView = csm->specialLayer.shadowView; + matShadowProj = csm->specialLayer.shadowProj; + matShadowViewProj = csm->specialLayer.shadowViewProj; if (mainLight.isShadowFixedArea()) { near = mainLight.getShadowNear(); far = mainLight.getShadowFar(); levelCount = static_cast(0); } else { near = 0.1F; - far = csmLayers.getSpecialLayer()->getShadowCameraFar(); + far = csm->specialLayer.shadowCameraFar; levelCount = scene::CSMLevel::LEVEL_1; } vec4ShadowInfo.set(static_cast(scene::LightType::DIRECTIONAL), packing, mainLight.getShadowNormalBias(), 0); setVec4Impl(data, layoutGraph, "cc_shadowLPNNInfo", vec4ShadowInfo); } else { - const auto &layer = *csmLayers.getLayers()[level]; - matShadowView = layer.getMatShadowView(); - matShadowProj = layer.getMatShadowProj(); - matShadowViewProj = layer.getMatShadowViewProj(); - - near = layer.getSplitCameraNear(); - far = layer.getSplitCameraFar(); + CC_EXPECTS(level < csm->layers.size()); + const auto &layer = csm->layers[level]; + matShadowView = layer.shadowView; + matShadowProj = layer.shadowProj; + matShadowViewProj = layer.shadowViewProj; + + near = layer.splitCameraNear; + far = layer.splitCameraFar; levelCount = mainLight.getCSMLevel(); } setMat4Impl(data, layoutGraph, "cc_matLightView", matShadowView); @@ -485,12 +491,120 @@ void setShadowUBOLightView( setColorImpl(data, layoutGraph, "cc_shadowColor", gfx::Color{color[0], color[1], color[2], color[3]}); } +namespace { + +void updatePlanarNormalAndDistance( + const LayoutGraphData &layoutGraph, + const scene::Shadows &shadowInfo, + RenderData &data) { + const Vec3 normal = shadowInfo.getNormal().getNormalized(); + const Vec4 planarNDInfo{normal.x, normal.y, normal.z, -shadowInfo.getDistance()}; + setVec4Impl(data, layoutGraph, "cc_planarNDInfo", planarNDInfo); +} + +std::tuple +computeShadowMatrices( + const gfx::DeviceCaps &cap, + const Mat4 &matShadowCamera, + float fov, float farPlane) { + auto matShadowView = matShadowCamera.getInversed(); + + Mat4 matShadowProj; + Mat4::createPerspective( + fov, 1.0F, 0.001F, farPlane, + true, cap.clipSpaceMinZ, cap.clipSpaceSignY, + 0, &matShadowProj); + + Mat4 matShadowViewProj = matShadowProj; + Mat4 matShadowInvProj = matShadowProj; + + matShadowInvProj.inverse(); + matShadowViewProj.multiply(matShadowView); + + return {matShadowView, matShadowViewProj, matShadowProj, matShadowInvProj}; +} + +} // namespace + +void setPunctualLightShadowUBO( + gfx::Device *device, + const LayoutGraphData &layoutGraph, + const pipeline::PipelineSceneData &pplSceneData, + const scene::DirectionalLight *mainLight, + const scene::Light &light, + RenderData &data) { + const auto &shadowInfo = *pplSceneData.getShadows(); + const auto &packing = pipeline::supportsR32FloatTexture(device) ? 0.0F : 1.0F; + const auto &cap = device->getCapabilities(); + Vec4 vec4ShadowInfo{}; + + if (mainLight) { + // update planar PROJ + updatePlanarNormalAndDistance(layoutGraph, shadowInfo, data); + } + + // ShadowMap + switch (light.getType()) { + case scene::LightType::DIRECTIONAL: + // noop + break; + case scene::LightType::SPHERE: { + const auto &shadowSize = shadowInfo.getSize(); + setVec4Impl( + data, layoutGraph, "cc_shadowWHPBInfo", + Vec4{shadowSize.x, shadowSize.y, 1.0F, 0.0F}); + setVec4Impl( + data, layoutGraph, "cc_shadowLPNNInfo", + Vec4{static_cast(scene::LightType::SPHERE), packing, 0.0F, 0.0F}); + } break; + case scene::LightType::SPOT: { + const auto &shadowSize = shadowInfo.getSize(); + const auto &spotLight = dynamic_cast(light); + const auto &matShadowCamera = spotLight.getNode()->getWorldMatrix(); + const auto [matShadowView, matShadowViewProj, matShadowProj, matShadowInvProj] = + computeShadowMatrices(cap, matShadowCamera, spotLight.getAngle(), spotLight.getRange()); + + setMat4Impl(data, layoutGraph, "cc_matLightView", matShadowView); + setMat4Impl(data, layoutGraph, "cc_matLightViewProj", matShadowViewProj); + setVec4Impl( + data, layoutGraph, "cc_shadowNFLSInfo", + Vec4{0.1F, spotLight.getRange(), 0.0F, 0.0F}); + setVec4Impl( + data, layoutGraph, "cc_shadowWHPBInfo", + Vec4{shadowSize.x, shadowSize.y, spotLight.getShadowPcf(), spotLight.getShadowBias()}); + setVec4Impl( + data, layoutGraph, "cc_shadowLPNNInfo", + Vec4{static_cast(scene::LightType::SPOT), packing, spotLight.getShadowNormalBias(), 0.0F}); + setVec4Impl( + data, layoutGraph, "cc_shadowInvProjDepthInfo", + Vec4{matShadowInvProj.m[10], matShadowInvProj.m[14], matShadowInvProj.m[11], matShadowInvProj.m[15]}); + setVec4Impl( + data, layoutGraph, "cc_shadowProjDepthInfo", + Vec4{matShadowProj.m[10], matShadowProj.m[14], matShadowProj.m[11], matShadowProj.m[15]}); + setVec4Impl( + data, layoutGraph, "cc_shadowProjInfo", + Vec4{matShadowProj.m[00], matShadowProj.m[05], 1.0F / matShadowProj.m[00], 1.0F / matShadowProj.m[05]}); + } break; + case scene::LightType::POINT: { + const auto &shadowSize = shadowInfo.getSize(); + setVec4Impl( + data, layoutGraph, "cc_shadowWHPBInfo", + Vec4{shadowSize.x, shadowSize.y, 1.0F, 0.0F}); + setVec4Impl( + data, layoutGraph, "cc_shadowLPNNInfo", + Vec4{static_cast(scene::LightType::POINT), packing, 0.0F, 0.0F}); + } break; + default: + break; + } +} + void setLegacyTextureUBOView( gfx::Device &device, const LayoutGraphData &layoutGraph, - const pipeline::PipelineSceneData &sceneData, + const pipeline::PipelineSceneData &pplSceneData, RenderData &data) { - const auto &skybox = *sceneData.getSkybox(); + const auto &skybox = *pplSceneData.getSkybox(); if (skybox.getReflectionMap()) { auto &texture = *skybox.getReflectionMap()->getGFXTexture(); auto *sampler = device.getSampler(skybox.getReflectionMap()->getSamplerInfo()); @@ -532,6 +646,251 @@ void setLegacyTextureUBOView( // setTextureImpl(data, layoutGraph, "cc_spotShadowMap", BuiltinResMgr::getInstance()->get("default-texture")->getGFXTexture()); } +namespace { + +float kLightMeterScale{10000.0F}; + +} // namespace + +void setLightUBO( + const scene::Light *light, bool bHDR, float exposure, + const scene::Shadows *shadowInfo, + char *buffer, size_t bufferSize) { + CC_EXPECTS(bufferSize % sizeof(float) == 0); + const auto maxSize = bufferSize / sizeof(float); + auto *lightBufferData = reinterpret_cast(buffer); + + size_t offset = 0; + + Vec3 position = Vec3(0.0F, 0.0F, 0.0F); + float size = 0.F; + float range = 0.F; + float luminanceHDR = 0.F; + float luminanceLDR = 0.F; + if (light->getType() == scene::LightType::SPHERE) { + const auto *sphereLight = static_cast(light); + position = sphereLight->getPosition(); + size = sphereLight->getSize(); + range = sphereLight->getRange(); + luminanceHDR = sphereLight->getLuminanceHDR(); + luminanceLDR = sphereLight->getLuminanceLDR(); + } else if (light->getType() == scene::LightType::SPOT) { + const auto *spotLight = static_cast(light); + position = spotLight->getPosition(); + size = spotLight->getSize(); + range = spotLight->getRange(); + luminanceHDR = spotLight->getLuminanceHDR(); + luminanceLDR = spotLight->getLuminanceLDR(); + } else if (light->getType() == scene::LightType::POINT) { + const auto *pointLight = static_cast(light); + position = pointLight->getPosition(); + size = 0.0F; + range = pointLight->getRange(); + luminanceHDR = pointLight->getLuminanceHDR(); + luminanceLDR = pointLight->getLuminanceLDR(); + } else if (light->getType() == scene::LightType::RANGED_DIRECTIONAL) { + const auto *rangedDirLight = static_cast(light); + position = rangedDirLight->getPosition(); + size = 0.0F; + range = 0.0F; + luminanceHDR = rangedDirLight->getIlluminanceHDR(); + luminanceLDR = rangedDirLight->getIlluminanceLDR(); + } + auto index = offset + pipeline::UBOForwardLight::LIGHT_POS_OFFSET; + CC_EXPECTS(index + 4 < maxSize); + lightBufferData[index++] = position.x; + lightBufferData[index++] = position.y; + lightBufferData[index] = position.z; + + index = offset + pipeline::UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET; + CC_EXPECTS(index + 4 < maxSize); + lightBufferData[index++] = size; + lightBufferData[index] = range; + + index = offset + pipeline::UBOForwardLight::LIGHT_COLOR_OFFSET; + CC_EXPECTS(index + 4 < maxSize); + const auto &color = light->getColor(); + if (light->isUseColorTemperature()) { + const auto &tempRGB = light->getColorTemperatureRGB(); + lightBufferData[index++] = color.x * tempRGB.x; + lightBufferData[index++] = color.y * tempRGB.y; + lightBufferData[index++] = color.z * tempRGB.z; + } else { + lightBufferData[index++] = color.x; + lightBufferData[index++] = color.y; + lightBufferData[index++] = color.z; + } + + if (bHDR) { + lightBufferData[index] = luminanceHDR * exposure * kLightMeterScale; + } else { + lightBufferData[index] = luminanceLDR; + } + + switch (light->getType()) { + case scene::LightType::SPHERE: + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_POS_OFFSET + 3] = + static_cast(scene::LightType::SPHERE); + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 2] = 0; + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 3] = 0; + break; + case scene::LightType::SPOT: { + const auto *spotLight = static_cast(light); + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_POS_OFFSET + 3] = static_cast(scene::LightType::SPOT); + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 2] = spotLight->getSpotAngle(); + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 3] = + (shadowInfo->isEnabled() && + spotLight->isShadowEnabled() && + shadowInfo->getType() == scene::ShadowType::SHADOW_MAP) + ? 1.0F + : 0.0F; + + index = offset + pipeline::UBOForwardLight::LIGHT_DIR_OFFSET; + const auto &direction = spotLight->getDirection(); + lightBufferData[index++] = direction.x; + lightBufferData[index++] = direction.y; + lightBufferData[index] = direction.z; + } break; + case scene::LightType::POINT: + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_POS_OFFSET + 3] = static_cast(scene::LightType::POINT); + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 2] = 0; + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 3] = 0; + break; + case scene::LightType::RANGED_DIRECTIONAL: { + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_POS_OFFSET + 3] = static_cast(scene::LightType::RANGED_DIRECTIONAL); + + const auto *rangedDirLight = static_cast(light); + const Vec3 &right = rangedDirLight->getRight(); + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 0] = right.x; + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 1] = right.y; + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 2] = right.z; + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 3] = 0; + + const auto &direction = rangedDirLight->getDirection(); + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_DIR_OFFSET + 0] = direction.x; + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_DIR_OFFSET + 1] = direction.y; + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_DIR_OFFSET + 2] = direction.z; + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_DIR_OFFSET + 3] = 0; + + const auto &scale = rangedDirLight->getScale(); + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_BOUNDING_SIZE_VS_OFFSET + 0] = scale.x * 0.5F; + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_BOUNDING_SIZE_VS_OFFSET + 1] = scale.y * 0.5F; + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_BOUNDING_SIZE_VS_OFFSET + 2] = scale.z * 0.5F; + lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_BOUNDING_SIZE_VS_OFFSET + 3] = 0; + } break; + default: + break; + } +} + +const BuiltinCascadedShadowMap *getBuiltinShadowCSM( + const PipelineRuntime &pplRuntime, + const scene::Camera &camera, + const scene::DirectionalLight *mainLight) { + const auto &ppl = dynamic_cast(pplRuntime); + // no main light + if (!mainLight) { + return nullptr; + } + // not attached to a node + if (!mainLight->getNode()) { + return nullptr; + } + const pipeline::PipelineSceneData &pplSceneData = *pplRuntime.getPipelineSceneData(); + auto &csmLayers = *pplSceneData.getCSMLayers(); + const auto &shadows = *pplSceneData.getShadows(); + // shadow not enabled + if (!shadows.isEnabled()) { + return nullptr; + } + // shadow type is planar + if (shadows.getType() == scene::ShadowType::PLANAR) { + return nullptr; + } + + // find csm + const BuiltinCascadedShadowMapKey key{&camera, mainLight}; + auto iter = ppl.builtinCSMs.find(key); + if (iter != ppl.builtinCSMs.end()) { + return &iter->second; + } + + // add new csm info + bool added = false; + std::tie(iter, added) = ppl.builtinCSMs.emplace( + std::piecewise_construct, + std::forward_as_tuple(key), + std::forward_as_tuple()); + CC_ENSURES(added); + + auto &csm = iter->second; + + // update csm layers + csmLayers.update(&pplSceneData, &camera); + + // copy csm data + CC_EXPECTS(csm.layers.size() == csmLayers.getLayers().size()); + for (uint32_t i = 0; i != csm.layers.size(); ++i) { + const auto &src = *csmLayers.getLayers()[i]; + auto &dst = csm.layers[i]; + dst.shadowView = src.getMatShadowView(); + dst.shadowProj = src.getMatShadowProj(); + dst.shadowViewProj = src.getMatShadowViewProj(); + dst.validFrustum = src.getValidFrustum(); + dst.splitFrustum = src.getSplitFrustum(); + dst.lightViewFrustum = src.getLightViewFrustum(); + dst.castLightViewBoundingBox = src.getCastLightViewBoundingBox(); + dst.shadowCameraFar = src.getShadowCameraFar(); + dst.splitCameraNear = src.getSplitCameraNear(); + dst.splitCameraFar = src.getSplitCameraFar(); + dst.csmAtlas = src.getCSMAtlas(); + } + + { + const auto &src = *csmLayers.getSpecialLayer(); + auto &dst = csm.specialLayer; + dst.shadowView = src.getMatShadowView(); + dst.shadowProj = src.getMatShadowProj(); + dst.shadowViewProj = src.getMatShadowViewProj(); + dst.validFrustum = src.getValidFrustum(); + dst.splitFrustum = src.getSplitFrustum(); + dst.lightViewFrustum = src.getLightViewFrustum(); + dst.castLightViewBoundingBox = src.getCastLightViewBoundingBox(); + dst.shadowCameraFar = src.getShadowCameraFar(); + } + + csm.shadowDistance = mainLight->getShadowDistance(); + + return &csm; +} + +const geometry::Frustum &getBuiltinShadowFrustum( + const PipelineRuntime &pplRuntime, + const scene::Camera &camera, + const scene::DirectionalLight *mainLight, + uint32_t level) { + const auto &ppl = dynamic_cast(pplRuntime); + + const auto &shadows = *ppl.pipelineSceneData->getShadows(); + if (shadows.getType() == scene::ShadowType::PLANAR) { + return camera.getFrustum(); + } + + BuiltinCascadedShadowMapKey key{&camera, mainLight}; + auto iter = ppl.builtinCSMs.find(key); + if (iter == ppl.builtinCSMs.end()) { + throw std::runtime_error("Builtin shadow CSM not found"); + } + + const auto &csmLevel = mainLight->getCSMLevel(); + const auto &csm = iter->second; + + if (mainLight->isShadowFixedArea() || csmLevel == scene::CSMLevel::LEVEL_1) { + return csm.specialLayer.validFrustum; + } + return csm.layers[level].validFrustum; +} + } // namespace render } // namespace cc diff --git a/native/cocos/renderer/pipeline/custom/NativeBuiltinUtils.h b/native/cocos/renderer/pipeline/custom/NativeBuiltinUtils.h index b123a5332ac..9c74502dfaa 100644 --- a/native/cocos/renderer/pipeline/custom/NativeBuiltinUtils.h +++ b/native/cocos/renderer/pipeline/custom/NativeBuiltinUtils.h @@ -24,17 +24,26 @@ #pragma once #include +#include "cocos/math/Vec4.h" +#include "cocos/renderer/gfx-base/GFXDevice.h" #include "cocos/renderer/pipeline/custom/LayoutGraphFwd.h" #include "cocos/renderer/pipeline/custom/NativeFwd.h" +#include "cocos/renderer/pipeline/custom/NativePipelineFwd.h" #include "cocos/renderer/pipeline/custom/RenderGraphFwd.h" namespace cc { namespace scene { class Camera; +class Light; class DirectionalLight; +class Shadows; } // namespace scene +namespace geometry { +class Frustum; +} // namespace geometry + namespace gfx { class Device; } // namespace gfx @@ -71,16 +80,43 @@ void setShadowUBOLightView( gfx::Device *device, const LayoutGraphData &layoutGraph, const pipeline::PipelineSceneData &sceneData, + const BuiltinCascadedShadowMap *csm, const scene::Light &light, uint32_t level, RenderData &data); +// Additive light +void setLightUBO( + const scene::Light *light, bool bHDR, float exposure, + const scene::Shadows *shadowInfo, + char *buffer, size_t bufferSize); + +void setPunctualLightShadowUBO( + gfx::Device *device, + const LayoutGraphData &layoutGraph, + const pipeline::PipelineSceneData &pplSceneData, + const scene::DirectionalLight *mainLight, + const scene::Light &light, + RenderData &data); + // Render graph void updateRasterPassConstants(uint32_t width, uint32_t height, Setter &setter); // Geometry void setupQuadVertexBuffer(gfx::Device &device, const Vec4 &viewport, float vbData[16]); +// Shadow +const BuiltinCascadedShadowMap *getBuiltinShadowCSM( + const PipelineRuntime &pplRuntime, + const scene::Camera &camera, + const scene::DirectionalLight *mainLight); + +const geometry::Frustum &getBuiltinShadowFrustum( + const PipelineRuntime &pplRuntime, + const scene::Camera &camera, + const scene::DirectionalLight *mainLight, + uint32_t level); + } // namespace render } // namespace cc diff --git a/native/cocos/renderer/pipeline/custom/NativeExecutor.cpp b/native/cocos/renderer/pipeline/custom/NativeExecutor.cpp index bacbc8a90a6..6ac1c309012 100644 --- a/native/cocos/renderer/pipeline/custom/NativeExecutor.cpp +++ b/native/cocos/renderer/pipeline/custom/NativeExecutor.cpp @@ -28,14 +28,15 @@ #include "LayoutGraphGraphs.h" #include "LayoutGraphTypes.h" #include "LayoutGraphUtils.h" +#include "NativeBuiltinUtils.h" #include "NativePipelineFwd.h" #include "NativePipelineTypes.h" +#include "NativeRenderGraphUtils.h" #include "NativeUtils.h" #include "PrivateTypes.h" #include "RenderGraphGraphs.h" #include "RenderGraphTypes.h" #include "RenderingModule.h" -#include "NativeRenderGraphUtils.h" #include "cocos/renderer/gfx-base/GFXBarrier.h" #include "cocos/renderer/gfx-base/GFXDef-common.h" #include "cocos/renderer/gfx-base/GFXDescriptorSetLayout.h" @@ -60,10 +61,11 @@ namespace { constexpr uint32_t INVALID_ID = 0xFFFFFFFF; constexpr gfx::Color RASTER_COLOR{0.0, 1.0, 0.0, 1.0}; +constexpr gfx::Color RASTER_UPLOAD_COLOR{1.0, 1.0, 0.0, 1.0}; constexpr gfx::Color RENDER_QUEUE_COLOR{0.0, 0.5, 0.5, 1.0}; constexpr gfx::Color COMPUTE_COLOR{0.0, 0.0, 1.0, 1.0}; -gfx::MarkerInfo makeMarkerInfo(const char *str, const gfx::Color &color) { +gfx::MarkerInfo makeMarkerInfo(const char* str, const gfx::Color& color) { return gfx::MarkerInfo{str, color}; } @@ -1124,9 +1126,6 @@ struct RenderGraphVisitor : boost::dfs_visitor<> { } } void begin(const RasterPass& pass, RenderGraph::vertex_descriptor vertID) const { -#if CC_DEBUG - ctx.cmdBuff->beginMarker(makeMarkerInfo(get(RenderGraph::NameTag{}, ctx.g, vertID).c_str(), RASTER_COLOR)); -#endif const auto& renderData = get(RenderGraph::DataTag{}, ctx.g, vertID); if (!renderData.custom.empty()) { const auto& passes = ctx.ppl->custom.renderPasses; @@ -1182,7 +1181,7 @@ struct RenderGraphVisitor : boost::dfs_visitor<> { if (subpass.subpassID) { ctx.cmdBuff->nextSubpass(); } - //ctx.cmdBuff->setViewport(subpass); + // ctx.cmdBuff->setViewport(subpass); tryBindPerPassDescriptorSet(vertID); ctx.subpassIndex = subpass.subpassID; // noop @@ -1382,16 +1381,14 @@ struct RenderGraphVisitor : boost::dfs_visitor<> { tryBindPerPassDescriptorSet(sceneID); } const auto* scene = camera->getScene(); - const auto& queueDesc = ctx.context.sceneCulling.sceneQueryIndex.at(sceneID); - const auto& queue = ctx.context.sceneCulling.renderQueues[queueDesc.renderQueueTarget]; - queue.opaqueQueue.recordCommandBuffer( - ctx.device, camera, ctx.currentPass, ctx.cmdBuff, 0); - queue.opaqueInstancingQueue.recordCommandBuffer( - ctx.currentPass, ctx.cmdBuff); - queue.transparentQueue.recordCommandBuffer( - ctx.device, camera, ctx.currentPass, ctx.cmdBuff, 0); - queue.transparentInstancingQueue.recordCommandBuffer( - ctx.currentPass, ctx.cmdBuff); + const auto& queueDesc = ctx.context.sceneCulling.renderQueueIndex.at(sceneID); + const auto& queue = ctx.context.sceneCulling.renderQueues[queueDesc.renderQueueTarget.value]; + + queue.recordCommands(ctx.cmdBuff, ctx.currentPass, 0); + + if (any(sceneData.flags & SceneFlags::REFLECTION_PROBE)) { + queue.probeQueue.removeMacro(); + } if (any(sceneData.flags & SceneFlags::UI)) { submitUICommands(ctx.currentPass, ctx.currentPassLayoutID, camera, ctx.cmdBuff); @@ -1481,10 +1478,6 @@ struct RenderGraphVisitor : boost::dfs_visitor<> { ctx.cmdBuff->endRenderPass(); ctx.currentPass = nullptr; ctx.currentPassLayoutID = LayoutGraphData::null_vertex(); - -#if CC_DEBUG - ctx.cmdBuff->endMarker(); -#endif } void end(const RasterSubpass& subpass, RenderGraph::vertex_descriptor vertID) const { // NOLINT(readability-convert-member-functions-to-static) const auto& renderData = get(RenderGraph::DataTag{}, ctx.g, vertID); @@ -1676,6 +1669,9 @@ struct RenderGraphVisitor : boost::dfs_visitor<> { visitObject( vertID, ctx.g, [&](const RasterPass& pass) { +#if CC_DEBUG + ctx.cmdBuff->beginMarker(makeMarkerInfo(get(RenderGraph::NameTag{}, ctx.g, vertID).c_str(), RASTER_COLOR)); +#endif mountResources(pass); { const auto& layoutName = get(RenderGraph::LayoutTag{}, ctx.g, vertID); @@ -1684,9 +1680,15 @@ struct RenderGraphVisitor : boost::dfs_visitor<> { } // update UniformBuffers and DescriptorSets in all children { +#if CC_DEBUG + ctx.cmdBuff->beginMarker(makeMarkerInfo("Upload", RASTER_UPLOAD_COLOR)); +#endif auto colors = ctx.g.colors(ctx.scratch); RenderGraphUploadVisitor visitor{{}, ctx}; boost::depth_first_visit(gv, vertID, visitor, get(colors, ctx.g)); +#if CC_DEBUG + ctx.cmdBuff->endMarker(); +#endif } if (pass.showStatistics) { const auto* profiler = ctx.ppl->getProfiler(); @@ -1792,6 +1794,9 @@ struct RenderGraphVisitor : boost::dfs_visitor<> { [&](const RasterPass& pass) { end(pass, vertID); rearBarriers(vertID); +#if CC_DEBUG + ctx.cmdBuff->endMarker(); +#endif }, [&](const RasterSubpass& subpass) { end(subpass, vertID); @@ -1976,7 +1981,7 @@ void NativePipeline::executeRenderGraph(const RenderGraph& rg) { { auto& context = ppl.nativeContext; auto& sceneCulling = context.sceneCulling; - sceneCulling.buildRenderQueues(rg, lg, *ppl.pipelineSceneData); + sceneCulling.buildRenderQueues(rg, lg, ppl); auto& group = ppl.nativeContext.resourceGroups[context.nextFenceValue]; // notice: we cannot use ranged-for of sceneCulling.renderQueues CC_EXPECTS(sceneCulling.numRenderQueues <= sceneCulling.renderQueues.size()); @@ -1986,6 +1991,16 @@ void NativePipeline::executeRenderGraph(const RenderGraph& rg) { } } + // light manangement + { + auto& ctx = ppl.nativeContext; + ctx.lightResources.clear(); + ctx.lightResources.buildLights( + ctx.sceneCulling, + ppl.pipelineSceneData->isHDR(), + ppl.pipelineSceneData->getShadows()); + } + // gpu driven if constexpr (ENABLE_GPU_DRIVEN) { // TODO(jilin): consider populating renderSceneResources here @@ -2007,6 +2022,11 @@ void NativePipeline::executeRenderGraph(const RenderGraph& rg) { // upload buffers { + auto& ctx = ppl.nativeContext; +#if CC_DEBUG + submit.primaryCommandBuffer->beginMarker(makeMarkerInfo("Internal Upload", RASTER_UPLOAD_COLOR)); +#endif + // scene const auto& sceneCulling = ppl.nativeContext.sceneCulling; for (uint32_t queueID = 0; queueID != sceneCulling.numRenderQueues; ++queueID) { // notice: we cannot use ranged-for of sceneCulling.renderQueues @@ -2015,6 +2035,13 @@ void NativePipeline::executeRenderGraph(const RenderGraph& rg) { queue.opaqueInstancingQueue.uploadBuffers(submit.primaryCommandBuffer); queue.transparentInstancingQueue.uploadBuffers(submit.primaryCommandBuffer); } + + // lights + ctx.lightResources.buildLightBuffer(submit.primaryCommandBuffer); + ctx.lightResources.tryUpdateRenderSceneLocalDescriptorSet(sceneCulling); +#if CC_DEBUG + submit.primaryCommandBuffer->endMarker(); +#endif } ccstd::pmr::unordered_map< diff --git a/native/cocos/renderer/pipeline/custom/NativePipeline.cpp b/native/cocos/renderer/pipeline/custom/NativePipeline.cpp index 004765b67e4..85cec43b9cf 100644 --- a/native/cocos/renderer/pipeline/custom/NativePipeline.cpp +++ b/native/cocos/renderer/pipeline/custom/NativePipeline.cpp @@ -32,8 +32,12 @@ #include "cocos/renderer/pipeline/custom/RenderGraphGraphs.h" #include "cocos/renderer/pipeline/custom/RenderingModule.h" #include "cocos/renderer/pipeline/custom/details/GslUtils.h" +#include "cocos/scene/ReflectionProbe.h" +#include "cocos/scene/ReflectionProbeManager.h" #include "cocos/scene/RenderScene.h" #include "cocos/scene/RenderWindow.h" +#include "pipeline/custom/RenderInterfaceTypes.h" + #if CC_USE_DEBUG_RENDERER #include "profiler/DebugRenderer.h" #endif @@ -42,14 +46,14 @@ namespace cc { namespace render { -template +template void addSubresourceNode(ResourceGraph::vertex_descriptor v, const ccstd::string &name, ResourceGraph &resg); template <> void addSubresourceNode(ResourceGraph::vertex_descriptor v, const ccstd::string &name, ResourceGraph &resg) { - const auto& desc = get(ResourceGraph::DescTag{}, resg, v); - const auto& traits = get(ResourceGraph::TraitsTag{}, resg, v); - const auto& samplerInfo = get(ResourceGraph::SamplerTag{}, resg, v); + const auto &desc = get(ResourceGraph::DescTag{}, resg, v); + const auto &traits = get(ResourceGraph::TraitsTag{}, resg, v); + const auto &samplerInfo = get(ResourceGraph::SamplerTag{}, resg, v); SubresourceView view{ nullptr, @@ -60,7 +64,6 @@ void addSubresourceNode(ResourceGraph::vertex_descri 1, // numArraySlices 0, // firstPlane 1, // numPlanes - desc.viewType, }; ccstd::string depthName{name}; @@ -120,6 +123,7 @@ PipelineCapabilities NativePipeline::getCapabilities() const { void NativePipeline::beginSetup() { renderGraph = RenderGraph(get_allocator()); + builtinCSMs.clear(); } void NativePipeline::endSetup() { @@ -314,7 +318,7 @@ uint32_t NativePipeline::addTexture(const ccstd::string &name, gfx::TextureType sampleCount, residency == ResourceResidency::MEMORYLESS ? gfx::TextureFlagBit::LAZILY_ALLOCATED : gfx::TextureFlagBit::NONE, flags, - type + type, }; return addVertex( ManagedTextureTag{}, @@ -351,15 +355,16 @@ void NativePipeline::updateBuffer(const ccstd::string &name, uint32_t size) { updateResource(name, gfx::Format::UNKNOWN, size, 0, 0, 0, 0, gfx::SampleCount::X1); } -uint32_t NativePipeline::addResource(const ccstd::string& name, ResourceDimension dimension, +uint32_t NativePipeline::addResource( + const ccstd::string &name, ResourceDimension dimension, gfx::Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t arraySize, uint32_t mipLevels, gfx::SampleCount sampleCount, ResourceFlags flags, ResourceResidency residency) { - return dimension == ResourceDimension::BUFFER ? addBuffer(name, width, flags, residency) : - addTexture(name, getTextureType(dimension, arraySize), format, width, height, depth, arraySize, mipLevels, sampleCount, flags, residency); + return dimension == ResourceDimension::BUFFER ? addBuffer(name, width, flags, residency) : addTexture(name, getTextureType(dimension, arraySize), format, width, height, depth, arraySize, mipLevels, sampleCount, flags, residency); } -void NativePipeline::updateResource(const ccstd::string& name, gfx::Format format, +void NativePipeline::updateResource( + const ccstd::string &name, gfx::Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t arraySize, uint32_t mipLevels, // NOLINT(bugprone-easily-swappable-parameters) gfx::SampleCount sampleCount) { auto resID = findVertex(ccstd::pmr::string(name, get_allocator()), resourceGraph); @@ -390,7 +395,7 @@ void NativePipeline::updateResource(const ccstd::string& name, gfx::Format forma resourceGraph.invalidatePersistentRenderPassAndFramebuffer(tex.texture.get()); } }, - [&](ManagedBuffer &/*buffer*/) { + [&](ManagedBuffer & /*buffer*/) { desc.width = width; }, [](const auto & /*res*/) {}); @@ -407,7 +412,7 @@ uint32_t NativePipeline::addStorageTexture(const ccstd::string &name, gfx::Forma desc.format = format; desc.sampleCount = gfx::SampleCount::X1; desc.textureFlags = gfx::TextureFlagBit::NONE; - desc.flags = ResourceFlags::STORAGE | ResourceFlags::SAMPLED | ResourceFlags::TRANSFER_SRC | ResourceFlags::TRANSFER_DST;; + desc.flags = ResourceFlags::STORAGE | ResourceFlags::SAMPLED | ResourceFlags::TRANSFER_SRC | ResourceFlags::TRANSFER_DST; CC_EXPECTS(residency == ResourceResidency::MANAGED || residency == ResourceResidency::MEMORYLESS); @@ -684,6 +689,99 @@ void NativePipeline::endFrame() { // noop } +namespace { + +gfx::LoadOp getLoadOpOfClearFlag(gfx::ClearFlagBit clearFlag, AttachmentType attachment) { + gfx::LoadOp loadOp = gfx::LoadOp::CLEAR; + if (!(clearFlag & gfx::ClearFlagBit::COLOR) && attachment == AttachmentType::RENDER_TARGET) { + if (static_cast(clearFlag) & cc::scene::Camera::SKYBOX_FLAG) { + loadOp = gfx::LoadOp::CLEAR; + } else { + loadOp = gfx::LoadOp::LOAD; + } + } + if ((clearFlag & gfx::ClearFlagBit::DEPTH_STENCIL) != gfx::ClearFlagBit::DEPTH_STENCIL && attachment == AttachmentType::DEPTH_STENCIL) { + if (!(clearFlag & gfx::ClearFlagBit::DEPTH)) { + loadOp = gfx::LoadOp::LOAD; + } + if (!(clearFlag & gfx::ClearFlagBit::STENCIL)) { + loadOp = gfx::LoadOp::LOAD; + } + } + return loadOp; +} + +void updateCameraUBO(Setter &setter, const scene::Camera *camera, NativePipeline &ppl) { + auto sceneData = ppl.pipelineSceneData; + auto *skybox = sceneData->getSkybox(); + setter.setBuiltinCameraConstants(camera); +} + +void buildReflectionProbePass( + const scene::Camera *camera, + render::NativePipeline *pipeline, + const scene::ReflectionProbe *probe, + scene::RenderWindow *renderWindow, + int faceIdx) { + const std::string cameraName = "Camera" + std::to_string(faceIdx); + const auto &area = probe->renderArea(); + const auto width = static_cast(area.x); + const auto height = static_cast(area.y); + const auto *probeCamera = probe->getCamera(); + const std::string probePassRTName = "reflectionProbePassColor" + cameraName; + const std::string probePassDSName = "reflectionProbePassDS" + cameraName; + if (!pipeline->containsResource(probePassRTName)) { + pipeline->addRenderWindow(probePassRTName, gfx::Format::RGBA8, width, height, renderWindow); + pipeline->addDepthStencil(probePassDSName, gfx::Format::DEPTH_STENCIL, width, height, ResourceResidency::EXTERNAL); + } + pipeline->updateRenderWindow(probePassRTName, renderWindow); + pipeline->updateDepthStencil(probePassDSName, width, height, gfx::Format::DEPTH_STENCIL); + std::unique_ptr passBuilder(pipeline->addRenderPass(width, height, "default")); + passBuilder->setName("ReflectionProbePass" + std::to_string(faceIdx)); + gfx::Viewport currViewport{}; + currViewport.width = width; + currViewport.height = height; + passBuilder->setViewport(currViewport); + gfx::Color clearColor{}; + clearColor.x = probeCamera->getClearColor().x; + clearColor.y = probeCamera->getClearColor().y; + clearColor.z = probeCamera->getClearColor().z; + clearColor.w = probeCamera->getClearColor().w; + passBuilder->addRenderTarget( + probePassRTName, + getLoadOpOfClearFlag(probeCamera->getClearFlag(), AttachmentType::RENDER_TARGET), + gfx::StoreOp::STORE, + clearColor); + passBuilder->addDepthStencil( + probePassDSName, + getLoadOpOfClearFlag(probeCamera->getClearFlag(), AttachmentType::DEPTH_STENCIL), + gfx::StoreOp::STORE, + probeCamera->getClearDepth(), + probeCamera->getClearStencil(), + probeCamera->getClearFlag()); + std::unique_ptr queueBuilder( + passBuilder->addQueue(QueueHint::RENDER_OPAQUE, "reflect-map")); + LightInfo lightInfo{}; + lightInfo.probe = const_cast(probe); + queueBuilder->addSceneOfCamera(const_cast(camera), lightInfo, SceneFlags::REFLECTION_PROBE | SceneFlags::OPAQUE_OBJECT); + updateCameraUBO(*queueBuilder, probeCamera, *pipeline); +} + +} // namespace + +void NativePipeline::addBuiltinReflectionProbePass(const scene::Camera *camera) { + const auto *reflectProbeManager = scene::ReflectionProbeManager::getInstance(); + if (!reflectProbeManager) return; + const auto &probes = reflectProbeManager->getAllProbes(); + for (auto *probe : probes) { + if (probe->needRender()) { + if (probe->getProbeType() == scene::ReflectionProbe::ProbeType::PLANAR) { + buildReflectionProbePass(camera, this, probe, probe->getRealtimePlanarTexture()->getWindow(), 0); + } + } + } +} + RenderPassBuilder *NativePipeline::addRenderPass( uint32_t width, uint32_t height, const ccstd::string &passName) { @@ -782,7 +880,7 @@ void NativePipeline::addMovePass(const ccstd::vector &movePairs) { namespace { void setupGpuDrivenResources( - NativePipeline& ppl, uint32_t cullingID, ResourceGraph& resg, const std::string &hzbName) { + NativePipeline &ppl, uint32_t cullingID, ResourceGraph &resg, const std::string &hzbName) { ccstd::pmr::string name(resg.get_allocator()); { // init resource name = "_GpuInit"; @@ -859,7 +957,6 @@ void setupGpuDrivenResources( } } if (!hzbName.empty()) { - } } @@ -894,7 +991,8 @@ void NativePipeline::addBuiltinGpuCullingPass( copyPass.copyPairs.emplace_back(std::move(copyPair)); } - auto copyID = addVertex2(CopyTag{}, + auto copyID = addVertex2( + CopyTag{}, std::forward_as_tuple("CopyInitialIndirectBuffer"), std::forward_as_tuple(), std::forward_as_tuple(), @@ -911,7 +1009,7 @@ void NativePipeline::addBuiltinGpuCullingPass( std::piecewise_construct, std::forward_as_tuple(drawIndirectBuffer), std::forward_as_tuple()); - auto& view = res.first->second.emplace_back(); + auto &view = res.first->second.emplace_back(); view.name = "CCDrawIndirectBuffer"; view.accessType = AccessType::WRITE; view.shaderStageFlags = gfx::ShaderStageFlagBit::COMPUTE; @@ -921,7 +1019,7 @@ void NativePipeline::addBuiltinGpuCullingPass( std::piecewise_construct, std::forward_as_tuple(drawInstanceBuffer), std::forward_as_tuple()); - auto& view = res.first->second.emplace_back(); + auto &view = res.first->second.emplace_back(); view.name = "CCDrawInstanceBuffer"; view.accessType = AccessType::WRITE; view.shaderStageFlags = gfx::ShaderStageFlagBit::COMPUTE; @@ -931,13 +1029,14 @@ void NativePipeline::addBuiltinGpuCullingPass( std::piecewise_construct, std::forward_as_tuple(visibilityBuffer), std::forward_as_tuple()); - auto& view = res.first->second.emplace_back(); + auto &view = res.first->second.emplace_back(); view.name = "CCVisibilityBuffer"; view.accessType = AccessType::WRITE; view.shaderStageFlags = gfx::ShaderStageFlagBit::COMPUTE; } - auto computePassID = addVertex2(ComputeTag{}, + auto computePassID = addVertex2( + ComputeTag{}, std::forward_as_tuple("Scene"), std::forward_as_tuple(), std::forward_as_tuple(), @@ -1096,6 +1195,7 @@ bool NativePipeline::activate(gfx::Swapchain *swapchainIn) { const auto &lg = programLibrary->layoutGraph; const auto numNodes = num_vertices(lg); nativeContext.layoutGraphResources.reserve(numNodes); + nativeContext.lightResources.init(*programLibrary, device, 16); for (uint32_t i = 0; i != numNodes; ++i) { auto &node = nativeContext.layoutGraphResources.emplace_back(); diff --git a/native/cocos/renderer/pipeline/custom/NativePipelineFwd.h b/native/cocos/renderer/pipeline/custom/NativePipelineFwd.h index 846d97ac32d..f83927c1b64 100644 --- a/native/cocos/renderer/pipeline/custom/NativePipelineFwd.h +++ b/native/cocos/renderer/pipeline/custom/NativePipelineFwd.h @@ -29,17 +29,35 @@ */ // clang-format off #pragma once -#include "cocos/base/std/hash/hash.h" #include "cocos/base/std/variant.h" -#include "cocos/renderer/pipeline/InstancedBuffer.h" #include "cocos/renderer/pipeline/custom/NativeFwd.h" namespace cc { +namespace scene { + +class ReflectionProbe; + +} // namespace scene + +namespace render { + +template +using Array4 = std::array; + +} // namespace render + +} // namespace cc + +#include "cocos/base/std/hash/hash.h" + +namespace cc { + namespace render { class NativeRenderNode; class NativeSetter; +class NativeSceneBuilder; class NativeRenderSubpassBuilderImpl; class NativeRenderQueueBuilder; class NativeRenderSubpassBuilder; @@ -51,6 +69,7 @@ class NativeComputeQueueBuilder; class NativeComputePassBuilder; struct RenderInstancingQueue; struct DrawInstance; +struct ProbeHelperQueue; struct RenderDrawQueue; struct NativeRenderQueue; struct ResourceGroup; @@ -64,13 +83,23 @@ struct QuadResource; enum class ResourceType; struct SceneResource; -struct CullingKey; -struct CullingQueries; +struct FrustumCullingKey; +struct FrustumCullingID; +struct FrustumCulling; +struct LightBoundsCullingID; +struct LightBoundsCullingKey; +struct LightBoundsCulling; +struct NativeRenderQueueID; struct NativeRenderQueueDesc; +struct LightBoundsCullingResult; struct SceneCulling; +struct LightResource; struct NativeRenderContext; class NativeProgramLibrary; struct PipelineCustomization; +struct BuiltinShadowTransform; +struct BuiltinCascadedShadowMapKey; +struct BuiltinCascadedShadowMap; class NativePipeline; class NativeProgramProxy; class NativeRenderingModule; @@ -82,8 +111,18 @@ class NativeRenderingModule; namespace ccstd { template <> -struct hash { - hash_t operator()(const cc::render::CullingKey& val) const noexcept; +struct hash { + hash_t operator()(const cc::render::FrustumCullingKey& val) const noexcept; +}; + +template <> +struct hash { + hash_t operator()(const cc::render::FrustumCullingID& val) const noexcept; +}; + +template <> +struct hash { + hash_t operator()(const cc::render::LightBoundsCullingKey& val) const noexcept; }; } // namespace ccstd diff --git a/native/cocos/renderer/pipeline/custom/NativePipelineTypes.cpp b/native/cocos/renderer/pipeline/custom/NativePipelineTypes.cpp index d8de417ef46..4046c22bc68 100644 --- a/native/cocos/renderer/pipeline/custom/NativePipelineTypes.cpp +++ b/native/cocos/renderer/pipeline/custom/NativePipelineTypes.cpp @@ -49,6 +49,15 @@ RenderInstancingQueue::RenderInstancingQueue(RenderInstancingQueue const& rhs, c passInstances(rhs.passInstances, alloc), instanceBuffers(rhs.instanceBuffers, alloc) {} +ProbeHelperQueue::ProbeHelperQueue(const allocator_type& alloc) noexcept +: probeMap(alloc) {} + +ProbeHelperQueue::ProbeHelperQueue(ProbeHelperQueue&& rhs, const allocator_type& alloc) +: probeMap(std::move(rhs.probeMap), alloc) {} + +ProbeHelperQueue::ProbeHelperQueue(ProbeHelperQueue const& rhs, const allocator_type& alloc) +: probeMap(rhs.probeMap, alloc) {} + RenderDrawQueue::RenderDrawQueue(const allocator_type& alloc) noexcept : instances(alloc) {} @@ -61,12 +70,14 @@ RenderDrawQueue::RenderDrawQueue(RenderDrawQueue const& rhs, const allocator_typ NativeRenderQueue::NativeRenderQueue(const allocator_type& alloc) noexcept : opaqueQueue(alloc), transparentQueue(alloc), + probeQueue(alloc), opaqueInstancingQueue(alloc), transparentInstancingQueue(alloc) {} NativeRenderQueue::NativeRenderQueue(SceneFlags sceneFlagsIn, uint32_t subpassOrPassLayoutIDIn, const allocator_type& alloc) noexcept : opaqueQueue(alloc), transparentQueue(alloc), + probeQueue(alloc), opaqueInstancingQueue(alloc), transparentInstancingQueue(alloc), sceneFlags(sceneFlagsIn), @@ -75,10 +86,12 @@ NativeRenderQueue::NativeRenderQueue(SceneFlags sceneFlagsIn, uint32_t subpassOr NativeRenderQueue::NativeRenderQueue(NativeRenderQueue&& rhs, const allocator_type& alloc) : opaqueQueue(std::move(rhs.opaqueQueue), alloc), transparentQueue(std::move(rhs.transparentQueue), alloc), + probeQueue(std::move(rhs.probeQueue), alloc), opaqueInstancingQueue(std::move(rhs.opaqueInstancingQueue), alloc), transparentInstancingQueue(std::move(rhs.transparentInstancingQueue), alloc), sceneFlags(rhs.sceneFlags), - subpassOrPassLayoutID(rhs.subpassOrPassLayoutID) {} + subpassOrPassLayoutID(rhs.subpassOrPassLayoutID), + lightByteOffset(rhs.lightByteOffset) {} ResourceGroup::ResourceGroup(const allocator_type& alloc) noexcept : instancingBuffers(alloc) {} @@ -159,36 +172,56 @@ SceneResource::SceneResource(SceneResource&& rhs, const allocator_type& alloc) storageBuffers(std::move(rhs.storageBuffers), alloc), storageImages(std::move(rhs.storageImages), alloc) {} -CullingQueries::CullingQueries(const allocator_type& alloc) noexcept -: culledResultIndex(alloc) {} +FrustumCulling::FrustumCulling(const allocator_type& alloc) noexcept +: resultIndex(alloc) {} + +FrustumCulling::FrustumCulling(FrustumCulling&& rhs, const allocator_type& alloc) +: resultIndex(std::move(rhs.resultIndex), alloc) {} -CullingQueries::CullingQueries(CullingQueries&& rhs, const allocator_type& alloc) -: culledResultIndex(std::move(rhs.culledResultIndex), alloc) {} +FrustumCulling::FrustumCulling(FrustumCulling const& rhs, const allocator_type& alloc) +: resultIndex(rhs.resultIndex, alloc) {} -CullingQueries::CullingQueries(CullingQueries const& rhs, const allocator_type& alloc) -: culledResultIndex(rhs.culledResultIndex, alloc) {} +LightBoundsCulling::LightBoundsCulling(const allocator_type& alloc) noexcept +: resultIndex(alloc) {} + +LightBoundsCulling::LightBoundsCulling(LightBoundsCulling&& rhs, const allocator_type& alloc) +: resultIndex(std::move(rhs.resultIndex), alloc) {} + +LightBoundsCulling::LightBoundsCulling(LightBoundsCulling const& rhs, const allocator_type& alloc) +: resultIndex(rhs.resultIndex, alloc) {} SceneCulling::SceneCulling(const allocator_type& alloc) noexcept -: sceneQueries(alloc), - culledResults(alloc), +: frustumCullings(alloc), + frustumCullingResults(alloc), + lightBoundsCullings(alloc), + lightBoundsCullingResults(alloc), renderQueues(alloc), - sceneQueryIndex(alloc) {} + renderQueueIndex(alloc) {} SceneCulling::SceneCulling(SceneCulling&& rhs, const allocator_type& alloc) -: sceneQueries(std::move(rhs.sceneQueries), alloc), - culledResults(std::move(rhs.culledResults), alloc), +: frustumCullings(std::move(rhs.frustumCullings), alloc), + frustumCullingResults(std::move(rhs.frustumCullingResults), alloc), + lightBoundsCullings(std::move(rhs.lightBoundsCullings), alloc), + lightBoundsCullingResults(std::move(rhs.lightBoundsCullingResults), alloc), renderQueues(std::move(rhs.renderQueues), alloc), - sceneQueryIndex(std::move(rhs.sceneQueryIndex), alloc), - numCullingQueries(rhs.numCullingQueries), + renderQueueIndex(std::move(rhs.renderQueueIndex), alloc), + numFrustumCulling(rhs.numFrustumCulling), + numLightBoundsCulling(rhs.numLightBoundsCulling), numRenderQueues(rhs.numRenderQueues), gpuCullingPassID(rhs.gpuCullingPassID) {} +LightResource::LightResource(const allocator_type& alloc) noexcept +: cpuBuffer(alloc), + lights(alloc), + lightIndex(alloc) {} + NativeRenderContext::NativeRenderContext(std::unique_ptr defaultResourceIn, const allocator_type& alloc) noexcept : defaultResource(std::move(defaultResourceIn)), resourceGroups(alloc), layoutGraphResources(alloc), renderSceneResources(alloc), - sceneCulling(alloc) {} + sceneCulling(alloc), + lightResources(alloc) {} NativeProgramLibrary::NativeProgramLibrary(const allocator_type& alloc) noexcept : layoutGraph(alloc), diff --git a/native/cocos/renderer/pipeline/custom/NativePipelineTypes.h b/native/cocos/renderer/pipeline/custom/NativePipelineTypes.h index 2f5704b28f8..c6c1cbb9c1f 100644 --- a/native/cocos/renderer/pipeline/custom/NativePipelineTypes.h +++ b/native/cocos/renderer/pipeline/custom/NativePipelineTypes.h @@ -33,6 +33,8 @@ #include "cocos/base/Ptr.h" #include "cocos/base/std/container/string.h" #include "cocos/base/std/hash/hash.h" +#include "cocos/core/geometry/AABB.h" +#include "cocos/core/geometry/Frustum.h" #include "cocos/renderer/gfx-base/GFXFramebuffer.h" #include "cocos/renderer/gfx-base/GFXRenderPass.h" #include "cocos/renderer/pipeline/GlobalDescriptorSetManager.h" @@ -41,6 +43,7 @@ #include "cocos/renderer/pipeline/custom/NativeTypes.h" #include "cocos/renderer/pipeline/custom/details/Map.h" #include "cocos/renderer/pipeline/custom/details/Set.h" +#include "cocos/scene/ReflectionProbe.h" #ifdef _MSC_VER #pragma warning(push) @@ -93,8 +96,8 @@ class NativeSetter : public NativeRenderNode { void setBuiltinSpotLightConstants(const scene::SpotLight *light, const scene::Camera *camera) /*implements*/; void setBuiltinPointLightConstants(const scene::PointLight *light, const scene::Camera *camera) /*implements*/; void setBuiltinRangedDirectionalLightConstants(const scene::RangedDirectionalLight *light, const scene::Camera *camera) /*implements*/; - void setBuiltinDirectionalLightViewConstants(const scene::DirectionalLight *light, uint32_t level) /*implements*/; - void setBuiltinSpotLightViewConstants(const scene::SpotLight *light) /*implements*/; + void setBuiltinDirectionalLightFrustumConstants(const scene::Camera *camera, const scene::DirectionalLight *light, uint32_t csmLevel) /*implements*/; + void setBuiltinSpotLightFrustumConstants(const scene::SpotLight *light) /*implements*/; void setVec4ArraySize(const ccstd::string& name, uint32_t sz); void setVec4ArrayElem(const ccstd::string& name, const cc::Vec4& vec, uint32_t id); @@ -106,6 +109,88 @@ class NativeSetter : public NativeRenderNode { uint32_t layoutID{LayoutGraphData::null_vertex()}; }; +class NativeSceneBuilder final : public SceneBuilder, public NativeSetter { +public: + NativeSceneBuilder(const PipelineRuntime* pipelineRuntimeIn, RenderGraph* renderGraphIn, uint32_t nodeIDIn, const LayoutGraphData* layoutGraphIn, uint32_t layoutIDIn) noexcept + : NativeSetter(pipelineRuntimeIn, renderGraphIn, nodeIDIn, layoutGraphIn, layoutIDIn) {} + + ccstd::string getName() const override { + return NativeRenderNode::getName(); + } + void setName(const ccstd::string &name) override { + NativeRenderNode::setName(name); + } + void setCustomBehavior(const ccstd::string &name) override { + NativeRenderNode::setCustomBehavior(name); + } + + void setMat4(const ccstd::string &name, const Mat4 &mat) override { + NativeSetter::setMat4(name, mat); + } + void setQuaternion(const ccstd::string &name, const Quaternion &quat) override { + NativeSetter::setQuaternion(name, quat); + } + void setColor(const ccstd::string &name, const gfx::Color &color) override { + NativeSetter::setColor(name, color); + } + void setVec4(const ccstd::string &name, const Vec4 &vec) override { + NativeSetter::setVec4(name, vec); + } + void setVec2(const ccstd::string &name, const Vec2 &vec) override { + NativeSetter::setVec2(name, vec); + } + void setFloat(const ccstd::string &name, float v) override { + NativeSetter::setFloat(name, v); + } + void setArrayBuffer(const ccstd::string &name, const ArrayBuffer *arrayBuffer) override { + NativeSetter::setArrayBuffer(name, arrayBuffer); + } + void setBuffer(const ccstd::string &name, gfx::Buffer *buffer) override { + NativeSetter::setBuffer(name, buffer); + } + void setTexture(const ccstd::string &name, gfx::Texture *texture) override { + NativeSetter::setTexture(name, texture); + } + void setReadWriteBuffer(const ccstd::string &name, gfx::Buffer *buffer) override { + NativeSetter::setReadWriteBuffer(name, buffer); + } + void setReadWriteTexture(const ccstd::string &name, gfx::Texture *texture) override { + NativeSetter::setReadWriteTexture(name, texture); + } + void setSampler(const ccstd::string &name, gfx::Sampler *sampler) override { + NativeSetter::setSampler(name, sampler); + } + void setBuiltinCameraConstants(const scene::Camera *camera) override { + NativeSetter::setBuiltinCameraConstants(camera); + } + void setBuiltinShadowMapConstants(const scene::DirectionalLight *light) override { + NativeSetter::setBuiltinShadowMapConstants(light); + } + void setBuiltinDirectionalLightConstants(const scene::DirectionalLight *light, const scene::Camera *camera) override { + NativeSetter::setBuiltinDirectionalLightConstants(light, camera); + } + void setBuiltinSphereLightConstants(const scene::SphereLight *light, const scene::Camera *camera) override { + NativeSetter::setBuiltinSphereLightConstants(light, camera); + } + void setBuiltinSpotLightConstants(const scene::SpotLight *light, const scene::Camera *camera) override { + NativeSetter::setBuiltinSpotLightConstants(light, camera); + } + void setBuiltinPointLightConstants(const scene::PointLight *light, const scene::Camera *camera) override { + NativeSetter::setBuiltinPointLightConstants(light, camera); + } + void setBuiltinRangedDirectionalLightConstants(const scene::RangedDirectionalLight *light, const scene::Camera *camera) override { + NativeSetter::setBuiltinRangedDirectionalLightConstants(light, camera); + } + void setBuiltinDirectionalLightFrustumConstants(const scene::Camera *camera, const scene::DirectionalLight *light, uint32_t csmLevel) override { + NativeSetter::setBuiltinDirectionalLightFrustumConstants(camera, light, csmLevel); + } + void setBuiltinSpotLightFrustumConstants(const scene::SpotLight *light) override { + NativeSetter::setBuiltinSpotLightFrustumConstants(light); + } + + void useLightFrustum(IntrusivePtr light, uint32_t csmLevel, const scene::Camera *optCamera) override; +}; + class NativeRenderSubpassBuilderImpl : public NativeSetter { public: NativeRenderSubpassBuilderImpl(const PipelineRuntime* pipelineRuntimeIn, RenderGraph* renderGraphIn, uint32_t nodeIDIn, const LayoutGraphData* layoutGraphIn, uint32_t layoutIDIn) @@ -195,17 +280,15 @@ class NativeRenderQueueBuilder final : public RenderQueueBuilder, public NativeS void setBuiltinRangedDirectionalLightConstants(const scene::RangedDirectionalLight *light, const scene::Camera *camera) override { NativeSetter::setBuiltinRangedDirectionalLightConstants(light, camera); } - void setBuiltinDirectionalLightViewConstants(const scene::DirectionalLight *light, uint32_t level) override { - NativeSetter::setBuiltinDirectionalLightViewConstants(light, level); + void setBuiltinDirectionalLightFrustumConstants(const scene::Camera *camera, const scene::DirectionalLight *light, uint32_t csmLevel) override { + NativeSetter::setBuiltinDirectionalLightFrustumConstants(camera, light, csmLevel); } - void setBuiltinSpotLightViewConstants(const scene::SpotLight *light) override { - NativeSetter::setBuiltinSpotLightViewConstants(light); + void setBuiltinSpotLightFrustumConstants(const scene::SpotLight *light) override { + NativeSetter::setBuiltinSpotLightFrustumConstants(light); } void addSceneOfCamera(scene::Camera *camera, LightInfo light, SceneFlags sceneFlags) override; - void addScene(const scene::Camera *camera, SceneFlags sceneFlags, const scene::Light *light) override; - void addSceneCulledByDirectionalLight(const scene::Camera *camera, SceneFlags sceneFlags, scene::DirectionalLight *light, uint32_t level) override; - void addSceneCulledBySpotLight(const scene::Camera *camera, SceneFlags sceneFlags, scene::SpotLight *light) override; + SceneBuilder *addScene(const scene::Camera *camera, SceneFlags sceneFlags, scene::Light *light) override; void addFullscreenQuad(Material *material, uint32_t passID, SceneFlags sceneFlags) override; void addCameraQuad(scene::Camera *camera, Material *material, uint32_t passID, SceneFlags sceneFlags) override; void clearRenderTarget(const ccstd::string &name, const gfx::Color &color) override; @@ -285,11 +368,11 @@ class NativeRenderSubpassBuilder final : public RenderSubpassBuilder, public Nat void setBuiltinRangedDirectionalLightConstants(const scene::RangedDirectionalLight *light, const scene::Camera *camera) override { NativeSetter::setBuiltinRangedDirectionalLightConstants(light, camera); } - void setBuiltinDirectionalLightViewConstants(const scene::DirectionalLight *light, uint32_t level) override { - NativeSetter::setBuiltinDirectionalLightViewConstants(light, level); + void setBuiltinDirectionalLightFrustumConstants(const scene::Camera *camera, const scene::DirectionalLight *light, uint32_t csmLevel) override { + NativeSetter::setBuiltinDirectionalLightFrustumConstants(camera, light, csmLevel); } - void setBuiltinSpotLightViewConstants(const scene::SpotLight *light) override { - NativeSetter::setBuiltinSpotLightViewConstants(light); + void setBuiltinSpotLightFrustumConstants(const scene::SpotLight *light) override { + NativeSetter::setBuiltinSpotLightFrustumConstants(light); } void addRenderTarget(const ccstd::string &name, AccessType accessType, const ccstd::string &slotName, gfx::LoadOp loadOp, gfx::StoreOp storeOp, const gfx::Color &color) override { @@ -396,11 +479,11 @@ class NativeMultisampleRenderSubpassBuilder final : public MultisampleRenderSubp void setBuiltinRangedDirectionalLightConstants(const scene::RangedDirectionalLight *light, const scene::Camera *camera) override { NativeSetter::setBuiltinRangedDirectionalLightConstants(light, camera); } - void setBuiltinDirectionalLightViewConstants(const scene::DirectionalLight *light, uint32_t level) override { - NativeSetter::setBuiltinDirectionalLightViewConstants(light, level); + void setBuiltinDirectionalLightFrustumConstants(const scene::Camera *camera, const scene::DirectionalLight *light, uint32_t csmLevel) override { + NativeSetter::setBuiltinDirectionalLightFrustumConstants(camera, light, csmLevel); } - void setBuiltinSpotLightViewConstants(const scene::SpotLight *light) override { - NativeSetter::setBuiltinSpotLightViewConstants(light); + void setBuiltinSpotLightFrustumConstants(const scene::SpotLight *light) override { + NativeSetter::setBuiltinSpotLightFrustumConstants(light); } void addRenderTarget(const ccstd::string &name, AccessType accessType, const ccstd::string &slotName, gfx::LoadOp loadOp, gfx::StoreOp storeOp, const gfx::Color &color) override { @@ -510,11 +593,11 @@ class NativeComputeSubpassBuilder final : public ComputeSubpassBuilder, public N void setBuiltinRangedDirectionalLightConstants(const scene::RangedDirectionalLight *light, const scene::Camera *camera) override { NativeSetter::setBuiltinRangedDirectionalLightConstants(light, camera); } - void setBuiltinDirectionalLightViewConstants(const scene::DirectionalLight *light, uint32_t level) override { - NativeSetter::setBuiltinDirectionalLightViewConstants(light, level); + void setBuiltinDirectionalLightFrustumConstants(const scene::Camera *camera, const scene::DirectionalLight *light, uint32_t csmLevel) override { + NativeSetter::setBuiltinDirectionalLightFrustumConstants(camera, light, csmLevel); } - void setBuiltinSpotLightViewConstants(const scene::SpotLight *light) override { - NativeSetter::setBuiltinSpotLightViewConstants(light); + void setBuiltinSpotLightFrustumConstants(const scene::SpotLight *light) override { + NativeSetter::setBuiltinSpotLightFrustumConstants(light); } void addRenderTarget(const ccstd::string &name, const ccstd::string &slotName) override; @@ -597,11 +680,11 @@ class NativeRenderPassBuilder final : public RenderPassBuilder, public NativeSet void setBuiltinRangedDirectionalLightConstants(const scene::RangedDirectionalLight *light, const scene::Camera *camera) override { NativeSetter::setBuiltinRangedDirectionalLightConstants(light, camera); } - void setBuiltinDirectionalLightViewConstants(const scene::DirectionalLight *light, uint32_t level) override { - NativeSetter::setBuiltinDirectionalLightViewConstants(light, level); + void setBuiltinDirectionalLightFrustumConstants(const scene::Camera *camera, const scene::DirectionalLight *light, uint32_t csmLevel) override { + NativeSetter::setBuiltinDirectionalLightFrustumConstants(camera, light, csmLevel); } - void setBuiltinSpotLightViewConstants(const scene::SpotLight *light) override { - NativeSetter::setBuiltinSpotLightViewConstants(light); + void setBuiltinSpotLightFrustumConstants(const scene::SpotLight *light) override { + NativeSetter::setBuiltinSpotLightFrustumConstants(light); } void addRenderTarget(const ccstd::string &name, gfx::LoadOp loadOp, gfx::StoreOp storeOp, const gfx::Color &color) override; @@ -696,11 +779,11 @@ class NativeMultisampleRenderPassBuilder final : public MultisampleRenderPassBui void setBuiltinRangedDirectionalLightConstants(const scene::RangedDirectionalLight *light, const scene::Camera *camera) override { NativeSetter::setBuiltinRangedDirectionalLightConstants(light, camera); } - void setBuiltinDirectionalLightViewConstants(const scene::DirectionalLight *light, uint32_t level) override { - NativeSetter::setBuiltinDirectionalLightViewConstants(light, level); + void setBuiltinDirectionalLightFrustumConstants(const scene::Camera *camera, const scene::DirectionalLight *light, uint32_t csmLevel) override { + NativeSetter::setBuiltinDirectionalLightFrustumConstants(camera, light, csmLevel); } - void setBuiltinSpotLightViewConstants(const scene::SpotLight *light) override { - NativeSetter::setBuiltinSpotLightViewConstants(light); + void setBuiltinSpotLightFrustumConstants(const scene::SpotLight *light) override { + NativeSetter::setBuiltinSpotLightFrustumConstants(light); } void addRenderTarget(const ccstd::string &name, gfx::LoadOp loadOp, gfx::StoreOp storeOp, const gfx::Color &color) override; @@ -794,11 +877,11 @@ class NativeComputeQueueBuilder final : public ComputeQueueBuilder, public Nativ void setBuiltinRangedDirectionalLightConstants(const scene::RangedDirectionalLight *light, const scene::Camera *camera) override { NativeSetter::setBuiltinRangedDirectionalLightConstants(light, camera); } - void setBuiltinDirectionalLightViewConstants(const scene::DirectionalLight *light, uint32_t level) override { - NativeSetter::setBuiltinDirectionalLightViewConstants(light, level); + void setBuiltinDirectionalLightFrustumConstants(const scene::Camera *camera, const scene::DirectionalLight *light, uint32_t csmLevel) override { + NativeSetter::setBuiltinDirectionalLightFrustumConstants(camera, light, csmLevel); } - void setBuiltinSpotLightViewConstants(const scene::SpotLight *light) override { - NativeSetter::setBuiltinSpotLightViewConstants(light); + void setBuiltinSpotLightFrustumConstants(const scene::SpotLight *light) override { + NativeSetter::setBuiltinSpotLightFrustumConstants(light); } void addDispatch(uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ, Material *material, uint32_t passID) override; @@ -876,11 +959,11 @@ class NativeComputePassBuilder final : public ComputePassBuilder, public NativeS void setBuiltinRangedDirectionalLightConstants(const scene::RangedDirectionalLight *light, const scene::Camera *camera) override { NativeSetter::setBuiltinRangedDirectionalLightConstants(light, camera); } - void setBuiltinDirectionalLightViewConstants(const scene::DirectionalLight *light, uint32_t level) override { - NativeSetter::setBuiltinDirectionalLightViewConstants(light, level); + void setBuiltinDirectionalLightFrustumConstants(const scene::Camera *camera, const scene::DirectionalLight *light, uint32_t csmLevel) override { + NativeSetter::setBuiltinDirectionalLightFrustumConstants(camera, light, csmLevel); } - void setBuiltinSpotLightViewConstants(const scene::SpotLight *light) override { - NativeSetter::setBuiltinSpotLightViewConstants(light); + void setBuiltinSpotLightFrustumConstants(const scene::SpotLight *light) override { + NativeSetter::setBuiltinSpotLightFrustumConstants(light); } void addTexture(const ccstd::string &name, const ccstd::string &slotName, gfx::Sampler *sampler, uint32_t plane) override; @@ -912,9 +995,9 @@ struct RenderInstancingQueue { void sort(); void uploadBuffers(gfx::CommandBuffer *cmdBuffer) const; void recordCommandBuffer( - gfx::RenderPass *renderPass, gfx::CommandBuffer *cmdBuffer, - gfx::DescriptorSet *ds = nullptr, uint32_t offset = 0, - const ccstd::vector *dynamicOffsets = nullptr) const; + gfx::RenderPass *renderPass, uint32_t subpassIndex, + gfx::CommandBuffer *cmdBuffer, + uint32_t lightByteOffset = 0xFFFFFFFF) const; ccstd::pmr::vector sortedBatches; PmrUnorderedMap passInstances; @@ -930,6 +1013,36 @@ struct DrawInstance { uint32_t passIndex{0}; }; +struct ProbeHelperQueue { + using allocator_type = boost::container::pmr::polymorphic_allocator; + allocator_type get_allocator() const noexcept { // NOLINT + return {probeMap.get_allocator().resource()}; + } + + ProbeHelperQueue(const allocator_type& alloc) noexcept; // NOLINT + ProbeHelperQueue(ProbeHelperQueue&& rhs, const allocator_type& alloc); + ProbeHelperQueue(ProbeHelperQueue const& rhs, const allocator_type& alloc); + + ProbeHelperQueue(ProbeHelperQueue&& rhs) noexcept = default; + ProbeHelperQueue(ProbeHelperQueue const& rhs) = delete; + ProbeHelperQueue& operator=(ProbeHelperQueue&& rhs) = default; + ProbeHelperQueue& operator=(ProbeHelperQueue const& rhs) = default; + + static LayoutGraphData::vertex_descriptor getDefaultId(const LayoutGraphData &lg); + + inline void clear() noexcept { + probeMap.clear(); + } + + void removeMacro() const; + + static uint32_t getPassIndexFromLayout(const IntrusivePtr& subModel, LayoutGraphData::vertex_descriptor phaseLayoutId); + + void applyMacro(const LayoutGraphData &lg, const scene::Model& model, LayoutGraphData::vertex_descriptor probeLayoutId); + + ccstd::pmr::vector probeMap; +}; + struct RenderDrawQueue { using allocator_type = boost::container::pmr::polymorphic_allocator; allocator_type get_allocator() const noexcept { // NOLINT @@ -948,9 +1061,10 @@ struct RenderDrawQueue { void add(const scene::Model& model, float depth, uint32_t subModelIdx, uint32_t passIdx); void sortOpaqueOrCutout(); void sortTransparent(); - void recordCommandBuffer(gfx::Device *device, const scene::Camera *camera, - gfx::RenderPass *renderPass, gfx::CommandBuffer *cmdBuffer, - uint32_t subpassIndex) const; + void recordCommandBuffer( + gfx::RenderPass *renderPass, uint32_t subpassIndex, + gfx::CommandBuffer *cmdBuffer, + uint32_t lightByteOffset = 0xFFFFFFFF) const; ccstd::pmr::vector instances; }; @@ -973,13 +1087,17 @@ struct NativeRenderQueue { void sort(); void clear() noexcept; bool empty() const noexcept; + void recordCommands( + gfx::CommandBuffer *cmdBuffer, gfx::RenderPass *renderPass, uint32_t subpassIndex) const; RenderDrawQueue opaqueQueue; RenderDrawQueue transparentQueue; + ProbeHelperQueue probeQueue; RenderInstancingQueue opaqueInstancingQueue; RenderInstancingQueue transparentInstancingQueue; SceneFlags sceneFlags{SceneFlags::NONE}; uint32_t subpassOrPassLayoutID{0xFFFFFFFF}; + uint32_t lightByteOffset{0xFFFFFFFF}; }; struct ResourceGroup { @@ -1105,7 +1223,7 @@ struct LayoutGraphNodeResource { LayoutGraphNodeResource& operator=(LayoutGraphNodeResource const& rhs) = delete; void syncResources() noexcept; - PmrFlatMap uniformBuffers; + ccstd::pmr::unordered_map uniformBuffers; DescriptorSetPool descriptorSetPool; PmrTransparentMap programResources; }; @@ -1146,56 +1264,124 @@ struct SceneResource { ccstd::pmr::unordered_map> storageImages; }; -struct CullingKey { +struct FrustumCullingKey { const scene::Camera* camera{nullptr}; + const scene::ReflectionProbe* probe{nullptr}; const scene::Light* light{nullptr}; - bool castShadow{false}; uint32_t lightLevel{0xFFFFFFFF}; + bool castShadow{false}; +}; + +inline bool operator==(const FrustumCullingKey& lhs, const FrustumCullingKey& rhs) noexcept { + return std::forward_as_tuple(lhs.camera, lhs.probe, lhs.light, lhs.lightLevel, lhs.castShadow) == + std::forward_as_tuple(rhs.camera, rhs.probe, rhs.light, rhs.lightLevel, rhs.castShadow); +} + +inline bool operator!=(const FrustumCullingKey& lhs, const FrustumCullingKey& rhs) noexcept { + return !(lhs == rhs); +} + +struct FrustumCullingID { + explicit operator uint32_t() const { + return value; + } + + uint32_t value{0xFFFFFFFF}; +}; + +inline bool operator==(const FrustumCullingID& lhs, const FrustumCullingID& rhs) noexcept { + return std::forward_as_tuple(lhs.value) == + std::forward_as_tuple(rhs.value); +} + +inline bool operator!=(const FrustumCullingID& lhs, const FrustumCullingID& rhs) noexcept { + return !(lhs == rhs); +} + +struct FrustumCulling { + using allocator_type = boost::container::pmr::polymorphic_allocator; + allocator_type get_allocator() const noexcept { // NOLINT + return {resultIndex.get_allocator().resource()}; + } + + FrustumCulling(const allocator_type& alloc) noexcept; // NOLINT + FrustumCulling(FrustumCulling&& rhs, const allocator_type& alloc); + FrustumCulling(FrustumCulling const& rhs, const allocator_type& alloc); + + FrustumCulling(FrustumCulling&& rhs) noexcept = default; + FrustumCulling(FrustumCulling const& rhs) = delete; + FrustumCulling& operator=(FrustumCulling&& rhs) = default; + FrustumCulling& operator=(FrustumCulling const& rhs) = default; + + ccstd::pmr::unordered_map resultIndex; }; -inline bool operator==(const CullingKey& lhs, const CullingKey& rhs) noexcept { - return std::forward_as_tuple(lhs.camera, lhs.light, lhs.castShadow, lhs.lightLevel) == - std::forward_as_tuple(rhs.camera, rhs.light, rhs.castShadow, rhs.lightLevel); +struct LightBoundsCullingID { + explicit operator uint32_t() const { + return value; + } + + uint32_t value{0xFFFFFFFF}; +}; + +struct LightBoundsCullingKey { + FrustumCullingID frustumCullingID; + const scene::Camera* camera{nullptr}; + const scene::ReflectionProbe* probe{nullptr}; + const scene::Light* cullingLight{nullptr}; +}; + +inline bool operator==(const LightBoundsCullingKey& lhs, const LightBoundsCullingKey& rhs) noexcept { + return std::forward_as_tuple(lhs.frustumCullingID, lhs.camera, lhs.probe, lhs.cullingLight) == + std::forward_as_tuple(rhs.frustumCullingID, rhs.camera, rhs.probe, rhs.cullingLight); } -inline bool operator!=(const CullingKey& lhs, const CullingKey& rhs) noexcept { +inline bool operator!=(const LightBoundsCullingKey& lhs, const LightBoundsCullingKey& rhs) noexcept { return !(lhs == rhs); } -struct CullingQueries { +struct LightBoundsCulling { using allocator_type = boost::container::pmr::polymorphic_allocator; allocator_type get_allocator() const noexcept { // NOLINT - return {culledResultIndex.get_allocator().resource()}; + return {resultIndex.get_allocator().resource()}; } - CullingQueries(const allocator_type& alloc) noexcept; // NOLINT - CullingQueries(CullingQueries&& rhs, const allocator_type& alloc); - CullingQueries(CullingQueries const& rhs, const allocator_type& alloc); + LightBoundsCulling(const allocator_type& alloc) noexcept; // NOLINT + LightBoundsCulling(LightBoundsCulling&& rhs, const allocator_type& alloc); + LightBoundsCulling(LightBoundsCulling const& rhs, const allocator_type& alloc); - CullingQueries(CullingQueries&& rhs) noexcept = default; - CullingQueries(CullingQueries const& rhs) = delete; - CullingQueries& operator=(CullingQueries&& rhs) = default; - CullingQueries& operator=(CullingQueries const& rhs) = default; + LightBoundsCulling(LightBoundsCulling&& rhs) noexcept = default; + LightBoundsCulling(LightBoundsCulling const& rhs) = delete; + LightBoundsCulling& operator=(LightBoundsCulling&& rhs) = default; + LightBoundsCulling& operator=(LightBoundsCulling const& rhs) = default; - ccstd::pmr::unordered_map culledResultIndex; + ccstd::pmr::unordered_map resultIndex; +}; + +struct NativeRenderQueueID { + explicit operator uint32_t() const { + return value; + } + + uint32_t value{0xFFFFFFFF}; }; struct NativeRenderQueueDesc { - NativeRenderQueueDesc() = default; - NativeRenderQueueDesc(uint32_t culledSourceIn, uint32_t renderQueueTargetIn, scene::LightType lightTypeIn) noexcept // NOLINT - : culledSource(culledSourceIn), - renderQueueTarget(renderQueueTargetIn), - lightType(lightTypeIn) {} - - uint32_t culledSource{0xFFFFFFFF}; - uint32_t renderQueueTarget{0xFFFFFFFF}; + FrustumCullingID frustumCulledResultID; + LightBoundsCullingID lightBoundsCulledResultID; + NativeRenderQueueID renderQueueTarget; scene::LightType lightType{scene::LightType::UNKNOWN}; }; +struct LightBoundsCullingResult { + ccstd::vector instances; + uint32_t lightByteOffset{0xFFFFFFFF}; +}; + struct SceneCulling { using allocator_type = boost::container::pmr::polymorphic_allocator; allocator_type get_allocator() const noexcept { // NOLINT - return {sceneQueries.get_allocator().resource()}; + return {frustumCullings.get_allocator().resource()}; } SceneCulling(const allocator_type& alloc) noexcept; // NOLINT @@ -1207,23 +1393,64 @@ struct SceneCulling { SceneCulling& operator=(SceneCulling const& rhs) = delete; void clear() noexcept; - void buildRenderQueues(const RenderGraph& rg, const LayoutGraphData& lg, const pipeline::PipelineSceneData& pplSceneData); + void buildRenderQueues(const RenderGraph& rg, const LayoutGraphData& lg, const NativePipeline& ppl); private: - uint32_t getOrCreateSceneCullingQuery(const SceneData& sceneData); - uint32_t createRenderQueue(SceneFlags sceneFlags, LayoutGraphData::vertex_descriptor subpassOrPassLayoutID); + FrustumCullingID getOrCreateFrustumCulling(const SceneData& sceneData); + LightBoundsCullingID getOrCreateLightBoundsCulling(const SceneData& sceneData, FrustumCullingID frustumCullingID); + NativeRenderQueueID createRenderQueue(SceneFlags sceneFlags, LayoutGraphData::vertex_descriptor subpassOrPassLayoutID); void collectCullingQueries(const RenderGraph& rg, const LayoutGraphData& lg); - void batchCulling(const pipeline::PipelineSceneData& pplSceneData); + void batchFrustumCulling(const NativePipeline& ppl); + void batchLightBoundsCulling(); void fillRenderQueues(const RenderGraph& rg, const pipeline::PipelineSceneData& pplSceneData); public: - ccstd::pmr::unordered_map sceneQueries; - ccstd::pmr::vector> culledResults; + ccstd::pmr::unordered_map frustumCullings; + ccstd::pmr::vector> frustumCullingResults; + ccstd::pmr::unordered_map lightBoundsCullings; + ccstd::pmr::vector lightBoundsCullingResults; ccstd::pmr::vector renderQueues; - PmrFlatMap sceneQueryIndex; - uint32_t numCullingQueries{0}; + PmrFlatMap renderQueueIndex; + uint32_t numFrustumCulling{0}; + uint32_t numLightBoundsCulling{0}; uint32_t numRenderQueues{0}; uint32_t gpuCullingPassID{0xFFFFFFFF}; }; +struct LightResource { + using allocator_type = boost::container::pmr::polymorphic_allocator; + allocator_type get_allocator() const noexcept { // NOLINT + return {cpuBuffer.get_allocator().resource()}; + } + + LightResource(const allocator_type& alloc) noexcept; // NOLINT + LightResource(LightResource&& rhs) = delete; + LightResource(LightResource const& rhs) = delete; + LightResource& operator=(LightResource&& rhs) = delete; + LightResource& operator=(LightResource const& rhs) = delete; + + void init(const NativeProgramLibrary& programLib, gfx::Device* deviceIn, uint32_t maxNumLights); + void buildLights( + SceneCulling& sceneCulling, + bool bHDR, + const scene::Shadows* shadowInfo); + void tryUpdateRenderSceneLocalDescriptorSet(const SceneCulling& sceneCulling); + void clear(); + + uint32_t addLight(const scene::Light* light, bool bHDR, float exposure, const scene::Shadows *shadowInfo); + void buildLightBuffer(gfx::CommandBuffer* cmdBuffer) const; + + ccstd::pmr::vector cpuBuffer; + const NativeProgramLibrary* programLibrary{nullptr}; + gfx::Device* device{nullptr}; + uint32_t elementSize{0}; + uint32_t maxNumLights{16}; + uint32_t binding{0xFFFFFFFF}; + bool resized{false}; + IntrusivePtr lightBuffer; + IntrusivePtr firstLightBufferView; + ccstd::pmr::vector lights; + PmrFlatMap lightIndex; +}; + struct NativeRenderContext { using allocator_type = boost::container::pmr::polymorphic_allocator; allocator_type get_allocator() const noexcept { // NOLINT @@ -1245,6 +1472,7 @@ struct NativeRenderContext { ccstd::pmr::unordered_map renderSceneResources; QuadResource fullscreenQuad; SceneCulling sceneCulling; + LightResource lightResources; }; class NativeProgramLibrary final : public ProgramLibrary { @@ -1314,6 +1542,36 @@ struct PipelineCustomization { PmrTransparentMap> renderCommands; }; +struct BuiltinShadowTransform { + Mat4 shadowView; + Mat4 shadowProj; + Mat4 shadowViewProj; + geometry::Frustum validFrustum; + geometry::Frustum splitFrustum; + geometry::Frustum lightViewFrustum; + geometry::AABB castLightViewBoundingBox; + float shadowCameraFar{0}; + float splitCameraNear{0}; + float splitCameraFar{0}; + Vec4 csmAtlas; +}; + +struct BuiltinCascadedShadowMapKey { + const scene::Camera* camera{nullptr}; + const scene::DirectionalLight* light{nullptr}; +}; + +inline bool operator<(const BuiltinCascadedShadowMapKey& lhs, const BuiltinCascadedShadowMapKey& rhs) noexcept { + return std::forward_as_tuple(lhs.camera, lhs.light) < + std::forward_as_tuple(rhs.camera, rhs.light); +} + +struct BuiltinCascadedShadowMap { + Array4 layers; + BuiltinShadowTransform specialLayer; + float shadowDistance{0}; +}; + class NativePipeline final : public Pipeline { public: using allocator_type = boost::container::pmr::polymorphic_allocator; @@ -1357,18 +1615,18 @@ class NativePipeline final : public Pipeline { void beginSetup() override; void endSetup() override; bool containsResource(const ccstd::string &name) const override; - uint32_t addExternalTexture(const ccstd::string &name, gfx::Texture *texture, ResourceFlags flags) override; - void updateExternalTexture(const ccstd::string &name, gfx::Texture *texture) override; uint32_t addRenderWindow(const ccstd::string &name, gfx::Format format, uint32_t width, uint32_t height, scene::RenderWindow *renderWindow) override; void updateRenderWindow(const ccstd::string &name, scene::RenderWindow *renderWindow) override; uint32_t addRenderTarget(const ccstd::string &name, gfx::Format format, uint32_t width, uint32_t height, ResourceResidency residency) override; uint32_t addDepthStencil(const ccstd::string &name, gfx::Format format, uint32_t width, uint32_t height, ResourceResidency residency) override; void updateRenderTarget(const ccstd::string &name, uint32_t width, uint32_t height, gfx::Format format) override; void updateDepthStencil(const ccstd::string &name, uint32_t width, uint32_t height, gfx::Format format) override; - uint32_t addTexture(const ccstd::string &name, gfx::TextureType type, gfx::Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t arraySize, uint32_t mipLevels, gfx::SampleCount sampleCount, ResourceFlags flags, ResourceResidency residency) override; - void updateTexture(const ccstd::string &name, gfx::Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t arraySize, uint32_t mipLevels, gfx::SampleCount sampleCount) override; uint32_t addBuffer(const ccstd::string &name, uint32_t size, ResourceFlags flags, ResourceResidency residency) override; void updateBuffer(const ccstd::string &name, uint32_t size) override; + uint32_t addExternalTexture(const ccstd::string &name, gfx::Texture *texture, ResourceFlags flags) override; + void updateExternalTexture(const ccstd::string &name, gfx::Texture *texture) override; + uint32_t addTexture(const ccstd::string &name, gfx::TextureType type, gfx::Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t arraySize, uint32_t mipLevels, gfx::SampleCount sampleCount, ResourceFlags flags, ResourceResidency residency) override; + void updateTexture(const ccstd::string &name, gfx::Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t arraySize, uint32_t mipLevels, gfx::SampleCount sampleCount) override; uint32_t addResource(const ccstd::string &name, ResourceDimension dimension, gfx::Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t arraySize, uint32_t mipLevels, gfx::SampleCount sampleCount, ResourceFlags flags, ResourceResidency residency) override; void updateResource(const ccstd::string &name, gfx::Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t arraySize, uint32_t mipLevels, gfx::SampleCount sampleCount) override; void beginFrame() override; @@ -1376,6 +1634,7 @@ class NativePipeline final : public Pipeline { void endFrame() override; void addResolvePass(const ccstd::vector &resolvePairs) override; void addCopyPass(const ccstd::vector ©Pairs) override; + void addBuiltinReflectionProbePass(const scene::Camera *camera) override; gfx::DescriptorSetLayout *getDescriptorSetLayout(const ccstd::string &shaderName, UpdateFrequency freq) override; uint32_t addStorageBuffer(const ccstd::string &name, gfx::Format format, uint32_t size, ResourceResidency residency) override; @@ -1424,6 +1683,7 @@ class NativePipeline final : public Pipeline { NativeRenderContext nativeContext; ResourceGraph resourceGraph; RenderGraph renderGraph; + mutable PmrFlatMap builtinCSMs; PipelineStatistics statistics; PipelineCustomization custom; }; @@ -1463,12 +1723,28 @@ class NativeRenderingModule final : public RenderingModule { namespace ccstd { -inline hash_t hash::operator()(const cc::render::CullingKey& val) const noexcept { +inline hash_t hash::operator()(const cc::render::FrustumCullingKey& val) const noexcept { hash_t seed = 0; hash_combine(seed, val.camera); + hash_combine(seed, val.probe); hash_combine(seed, val.light); - hash_combine(seed, val.castShadow); hash_combine(seed, val.lightLevel); + hash_combine(seed, val.castShadow); + return seed; +} + +inline hash_t hash::operator()(const cc::render::FrustumCullingID& val) const noexcept { + hash_t seed = 0; + hash_combine(seed, val.value); + return seed; +} + +inline hash_t hash::operator()(const cc::render::LightBoundsCullingKey& val) const noexcept { + hash_t seed = 0; + hash_combine(seed, val.frustumCullingID); + hash_combine(seed, val.camera); + hash_combine(seed, val.probe); + hash_combine(seed, val.cullingLight); return seed; } diff --git a/native/cocos/renderer/pipeline/custom/NativeRenderGraph.cpp b/native/cocos/renderer/pipeline/custom/NativeRenderGraph.cpp index 960cb08d0d4..a11df267403 100644 --- a/native/cocos/renderer/pipeline/custom/NativeRenderGraph.cpp +++ b/native/cocos/renderer/pipeline/custom/NativeRenderGraph.cpp @@ -50,8 +50,8 @@ void NativeRenderNode::setCustomBehavior(const ccstd::string &name) { // NOLINT( RenderGraph::vertex_descriptor RenderGraph::getPassID(vertex_descriptor nodeID) const { CC_EXPECTS(nodeID != null_vertex()); for (auto parentID = nodeID; - parentID != RenderGraph::null_vertex(); - parentID = parent(nodeID, *this)) { + parentID != RenderGraph::null_vertex(); + parentID = parent(nodeID, *this)) { nodeID = parentID; } CC_ENSURES(nodeID != null_vertex()); @@ -690,10 +690,27 @@ ComputeQueueBuilder *NativeComputeSubpassBuilder::addQueue(const ccstd::string & return new NativeComputeQueueBuilder(pipelineRuntime, renderGraph, queueID, layoutGraph, phaseLayoutID); } +namespace { + +CullingFlags makeCullingFlags(const LightInfo &light) { + auto cullingFlags = CullingFlags::NONE; + if (light.culledByLight) { + cullingFlags |= CullingFlags::LIGHT_FRUSTUM; + } else { + cullingFlags |= CullingFlags::CAMERA_FRUSTUM; + if (light.light) { + cullingFlags |= CullingFlags::LIGHT_BOUNDS; + } + } + return cullingFlags; +} + +} // namespace + void NativeRenderQueueBuilder::addSceneOfCamera( scene::Camera *camera, LightInfo light, SceneFlags sceneFlags) { const auto *pLight = light.light.get(); - SceneData scene(camera->getScene(), camera, sceneFlags, light); + SceneData scene(camera->getScene(), camera, sceneFlags, light, makeCullingFlags(light), light.light); auto sceneID = addVertex2( SceneTag{}, std::forward_as_tuple("Camera"), @@ -712,12 +729,18 @@ void NativeRenderQueueBuilder::addSceneOfCamera( *pipelineRuntime->getPipelineSceneData(), camera->getScene()->getMainLight(), data); + // notice: if light is not directional light, csm will be nullptr + const auto *csm = getBuiltinShadowCSM( + *pipelineRuntime, *camera, + dynamic_cast(pLight)); + if (any(sceneFlags & SceneFlags::SHADOW_CASTER)) { if (pLight) { setShadowUBOLightView( pipelineRuntime->getDevice(), *layoutGraph, *pipelineRuntime->getPipelineSceneData(), + csm, // csm might be nullptr *pLight, light.level, data); } } else { @@ -736,23 +759,108 @@ void NativeRenderQueueBuilder::addSceneOfCamera( data); } -void NativeRenderQueueBuilder::addScene(const scene::Camera *camera, SceneFlags sceneFlags, const scene::Light *light) { - std::ignore = light; - SceneData data(camera->getScene(), camera, sceneFlags, LightInfo{}); +void NativeSceneBuilder::useLightFrustum( + IntrusivePtr light, uint32_t csmLevel, const scene::Camera *optCamera) { + auto &sceneData = get(SceneTag{}, nodeID, *renderGraph); + sceneData.light.light = light; + sceneData.light.level = csmLevel; + sceneData.light.culledByLight = true; + if (optCamera) { + sceneData.camera = optCamera; + } - auto sceneID = addVertex2( + // Disable camera frustum projection + sceneData.cullingFlags &= ~CullingFlags::CAMERA_FRUSTUM; + + // Enable light frustum projection + sceneData.cullingFlags |= CullingFlags::LIGHT_FRUSTUM; + + if (any(sceneData.flags & SceneFlags::NON_BUILTIN)) { + return; + } + + switch (light->getType()) { + case scene::LightType::DIRECTIONAL: { + setBuiltinDirectionalLightFrustumConstants( + sceneData.camera, dynamic_cast(light.get()), csmLevel); + } break; + case scene::LightType::SPOT: { + setBuiltinSpotLightFrustumConstants( + dynamic_cast(light.get())); + } break; + default: + // noop + break; + } +} + +SceneBuilder *NativeRenderQueueBuilder::addScene( + const scene::Camera *camera, SceneFlags sceneFlags, scene::Light *light) { + const auto sceneID = addVertex2( SceneTag{}, std::forward_as_tuple("Scene"), std::forward_as_tuple(), std::forward_as_tuple(), std::forward_as_tuple(), - std::forward_as_tuple(std::move(data)), + std::forward_as_tuple( + camera->getScene(), // Scene and camera should be decoupled. + camera, // They are coupled for now. + sceneFlags, + LightInfo{nullptr, 0}, + // Objects are projected to camera by default and are culled further if light is available. + light ? CullingFlags::CAMERA_FRUSTUM | CullingFlags::LIGHT_BOUNDS + : CullingFlags::CAMERA_FRUSTUM, + light), *renderGraph, nodeID); CC_ENSURES(sceneID != RenderGraph::null_vertex()); + auto builder = std::make_unique( + pipelineRuntime, + renderGraph, + sceneID, + layoutGraph, + layoutID); + + if (!any(sceneFlags & SceneFlags::NON_BUILTIN)) { + // objects are projected to camera, set camera ubo + builder->setBuiltinCameraConstants(camera); + + if (light) { + switch (light->getType()) { + case scene::LightType::DIRECTIONAL: { + const auto *pDirLight = dynamic_cast(light); + builder->setBuiltinDirectionalLightConstants(pDirLight, camera); + } break; + case scene::LightType::SPHERE: { + const auto *pSphereLight = dynamic_cast(light); + builder->setBuiltinSphereLightConstants(pSphereLight, camera); + } break; + case scene::LightType::SPOT: { + const auto *pSpotLight = dynamic_cast(light); + builder->setBuiltinSpotLightConstants(pSpotLight, camera); + } break; + case scene::LightType::POINT: { + const auto *pPointLight = dynamic_cast(light); + builder->setBuiltinPointLightConstants(pPointLight, camera); + } break; + default: + // noop + break; + } + } + + // set builtin legacy ubo + auto &data = get(RenderGraph::DataTag{}, *renderGraph, sceneID); + setLegacyTextureUBOView( + *pipelineRuntime->getDevice(), + *layoutGraph, + *pipelineRuntime->getPipelineSceneData(), + data); + } + if (any(sceneFlags & SceneFlags::GPU_DRIVEN)) { const auto passID = renderGraph->getPassID(nodeID); - const auto cullingID = dynamic_cast(pipelineRuntime)->nativeContext.sceneCulling.gpuCullingPassID; + const auto cullingID = dynamic_cast(pipelineRuntime)->nativeContext.sceneCulling.gpuCullingPassID; CC_EXPECTS(cullingID != 0xFFFFFFFF); if (holds(passID, *renderGraph)) { ccstd::pmr::string drawIndirectBuffer("CCDrawIndirectBuffer"); @@ -760,14 +868,14 @@ void NativeRenderQueueBuilder::addScene(const scene::Camera *camera, SceneFlags ccstd::pmr::string drawInstanceBuffer("CCDrawInstanceBuffer"); drawInstanceBuffer.append(std::to_string(cullingID)); - auto& rasterPass = get(RasterPassTag{}, passID, *renderGraph); + auto &rasterPass = get(RasterPassTag{}, passID, *renderGraph); if (rasterPass.computeViews.find(drawIndirectBuffer) != rasterPass.computeViews.end()) { auto res = rasterPass.computeViews.emplace( std::piecewise_construct, std::forward_as_tuple(drawIndirectBuffer), std::forward_as_tuple()); CC_ENSURES(res.second); - auto& view = res.first->second.emplace_back(); + auto &view = res.first->second.emplace_back(); view.name = "CCDrawIndirectBuffer"; view.accessType = AccessType::READ; view.shaderStageFlags = gfx::ShaderStageFlagBit::VERTEX | gfx::ShaderStageFlagBit::FRAGMENT; @@ -778,49 +886,15 @@ void NativeRenderQueueBuilder::addScene(const scene::Camera *camera, SceneFlags std::forward_as_tuple(drawInstanceBuffer), std::forward_as_tuple()); CC_ENSURES(res.second); - auto& view = res.first->second.emplace_back(); + auto &view = res.first->second.emplace_back(); view.name = "CCDrawInstanceBuffer"; view.accessType = AccessType::READ; view.shaderStageFlags = gfx::ShaderStageFlagBit::VERTEX | gfx::ShaderStageFlagBit::FRAGMENT; } } } -} -void NativeRenderQueueBuilder::addSceneCulledByDirectionalLight( - const scene::Camera *camera, SceneFlags sceneFlags, - scene::DirectionalLight *light, uint32_t level) { - CC_EXPECTS(light); - CC_EXPECTS(light->getType() != scene::LightType::UNKNOWN); - SceneData data(camera->getScene(), camera, sceneFlags, LightInfo{light, level}); - - auto sceneID = addVertex2( - SceneTag{}, - std::forward_as_tuple("Scene"), - std::forward_as_tuple(), - std::forward_as_tuple(), - std::forward_as_tuple(), - std::forward_as_tuple(std::move(data)), - *renderGraph, nodeID); - CC_ENSURES(sceneID != RenderGraph::null_vertex()); -} - -void NativeRenderQueueBuilder::addSceneCulledBySpotLight( - const scene::Camera *camera, SceneFlags sceneFlags, - scene::SpotLight *light) { - CC_EXPECTS(light); - CC_EXPECTS(light->getType() != scene::LightType::UNKNOWN); - SceneData data(camera->getScene(), camera, sceneFlags, LightInfo{light, 0}); - - auto sceneID = addVertex2( - SceneTag{}, - std::forward_as_tuple("Scene"), - std::forward_as_tuple(), - std::forward_as_tuple(), - std::forward_as_tuple(), - std::forward_as_tuple(std::move(data)), - *renderGraph, nodeID); - CC_ENSURES(sceneID != RenderGraph::null_vertex()); + return builder.release(); } void NativeRenderQueueBuilder::addFullscreenQuad( diff --git a/native/cocos/renderer/pipeline/custom/NativeRenderQueue.cpp b/native/cocos/renderer/pipeline/custom/NativeRenderQueue.cpp index 3f95918ac34..d4b4f4c9d69 100644 --- a/native/cocos/renderer/pipeline/custom/NativeRenderQueue.cpp +++ b/native/cocos/renderer/pipeline/custom/NativeRenderQueue.cpp @@ -26,13 +26,83 @@ #include #include "NativePipelineTypes.h" #include "cocos/renderer/pipeline/Define.h" +#include "cocos/renderer/pipeline/InstancedBuffer.h" #include "cocos/renderer/pipeline/PipelineStateManager.h" +#include "cocos/renderer/pipeline/custom/LayoutGraphGraphs.h" #include "cocos/renderer/pipeline/custom/details/GslUtils.h" namespace cc { namespace render { +LayoutGraphData::vertex_descriptor ProbeHelperQueue::getDefaultId(const LayoutGraphData &lg) { + const auto passID = locate(LayoutGraphData::null_vertex(), "default", lg); + CC_ENSURES(passID != LayoutGraphData::null_vertex()); + const auto phaseID = locate(passID, "default", lg); + CC_ENSURES(phaseID != LayoutGraphData::null_vertex()); + return phaseID; +} + +void ProbeHelperQueue::removeMacro() const { + for (auto *subModel : probeMap) { + std::vector patches; + patches.insert(patches.end(), subModel->getPatches().begin(), subModel->getPatches().end()); + + for (int j = 0; j != patches.size(); ++j) { + const cc::scene::IMacroPatch &patch = patches[j]; + if (patch.name == "CC_USE_RGBE_OUTPUT") { + patches.erase(patches.begin() + j); + break; + } + } + + subModel->onMacroPatchesStateChanged(patches); + } +} + +uint32_t ProbeHelperQueue::getPassIndexFromLayout( + const cc::IntrusivePtr &subModel, + LayoutGraphData::vertex_descriptor phaseLayoutId) { + const auto &passes = subModel->getPasses(); + for (uint32_t k = 0; k != passes->size(); ++k) { + if (passes->at(k)->getPhaseID() == phaseLayoutId) { + return static_cast(k); + } + } + return 0xFFFFFFFF; +} + +void ProbeHelperQueue::applyMacro( + const LayoutGraphData &lg, const cc::scene::Model &model, + LayoutGraphData::vertex_descriptor probeLayoutId) { + const std::vector> &subModels = model.getSubModels(); + for (const auto &subModel : subModels) { + const bool isTransparent = subModel->getPasses()->at(0)->getBlendState()->targets[0].blend; + if (isTransparent) { + continue; + } + + auto passIdx = getPassIndexFromLayout(subModel, probeLayoutId); + bool bUseReflectPass = true; + if (passIdx < 0) { + probeLayoutId = getDefaultId(lg); + passIdx = getPassIndexFromLayout(subModel, probeLayoutId); + bUseReflectPass = false; + } + if (passIdx < 0) { + continue; + } + if (!bUseReflectPass) { + std::vector patches; + patches.insert(patches.end(), subModel->getPatches().begin(), subModel->getPatches().end()); + const cc::scene::IMacroPatch useRGBEPatch = {"CC_USE_RGBE_OUTPUT", true}; + patches.emplace_back(useRGBEPatch); + subModel->onMacroPatchesStateChanged(patches); + probeMap.emplace_back(subModel); + } + } +} + // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) void RenderDrawQueue::add(const scene::Model &model, float depth, uint32_t subModelIdx, uint32_t passIdx) { const auto *subModel = model.getSubModels()[subModelIdx].get(); @@ -62,9 +132,9 @@ void RenderDrawQueue::sortTransparent() { } void RenderDrawQueue::recordCommandBuffer( - gfx::Device * /*device*/, const scene::Camera * /*camera*/, - gfx::RenderPass *renderPass, gfx::CommandBuffer *cmdBuff, - uint32_t subpassIndex) const { + gfx::RenderPass *renderPass, uint32_t subpassIndex, + gfx::CommandBuffer *cmdBuff, + uint32_t lightByteOffset) const { for (const auto &instance : instances) { const auto *subModel = instance.subModel; @@ -76,7 +146,11 @@ void RenderDrawQueue::recordCommandBuffer( cmdBuff->bindPipelineState(pso); cmdBuff->bindDescriptorSet(pipeline::materialSet, pass->getDescriptorSet()); - cmdBuff->bindDescriptorSet(pipeline::localSet, subModel->getDescriptorSet()); + if (lightByteOffset != 0xFFFFFFFF) { + cmdBuff->bindDescriptorSet(pipeline::localSet, subModel->getDescriptorSet(), 1, &lightByteOffset); + } else { + cmdBuff->bindDescriptorSet(pipeline::localSet, subModel->getDescriptorSet()); + } cmdBuff->bindInputAssembler(inputAssembler); cmdBuff->draw(inputAssembler); } @@ -138,8 +212,9 @@ void RenderInstancingQueue::uploadBuffers(gfx::CommandBuffer *cmdBuffer) const { } void RenderInstancingQueue::recordCommandBuffer( - gfx::RenderPass *renderPass, gfx::CommandBuffer *cmdBuffer, - gfx::DescriptorSet *ds, uint32_t offset, const ccstd::vector *dynamicOffsets) const { + gfx::RenderPass *renderPass, uint32_t subpassIndex, + gfx::CommandBuffer *cmdBuffer, + uint32_t lightByteOffset) const { // const auto &renderQueue = sortedBatches; for (const auto *instanceBuffer : renderQueue) { if (!instanceBuffer->hasPendingModels()) { @@ -154,16 +229,13 @@ void RenderInstancingQueue::recordCommandBuffer( continue; } auto *pso = pipeline::PipelineStateManager::getOrCreatePipelineState( - drawPass, instance.shader, instance.ia, renderPass); + drawPass, instance.shader, instance.ia, renderPass, subpassIndex); if (lastPSO != pso) { cmdBuffer->bindPipelineState(pso); lastPSO = pso; } - if (ds) { - cmdBuffer->bindDescriptorSet(pipeline::globalSet, ds, 1, &offset); - } - if (dynamicOffsets) { - cmdBuffer->bindDescriptorSet(pipeline::localSet, instance.descriptorSet, *dynamicOffsets); + if (lightByteOffset != 0xFFFFFFFF) { + cmdBuffer->bindDescriptorSet(pipeline::localSet, instance.descriptorSet, 1, &lightByteOffset); } else { cmdBuffer->bindDescriptorSet(pipeline::localSet, instance.descriptorSet, instanceBuffer->dynamicOffsets()); } @@ -180,6 +252,20 @@ void NativeRenderQueue::sort() { transparentInstancingQueue.sort(); } +void NativeRenderQueue::recordCommands( + gfx::CommandBuffer *cmdBuffer, + gfx::RenderPass *renderPass, + uint32_t subpassIndex) const { + opaqueQueue.recordCommandBuffer( + renderPass, subpassIndex, cmdBuffer, lightByteOffset); + opaqueInstancingQueue.recordCommandBuffer( + renderPass, subpassIndex, cmdBuffer, lightByteOffset); + transparentQueue.recordCommandBuffer( + renderPass, subpassIndex, cmdBuffer, lightByteOffset); + transparentInstancingQueue.recordCommandBuffer( + renderPass, subpassIndex, cmdBuffer, lightByteOffset); +} + } // namespace render } // namespace cc diff --git a/native/cocos/renderer/pipeline/custom/NativeResourceGraph.cpp b/native/cocos/renderer/pipeline/custom/NativeResourceGraph.cpp index 750616d549a..736283688ab 100644 --- a/native/cocos/renderer/pipeline/custom/NativeResourceGraph.cpp +++ b/native/cocos/renderer/pipeline/custom/NativeResourceGraph.cpp @@ -143,12 +143,12 @@ gfx::TextureInfo getTextureInfo(const ResourceDesc& desc) { }; } -gfx::TextureViewInfo getTextureViewInfo(const SubresourceView& subresView) { +gfx::TextureViewInfo getTextureViewInfo(const SubresourceView& subresView, gfx::TextureType viewType) { using namespace gfx; // NOLINT(google-build-using-namespace) return { nullptr, - subresView.viewType, + viewType, subresView.format, subresView.indexOrFirstMipLevel, subresView.numMipLevels, @@ -207,12 +207,12 @@ void ResourceGraph::mount(gfx::Device* device, vertex_descriptor vertID) { CC_ENSURES(texture.texture); texture.fenceValue = nextFenceValue; }, - [&](const IntrusivePtr& buffer) { - CC_EXPECTS(buffer); + [&](const PersistentBuffer& buffer) { + CC_EXPECTS(buffer.buffer); std::ignore = buffer; }, - [&](const IntrusivePtr& texture) { - CC_EXPECTS(texture); + [&](const PersistentTexture& texture) { + CC_EXPECTS(texture.texture); std::ignore = texture; }, [&](const IntrusivePtr& fb) { @@ -252,7 +252,8 @@ void ResourceGraph::mount(gfx::Device* device, vertex_descriptor vertID) { mount(device, parentID); // NOLINT(misc-no-recursion) auto* parentTexture = resg.getTexture(parentID); if (!view.textureView) { - auto textureViewInfo = getTextureViewInfo(originView); + const auto& desc = get(ResourceGraph::DescTag{}, resg, vertID); + auto textureViewInfo = getTextureViewInfo(originView, desc.viewType); textureViewInfo.texture = parentTexture; view.textureView = device->createTexture(textureViewInfo); } diff --git a/native/cocos/renderer/pipeline/custom/NativeSceneCulling.cpp b/native/cocos/renderer/pipeline/custom/NativeSceneCulling.cpp index 0b9a2865259..2b6cf72cf8c 100644 --- a/native/cocos/renderer/pipeline/custom/NativeSceneCulling.cpp +++ b/native/cocos/renderer/pipeline/custom/NativeSceneCulling.cpp @@ -1,17 +1,26 @@ +#include "cocos/renderer/pipeline/Define.h" +#include "cocos/renderer/pipeline/custom/LayoutGraphUtils.h" +#include "cocos/renderer/pipeline/custom/NativeBuiltinUtils.h" #include "cocos/renderer/pipeline/custom/NativePipelineTypes.h" #include "cocos/renderer/pipeline/custom/NativeRenderGraphUtils.h" #include "cocos/renderer/pipeline/custom/details/GslUtils.h" #include "cocos/renderer/pipeline/custom/details/Range.h" #include "cocos/scene/Octree.h" +#include "cocos/scene/ReflectionProbe.h" #include "cocos/scene/RenderScene.h" #include "cocos/scene/Skybox.h" #include "cocos/scene/SpotLight.h" +#include + namespace cc { namespace render { +const static uint32_t REFLECTION_PROBE_DEFAULT_MASK = ~static_cast(pipeline::LayerList::UI_2D) & ~static_cast(pipeline::LayerList::PROFILER) & ~static_cast(pipeline::LayerList::UI_3D) & ~static_cast(pipeline::LayerList::GIZMOS) & ~static_cast(pipeline::LayerList::SCENE_GIZMO) & ~static_cast(pipeline::LayerList::EDITOR); + void NativeRenderQueue::clear() noexcept { + probeQueue.clear(); opaqueQueue.instances.clear(); transparentQueue.instances.clear(); opaqueInstancingQueue.clear(); @@ -27,43 +36,84 @@ bool NativeRenderQueue::empty() const noexcept { transparentInstancingQueue.empty(); } -uint32_t SceneCulling::getOrCreateSceneCullingQuery(const SceneData& sceneData) { +FrustumCullingID SceneCulling::getOrCreateFrustumCulling(const SceneData& sceneData) { const auto* const scene = sceneData.scene; // get or add scene to queries - auto& queries = sceneQueries[scene]; + auto& queries = frustumCullings[scene]; // check cast shadow const bool bCastShadow = any(sceneData.flags & SceneFlags::SHADOW_CASTER); // get or create query source // make query key - const auto key = CullingKey{ + const auto key = FrustumCullingKey{ sceneData.camera, + sceneData.light.probe, sceneData.light.light, - bCastShadow, sceneData.light.level, + bCastShadow, }; // find query source - auto iter = queries.culledResultIndex.find(key); - if (iter == queries.culledResultIndex.end()) { + auto iter = queries.resultIndex.find(key); + if (iter == queries.resultIndex.end()) { // create query source // make query source id - const auto sourceID = numCullingQueries++; - if (numCullingQueries > culledResults.size()) { + const FrustumCullingID frustomCulledResultID{numFrustumCulling++}; + if (numFrustumCulling > frustumCullingResults.size()) { // space is not enough, create query source - CC_EXPECTS(numCullingQueries == culledResults.size() + 1); - culledResults.emplace_back(); + CC_EXPECTS(numFrustumCulling == frustumCullingResults.size() + 1); + frustumCullingResults.emplace_back(); } // add query source to query index bool added = false; - std::tie(iter, added) = queries.culledResultIndex.emplace(key, sourceID); + std::tie(iter, added) = queries.resultIndex.emplace(key, frustomCulledResultID); CC_ENSURES(added); } return iter->second; } -uint32_t SceneCulling::createRenderQueue( +LightBoundsCullingID SceneCulling::getOrCreateLightBoundsCulling( + const SceneData& sceneData, FrustumCullingID frustumCullingID) { + if (!any(sceneData.cullingFlags & CullingFlags::LIGHT_BOUNDS)) { + return {}; + } + + CC_EXPECTS(sceneData.shadingLight); + const auto* const scene = sceneData.scene; + CC_EXPECTS(scene); + + auto& queries = lightBoundsCullings[scene]; + + // get or create query source + // make query key + const auto key = LightBoundsCullingKey{ + frustumCullingID, + sceneData.camera, + sceneData.light.probe, + sceneData.shadingLight, + }; + + // find query source + auto iter = queries.resultIndex.find(key); + if (iter == queries.resultIndex.end()) { + // create query source + // make query source id + const LightBoundsCullingID lightBoundsCullingID{numLightBoundsCulling++}; + if (numLightBoundsCulling > lightBoundsCullingResults.size()) { + // space is not enough, create query source + CC_EXPECTS(numLightBoundsCulling == lightBoundsCullingResults.size() + 1); + lightBoundsCullingResults.emplace_back(); + } + // add query source to query index + bool added = false; + std::tie(iter, added) = queries.resultIndex.emplace(key, lightBoundsCullingID); + CC_ENSURES(added); + } + return iter->second; +} + +NativeRenderQueueID SceneCulling::createRenderQueue( SceneFlags sceneFlags, LayoutGraphData::vertex_descriptor subpassOrPassLayoutID) { const auto targetID = numRenderQueues++; if (numRenderQueues > renderQueues.size()) { @@ -77,7 +127,7 @@ uint32_t SceneCulling::createRenderQueue( CC_EXPECTS(rq.subpassOrPassLayoutID == 0xFFFFFFFF); rq.sceneFlags = sceneFlags; rq.subpassOrPassLayoutID = subpassOrPassLayoutID; - return targetID; + return NativeRenderQueueID{targetID}; } void SceneCulling::collectCullingQueries( @@ -91,7 +141,8 @@ void SceneCulling::collectCullingQueries( CC_EXPECTS(false); continue; } - const auto sourceID = getOrCreateSceneCullingQuery(sceneData); + const auto frustomCulledResultID = getOrCreateFrustumCulling(sceneData); + const auto lightBoundsCullingID = getOrCreateLightBoundsCulling(sceneData, frustomCulledResultID); const auto layoutID = getSubpassOrPassID(vertID, rg, lg); const auto targetID = createRenderQueue(sceneData.flags, layoutID); const auto lightType = sceneData.light.light @@ -99,12 +150,23 @@ void SceneCulling::collectCullingQueries( : scene::LightType::UNKNOWN; // add render queue to query source - sceneQueryIndex.emplace(vertID, NativeRenderQueueDesc(sourceID, targetID, lightType)); + renderQueueIndex.emplace( + vertID, + NativeRenderQueueDesc{ + frustomCulledResultID, + lightBoundsCullingID, + targetID, + lightType, + }); } } namespace { -const pipeline::PipelineSceneData* pSceneData = nullptr; + +const pipeline::PipelineSceneData* kPipelineSceneData = nullptr; + +const LayoutGraphData* kLayoutGraph = nullptr; + bool isNodeVisible(const Node* node, uint32_t visibility) { return node && ((visibility & node->getLayer()) == node->getLayer()); } @@ -113,46 +175,46 @@ uint32_t isModelVisible(const scene::Model& model, uint32_t visibility) { return visibility & static_cast(model.getVisFlags()); } +bool isReflectProbeMask(const scene::Model& model) { + return ((model.getNode()->getLayer() & REFLECTION_PROBE_DEFAULT_MASK) == model.getNode()->getLayer()) || (REFLECTION_PROBE_DEFAULT_MASK & static_cast(model.getVisFlags())); +} + +bool isIntersectAABB(const geometry::AABB& lAABB, const geometry::AABB& rAABB) { + return !lAABB.aabbAabb(rAABB); +} + bool isFrustumVisible(const scene::Model& model, const geometry::Frustum& frustum, bool castShadow) { const auto* const modelWorldBounds = model.getWorldBounds(); if (!modelWorldBounds) { - return true; + return false; } geometry::AABB transWorldBounds{}; transWorldBounds.set(modelWorldBounds->getCenter(), modelWorldBounds->getHalfExtents()); - const scene::Shadows& shadows = *pSceneData->getShadows(); + const scene::Shadows& shadows = *kPipelineSceneData->getShadows(); if (shadows.getType() == scene::ShadowType::PLANAR && castShadow) { modelWorldBounds->transform(shadows.getMatLight(), &transWorldBounds); } - return transWorldBounds.aabbFrustum(frustum); + return !transWorldBounds.aabbFrustum(frustum); } void octreeCulling( const scene::Octree& octree, - const scene::Model* skyboxModelToSkip, + const scene::Model* skyboxModel, const scene::RenderScene& scene, const scene::Camera& camera, const geometry::Frustum& cameraOrLightFrustum, bool bCastShadow, ccstd::vector& models) { const auto visibility = camera.getVisibility(); + const auto camSkyboxFlag = (static_cast(camera.getClearFlag()) & scene::Camera::SKYBOX_FLAG); + if (!bCastShadow && skyboxModel && camSkyboxFlag) { + models.emplace_back(skyboxModel); + } // add instances without world bounds for (const auto& pModel : scene.getModels()) { CC_EXPECTS(pModel); const auto& model = *pModel; - if (!model.isEnabled()) { - continue; - } - // has world bounds, should be in octree - if (model.getWorldBounds()) { - continue; - } - // is skybox, skip - if (&model == skyboxModelToSkip) { - continue; - } - // check cast shadow - if (bCastShadow && !model.isCastShadow()) { + if (!model.isEnabled() || !model.getNode() || model.getWorldBounds() || (bCastShadow && !model.isCastShadow())) { continue; } // filter model by view visibility @@ -173,113 +235,117 @@ void octreeCulling( } void bruteForceCulling( - const scene::Model* skyboxModelToSkip, + const scene::Model* skyboxModel, const scene::RenderScene& scene, const scene::Camera& camera, const geometry::Frustum& cameraOrLightFrustum, bool bCastShadow, + const scene::ReflectionProbe* probe, ccstd::vector& models) { const auto visibility = camera.getVisibility(); + const auto camSkyboxFlag = (static_cast(camera.getClearFlag()) & scene::Camera::SKYBOX_FLAG); + if (!bCastShadow && skyboxModel && camSkyboxFlag) { + models.emplace_back(skyboxModel); + } for (const auto& pModel : scene.getModels()) { CC_EXPECTS(pModel); const auto& model = *pModel; - if (!model.isEnabled()) { + if (!model.isEnabled() || !model.getNode() || (bCastShadow && !model.isCastShadow())) { continue; } - if (bCastShadow && !model.isCastShadow()) { + // lod culling + if (scene.isCulledByLod(&camera, &model)) { continue; } - // filter model by view visibility - if (isNodeVisible(model.getNode(), visibility) || isModelVisible(model, visibility)) { - // frustum culling - if (!isFrustumVisible(model, cameraOrLightFrustum, bCastShadow)) { - continue; - } - // is skybox, skip - if (&model == skyboxModelToSkip) { - continue; - } - // lod culling - if (scene.isCulledByLod(&camera, &model)) { - continue; + if (!probe || (probe && probe->getProbeType() == cc::scene::ReflectionProbe::ProbeType::CUBE)) { + // filter model by view visibility + if (isNodeVisible(model.getNode(), visibility) || isModelVisible(model, visibility)) { + const auto* const wBounds = model.getWorldBounds(); + // frustum culling + if (wBounds && ((!probe && isFrustumVisible(model, cameraOrLightFrustum, bCastShadow)) || + (probe && isIntersectAABB(*wBounds, *probe->getBoundingBox())))) { + continue; + } + + models.emplace_back(&model); } + } else if (isReflectProbeMask(model)) { models.emplace_back(&model); } } } void sceneCulling( - const scene::Model* skyboxModelToSkip, + const scene::Model* skyboxModel, const scene::RenderScene& scene, const scene::Camera& camera, const geometry::Frustum& cameraOrLightFrustum, bool bCastShadow, + const scene::ReflectionProbe* probe, ccstd::vector& models) { const auto* const octree = scene.getOctree(); - if (octree && octree->isEnabled()) { + if (octree && octree->isEnabled() && !probe) { octreeCulling( - *octree, skyboxModelToSkip, + *octree, skyboxModel, scene, camera, cameraOrLightFrustum, bCastShadow, models); } else { bruteForceCulling( - skyboxModelToSkip, - scene, camera, cameraOrLightFrustum, bCastShadow, models); + skyboxModel, + scene, camera, cameraOrLightFrustum, bCastShadow, probe, models); } } } // namespace -void SceneCulling::batchCulling(const pipeline::PipelineSceneData& pplSceneData) { +void SceneCulling::batchFrustumCulling(const NativePipeline& ppl) { + const auto& pplSceneData = *ppl.getPipelineSceneData(); const auto* const skybox = pplSceneData.getSkybox(); - const auto* const skyboxModelToSkip = skybox ? skybox->getModel() : nullptr; + const auto* const skyboxModel = skybox && skybox->isEnabled() ? skybox->getModel() : nullptr; - for (const auto& [scene, queries] : sceneQueries) { + for (const auto& [scene, queries] : frustumCullings) { CC_ENSURES(scene); - for (const auto& [key, sourceID] : queries.culledResultIndex) { + for (const auto& [key, frustomCulledResultID] : queries.resultIndex) { CC_EXPECTS(key.camera); CC_EXPECTS(key.camera->getScene() == scene); - const auto& camera = *key.camera; const auto* light = key.light; const auto level = key.lightLevel; const auto bCastShadow = key.castShadow; + const auto* probe = key.probe; + const auto& camera = probe ? *probe->getCamera() : *key.camera; + CC_EXPECTS(frustomCulledResultID.value < frustumCullingResults.size()); + auto& models = frustumCullingResults[frustomCulledResultID.value]; - CC_EXPECTS(sourceID < culledResults.size()); - auto& models = culledResults[sourceID]; + if (probe) { + sceneCulling( + skyboxModel, + *scene, camera, + camera.getFrustum(), + bCastShadow, + probe, + models); + continue; + } if (light) { switch (light->getType()) { case scene::LightType::SPOT: sceneCulling( - skyboxModelToSkip, + skyboxModel, *scene, camera, dynamic_cast(light)->getFrustum(), bCastShadow, + nullptr, models); break; case scene::LightType::DIRECTIONAL: { - auto& csmLayers = *pplSceneData.getCSMLayers(); const auto* mainLight = dynamic_cast(light); - const auto& csmLevel = mainLight->getCSMLevel(); - const geometry::Frustum* frustum = nullptr; - const auto& shadows = *pplSceneData.getShadows(); - if (shadows.getType() == scene::ShadowType::PLANAR) { - frustum = &camera.getFrustum(); - } else { - if (shadows.isEnabled() && shadows.getType() == scene::ShadowType::SHADOW_MAP && mainLight && mainLight->getNode()) { - csmLayers.update(&pplSceneData, &camera); - } - // const - if (mainLight->isShadowFixedArea() || csmLevel == scene::CSMLevel::LEVEL_1) { - frustum = &csmLayers.getSpecialLayer()->getValidFrustum(); - } else { - frustum = &csmLayers.getLayers()[level]->getValidFrustum(); - } - } + const auto& frustum = getBuiltinShadowFrustum(ppl, camera, mainLight, level); sceneCulling( - skyboxModelToSkip, + skyboxModel, *scene, camera, - *frustum, + frustum, bCastShadow, + nullptr, models); } break; default: @@ -288,10 +354,11 @@ void SceneCulling::batchCulling(const pipeline::PipelineSceneData& pplSceneData) } } else { sceneCulling( - skyboxModelToSkip, + skyboxModel, *scene, camera, camera.getFrustum(), bCastShadow, + nullptr, models); } } @@ -299,6 +366,112 @@ void SceneCulling::batchCulling(const pipeline::PipelineSceneData& pplSceneData) } namespace { + +void executeSphereLightCulling( + const scene::SphereLight& light, + const ccstd::vector& frustumCullingResult, + ccstd::vector& lightBoundsCullingResult) { + const auto& lightAABB = light.getAABB(); + for (const auto* const model : frustumCullingResult) { + CC_EXPECTS(model); + const auto* const modelBounds = model->getWorldBounds(); + if (!modelBounds || modelBounds->aabbAabb(lightAABB)) { + lightBoundsCullingResult.emplace_back(model); + } + } +} + +void executeSpotLightCulling( + const scene::SpotLight& light, + const ccstd::vector& frustumCullingResult, + ccstd::vector& lightBoundsCullingResult) { + const auto& lightAABB = light.getAABB(); + const auto& lightFrustum = light.getFrustum(); + for (const auto* const model : frustumCullingResult) { + CC_EXPECTS(model); + const auto* const modelBounds = model->getWorldBounds(); + if (!modelBounds || (modelBounds->aabbAabb(lightAABB) && modelBounds->aabbFrustum(lightFrustum))) { + lightBoundsCullingResult.emplace_back(model); + } + } +} + +void executePointLightCulling( + const scene::PointLight& light, + const ccstd::vector& frustumCullingResult, + ccstd::vector& lightBoundsCullingResult) { + const auto& lightAABB = light.getAABB(); + for (const auto* const model : frustumCullingResult) { + CC_EXPECTS(model); + const auto* const modelBounds = model->getWorldBounds(); + if (!modelBounds || modelBounds->aabbAabb(lightAABB)) { + lightBoundsCullingResult.emplace_back(model); + } + } +} + +void executeRangedDirectionalLightCulling( + const scene::RangedDirectionalLight& light, + const ccstd::vector& frustumCullingResult, + ccstd::vector& lightBoundsCullingResult) { + const geometry::AABB rangedDirLightBoundingBox(0.0F, 0.0F, 0.0F, 0.5F, 0.5F, 0.5F); + // when execute render graph, we should never update world matrix + // light->getNode()->updateWorldTransform(); + geometry::AABB lightAABB{}; + rangedDirLightBoundingBox.transform(light.getNode()->getWorldMatrix(), &lightAABB); + for (const auto* const model : frustumCullingResult) { + CC_EXPECTS(model); + const auto* const modelBounds = model->getWorldBounds(); + if (!modelBounds || modelBounds->aabbAabb(lightAABB)) { + lightBoundsCullingResult.emplace_back(model); + } + } +} + +} // namespace + +void SceneCulling::batchLightBoundsCulling() { + for (const auto& [scene, queries] : lightBoundsCullings) { + CC_ENSURES(scene); + for (const auto& [key, cullingID] : queries.resultIndex) { + CC_EXPECTS(key.camera); + CC_EXPECTS(key.camera->getScene() == scene); + const auto& frustumCullingResult = frustumCullingResults.at(key.frustumCullingID.value); + auto& lightBoundsCullingResult = lightBoundsCullingResults.at(cullingID.value); + CC_EXPECTS(lightBoundsCullingResult.instances.empty()); + switch (key.cullingLight->getType()) { + case scene::LightType::SPHERE: { + const auto* light = dynamic_cast(key.cullingLight); + CC_ENSURES(light); + executeSphereLightCulling(*light, frustumCullingResult, lightBoundsCullingResult.instances); + } break; + case scene::LightType::SPOT: { + const auto* light = dynamic_cast(key.cullingLight); + CC_ENSURES(light); + executeSpotLightCulling(*light, frustumCullingResult, lightBoundsCullingResult.instances); + } break; + case scene::LightType::POINT: { + const auto* light = dynamic_cast(key.cullingLight); + CC_ENSURES(light); + executePointLightCulling(*light, frustumCullingResult, lightBoundsCullingResult.instances); + } break; + case scene::LightType::RANGED_DIRECTIONAL: { + const auto* light = dynamic_cast(key.cullingLight); + CC_ENSURES(light); + executeRangedDirectionalLightCulling(*light, frustumCullingResult, lightBoundsCullingResult.instances); + } break; + case scene::LightType::DIRECTIONAL: + case scene::LightType::UNKNOWN: + default: + // noop + break; + } + } + } +} + +namespace { + bool isBlend(const scene::Pass& pass) { bool bBlend = false; for (const auto& target : pass.getBlendState()->targets) { @@ -314,7 +487,8 @@ float computeSortingDepth(const scene::Camera& camera, const scene::Model& model if (model.getNode()) { const auto* node = model.getTransform(); Vec3 position; - Vec3::subtract(node->getWorldPosition(), camera.getPosition(), &position); + const auto* bounds = model.getWorldBounds(); + Vec3::subtract(bounds ? bounds->center : node->getWorldPosition(), camera.getPosition(), &position); depth = position.dot(camera.getForward()); } return depth; @@ -324,15 +498,23 @@ void addRenderObject( LayoutGraphData::vertex_descriptor phaseLayoutID, const bool bDrawOpaqueOrMask, const bool bDrawBlend, + const bool bDrawProbe, const scene::Camera& camera, const scene::Model& model, NativeRenderQueue& queue) { + if (bDrawProbe) { + queue.probeQueue.applyMacro(*kLayoutGraph, model, phaseLayoutID); + } const auto& subModels = model.getSubModels(); const auto subModelCount = subModels.size(); for (uint32_t subModelIdx = 0; subModelIdx < subModelCount; ++subModelIdx) { const auto& subModel = subModels[subModelIdx]; const auto& passes = *(subModel->getPasses()); const auto passCount = passes.size(); + auto probeIt = std::find(queue.probeQueue.probeMap.begin(), queue.probeQueue.probeMap.end(), subModel.get()); + if (probeIt != queue.probeQueue.probeMap.end()) { + phaseLayoutID = ProbeHelperQueue::getDefaultId(*kLayoutGraph); + } for (uint32_t passIdx = 0; passIdx < passCount; ++passIdx) { auto& pass = *passes[passIdx]; // check phase @@ -378,9 +560,10 @@ void addRenderObject( void SceneCulling::fillRenderQueues( const RenderGraph& rg, const pipeline::PipelineSceneData& pplSceneData) { const auto* const skybox = pplSceneData.getSkybox(); - for (auto&& [sceneID, desc] : sceneQueryIndex) { + for (auto&& [sceneID, desc] : renderQueueIndex) { CC_EXPECTS(holds(sceneID, rg)); - const auto sourceID = desc.culledSource; + const auto frustomCulledResultID = desc.frustumCulledResultID; + const auto lightBoundsCullingID = desc.lightBoundsCulledResultID; const auto targetID = desc.renderQueueTarget; const auto& sceneData = get(SceneTag{}, sceneID, rg); @@ -388,8 +571,8 @@ void SceneCulling::fillRenderQueues( const bool bDrawBlend = any(sceneData.flags & SceneFlags::TRANSPARENT_OBJECT); const bool bDrawOpaqueOrMask = any(sceneData.flags & (SceneFlags::OPAQUE_OBJECT | SceneFlags::CUTOUT_OBJECT)); const bool bDrawShadowCaster = any(sceneData.flags & SceneFlags::SHADOW_CASTER); - - if (!bDrawShadowCaster && !bDrawBlend && !bDrawOpaqueOrMask) { + const bool bDrawProbe = any(sceneData.flags & SceneFlags::REFLECTION_PROBE); + if (!bDrawShadowCaster && !bDrawBlend && !bDrawOpaqueOrMask && !bDrawProbe) { // nothing to draw continue; } @@ -402,37 +585,32 @@ void SceneCulling::fillRenderQueues( CC_EXPECTS(phaseLayoutID != LayoutGraphData::null_vertex()); // culling source - CC_EXPECTS(sourceID < culledResults.size()); - const auto& sourceModels = culledResults[sourceID]; + CC_EXPECTS(frustomCulledResultID.value < frustumCullingResults.size()); + const auto& sourceModels = [&]() -> const auto& { + // is culled by light bounds + if (lightBoundsCullingID.value != 0xFFFFFFFF) { + CC_EXPECTS(lightBoundsCullingID.value < lightBoundsCullingResults.size()); + return lightBoundsCullingResults.at(lightBoundsCullingID.value).instances; + } + // not culled by light bounds + return frustumCullingResults.at(frustomCulledResultID.value); + } + (); // native queue target - CC_EXPECTS(targetID < renderQueues.size()); - auto& nativeQueue = renderQueues[targetID]; + CC_EXPECTS(targetID.value < renderQueues.size()); + auto& nativeQueue = renderQueues[targetID.value]; CC_EXPECTS(nativeQueue.empty()); // skybox const auto* camera = sceneData.camera; CC_EXPECTS(camera); - if (!any(sceneData.flags & SceneFlags::SHADOW_CASTER) && - skybox && skybox->isEnabled() && - (static_cast(camera->getClearFlag()) & scene::Camera::SKYBOX_FLAG)) { - CC_EXPECTS(skybox->getModel()); - const auto& model = *skybox->getModel(); - const auto* node = model.getNode(); - float depth = 0; - if (node) { - Vec3 tempVec3{}; - tempVec3 = node->getWorldPosition() - camera->getPosition(); - depth = tempVec3.dot(camera->getForward()); - } - nativeQueue.opaqueQueue.add(model, depth, 0, 0); - } // fill native queue for (const auto* const model : sourceModels) { addRenderObject( phaseLayoutID, bDrawOpaqueOrMask, bDrawBlend, - *sceneData.camera, *model, nativeQueue); + bDrawProbe, *sceneData.camera, *model, nativeQueue); } // post-processing @@ -442,26 +620,188 @@ void SceneCulling::fillRenderQueues( void SceneCulling::buildRenderQueues( const RenderGraph& rg, const LayoutGraphData& lg, - const pipeline::PipelineSceneData& pplSceneData) { - pSceneData = &pplSceneData; + const NativePipeline& ppl) { + kPipelineSceneData = ppl.pipelineSceneData; + kLayoutGraph = ≶ collectCullingQueries(rg, lg); - batchCulling(pplSceneData); - fillRenderQueues(rg, pplSceneData); + batchFrustumCulling(ppl); + batchLightBoundsCulling(); // cull frustum-culling's results by light bounds + fillRenderQueues(rg, *ppl.pipelineSceneData); } void SceneCulling::clear() noexcept { - sceneQueries.clear(); - for (auto& c : culledResults) { + // frustum culling + frustumCullings.clear(); + for (auto& c : frustumCullingResults) { c.clear(); } + // light bounds culling + lightBoundsCullings.clear(); + for (auto& c : lightBoundsCullingResults) { + c.instances.clear(); + c.lightByteOffset = 0xFFFFFFFF; + } + // native render queues for (auto& q : renderQueues) { q.clear(); } - sceneQueryIndex.clear(); - numCullingQueries = 0; + + // clear render graph scene vertex query index + renderQueueIndex.clear(); + // do not clear this->renderQueues, it is reused to avoid memory allocation + + // reset all counters + numFrustumCulling = 0; + numLightBoundsCulling = 0; numRenderQueues = 0; } +void LightResource::init(const NativeProgramLibrary& programLib, gfx::Device* deviceIn, uint32_t maxNumLightsIn) { + CC_EXPECTS(!device); + device = deviceIn; + programLibrary = &programLib; + + const auto& instanceLayout = programLibrary->localLayoutData; + const auto attrID = at(programLib.layoutGraph.attributeIndex, std::string_view{"CCForwardLight"}); + const auto& uniformBlock = instanceLayout.uniformBlocks.at(attrID); + + elementSize = boost::alignment::align_up( + getUniformBlockSize(uniformBlock.members), + device->getCapabilities().uboOffsetAlignment); + maxNumLights = maxNumLightsIn; + binding = programLib.localLayoutData.bindingMap.at(attrID); + + const auto bufferSize = elementSize * maxNumLights; + + lightBuffer = device->createBuffer(gfx::BufferInfo{ + gfx::BufferUsageBit::UNIFORM | gfx::BufferUsageBit::TRANSFER_DST, + gfx::MemoryUsageBit::HOST | gfx::MemoryUsageBit::DEVICE, + bufferSize, + elementSize, + }); + firstLightBufferView = device->createBuffer({lightBuffer, 0, elementSize}); + + cpuBuffer.resize(bufferSize); + lights.reserve(maxNumLights); + lightIndex.reserve(maxNumLights); + + CC_ENSURES(elementSize); + CC_ENSURES(maxNumLights); + + resized = true; +} + +uint32_t LightResource::addLight( + const scene::Light* light, + bool bHDR, + float exposure, + const scene::Shadows* shadowInfo) { + // already added + auto iter = lightIndex.find(light); + if (iter != lightIndex.end()) { + return iter->second; + } + + // resize buffer + if (lights.size() == maxNumLights) { + resized = true; + maxNumLights *= 2; + const auto bufferSize = elementSize * maxNumLights; + lightBuffer->resize(bufferSize); + firstLightBufferView = device->createBuffer({lightBuffer, 0, elementSize}); + cpuBuffer.resize(bufferSize); + lights.reserve(maxNumLights); + lightIndex.reserve(maxNumLights); + } + CC_ENSURES(lights.size() < maxNumLights); + + // add light + const auto lightID = static_cast(lights.size()); + lights.emplace_back(light); + auto res = lightIndex.emplace(light, lightID); + CC_ENSURES(res.second); + + // update buffer + const auto offset = elementSize * lightID; + setLightUBO(light, bHDR, exposure, shadowInfo, cpuBuffer.data() + offset, elementSize); + + return lightID * elementSize; +} + +void LightResource::buildLights( + SceneCulling& sceneCulling, + bool bHDR, + const scene::Shadows* shadowInfo) { + // build light buffer + for (const auto& [scene, lightBoundsCullings] : sceneCulling.lightBoundsCullings) { + for (const auto& [key, lightBoundsCullingID] : lightBoundsCullings.resultIndex) { + float exposure = 1.0F; + if (key.camera) { + exposure = key.camera->getExposure(); + } else if (key.probe && key.probe->getCamera()) { + exposure = key.probe->getCamera()->getExposure(); + } else { + CC_EXPECTS(false); + } + const auto lightByteOffset = addLight( + key.cullingLight, + bHDR, + exposure, + shadowInfo); + + // save light byte offset for each light bounds culling + auto& result = sceneCulling.lightBoundsCullingResults.at(lightBoundsCullingID.value); + result.lightByteOffset = lightByteOffset; + } + } + + // assign light byte offset to each queue + for (const auto& [sceneID, desc] : sceneCulling.renderQueueIndex) { + if (desc.lightBoundsCulledResultID.value == 0xFFFFFFFF) { + continue; + } + const auto lightByteOffset = sceneCulling.lightBoundsCullingResults.at( + desc.lightBoundsCulledResultID.value) + .lightByteOffset; + + sceneCulling.renderQueues.at(desc.renderQueueTarget.value).lightByteOffset = lightByteOffset; + } +} + +void LightResource::clear() { + std::fill(cpuBuffer.begin(), cpuBuffer.end(), 0); + lights.clear(); + lightIndex.clear(); +} + +void LightResource::buildLightBuffer(gfx::CommandBuffer* cmdBuffer) const { + if (lights.empty()) { + return; + } + cmdBuffer->updateBuffer( + lightBuffer, + cpuBuffer.data(), + static_cast(lights.size()) * elementSize); +} + +void LightResource::tryUpdateRenderSceneLocalDescriptorSet(const SceneCulling& sceneCulling) { + if (!resized) { + return; + } + + for (const auto& [scene, culling] : sceneCulling.frustumCullings) { + for (const auto& model : scene->getModels()) { + CC_EXPECTS(model); + for (const auto& submodel : model->getSubModels()) { + auto* set = submodel->getDescriptorSet(); + set->bindBuffer(binding, firstLightBufferView); + set->update(); + } + } + } + resized = false; +} + } // namespace render } // namespace cc diff --git a/native/cocos/renderer/pipeline/custom/NativeSetter.cpp b/native/cocos/renderer/pipeline/custom/NativeSetter.cpp index bb313d6cfca..16141922bd0 100644 --- a/native/cocos/renderer/pipeline/custom/NativeSetter.cpp +++ b/native/cocos/renderer/pipeline/custom/NativeSetter.cpp @@ -26,6 +26,7 @@ #include "cocos/renderer/pipeline/custom/NativePipelineTypes.h" #include "cocos/renderer/pipeline/custom/NativeUtils.h" #include "cocos/renderer/pipeline/custom/RenderGraphGraphs.h" +#include "cocos/scene/Light.h" #include "cocos/scene/RenderScene.h" #include "cocos/scene/SpotLight.h" @@ -122,21 +123,27 @@ void NativeSetter::setBuiltinCameraConstants(const scene::Camera *camera) { camera->getScene()->getMainLight(), data); } -void NativeSetter::setBuiltinDirectionalLightViewConstants( +void NativeSetter::setBuiltinDirectionalLightFrustumConstants( + const scene::Camera *camera, const scene::DirectionalLight *light, uint32_t level) { CC_EXPECTS(light); + // if csm is actually activated, csm is not nullptr + // update and get csm + const auto *csm = getBuiltinShadowCSM(*pipelineRuntime, *camera, light); + + // set data auto *device = pipelineRuntime->getDevice(); const auto &sceneData = *pipelineRuntime->getPipelineSceneData(); auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID); - setShadowUBOLightView(device, *layoutGraph, sceneData, *light, level, data); + setShadowUBOLightView(device, *layoutGraph, sceneData, csm, *light, level, data); } -void NativeSetter::setBuiltinSpotLightViewConstants(const scene::SpotLight *light) { +void NativeSetter::setBuiltinSpotLightFrustumConstants(const scene::SpotLight *light) { CC_EXPECTS(light); auto *device = pipelineRuntime->getDevice(); const auto &sceneData = *pipelineRuntime->getPipelineSceneData(); auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID); - setShadowUBOLightView(device, *layoutGraph, sceneData, *light, 0, data); + setShadowUBOLightView(device, *layoutGraph, sceneData, nullptr, *light, 0, data); } void NativeSetter::setBuiltinShadowMapConstants( @@ -148,19 +155,177 @@ void NativeSetter::setBuiltinShadowMapConstants( setShadowUBOView(*device, *layoutGraph, sceneData, *light, data); } +namespace { + +constexpr float LIGHT_METER_SCALE = 10000.0F; +constexpr bool ENABLE_NEW_MULTI_LIGHT = false; + +} // namespace + void NativeSetter::setBuiltinDirectionalLightConstants(const scene::DirectionalLight *light, const scene::Camera *camera) { } -void NativeSetter::setBuiltinSphereLightConstants(const scene::SphereLight *light, const scene::Camera *camera) { +void NativeSetter::setBuiltinSphereLightConstants( + const scene::SphereLight *light, const scene::Camera *camera) { + CC_EXPECTS(light); + const auto &sceneData = *pipelineRuntime->getPipelineSceneData(); + const auto &shadowInfo = *sceneData.getShadows(); + + auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID); + + if constexpr (ENABLE_NEW_MULTI_LIGHT) { + setVec4Impl( + data, *layoutGraph, "cc_lightPos", + toVec4(light->getPosition(), static_cast(scene::LightType::SPHERE))); + auto color = toVec4(light->getColor()); + if (light->isUseColorTemperature()) { + const auto &rgb = light->getColorTemperatureRGB(); + color.x *= rgb.x; + color.y *= rgb.y; + color.z *= rgb.z; + } + if (sceneData.isHDR()) { + color.w = light->getLuminance() * camera->getExposure() * LIGHT_METER_SCALE; + } else { + color.w = light->getLuminance(); + } + + setVec4Impl( + data, *layoutGraph, "cc_lightColor", color); + setVec4Impl( + data, *layoutGraph, "cc_lightSizeRangeAngle", + Vec4( + light->getSize(), + light->getRange(), + 0.F, + 0.F)); + } + setPunctualLightShadowUBO( + pipelineRuntime->getDevice(), *layoutGraph, sceneData, + camera->getScene()->getMainLight(), *light, data); } void NativeSetter::setBuiltinSpotLightConstants(const scene::SpotLight *light, const scene::Camera *camera) { + CC_EXPECTS(light); + const auto &sceneData = *this->pipelineRuntime->getPipelineSceneData(); + const auto &shadowInfo = *sceneData.getShadows(); + + auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID); + + if constexpr (ENABLE_NEW_MULTI_LIGHT) { + setVec4Impl( + data, *layoutGraph, "cc_lightPos", + toVec4(light->getPosition(), static_cast(scene::LightType::SPOT))); + + auto color = toVec4(light->getColor()); + if (light->isUseColorTemperature()) { + const auto &rgb = light->getColorTemperatureRGB(); + color.x *= rgb.x; + color.y *= rgb.y; + color.z *= rgb.z; + } + if (sceneData.isHDR()) { + color.w = light->getLuminance() * camera->getExposure() * LIGHT_METER_SCALE; + } else { + color.w = light->getLuminance(); + } + + setVec4Impl( + data, *layoutGraph, "cc_lightColor", color); + + setVec4Impl( + data, *layoutGraph, "cc_lightSizeRangeAngle", + Vec4( + light->getSize(), + light->getRange(), + light->getSpotAngle(), + shadowInfo.isEnabled() && + light->isShadowEnabled() && + shadowInfo.getType() == scene::ShadowType::SHADOW_MAP + ? 1.0F + : 0.0F)); + + setVec4Impl( + data, *layoutGraph, "cc_lightDir", + toVec4(light->getDirection())); + } + setPunctualLightShadowUBO( + pipelineRuntime->getDevice(), *layoutGraph, sceneData, + camera->getScene()->getMainLight(), *light, data); } void NativeSetter::setBuiltinPointLightConstants(const scene::PointLight *light, const scene::Camera *camera) { + CC_EXPECTS(light); + const auto &sceneData = *this->pipelineRuntime->getPipelineSceneData(); + const auto &shadowInfo = *sceneData.getShadows(); + + auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID); + + if constexpr (ENABLE_NEW_MULTI_LIGHT) { + setVec4Impl( + data, *layoutGraph, "cc_lightPos", + toVec4(light->getPosition(), static_cast(scene::LightType::POINT))); + auto color = toVec4(light->getColor()); + if (light->isUseColorTemperature()) { + const auto &rgb = light->getColorTemperatureRGB(); + color.x *= rgb.x; + color.y *= rgb.y; + color.z *= rgb.z; + } + if (sceneData.isHDR()) { + color.w = light->getLuminance() * camera->getExposure() * LIGHT_METER_SCALE; + } else { + color.w = light->getLuminance(); + } + + setVec4Impl( + data, *layoutGraph, "cc_lightColor", color); + setVec4Impl( + data, *layoutGraph, "cc_lightSizeRangeAngle", + Vec4( + 0.F, + light->getRange(), + 0.F, + 0.F)); + } + setPunctualLightShadowUBO( + pipelineRuntime->getDevice(), *layoutGraph, sceneData, + camera->getScene()->getMainLight(), *light, data); } void NativeSetter::setBuiltinRangedDirectionalLightConstants(const scene::RangedDirectionalLight *light, const scene::Camera *camera) { + const auto &sceneData = *this->pipelineRuntime->getPipelineSceneData(); + const auto &shadowInfo = *sceneData.getShadows(); + + auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID); + + if constexpr (ENABLE_NEW_MULTI_LIGHT) { + setVec4Impl( + data, *layoutGraph, "cc_lightPos", + toVec4(light->getPosition(), static_cast(scene::LightType::RANGED_DIRECTIONAL))); + auto color = toVec4(light->getColor()); + if (light->isUseColorTemperature()) { + const auto &rgb = light->getColorTemperatureRGB(); + color.x *= rgb.x; + color.y *= rgb.y; + color.z *= rgb.z; + } + if (sceneData.isHDR()) { + color.w = light->getIlluminance() * camera->getExposure(); + } else { + color.w = light->getIlluminance(); + } + + setVec4Impl( + data, *layoutGraph, "cc_lightColor", color); + setVec4Impl( + data, *layoutGraph, "cc_lightSizeRangeAngle", + Vec4( + light->getRight().x, + light->getRight().y, + light->getRight().z, + 0.F)); + } } } // namespace render diff --git a/native/cocos/renderer/pipeline/custom/NativeUtils.h b/native/cocos/renderer/pipeline/custom/NativeUtils.h index 82595dc3c92..83a11227a36 100644 --- a/native/cocos/renderer/pipeline/custom/NativeUtils.h +++ b/native/cocos/renderer/pipeline/custom/NativeUtils.h @@ -24,7 +24,10 @@ #pragma once #include "cocos/core/ArrayBuffer.h" +#include "cocos/math/Vec2.h" +#include "cocos/math/Vec3.h" #include "cocos/math/Vec4.h" +#include "cocos/renderer/gfx-base/GFXDef-common.h" #include "cocos/renderer/pipeline/custom/LayoutGraphFwd.h" #include "cocos/renderer/pipeline/custom/RenderGraphFwd.h" #include "cocos/renderer/pipeline/custom/RenderInterfaceFwd.h" @@ -75,6 +78,10 @@ void setReadWriteTextureImpl(RenderData &data, const LayoutGraphData &lg, const void setSamplerImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, gfx::Sampler *sampler); +inline Vec4 toVec4(const Vec3 &vec, float w = 0.0F) noexcept { + return {vec.x, vec.y, vec.z, w}; +} + } // namespace render } // namespace cc diff --git a/native/cocos/renderer/pipeline/custom/PrivateFwd.h b/native/cocos/renderer/pipeline/custom/PrivateFwd.h index 9bdfb3b4e7d..5c6f8fc2802 100644 --- a/native/cocos/renderer/pipeline/custom/PrivateFwd.h +++ b/native/cocos/renderer/pipeline/custom/PrivateFwd.h @@ -30,7 +30,6 @@ // clang-format off #pragma once #include "cocos/base/std/variant.h" -#include "cocos/renderer/core/ProgramLib.h" #include "cocos/renderer/pipeline/custom/RenderInterfaceFwd.h" namespace cc { diff --git a/native/cocos/renderer/pipeline/custom/RenderCommonFwd.h b/native/cocos/renderer/pipeline/custom/RenderCommonFwd.h index 1628d725ef7..929719b046a 100644 --- a/native/cocos/renderer/pipeline/custom/RenderCommonFwd.h +++ b/native/cocos/renderer/pipeline/custom/RenderCommonFwd.h @@ -31,7 +31,6 @@ #pragma once #include "cocos/base/std/hash/hash.h" #include "cocos/base/std/variant.h" -#include "cocos/renderer/gfx-base/GFXDef-common.h" namespace cc { diff --git a/native/cocos/renderer/pipeline/custom/RenderCommonJsb.cpp b/native/cocos/renderer/pipeline/custom/RenderCommonJsb.cpp index c7fed6ceedb..249ddbbd78c 100644 --- a/native/cocos/renderer/pipeline/custom/RenderCommonJsb.cpp +++ b/native/cocos/renderer/pipeline/custom/RenderCommonJsb.cpp @@ -41,6 +41,9 @@ bool nativevalue_to_se(const cc::render::LightInfo &from, se::Value &to, se::Obj nativevalue_to_se(from.light, tmp, ctx); obj->setProperty("light", tmp); + nativevalue_to_se(from.probe, tmp, ctx); + obj->setProperty("probe", tmp); + nativevalue_to_se(from.level, tmp, ctx); obj->setProperty("level", tmp); @@ -241,6 +244,10 @@ bool sevalue_to_native(const se::Value &from, cc::render: if(!field.isNullOrUndefined()) { ok &= sevalue_to_native(field, &(to->light), ctx); } + obj->getProperty("probe", &field, true); + if(!field.isNullOrUndefined()) { + ok &= sevalue_to_native(field, &(to->probe), ctx); + } obj->getProperty("level", &field, true); if(!field.isNullOrUndefined()) { ok &= sevalue_to_native(field, &(to->level), ctx); diff --git a/native/cocos/renderer/pipeline/custom/RenderCommonSerialization.h b/native/cocos/renderer/pipeline/custom/RenderCommonSerialization.h index 4c9467badf2..913dbab6af1 100644 --- a/native/cocos/renderer/pipeline/custom/RenderCommonSerialization.h +++ b/native/cocos/renderer/pipeline/custom/RenderCommonSerialization.h @@ -39,12 +39,14 @@ namespace render { inline void save(OutputArchive& ar, const LightInfo& v) { // skip, light: IntrusivePtr + // skip, probe: scene::ReflectionProbe save(ar, v.level); save(ar, v.culledByLight); } inline void load(InputArchive& ar, LightInfo& v) { // skip, light: IntrusivePtr + // skip, probe: scene::ReflectionProbe load(ar, v.level); load(ar, v.culledByLight); } diff --git a/native/cocos/renderer/pipeline/custom/RenderCommonTypes.h b/native/cocos/renderer/pipeline/custom/RenderCommonTypes.h index cad5d71c02c..873286c62f6 100644 --- a/native/cocos/renderer/pipeline/custom/RenderCommonTypes.h +++ b/native/cocos/renderer/pipeline/custom/RenderCommonTypes.h @@ -39,6 +39,16 @@ namespace cc { +namespace scene { + +class ReflectionProbe; + +} // namespace scene + +} // namespace cc + +namespace cc { + namespace render { enum class UpdateFrequency { @@ -126,6 +136,10 @@ constexpr bool operator!(ResourceFlags e) noexcept { return e == static_cast(0); } +constexpr ResourceFlags operator~(ResourceFlags e) noexcept { + return static_cast(~static_cast>(e)); +} + constexpr bool any(ResourceFlags e) noexcept { return !!e; } @@ -158,6 +172,7 @@ enum class SceneFlags : uint32_t { DRAW_NON_INSTANCING = 0x1000, REFLECTION_PROBE = 0x2000, GPU_DRIVEN = 0x4000, + NON_BUILTIN = 0x8000, ALL = 0xFFFFFFFF, }; @@ -181,6 +196,10 @@ constexpr bool operator!(SceneFlags e) noexcept { return e == static_cast(0); } +constexpr SceneFlags operator~(SceneFlags e) noexcept { + return static_cast(~static_cast>(e)); +} + constexpr bool any(SceneFlags e) noexcept { return !!e; } @@ -211,8 +230,9 @@ enum class ClearValueType { struct LightInfo { LightInfo() = default; - LightInfo(IntrusivePtr lightIn, uint32_t levelIn, bool culledByLightIn) noexcept + LightInfo(IntrusivePtr lightIn, uint32_t levelIn, bool culledByLightIn, scene::ReflectionProbe* probeIn) noexcept : light(std::move(lightIn)), + probe(probeIn), level(levelIn), culledByLight(culledByLightIn) {} LightInfo(IntrusivePtr lightIn, uint32_t levelIn) noexcept @@ -220,6 +240,7 @@ struct LightInfo { level(levelIn) {} IntrusivePtr light; + scene::ReflectionProbe* probe{nullptr}; uint32_t level{0}; bool culledByLight{false}; }; @@ -307,6 +328,10 @@ constexpr bool operator!(ResolveFlags e) noexcept { return e == static_cast(0); } +constexpr ResolveFlags operator~(ResolveFlags e) noexcept { + return static_cast(~static_cast>(e)); +} + constexpr bool any(ResolveFlags e) noexcept { return !!e; } diff --git a/native/cocos/renderer/pipeline/custom/RenderGraphFwd.h b/native/cocos/renderer/pipeline/custom/RenderGraphFwd.h index 0ec6698a935..9714e8db649 100644 --- a/native/cocos/renderer/pipeline/custom/RenderGraphFwd.h +++ b/native/cocos/renderer/pipeline/custom/RenderGraphFwd.h @@ -32,7 +32,6 @@ #include "cocos/base/std/hash/hash.h" #include "cocos/base/std/variant.h" #include "cocos/renderer/pipeline/custom/RenderCommonFwd.h" -#include "cocos/scene/Camera.h" namespace cc { @@ -46,7 +45,9 @@ struct ResourceTraits; struct RenderSwapchain; struct ResourceStates; struct ManagedBuffer; +struct PersistentBuffer; struct ManagedTexture; +struct PersistentTexture; struct ManagedResource; struct Subpass; struct SubpassGraph; @@ -80,6 +81,9 @@ struct ClearTag; struct ViewportTag; struct ClearView; struct RenderQueue; + +enum class CullingFlags : uint32_t; + struct SceneData; struct Dispatch; struct Blit; diff --git a/native/cocos/renderer/pipeline/custom/RenderGraphGraphs.h b/native/cocos/renderer/pipeline/custom/RenderGraphGraphs.h index e14bfd7c411..9f129ec00ea 100644 --- a/native/cocos/renderer/pipeline/custom/RenderGraphGraphs.h +++ b/native/cocos/renderer/pipeline/custom/RenderGraphGraphs.h @@ -1523,7 +1523,7 @@ holds_alternative(ResourceGraph::vertex_descriptor v, const Reso template <> inline bool -holds_alternative>(ResourceGraph::vertex_descriptor v, const ResourceGraph& g) noexcept { // NOLINT +holds_alternative(ResourceGraph::vertex_descriptor v, const ResourceGraph& g) noexcept { // NOLINT return ccstd::holds_alternative< impl::ValueHandle>( g._vertices[v].handle); @@ -1531,7 +1531,7 @@ holds_alternative>(ResourceGraph::vertex_descriptor v, template <> inline bool -holds_alternative>(ResourceGraph::vertex_descriptor v, const ResourceGraph& g) noexcept { // NOLINT +holds_alternative(ResourceGraph::vertex_descriptor v, const ResourceGraph& g) noexcept { // NOLINT return ccstd::holds_alternative< impl::ValueHandle>( g._vertices[v].handle); @@ -1601,8 +1601,8 @@ get(ResourceGraph::vertex_descriptor v, ResourceGraph& g) { } template <> -inline IntrusivePtr& -get>(ResourceGraph::vertex_descriptor v, ResourceGraph& g) { +inline PersistentBuffer& +get(ResourceGraph::vertex_descriptor v, ResourceGraph& g) { auto& handle = ccstd::get< impl::ValueHandle>( g._vertices[v].handle); @@ -1610,8 +1610,8 @@ get>(ResourceGraph::vertex_descriptor v, ResourceGraph } template <> -inline IntrusivePtr& -get>(ResourceGraph::vertex_descriptor v, ResourceGraph& g) { +inline PersistentTexture& +get(ResourceGraph::vertex_descriptor v, ResourceGraph& g) { auto& handle = ccstd::get< impl::ValueHandle>( g._vertices[v].handle); @@ -1686,8 +1686,8 @@ get(ResourceGraph::vertex_descriptor v, const ResourceGraph& g) } template <> -inline const IntrusivePtr& -get>(ResourceGraph::vertex_descriptor v, const ResourceGraph& g) { +inline const PersistentBuffer& +get(ResourceGraph::vertex_descriptor v, const ResourceGraph& g) { const auto& handle = ccstd::get< impl::ValueHandle>( g._vertices[v].handle); @@ -1695,8 +1695,8 @@ get>(ResourceGraph::vertex_descriptor v, const Resourc } template <> -inline const IntrusivePtr& -get>(ResourceGraph::vertex_descriptor v, const ResourceGraph& g) { +inline const PersistentTexture& +get(ResourceGraph::vertex_descriptor v, const ResourceGraph& g) { const auto& handle = ccstd::get< impl::ValueHandle>( g._vertices[v].handle); @@ -1763,7 +1763,7 @@ get(ManagedTextureTag /*tag*/, ResourceGraph::vertex_descriptor v, ResourceGraph return g.managedTextures[handle.value]; } -inline IntrusivePtr& +inline PersistentBuffer& get(PersistentBufferTag /*tag*/, ResourceGraph::vertex_descriptor v, ResourceGraph& g) { auto& handle = ccstd::get< impl::ValueHandle>( @@ -1771,7 +1771,7 @@ get(PersistentBufferTag /*tag*/, ResourceGraph::vertex_descriptor v, ResourceGra return g.buffers[handle.value]; } -inline IntrusivePtr& +inline PersistentTexture& get(PersistentTextureTag /*tag*/, ResourceGraph::vertex_descriptor v, ResourceGraph& g) { auto& handle = ccstd::get< impl::ValueHandle>( @@ -1835,7 +1835,7 @@ get(ManagedTextureTag /*tag*/, ResourceGraph::vertex_descriptor v, const Resourc return g.managedTextures[handle.value]; } -inline const IntrusivePtr& +inline const PersistentBuffer& get(PersistentBufferTag /*tag*/, ResourceGraph::vertex_descriptor v, const ResourceGraph& g) { const auto& handle = ccstd::get< impl::ValueHandle>( @@ -1843,7 +1843,7 @@ get(PersistentBufferTag /*tag*/, ResourceGraph::vertex_descriptor v, const Resou return g.buffers[handle.value]; } -inline const IntrusivePtr& +inline const PersistentTexture& get(PersistentTextureTag /*tag*/, ResourceGraph::vertex_descriptor v, const ResourceGraph& g) { const auto& handle = ccstd::get< impl::ValueHandle>( @@ -1939,9 +1939,9 @@ get_if(ResourceGraph::vertex_descriptor v, ResourceGraph* pGraph } template <> -inline IntrusivePtr* -get_if>(ResourceGraph::vertex_descriptor v, ResourceGraph* pGraph) noexcept { // NOLINT - IntrusivePtr* ptr = nullptr; +inline PersistentBuffer* +get_if(ResourceGraph::vertex_descriptor v, ResourceGraph* pGraph) noexcept { // NOLINT + PersistentBuffer* ptr = nullptr; if (!pGraph) { return ptr; } @@ -1956,9 +1956,9 @@ get_if>(ResourceGraph::vertex_descriptor v, ResourceGr } template <> -inline IntrusivePtr* -get_if>(ResourceGraph::vertex_descriptor v, ResourceGraph* pGraph) noexcept { // NOLINT - IntrusivePtr* ptr = nullptr; +inline PersistentTexture* +get_if(ResourceGraph::vertex_descriptor v, ResourceGraph* pGraph) noexcept { // NOLINT + PersistentTexture* ptr = nullptr; if (!pGraph) { return ptr; } @@ -2096,9 +2096,9 @@ get_if(ResourceGraph::vertex_descriptor v, const ResourceGraph* } template <> -inline const IntrusivePtr* -get_if>(ResourceGraph::vertex_descriptor v, const ResourceGraph* pGraph) noexcept { // NOLINT - const IntrusivePtr* ptr = nullptr; +inline const PersistentBuffer* +get_if(ResourceGraph::vertex_descriptor v, const ResourceGraph* pGraph) noexcept { // NOLINT + const PersistentBuffer* ptr = nullptr; if (!pGraph) { return ptr; } @@ -2113,9 +2113,9 @@ get_if>(ResourceGraph::vertex_descriptor v, const Reso } template <> -inline const IntrusivePtr* -get_if>(ResourceGraph::vertex_descriptor v, const ResourceGraph* pGraph) noexcept { // NOLINT - const IntrusivePtr* ptr = nullptr; +inline const PersistentTexture* +get_if(ResourceGraph::vertex_descriptor v, const ResourceGraph* pGraph) noexcept { // NOLINT + const PersistentTexture* ptr = nullptr; if (!pGraph) { return ptr; } @@ -2432,7 +2432,7 @@ void addVertexImpl( // NOLINT template void addVertexImpl( // NOLINT ValueT &&val, ResourceGraph &g, ResourceGraph::Vertex &vert, // NOLINT - std::enable_if_t, IntrusivePtr>::value>* dummy = nullptr) { // NOLINT + std::enable_if_t, PersistentBuffer>::value>* dummy = nullptr) { // NOLINT vert.handle = impl::ValueHandle{ gsl::narrow_cast(g.buffers.size())}; g.buffers.emplace_back(std::forward(val)); @@ -2441,7 +2441,7 @@ void addVertexImpl( // NOLINT template void addVertexImpl( // NOLINT ValueT &&val, ResourceGraph &g, ResourceGraph::Vertex &vert, // NOLINT - std::enable_if_t, IntrusivePtr>::value>* dummy = nullptr) { // NOLINT + std::enable_if_t, PersistentTexture>::value>* dummy = nullptr) { // NOLINT vert.handle = impl::ValueHandle{ gsl::narrow_cast(g.textures.size())}; g.textures.emplace_back(std::forward(val)); diff --git a/native/cocos/renderer/pipeline/custom/RenderGraphTypes.cpp b/native/cocos/renderer/pipeline/custom/RenderGraphTypes.cpp index bcb977b9e35..46c87e4227e 100644 --- a/native/cocos/renderer/pipeline/custom/RenderGraphTypes.cpp +++ b/native/cocos/renderer/pipeline/custom/RenderGraphTypes.cpp @@ -171,6 +171,11 @@ SubpassGraph::Vertex::Vertex(Vertex const& rhs, const allocator_type& alloc) : outEdges(rhs.outEdges, alloc), inEdges(rhs.inEdges, alloc) {} +RasterSubpass::RasterSubpass(const allocator_type& alloc) noexcept +: rasterViews(alloc), + computeViews(alloc), + resolvePairs(alloc) {} + RasterSubpass::RasterSubpass(uint32_t subpassIDIn, uint32_t countIn, uint32_t qualityIn, const allocator_type& alloc) noexcept : rasterViews(alloc), computeViews(alloc), @@ -199,6 +204,10 @@ RasterSubpass::RasterSubpass(RasterSubpass const& rhs, const allocator_type& all quality(rhs.quality), showStatistics(rhs.showStatistics) {} +ComputeSubpass::ComputeSubpass(const allocator_type& alloc) noexcept +: rasterViews(alloc), + computeViews(alloc) {} + ComputeSubpass::ComputeSubpass(uint32_t subpassIDIn, const allocator_type& alloc) noexcept : rasterViews(alloc), computeViews(alloc), diff --git a/native/cocos/renderer/pipeline/custom/RenderGraphTypes.h b/native/cocos/renderer/pipeline/custom/RenderGraphTypes.h index 75abe2d1bf1..300a53b8c6b 100644 --- a/native/cocos/renderer/pipeline/custom/RenderGraphTypes.h +++ b/native/cocos/renderer/pipeline/custom/RenderGraphTypes.h @@ -211,6 +211,15 @@ struct ManagedBuffer { uint64_t fenceValue{0}; }; +struct PersistentBuffer { + PersistentBuffer() = default; + PersistentBuffer(IntrusivePtr bufferIn) noexcept // NOLINT + : buffer(std::move(bufferIn)) {} + + IntrusivePtr buffer; + uint64_t fenceValue{0}; +}; + struct ManagedTexture { ManagedTexture() = default; ManagedTexture(IntrusivePtr textureIn) noexcept // NOLINT @@ -222,6 +231,17 @@ struct ManagedTexture { uint64_t fenceValue{0}; }; +struct PersistentTexture { + PersistentTexture() = default; + PersistentTexture(IntrusivePtr textureIn) noexcept // NOLINT + : texture(std::move(textureIn)) {} + + bool checkResource(const ResourceDesc &desc) const; + + IntrusivePtr texture; + uint64_t fenceValue{0}; +}; + struct ManagedResource { uint32_t unused{0}; }; @@ -390,6 +410,7 @@ struct RasterSubpass { return {rasterViews.get_allocator().resource()}; } + RasterSubpass(const allocator_type& alloc) noexcept; // NOLINT RasterSubpass(uint32_t subpassIDIn, uint32_t countIn, uint32_t qualityIn, const allocator_type& alloc) noexcept; RasterSubpass(RasterSubpass&& rhs, const allocator_type& alloc); RasterSubpass(RasterSubpass const& rhs, const allocator_type& alloc); @@ -415,6 +436,7 @@ struct ComputeSubpass { return {rasterViews.get_allocator().resource()}; } + ComputeSubpass(const allocator_type& alloc) noexcept; // NOLINT ComputeSubpass(uint32_t subpassIDIn, const allocator_type& alloc) noexcept; ComputeSubpass(ComputeSubpass&& rhs, const allocator_type& alloc); ComputeSubpass(ComputeSubpass const& rhs, const allocator_type& alloc); @@ -516,7 +538,6 @@ struct SubresourceView { uint16_t numArraySlices{0}; uint16_t firstPlane{0}; uint16_t numPlanes{0}; - gfx::TextureType viewType; }; struct ResourceGraph { @@ -637,8 +658,8 @@ struct ResourceGraph { // PolymorphicGraph using VertexTag = ccstd::variant; - using VertexValue = ccstd::variant*, IntrusivePtr*, IntrusivePtr*, RenderSwapchain*, FormatView*, SubresourceView*>; - using VertexConstValue = ccstd::variant*, const IntrusivePtr*, const IntrusivePtr*, const RenderSwapchain*, const FormatView*, const SubresourceView*>; + using VertexValue = ccstd::variant*, RenderSwapchain*, FormatView*, SubresourceView*>; + using VertexConstValue = ccstd::variant*, const RenderSwapchain*, const FormatView*, const SubresourceView*>; using VertexHandle = ccstd::variant< impl::ValueHandle, impl::ValueHandle, @@ -701,8 +722,8 @@ struct ResourceGraph { ccstd::pmr::vector resources; ccstd::pmr::vector managedBuffers; ccstd::pmr::vector managedTextures; - ccstd::pmr::vector> buffers; - ccstd::pmr::vector> textures; + ccstd::pmr::vector buffers; + ccstd::pmr::vector textures; ccstd::pmr::vector> framebuffers; ccstd::pmr::vector swapchains; ccstd::pmr::vector formatViews; @@ -847,18 +868,57 @@ struct RenderQueue { gfx::Viewport viewport; }; +enum class CullingFlags : uint32_t { + NONE = 0, + CAMERA_FRUSTUM = 0x1, + LIGHT_FRUSTUM = 0x2, + LIGHT_BOUNDS = 0x4, +}; + +constexpr CullingFlags operator|(const CullingFlags lhs, const CullingFlags rhs) noexcept { + return static_cast(static_cast(lhs) | static_cast(rhs)); +} + +constexpr CullingFlags operator&(const CullingFlags lhs, const CullingFlags rhs) noexcept { + return static_cast(static_cast(lhs) & static_cast(rhs)); +} + +constexpr CullingFlags& operator|=(CullingFlags& lhs, const CullingFlags rhs) noexcept { + return lhs = lhs | rhs; +} + +constexpr CullingFlags& operator&=(CullingFlags& lhs, const CullingFlags rhs) noexcept { + return lhs = lhs & rhs; +} + +constexpr bool operator!(CullingFlags e) noexcept { + return e == static_cast(0); +} + +constexpr CullingFlags operator~(CullingFlags e) noexcept { + return static_cast(~static_cast>(e)); +} + +constexpr bool any(CullingFlags e) noexcept { + return !!e; +} + struct SceneData { SceneData() = default; - SceneData(const scene::RenderScene* sceneIn, const scene::Camera* cameraIn, SceneFlags flagsIn, LightInfo lightIn) noexcept + SceneData(const scene::RenderScene* sceneIn, const scene::Camera* cameraIn, SceneFlags flagsIn, LightInfo lightIn, CullingFlags cullingFlagsIn, IntrusivePtr shadingLightIn) noexcept : scene(sceneIn), camera(cameraIn), light(std::move(lightIn)), - flags(flagsIn) {} + flags(flagsIn), + cullingFlags(cullingFlagsIn), + shadingLight(std::move(shadingLightIn)) {} const scene::RenderScene* scene{nullptr}; const scene::Camera* camera{nullptr}; LightInfo light; SceneFlags flags{SceneFlags::NONE}; + CullingFlags cullingFlags{CullingFlags::CAMERA_FRUSTUM}; + IntrusivePtr shadingLight; }; struct Dispatch { diff --git a/native/cocos/renderer/pipeline/custom/RenderInterfaceFwd.h b/native/cocos/renderer/pipeline/custom/RenderInterfaceFwd.h index 7a72a5f60e8..8a6545cc0e1 100644 --- a/native/cocos/renderer/pipeline/custom/RenderInterfaceFwd.h +++ b/native/cocos/renderer/pipeline/custom/RenderInterfaceFwd.h @@ -30,9 +30,6 @@ // clang-format off #pragma once #include "cocos/base/std/variant.h" -#include "cocos/core/assets/EffectAsset.h" -#include "cocos/renderer/core/PassUtils.h" -#include "cocos/renderer/pipeline/PipelineSceneData.h" #include "cocos/renderer/pipeline/custom/CustomFwd.h" namespace cc { @@ -47,6 +44,7 @@ enum class SubpassCapabilities : uint32_t; struct PipelineCapabilities; class RenderNode; class Setter; +class SceneBuilder; class RenderQueueBuilder; class BasicRenderPassBuilder; class BasicMultisampleRenderPassBuilder; diff --git a/native/cocos/renderer/pipeline/custom/RenderInterfaceTypes.h b/native/cocos/renderer/pipeline/custom/RenderInterfaceTypes.h index 29e13290601..dfa2210c52b 100644 --- a/native/cocos/renderer/pipeline/custom/RenderInterfaceTypes.h +++ b/native/cocos/renderer/pipeline/custom/RenderInterfaceTypes.h @@ -320,6 +320,10 @@ constexpr bool operator!(SubpassCapabilities e) noexcept { return e == static_cast(0); } +constexpr SubpassCapabilities operator~(SubpassCapabilities e) noexcept { + return static_cast(~static_cast>(e)); +} + constexpr bool any(SubpassCapabilities e) noexcept { return !!e; } @@ -460,10 +464,23 @@ class Setter : public RenderNode { virtual void setBuiltinSpotLightConstants(const scene::SpotLight *light, const scene::Camera *camera) = 0; virtual void setBuiltinPointLightConstants(const scene::PointLight *light, const scene::Camera *camera) = 0; virtual void setBuiltinRangedDirectionalLightConstants(const scene::RangedDirectionalLight *light, const scene::Camera *camera) = 0; - virtual void setBuiltinDirectionalLightViewConstants(const scene::DirectionalLight *light, uint32_t level) = 0; - virtual void setBuiltinSpotLightViewConstants(const scene::SpotLight *light) = 0; - void setBuiltinDirectionalLightViewConstants(const scene::DirectionalLight *light) { - setBuiltinDirectionalLightViewConstants(light, 0); + virtual void setBuiltinDirectionalLightFrustumConstants(const scene::Camera *camera, const scene::DirectionalLight *light, uint32_t csmLevel) = 0; + virtual void setBuiltinSpotLightFrustumConstants(const scene::SpotLight *light) = 0; + void setBuiltinDirectionalLightFrustumConstants(const scene::Camera *camera, const scene::DirectionalLight *light) { + setBuiltinDirectionalLightFrustumConstants(camera, light, 0); + } +}; + +class SceneBuilder : public Setter { +public: + SceneBuilder() noexcept = default; + + virtual void useLightFrustum(IntrusivePtr light, uint32_t csmLevel, const scene::Camera *optCamera) = 0; + void useLightFrustum(IntrusivePtr light) { + useLightFrustum(std::move(light), 0, nullptr); + } + void useLightFrustum(IntrusivePtr light, uint32_t csmLevel) { + useLightFrustum(std::move(light), csmLevel, nullptr); } }; @@ -488,9 +505,7 @@ class RenderQueueBuilder : public Setter { * @param sceneFlags @en Rendering flags of the scene @zh 场景渲染标志位 */ virtual void addSceneOfCamera(scene::Camera *camera, LightInfo light, SceneFlags sceneFlags) = 0; - virtual void addScene(const scene::Camera *camera, SceneFlags sceneFlags, const scene::Light *light) = 0; - virtual void addSceneCulledByDirectionalLight(const scene::Camera *camera, SceneFlags sceneFlags, scene::DirectionalLight *light, uint32_t level) = 0; - virtual void addSceneCulledBySpotLight(const scene::Camera *camera, SceneFlags sceneFlags, scene::SpotLight *light) = 0; + virtual SceneBuilder *addScene(const scene::Camera *camera, SceneFlags sceneFlags, scene::Light *light) = 0; /** * @en Render a full-screen quad. * @zh 渲染全屏四边形 @@ -528,8 +543,8 @@ class RenderQueueBuilder : public Setter { void addSceneOfCamera(scene::Camera *camera, LightInfo light) { addSceneOfCamera(camera, std::move(light), SceneFlags::NONE); } - void addScene(const scene::Camera *camera, SceneFlags sceneFlags) { - addScene(camera, sceneFlags, nullptr); + SceneBuilder *addScene(const scene::Camera *camera, SceneFlags sceneFlags) { + return addScene(camera, sceneFlags, nullptr); } void addFullscreenQuad(Material *material, uint32_t passID) { addFullscreenQuad(material, passID, SceneFlags::NONE); @@ -771,14 +786,14 @@ class BasicPipeline : public PipelineRuntime { * @param format @en Format of the resource @zh 资源的格式 */ virtual void updateDepthStencil(const ccstd::string &name, uint32_t width, uint32_t height, gfx::Format format) = 0; - virtual uint32_t addResource(const ccstd::string &name, ResourceDimension dimension, gfx::Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t arraySize, uint32_t mipLevels, gfx::SampleCount sampleCount, ResourceFlags flags, ResourceResidency residency) = 0; - virtual void updateResource(const ccstd::string &name, gfx::Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t arraySize, uint32_t mipLevels, gfx::SampleCount sampleCount) = 0; - virtual uint32_t addTexture(const ccstd::string &name, gfx::TextureType type, gfx::Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t arraySize, uint32_t mipLevels, gfx::SampleCount sampleCount, ResourceFlags flags, ResourceResidency residency) = 0; - virtual void updateTexture(const ccstd::string &name, gfx::Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t arraySize, uint32_t mipLevels, gfx::SampleCount sampleCount) = 0; virtual uint32_t addBuffer(const ccstd::string &name, uint32_t size, ResourceFlags flags, ResourceResidency residency) = 0; virtual void updateBuffer(const ccstd::string &name, uint32_t size) = 0; virtual uint32_t addExternalTexture(const ccstd::string &name, gfx::Texture *texture, ResourceFlags flags) = 0; virtual void updateExternalTexture(const ccstd::string &name, gfx::Texture *texture) = 0; + virtual uint32_t addTexture(const ccstd::string &name, gfx::TextureType type, gfx::Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t arraySize, uint32_t mipLevels, gfx::SampleCount sampleCount, ResourceFlags flags, ResourceResidency residency) = 0; + virtual void updateTexture(const ccstd::string &name, gfx::Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t arraySize, uint32_t mipLevels, gfx::SampleCount sampleCount) = 0; + virtual uint32_t addResource(const ccstd::string &name, ResourceDimension dimension, gfx::Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t arraySize, uint32_t mipLevels, gfx::SampleCount sampleCount, ResourceFlags flags, ResourceResidency residency) = 0; + virtual void updateResource(const ccstd::string &name, gfx::Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t arraySize, uint32_t mipLevels, gfx::SampleCount sampleCount) = 0; /** * @engineInternal * @en Begin rendering one frame @@ -844,6 +859,7 @@ class BasicPipeline : public PipelineRuntime { * @param copyPairs @en Array of copy source and target @zh 拷贝来源与目标的数组 */ virtual void addCopyPass(const ccstd::vector ©Pairs) = 0; + virtual void addBuiltinReflectionProbePass(const scene::Camera *camera) = 0; /** * @engineInternal */ @@ -1497,6 +1513,7 @@ class PipelineBuilder { * @param pipeline @en Current render pipeline @zh 当前管线 */ virtual void setup(const ccstd::vector &cameras, BasicPipeline *pipeline) = 0; + virtual void onGlobalPipelineStateChanged() = 0; }; /** diff --git a/native/cocos/renderer/pipeline/custom/details/Map.h b/native/cocos/renderer/pipeline/custom/details/Map.h index a82d85a0472..ae6be1cc54d 100644 --- a/native/cocos/renderer/pipeline/custom/details/Map.h +++ b/native/cocos/renderer/pipeline/custom/details/Map.h @@ -106,6 +106,46 @@ using PmrUnorderedStringMultiMap = std::unordered_multimap< TransparentStringHash, std::equal_to<>, boost::container::pmr::polymorphic_allocator>>; +template +inline typename std::map, Allocator>::mapped_type& +at(std::map, Allocator>& m, const KeyLike& key) { + auto iter = m.find(key); + if (iter == m.end()) { + throw std::out_of_range("at(std::map) out of range"); + } + return iter->second; +} + +template +inline typename std::map, Allocator>::mapped_type const& +at(const std::map, Allocator>& m, const KeyLike& key) { + auto iter = m.find(key); + if (iter == m.end()) { + throw std::out_of_range("at(std::map) out of range"); + } + return iter->second; +} + +template +inline typename boost::container::flat_map, Allocator>::mapped_type& +at(boost::container::flat_map, Allocator>& m, const KeyLike& key) { + auto iter = m.find(key); + if (iter == m.end()) { + throw std::out_of_range("at(boost::container::flat_map) out of range"); + } + return iter->second; +} + +template +inline typename boost::container::flat_map, Allocator>::mapped_type const& +at(const boost::container::flat_map, Allocator>& m, const KeyLike& key) { + auto iter = m.find(key); + if (iter == m.end()) { + throw std::out_of_range("at(boost::container::flat_map) out of range"); + } + return iter->second; +} + } // namespace cc namespace ccstd { diff --git a/native/tools/swig-config/render.i b/native/tools/swig-config/render.i index dbaf304bec1..877b83049fe 100644 --- a/native/tools/swig-config/render.i +++ b/native/tools/swig-config/render.i @@ -81,6 +81,7 @@ using namespace cc::render; %release_returned_cpp_object_in_gc(cc::render::RenderPassBuilder::addMultisampleRenderSubpass); %release_returned_cpp_object_in_gc(cc::render::RenderPassBuilder::addComputeSubpass); %release_returned_cpp_object_in_gc(cc::render::ComputePassBuilder::addQueue); +%release_returned_cpp_object_in_gc(cc::render::RenderQueueBuilder::addScene); %release_returned_cpp_object_in_gc(cc::render::Pipeline::addRenderPass); %release_returned_cpp_object_in_gc(cc::render::Pipeline::addComputePass);