Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
276 changes: 274 additions & 2 deletions cocos/core/pipeline/custom/web-descriptor-hierarchy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,290 @@

import { EffectAsset } from '../../assets';
import { DescriptorHierarchy } from './pipeline';
import { LayoutGraph } from './layout-graph';
import { Descriptor, DescriptorBlock, DescriptorBlockIndex, DescriptorDB, DescriptorIndex, LayoutGraph, LayoutGraphValue, RenderPhase, UniformBlockDB } from './layout-graph';
import { ShaderStageFlagBit, Type, Uniform } from '../../gfx';
import { ParameterType, UpdateFrequency } from './types';
import { JOINT_UNIFORM_CAPACITY, UBOForwardLight, UBOLocalBatched, UBOMorph } from '../define';

export class WebDescriptorHierarchy extends DescriptorHierarchy {
constructor () {
super();
this._layoutGraph = new LayoutGraph();
}

private getLayoutBlock(freq: UpdateFrequency, paraType: ParameterType, descType: DescriptorIndex, vis: ShaderStageFlagBit, descriptorDB: DescriptorDB): DescriptorBlock {
const blockIndex: DescriptorBlockIndex = new DescriptorBlockIndex(freq, paraType, descType, vis);
const key = JSON.stringify(blockIndex);
if (descriptorDB.blocks.get(key) === undefined) {
const uniformBlock: DescriptorBlock = new DescriptorBlock();
descriptorDB.blocks.set(key, uniformBlock);
}
return descriptorDB.blocks.get(key) as DescriptorBlock;
}

private getUniformBlock(blockName: string, targetBlock: DescriptorBlock): UniformBlockDB {
if (targetBlock.uniformBlocks.get(blockName) === undefined) {
let uniformDB: UniformBlockDB = new UniformBlockDB();
targetBlock.uniformBlocks.set(blockName, uniformDB);
}
return targetBlock.uniformBlocks.get(blockName) as UniformBlockDB;
}

private setUniform(uniformDB: UniformBlockDB, name: string, type: Type, count: number) {
const uniform: Uniform = new Uniform(name, type, count);
uniformDB.values.set(uniform.name, uniform);
}

private setDescriptor(targetBlock: DescriptorBlock, name: string, type: Type) {
const descriptor: Descriptor = new Descriptor(type);
targetBlock.descriptors.set(name, descriptor);
}

public addEffect (asset: EffectAsset): void {
const sz = asset.shaders.length;

let hasCCGlobal = false;
let hasCCCamera = false;
let hasCCShadow = false;
let hasShadowmap = false;
let hasEnv = false;
let hasDiffuse = false;
let hasSpot = false;

for (let i = 0; i !== sz; ++i) {
const shader = asset.shaders[i];
const shader: EffectAsset.IShaderInfo = asset.shaders[i];

const queueDB: DescriptorDB = new DescriptorDB();

for (let k in shader.blocks) {
const blockInfo: EffectAsset.IBlockInfo = shader.blocks[k];
let targetBlock: DescriptorBlock = this.getLayoutBlock(UpdateFrequency.PER_INSTANCE,
ParameterType.TABLE, DescriptorIndex.UNIFORM_BLOCK, blockInfo.stageFlags, queueDB);
let uniformDB: UniformBlockDB = this.getUniformBlock(blockInfo.name, targetBlock);
for (let kk in blockInfo.members) {
const uniform: Uniform = blockInfo.members[kk];
uniformDB.values.set(uniform.name, uniform);
}
}

for (let k in shader.buffers) {
const bufferInfo: EffectAsset.IBufferInfo = shader.buffers[k];
let targetBlock: DescriptorBlock = this.getLayoutBlock(UpdateFrequency.PER_QUEUE,
ParameterType.TABLE, DescriptorIndex.STORAGE_BUFFER, bufferInfo.stageFlags, queueDB);
this.setDescriptor(targetBlock, bufferInfo.name, Type.UNKNOWN);
}

for (let k in shader.images) {
const imageInfo: EffectAsset.IImageInfo = shader.images[k];
let targetBlock: DescriptorBlock = this.getLayoutBlock(UpdateFrequency.PER_QUEUE,
ParameterType.TABLE, DescriptorIndex.STORAGE_TEXTURE, imageInfo.stageFlags, queueDB);
this.setDescriptor(targetBlock, imageInfo.name, imageInfo.type);
}

for (let k in shader.samplerTextures) {
const samplerTexInfo: EffectAsset.ISamplerTextureInfo = shader.samplerTextures[k];
let targetBlock: DescriptorBlock = this.getLayoutBlock(UpdateFrequency.PER_BATCH,
ParameterType.TABLE, DescriptorIndex.SAMPLER_TEXTURE, samplerTexInfo.stageFlags, queueDB);
this.setDescriptor(targetBlock, samplerTexInfo.name, samplerTexInfo.type);
}

for (let k in shader.samplers) {
const samplerInfo: EffectAsset.ISamplerInfo = shader.samplers[k];
let targetBlock: DescriptorBlock = this.getLayoutBlock(UpdateFrequency.PER_QUEUE,
ParameterType.TABLE, DescriptorIndex.SAMPLER, samplerInfo.stageFlags, queueDB);
this.setDescriptor(targetBlock, samplerInfo.name, Type.SAMPLER);
}

for (let k in shader.textures) {
const texInfo: EffectAsset.ITextureInfo = shader.textures[k];
let targetBlock: DescriptorBlock = this.getLayoutBlock(UpdateFrequency.PER_QUEUE,
ParameterType.TABLE, DescriptorIndex.TEXTURE, texInfo.stageFlags, queueDB);
this.setDescriptor(targetBlock, texInfo.name, texInfo.type);
}

for (let k in shader.subpassInputs) {
const subpassInfo: EffectAsset.IInputAttachmentInfo = shader.subpassInputs[k];
let targetBlock: DescriptorBlock = this.getLayoutBlock(UpdateFrequency.PER_QUEUE,
ParameterType.TABLE, DescriptorIndex.SUBPASS_INPUT, subpassInfo.stageFlags, queueDB);
this.setDescriptor(targetBlock, subpassInfo.name, Type.SUBPASS_INPUT);
}

// Add queue layout from define.ts
const localUniformTarget: DescriptorBlock = this.getLayoutBlock(UpdateFrequency.PER_INSTANCE,
ParameterType.TABLE, DescriptorIndex.UNIFORM_BLOCK, ShaderStageFlagBit.VERTEX, queueDB);
const localLightTarget: DescriptorBlock = this.getLayoutBlock(UpdateFrequency.PER_QUEUE,
ParameterType.TABLE, DescriptorIndex.UNIFORM_BLOCK, ShaderStageFlagBit.FRAGMENT, queueDB);
const localModelTarget: DescriptorBlock = this.getLayoutBlock(UpdateFrequency.PER_INSTANCE,
ParameterType.TABLE, DescriptorIndex.UNIFORM_BLOCK, ShaderStageFlagBit.VERTEX | ShaderStageFlagBit.COMPUTE, queueDB);
const localSamplerVertTarget: DescriptorBlock = this.getLayoutBlock(UpdateFrequency.PER_BATCH,
ParameterType.TABLE, DescriptorIndex.SAMPLER_TEXTURE, ShaderStageFlagBit.VERTEX, queueDB);
const localSamplerFragTarget: DescriptorBlock = this.getLayoutBlock(UpdateFrequency.PER_BATCH,
ParameterType.TABLE, DescriptorIndex.SAMPLER_TEXTURE, ShaderStageFlagBit.FRAGMENT, queueDB);
const localSamplerCompTarget: DescriptorBlock = this.getLayoutBlock(UpdateFrequency.PER_BATCH,
ParameterType.TABLE, DescriptorIndex.SAMPLER_TEXTURE, ShaderStageFlagBit.COMPUTE, queueDB);

for (let k = 0; k < shader.builtins.locals.blocks.length; ++k) {
const blockName: string = shader.builtins.locals.blocks[k].name;
if (blockName === 'CCMorph') {
let morphDB: UniformBlockDB = this.getUniformBlock('CCMorph', localUniformTarget);
this.setUniform(morphDB, 'cc_displacementWeights', Type.FLOAT4, UBOMorph.MAX_MORPH_TARGET_COUNT / 4);
this.setUniform(morphDB, 'cc_displacementTextureInfo', Type.FLOAT4, 1);
} else if (blockName === 'CCSkinningTexture') {
let skinningTexDB: UniformBlockDB = this.getUniformBlock('CCSkinningTexture', localUniformTarget);
this.setUniform(skinningTexDB, 'cc_jointTextureInfo', Type.FLOAT4, 1);
} else if (blockName === 'CCSkinningAnimation') {
let skinningAnimDB: UniformBlockDB = this.getUniformBlock('CCSkinningAnimation', localUniformTarget);
this.setUniform(skinningAnimDB, 'cc_jointAnimInfo', Type.FLOAT4, 1);
} else if (blockName === 'CCSkinning') {
let skinningDB: UniformBlockDB = this.getUniformBlock('CCSkinning', localUniformTarget);
this.setUniform(skinningDB, 'cc_joints', Type.FLOAT4, JOINT_UNIFORM_CAPACITY * 3);
} else if (blockName === 'CCUILocal') {
let uiDB: UniformBlockDB = this.getUniformBlock('CCUILocal', localUniformTarget);
this.setUniform(uiDB, 'cc_local_data', Type.FLOAT4, 1);
} else if (blockName === 'CCForwardLight') {
let lightDB: UniformBlockDB = this.getUniformBlock('CCForwardLight', localLightTarget);
this.setUniform(lightDB, 'cc_lightPos', Type.FLOAT4, UBOForwardLight.LIGHTS_PER_PASS);
this.setUniform(lightDB, 'cc_lightColor', Type.FLOAT4, UBOForwardLight.LIGHTS_PER_PASS);
this.setUniform(lightDB, 'cc_lightSizeRangeAngle', Type.FLOAT4, UBOForwardLight.LIGHTS_PER_PASS);
this.setUniform(lightDB, 'cc_lightDir', Type.FLOAT4, UBOForwardLight.LIGHTS_PER_PASS);
} else if (blockName === 'CCLocal') {
let localDB: UniformBlockDB = this.getUniformBlock('CCLocal', localModelTarget);
this.setUniform(localDB, 'cc_matWorld', Type.MAT4, 1);
this.setUniform(localDB, 'cc_matWorldIT', Type.MAT4, 1);
this.setUniform(localDB, 'cc_lightingMapUVParam', Type.FLOAT4, 1);
} else if (blockName === 'CCLocalBatched') {
let batchDB: UniformBlockDB = this.getUniformBlock('CCLocalBatched', localModelTarget);
this.setUniform(batchDB, 'cc_matWorlds', Type.MAT4, UBOLocalBatched.BATCHING_COUNT);
} else if (blockName === 'CCWorldBound') {
let boundDB: UniformBlockDB = this.getUniformBlock('CCWorldBound', localModelTarget);
this.setUniform(boundDB, 'cc_worldBoundCenter', Type.FLOAT4, 1);
this.setUniform(boundDB, 'cc_worldBoundHalfExtents', Type.FLOAT4, 1);
}
}

for (let k = 0; k < shader.builtins.locals.samplerTextures.length; ++k) {
const samplerName: string = shader.builtins.locals.samplerTextures[k].name;
if (samplerName === 'cc_jointTexture') {
this.setDescriptor(localSamplerVertTarget, 'cc_jointTexture', Type.SAMPLER2D);
} else if (samplerName === 'cc_PositionDisplacements') {
this.setDescriptor(localSamplerVertTarget, 'cc_PositionDisplacements', Type.SAMPLER2D);
} else if (samplerName === 'cc_NormalDisplacements') {
this.setDescriptor(localSamplerVertTarget, 'cc_NormalDisplacements', Type.SAMPLER2D);
} else if (samplerName === 'cc_TangentDisplacements') {
this.setDescriptor(localSamplerVertTarget, 'cc_TangentDisplacements', Type.SAMPLER2D);
} else if (samplerName === 'cc_lightingMap') {
this.setDescriptor(localSamplerFragTarget, 'cc_lightingMap', Type.SAMPLER2D);
} else if (samplerName === 'cc_spriteTexture') {
this.setDescriptor(localSamplerFragTarget, 'cc_spriteTexture', Type.SAMPLER2D);
} else if (samplerName === 'cc_reflectionTexture') {
this.setDescriptor(localSamplerFragTarget, 'cc_reflectionTexture', Type.SAMPLER2D);
}
}

for (let k = 0; k < shader.builtins.locals.images.length; ++k) {
const imgName: string = shader.builtins.locals.images[k].name;
if (imgName === 'cc_reflectionStorage') {
this.setDescriptor(localSamplerCompTarget, 'cc_reflectionStorage', Type.IMAGE2D);
}
}

const phase: RenderPhase = new RenderPhase();
phase.shaders.add(shader.name);
this._layoutGraph.addVertex<LayoutGraphValue.RenderPhase>(LayoutGraphValue.RenderPhase, phase, shader.name, queueDB);

for (let k = 0; k < shader.builtins.globals.blocks.length; ++k) {
const blockName = shader.builtins.globals.blocks[k].name;
if (blockName === 'CCGlobal') {
hasCCGlobal = true;
} else if (blockName === 'CCCamera') {
hasCCCamera = true;
} else if (blockName === 'CCShadow') {
hasCCShadow = true;
}
}

for (let k = 0; k < shader.builtins.globals.samplerTextures.length; ++k) {
const samplerName = shader.builtins.globals.samplerTextures[k].name;
if (samplerName === 'cc_shadowMap') {
hasShadowmap = true;
} else if (samplerName === 'cc_environment') {
hasEnv = true;
} else if (samplerName === 'cc_diffuseMap') {
hasDiffuse = true;
} else if (samplerName === 'cc_spotLightingMap') {
hasSpot = true;
}
}
}

const passDB: DescriptorDB = new DescriptorDB();
// Add pass layout from define.ts
let globalUniformTarget: DescriptorBlock = this.getLayoutBlock(UpdateFrequency.PER_PASS,
ParameterType.TABLE, DescriptorIndex.UNIFORM_BLOCK, ShaderStageFlagBit.ALL, passDB);
let globalSamplerTexTarget: DescriptorBlock = this.getLayoutBlock(UpdateFrequency.PER_PASS,
ParameterType.TABLE, DescriptorIndex.SAMPLER_TEXTURE, ShaderStageFlagBit.FRAGMENT, passDB);

if (hasCCGlobal) {
let globalDB: UniformBlockDB = this.getUniformBlock('CCGlobal', globalUniformTarget);
this.setUniform(globalDB, 'cc_time', Type.FLOAT4, 1);
this.setUniform(globalDB, 'cc_screenSize', Type.FLOAT4, 1);
this.setUniform(globalDB, 'cc_nativeSize', Type.FLOAT4, 1);
}

if (hasCCCamera) {
let cameraDB: UniformBlockDB = this.getUniformBlock('CCCamera', globalUniformTarget);
this.setUniform(cameraDB, 'cc_matView', Type.MAT4, 1);
this.setUniform(cameraDB, 'cc_matViewInv', Type.MAT4, 1);
this.setUniform(cameraDB, 'cc_matProj', Type.MAT4, 1);
this.setUniform(cameraDB, 'cc_matProjInv', Type.MAT4, 1);
this.setUniform(cameraDB, 'cc_matViewProj', Type.MAT4, 1);
this.setUniform(cameraDB, 'cc_matViewProjInv', Type.MAT4, 1);
this.setUniform(cameraDB, 'cc_cameraPos', Type.FLOAT4, 1);
this.setUniform(cameraDB, 'cc_screenScale', Type.FLOAT4, 1);
this.setUniform(cameraDB, 'cc_exposure', Type.FLOAT4, 1);
this.setUniform(cameraDB, 'cc_mainLitDir', Type.FLOAT4, 1);
this.setUniform(cameraDB, 'cc_mainLitColor', Type.FLOAT4, 1);
this.setUniform(cameraDB, 'cc_ambientSky', Type.FLOAT4, 1);
this.setUniform(cameraDB, 'cc_ambientGround', Type.FLOAT4, 1);
this.setUniform(cameraDB, 'cc_fogColor', Type.FLOAT4, 1);
this.setUniform(cameraDB, 'cc_fogBase', Type.FLOAT4, 1);
this.setUniform(cameraDB, 'cc_fogAdd', Type.FLOAT4, 1);
this.setUniform(cameraDB, 'cc_nearFar', Type.FLOAT4, 1);
this.setUniform(cameraDB, 'cc_viewPort', Type.FLOAT4, 1);
}

if (hasCCShadow) {
let shadowDB: UniformBlockDB = this.getUniformBlock('CCShadow', globalUniformTarget);
this.setUniform(shadowDB, 'cc_matLightPlaneProj', Type.MAT4, 1);
this.setUniform(shadowDB, 'cc_matLightView', Type.MAT4, 1);
this.setUniform(shadowDB, 'cc_matLightViewProj', Type.MAT4, 1);
this.setUniform(shadowDB, 'cc_shadowInvProjDepthInfo', Type.FLOAT4, 1);
this.setUniform(shadowDB, 'cc_shadowProjDepthInfo', Type.FLOAT4, 1);
this.setUniform(shadowDB, 'cc_shadowProjInfo', Type.FLOAT4, 1);
this.setUniform(shadowDB, 'cc_shadowNFLSInfo', Type.FLOAT4, 1);
this.setUniform(shadowDB, 'cc_shadowWHPBInfo', Type.FLOAT4, 1);
this.setUniform(shadowDB, 'cc_shadowLPNNInfo', Type.FLOAT4, 1);
this.setUniform(shadowDB, 'cc_shadowColor', Type.FLOAT4, 1);
}

if (hasShadowmap) {
this.setDescriptor(globalSamplerTexTarget, 'cc_shadowMap', Type.SAMPLER2D);
}
if (hasEnv) {
this.setDescriptor(globalSamplerTexTarget, 'cc_environment', Type.SAMPLER_CUBE);
}
if (hasDiffuse) {
this.setDescriptor(globalSamplerTexTarget, 'cc_diffuseMap', Type.SAMPLER_CUBE);
}
if (hasSpot) {
this.setDescriptor(globalSamplerTexTarget, 'cc_spotLightingMap', Type.SAMPLER2D);
}

this._layoutGraph.addVertex<LayoutGraphValue.RenderStage>(LayoutGraphValue.RenderStage, LayoutGraphValue.RenderStage, asset.name, passDB);
}
private _layoutGraph: LayoutGraph;

public get layoutGraph () {
return this._layoutGraph;
}
}