Skip to content

Commit 2c05e20

Browse files
authored
Add the logic for merging render passes (#18972)
1 parent 1ba8584 commit 2c05e20

File tree

3 files changed

+124
-43
lines changed

3 files changed

+124
-43
lines changed

cocos/rendering/custom/define.ts

Lines changed: 98 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,14 @@ import {
4343
AttachmentType, LightInfo,
4444
QueueHint, ResourceResidency, SceneFlags, UpdateFrequency,
4545
} from './types';
46-
import { Vec4, geometry, toRadian, cclegacy } from '../../core';
46+
import { Vec4, geometry, toRadian, cclegacy, RecyclePool } from '../../core';
4747
import { RenderWindow } from '../../render-scene/core/render-window';
4848
import { RasterPass, RenderData, RenderGraph } from './render-graph';
4949
import { WebPipeline } from './web-pipeline';
5050
import { DescriptorSetData, LayoutGraphData } from './layout-graph';
5151
import { AABB } from '../../core/geometry';
5252
import { getUBOTypeCount } from './utils';
53+
import { init } from '.';
5354

5455
const _rangedDirLightBoundingBox = new AABB(0.0, 0.0, 0.0, 0.5, 0.5, 0.5);
5556
const _tmpBoundingBox = new AABB();
@@ -860,37 +861,104 @@ export function getSubpassOrPassID (sceneId: number, rg: RenderGraph, lg: Layout
860861
return layoutId;
861862
}
862863

864+
export class RenderPassMergeInfo {
865+
constructor (
866+
public combineHash: number = 0,
867+
public needBeginRP: boolean = true,
868+
public needEndRP: boolean = true,
869+
) {}
870+
init (
871+
combineHash: number,
872+
needBeginRP: boolean = true,
873+
needEndRP: boolean = true,
874+
): void {
875+
this.combineHash = combineHash;
876+
this.needBeginRP = needBeginRP;
877+
this.needEndRP = needEndRP;
878+
}
879+
}
880+
881+
const passOrders: RasterPass[] = [];
882+
const rpCombineMap: Map<RasterPass, number> = new Map();
883+
export const rpMergeInfos: Map<RasterPass, RenderPassMergeInfo> = new Map();
884+
const rpMergeInfoPool = new RecyclePool<RenderPassMergeInfo>((): RenderPassMergeInfo => new RenderPassMergeInfo(), 16);
885+
export function resetPassMGState (): void {
886+
rpMergeInfoPool.reset();
887+
rpMergeInfos.clear();
888+
rpCombineMap.clear();
889+
passOrders.length = 0;
890+
}
891+
export function processPassMG (pass: RasterPass): void {
892+
const currCHash = rpCombineMap.get(pass)!;
893+
const currRPInfo = rpMergeInfoPool.add();
894+
if (!rpMergeInfos.has(pass)) {
895+
rpMergeInfos.set(pass, currRPInfo);
896+
}
897+
currRPInfo.init(currCHash);
898+
const poLen = passOrders.length;
899+
if (poLen !== 0) {
900+
let isLoadOP = false;
901+
for (const [_, raster] of pass.rasterViews) {
902+
if (raster.loadOp === LoadOp.LOAD) {
903+
isLoadOP = true;
904+
break;
905+
}
906+
}
907+
const prevPass = passOrders[poLen - 1];
908+
if (isLoadOP && rpCombineMap.get(prevPass) === currCHash) {
909+
const prevInfo = rpMergeInfos.get(prevPass)!;
910+
prevInfo.needEndRP = false;
911+
currRPInfo.needBeginRP = false;
912+
}
913+
}
914+
passOrders.push(pass);
915+
}
916+
863917
export function genHashValue (pass: RasterPass): void {
864-
let hashCode = '';
918+
const hashCodeParts: string[] = [];
919+
const combineHashParts: string[] = [];
865920
for (const [name, raster] of pass.rasterViews) {
866-
hashCode += hashCombineKey(name);
867-
hashCode += hashCombineKey(raster.slotName);
868-
hashCode += hashCombineKey(raster.accessType);
869-
hashCode += hashCombineKey(raster.attachmentType);
870-
hashCode += hashCombineKey(raster.loadOp);
871-
hashCode += hashCombineKey(raster.storeOp);
872-
hashCode += hashCombineKey(raster.clearFlags);
873-
hashCode += hashCombineKey(raster.clearColor.x);
874-
hashCode += hashCombineKey(raster.clearColor.y);
875-
hashCode += hashCombineKey(raster.clearColor.z);
876-
hashCode += hashCombineKey(raster.clearColor.w);
877-
hashCode += hashCombineKey(raster.slotID);
878-
hashCode += hashCombineKey(raster.shaderStageFlags);
879-
}
880-
for (const [name, computes] of pass.computeViews) {
881-
hashCode += hashCombineKey(name);
882-
for (const compute of computes) {
883-
hashCode += hashCombineKey(compute.name);
884-
hashCode += hashCombineKey(compute.accessType);
885-
hashCode += hashCombineKey(compute.clearFlags);
886-
hashCode += hashCombineKey(compute.clearValueType);
887-
hashCode += hashCombineKey(compute.clearValue.x);
888-
hashCode += hashCombineKey(compute.clearValue.y);
889-
hashCode += hashCombineKey(compute.clearValue.z);
890-
hashCode += hashCombineKey(compute.clearValue.w);
891-
hashCode += hashCombineKey(compute.shaderStageFlags);
921+
const commonParts = [
922+
hashCombineKey(name),
923+
hashCombineKey(raster.slotName),
924+
hashCombineKey(raster.accessType),
925+
hashCombineKey(raster.attachmentType),
926+
hashCombineKey(raster.storeOp),
927+
hashCombineKey(raster.clearFlags),
928+
hashCombineKey(raster.slotID),
929+
hashCombineKey(raster.shaderStageFlags),
930+
];
931+
932+
const extraParts = [
933+
hashCombineKey(raster.loadOp),
934+
hashCombineKey(raster.clearColor.x),
935+
hashCombineKey(raster.clearColor.y),
936+
hashCombineKey(raster.clearColor.z),
937+
hashCombineKey(raster.clearColor.w),
938+
];
939+
940+
const fullHash = commonParts.concat(extraParts).join('');
941+
const combineHash = commonParts.join('');
942+
943+
hashCodeParts.push(fullHash);
944+
combineHashParts.push(combineHash);
945+
}
946+
947+
const subpassGraph = pass.subpassGraph;
948+
const subpasses = subpassGraph._subpasses;
949+
for (const subpass of subpasses) {
950+
const resolvePairs = subpass.resolvePairs;
951+
for (const resolve of resolvePairs) {
952+
const commonParts = [
953+
hashCombineKey(resolve.source),
954+
hashCombineKey(resolve.target),
955+
];
956+
const combineHash = commonParts.join('');
957+
combineHashParts.push(combineHash);
892958
}
893959
}
894-
hashCode += hashCombineKey(pass.showStatistics ? 1 : 0);
895-
pass.hashValue = hashCombineStr(hashCode);
960+
961+
pass.hashValue = hashCombineStr(hashCodeParts.join(''));
962+
rpCombineMap.set(pass, hashCombineStr(combineHashParts.join('')));
963+
processPassMG(pass);
896964
}

cocos/rendering/custom/executor.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ import {
137137
bool,
138138
getDescriptorSetDataFromLayout,
139139
getRenderArea,
140+
RenderPassMergeInfo,
141+
rpMergeInfos,
140142
updateGlobalDescBinding,
141143
} from './define';
142144
import { LightResource, SceneCulling } from './scene-culling';
@@ -833,6 +835,7 @@ class DeviceRenderPass implements RecordingInterface {
833835
const resTex = this._getOrCreateDeviceTex(resName);
834836
if (!swapchain) swapchain = resTex.swapchain;
835837
if (!framebuffer) framebuffer = resTex.framebuffer;
838+
const isLoadAttachment = rasterV.loadOp === LoadOp.LOAD;
836839
if (rasterV.attachmentType === AttachmentType.RENDER_TARGET) {
837840
if (!resTex.swapchain && !resTex.framebuffer) colorTexs.push(resTex.texture!);
838841
const colAtt = new ColorAttachment();
@@ -841,7 +844,7 @@ class DeviceRenderPass implements RecordingInterface {
841844
colAtt.loadOp = rasterV.loadOp;
842845
colAtt.storeOp = rasterV.storeOp;
843846
colAtt.barrier = device.getGeneralBarrier(new GeneralBarrierInfo(
844-
rasterV.loadOp === LoadOp.LOAD ? AccessFlagBit.COLOR_ATTACHMENT_WRITE : AccessFlagBit.NONE,
847+
isLoadAttachment ? AccessFlagBit.COLOR_ATTACHMENT_WRITE : AccessFlagBit.NONE,
845848
rasterV.storeOp === StoreOp.STORE ? AccessFlagBit.COLOR_ATTACHMENT_WRITE : AccessFlagBit.NONE,
846849
));
847850
const currCol = new Color();
@@ -855,7 +858,7 @@ class DeviceRenderPass implements RecordingInterface {
855858
depAtt.sampleCount = resTex.description!.sampleCount;
856859
depAtt.stencilLoadOp = rasterV.loadOp;
857860
depAtt.barrier = device.getGeneralBarrier(new GeneralBarrierInfo(
858-
rasterV.loadOp === LoadOp.LOAD ? AccessFlagBit.DEPTH_STENCIL_ATTACHMENT_WRITE : AccessFlagBit.NONE,
861+
isLoadAttachment ? AccessFlagBit.DEPTH_STENCIL_ATTACHMENT_WRITE : AccessFlagBit.NONE,
859862
rasterV.storeOp === StoreOp.STORE ? AccessFlagBit.DEPTH_STENCIL_ATTACHMENT_WRITE : AccessFlagBit.NONE,
860863
));
861864
if (!resTex.swapchain && !resTex.framebuffer) {
@@ -889,6 +892,7 @@ class DeviceRenderPass implements RecordingInterface {
889892
swapchain ? swapchain.depthStencilTexture : depthTex,
890893
);
891894
}
895+
get passMergeInfo (): RenderPassMergeInfo { return rpMergeInfos.get(this._rasterPass)!; }
892896
get indexOfRD (): number { return this._idxOfRenderData; }
893897
get rasterID (): number { return this._rasterID; }
894898
get layoutName (): string { return this._layoutName; }
@@ -944,11 +948,23 @@ class DeviceRenderPass implements RecordingInterface {
944948
}
945949
}
946950

951+
bindGlobalDesc (): void {
952+
const cmdBuff = context.commandBuffer;
953+
if (context.passDescriptorSet) {
954+
cmdBuff.bindDescriptorSet(
955+
SetIndex.GLOBAL,
956+
context.passDescriptorSet,
957+
);
958+
}
959+
}
947960
beginPass (): void {
961+
if (!this.passMergeInfo.needBeginRP) {
962+
this.bindGlobalDesc();
963+
return;
964+
}
965+
const cmdBuff = context.commandBuffer;
948966
const tex = this.framebuffer.colorTextures[0]!;
949967
this._applyViewport(tex);
950-
const cmdBuff = context.commandBuffer;
951-
952968
if (this._viewport) {
953969
renderPassArea.x = this._viewport.left;
954970
renderPassArea.y = this._viewport.top;
@@ -967,15 +983,11 @@ class DeviceRenderPass implements RecordingInterface {
967983
this.clearDepth,
968984
this.clearStencil,
969985
);
970-
if (context.passDescriptorSet) {
971-
cmdBuff.bindDescriptorSet(
972-
SetIndex.GLOBAL,
973-
context.passDescriptorSet,
974-
);
975-
}
986+
this.bindGlobalDesc();
976987
}
977988

978989
endPass (): void {
990+
if (!this.passMergeInfo.needEndRP) return;
979991
const cmdBuff = context.commandBuffer;
980992
cmdBuff.endRenderPass();
981993
}
@@ -1191,8 +1203,6 @@ class DeviceRenderScene implements RecordingInterface {
11911203
this._currentQueue.createBlitDesc(this._blit);
11921204
this._currentQueue.blitDesc!.update();
11931205
}
1194-
context.lightResource.buildLightBuffer(context.commandBuffer);
1195-
context.lightResource.tryUpdateRenderSceneLocalDescriptorSet(context.culling);
11961206
}
11971207
postRecord (): void {
11981208
// nothing to do
@@ -1724,6 +1734,8 @@ export class Executor {
17241734
context.lightResource.buildLights(culling, context.pipelineSceneData.isHDR, context.pipelineSceneData.shadows);
17251735
this._removeDeviceResource();
17261736
cmdBuff.begin();
1737+
context.lightResource.buildLightBuffer(cmdBuff);
1738+
context.lightResource.tryUpdateRenderSceneLocalDescriptorSet(context.culling);
17271739
culling.uploadInstancing(cmdBuff);
17281740
if (!this._visitor) this._visitor = new RenderVisitor();
17291741
depthFirstSearch(this._visitor.graphView, this._visitor, this._visitor.colorMap);

cocos/rendering/custom/web-pipeline.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import { GeometryRenderer } from '../geometry-renderer';
4545
import { Material } from '../../asset/assets';
4646
import { decideProfilerCamera } from '../pipeline-funcs';
4747
import { DebugViewCompositeType } from '../debug-view';
48-
import { buildReflectionProbePass, genHashValue } from './define';
48+
import { buildReflectionProbePass, genHashValue, resetPassMGState } from './define';
4949
import { createGfxDescriptorSetsAndPipelines } from './layout-graph-utils';
5050
import { Root } from '../../root';
5151
import { Scene } from '../../scene-graph';
@@ -1644,6 +1644,7 @@ export class WebPipeline extends WebSetter implements BasicPipeline {
16441644
if (!this._renderGraph) {
16451645
throw new Error('RenderGraph cannot be built without being created');
16461646
}
1647+
resetPassMGState();
16471648
if (DEBUG) {
16481649
if (!this._compiler) {
16491650
this._compiler = new Compiler(this, this._renderGraph, this._resourceGraph, this._lg);

0 commit comments

Comments
 (0)