no message

This commit is contained in:
gem
2025-02-18 15:21:31 +08:00
commit 2d133e56d7
1980 changed files with 465595 additions and 0 deletions

View File

@@ -0,0 +1,894 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "ClusterLightCulling.h"
#include "Define.h"
#include "PipelineSceneData.h"
#include "PipelineUBO.h"
#include "base/StringUtil.h"
#include "deferred/DeferredPipeline.h"
#include "frame-graph/FrameGraph.h"
#include "renderer/gfx-base/GFXDevice.h"
#include "renderer/pipeline/RenderPipeline.h"
#include "scene/Camera.h"
#include "scene/SphereLight.h"
#include "scene/SpotLight.h"
#include "scene/PointLight.h"
#include "scene/RangedDirectionalLight.h"
namespace cc {
namespace pipeline {
framegraph::StringHandle fgStrHandleClusterBuffer = framegraph::FrameGraph::stringToHandle("clusterBuffer");
framegraph::StringHandle fgStrHandleClusterGlobalIndexBuffer = framegraph::FrameGraph::stringToHandle("globalIndexBuffer");
framegraph::StringHandle fgStrHandleClusterLightBuffer = framegraph::FrameGraph::stringToHandle("clusterLightBuffer");
framegraph::StringHandle fgStrHandleClusterLightIndexBuffer = framegraph::FrameGraph::stringToHandle("lightIndexBuffer");
framegraph::StringHandle fgStrHandleClusterLightGridBuffer = framegraph::FrameGraph::stringToHandle("lightGridBuffer");
framegraph::StringHandle fgStrHandleClusterBuildPass = framegraph::FrameGraph::stringToHandle("clusterBuildPass");
framegraph::StringHandle fgStrHandleClusterCullingPass = framegraph::FrameGraph::stringToHandle("clusterCullingPass");
ClusterLightCulling::ClusterLightCulling(RenderPipeline *pipeline) : _pipeline(pipeline) {
}
ClusterLightCulling::~ClusterLightCulling() = default;
void ClusterLightCulling::initialize(gfx::Device *dev) {
_device = dev;
if (!_device->hasFeature(gfx::Feature::COMPUTE_SHADER)) return;
uint32_t maxInvocations = _device->getCapabilities().maxComputeWorkGroupInvocations;
if (CLUSTERS_X_THREADS * CLUSTERS_Y_THREADS * 4 <= maxInvocations) {
clusterZThreads = 4;
} else if (CLUSTERS_X_THREADS * CLUSTERS_Y_THREADS * 2 <= maxInvocations) {
clusterZThreads = 2;
} else {
clusterZThreads = 1;
}
CC_ASSERT(CLUSTERS_X_THREADS * CLUSTERS_Y_THREADS * clusterZThreads <= maxInvocations); // maxInvocations is too small
CC_LOG_INFO(" work group size: %dx%dx%d", CLUSTERS_X_THREADS, CLUSTERS_Y_THREADS, clusterZThreads);
_constantsBuffer = _device->createBuffer({
gfx::BufferUsageBit::UNIFORM,
gfx::MemoryUsageBit::HOST | gfx::MemoryUsageBit::DEVICE,
2 * sizeof(Vec4) + 2 * sizeof(Mat4),
2 * sizeof(Vec4) + 2 * sizeof(Mat4),
gfx::BufferFlagBit::NONE,
});
_lightBufferStride = 4 * sizeof(Vec4);
_buildingDispatchInfo = {CLUSTERS_X / CLUSTERS_X_THREADS, CLUSTERS_Y / CLUSTERS_Y_THREADS, CLUSTERS_Z / clusterZThreads};
_resetDispatchInfo = {1, 1, 1};
_cullingDispatchInfo = {CLUSTERS_X / CLUSTERS_X_THREADS, CLUSTERS_Y / CLUSTERS_Y_THREADS, CLUSTERS_Z / clusterZThreads};
_resetBarrier = _device->getGeneralBarrier({
gfx::AccessFlagBit::COMPUTE_SHADER_WRITE,
gfx::AccessFlagBit::COMPUTE_SHADER_READ_OTHER,
});
initBuildingSatge();
initResetStage();
initCullingStage();
_initialized = true;
}
void ClusterLightCulling::update() {
if (!_initialized) return;
auto *const sceneData = _pipeline->getPipelineSceneData();
_constants[NEAR_FAR_OFFSET + 0] = static_cast<float>(_camera->getNearClip());
_constants[NEAR_FAR_OFFSET + 1] = static_cast<float>(_camera->getFarClip());
const auto &viewport = _camera->getViewport();
_constants[VIEW_PORT_OFFSET + 0] = viewport.x * static_cast<float>(_camera->getWidth()) * sceneData->getShadingScale();
_constants[VIEW_PORT_OFFSET + 1] = viewport.y * static_cast<float>(_camera->getHeight()) * sceneData->getShadingScale();
_constants[VIEW_PORT_OFFSET + 2] = viewport.z * static_cast<float>(_camera->getWidth()) * sceneData->getShadingScale();
_constants[VIEW_PORT_OFFSET + 3] = viewport.w * static_cast<float>(_camera->getHeight()) * sceneData->getShadingScale();
memcpy(_constants.data() + MAT_VIEW_OFFSET, _camera->getMatView().m, sizeof(cc::Mat4));
memcpy(_constants.data() + MAT_PROJ_INV_OFFSET, _camera->getMatProjInv().m, sizeof(cc::Mat4));
_constantsBuffer->update(_constants.data(), 2 * sizeof(Vec4) + 2 * sizeof(Mat4));
updateLights();
uint32_t cameraIndex = _pipeline->getPipelineUBO()->getCurrentCameraUBOOffset();
if (cameraIndex >= _oldCamProjMats.size()) {
_rebuildClusters = true;
uint32_t nextLength = std::max(nextPow2(static_cast<uint32_t>(cameraIndex)), uint32_t(1));
_oldCamProjMats.resize(nextLength, Mat4::ZERO);
_oldCamProjMats[cameraIndex] = _camera->getMatProj();
} else {
_rebuildClusters = ClusterLightCulling::isProjMatChange(_camera->getMatProj(), _oldCamProjMats[cameraIndex]);
_oldCamProjMats[cameraIndex] = _camera->getMatProj();
}
}
void ClusterLightCulling::updateLights() {
if (!_pipeline) {
return;
}
_validLights.clear();
geometry::Sphere sphere;
const auto *const scene = _camera->getScene();
for (const auto &light : scene->getSphereLights()) {
sphere.setCenter(light->getPosition());
sphere.setRadius(light->getRange());
if (sphere.sphereFrustum(_camera->getFrustum())) {
_validLights.emplace_back(static_cast<scene::Light *>(light));
}
}
for (const auto &light : scene->getSpotLights()) {
sphere.setCenter(light->getPosition());
sphere.setRadius(light->getRange());
if (sphere.sphereFrustum(_camera->getFrustum())) {
_validLights.emplace_back(static_cast<scene::Light *>(light));
}
}
for (const auto &light : scene->getPointLights()) {
sphere.setCenter(light->getPosition());
sphere.setRadius(light->getRange());
if (sphere.sphereFrustum(_camera->getFrustum())) {
_validLights.emplace_back(static_cast<scene::Light *>(light));
}
}
for (const auto &light : scene->getRangedDirLights()) {
geometry::AABB rangedDirLightBoundingBox(0.0F, 0.0F, 0.0F, 0.5F, 0.5F, 0.5F);
light->getNode()->updateWorldTransform();
rangedDirLightBoundingBox.transform(light->getNode()->getWorldMatrix(), &rangedDirLightBoundingBox);
if (rangedDirLightBoundingBox.aabbFrustum(_camera->getFrustum())) {
_validLights.emplace_back(static_cast<scene::Light *>(light));
}
}
const auto exposure = _camera->getExposure();
const auto validLightCount = _validLights.size();
auto *const sceneData = _pipeline->getPipelineSceneData();
if (validLightCount > _lightBufferCount) {
_lightBufferResized = true;
_lightBufferCount = nextPow2(static_cast<uint32_t>(validLightCount));
_lightBufferData.resize(16 * _lightBufferCount);
}
for (unsigned l = 0, offset = 0; l < validLightCount; l++, offset += 16) {
auto *light = _validLights[l];
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<const scene::SphereLight *>(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<const scene::SpotLight *>(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<const scene::PointLight *>(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<const scene::RangedDirectionalLight *>(light);
position = rangedDirLight->getPosition();
size = 0.0F;
range = 0.0F;
luminanceHDR = rangedDirLight->getIlluminanceHDR();
luminanceLDR = rangedDirLight->getIlluminanceLDR();
}
auto index = offset + UBOForwardLight::LIGHT_POS_OFFSET;
_lightBufferData[index++] = position.x;
_lightBufferData[index++] = position.y;
_lightBufferData[index] = position.z;
index = offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET;
_lightBufferData[index++] = size;
_lightBufferData[index] = range;
index = offset + UBOForwardLight::LIGHT_COLOR_OFFSET;
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 (sceneData->isHDR()) {
_lightBufferData[index] = luminanceHDR * exposure * _lightMeterScale;
} else {
_lightBufferData[index] = luminanceLDR;
}
switch (light->getType()) {
case scene::LightType::SPHERE: {
_lightBufferData[offset + UBOForwardLight::LIGHT_POS_OFFSET + 3] = static_cast<float>(scene::LightType::SPHERE);
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 2] = 0;
} break;
case scene::LightType::SPOT: {
const auto *spotLight = static_cast<const scene::SpotLight *>(light);
_lightBufferData[offset + UBOForwardLight::LIGHT_POS_OFFSET + 3] = static_cast<float>(scene::LightType::SPOT);
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 2] = spotLight->getSpotAngle();
index = offset + 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 + UBOForwardLight::LIGHT_POS_OFFSET + 3] = static_cast<float>(scene::LightType::POINT);
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 2] = 0;
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 3] = 0;
} break;
case scene::LightType::RANGED_DIRECTIONAL: {
const auto *rangedDirLight = static_cast<scene::RangedDirectionalLight *>(light);
_lightBufferData[offset + UBOForwardLight::LIGHT_POS_OFFSET + 3] = static_cast<float>(scene::LightType::RANGED_DIRECTIONAL);
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 0] = rangedDirLight->getRight().x;
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 1] = rangedDirLight->getRight().y;
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 2] = rangedDirLight->getRight().z;
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 3] = 0.0F;
_lightBufferData[offset + UBOForwardLight::LIGHT_DIR_OFFSET + 0] = rangedDirLight->getDirection().x;
_lightBufferData[offset + UBOForwardLight::LIGHT_DIR_OFFSET + 1] = rangedDirLight->getDirection().y;
_lightBufferData[offset + UBOForwardLight::LIGHT_DIR_OFFSET + 2] = rangedDirLight->getDirection().z;
_lightBufferData[offset + UBOForwardLight::LIGHT_DIR_OFFSET + 3] = 0.0F;
_lightBufferData[offset + UBOForwardLight::LIGHT_BOUNDING_SIZE_VS_OFFSET + 0] = rangedDirLight->getScale().x * 0.5F;
_lightBufferData[offset + UBOForwardLight::LIGHT_BOUNDING_SIZE_VS_OFFSET + 1] = rangedDirLight->getScale().y * 0.5F;
_lightBufferData[offset + UBOForwardLight::LIGHT_BOUNDING_SIZE_VS_OFFSET + 2] = rangedDirLight->getScale().z * 0.5F;
_lightBufferData[offset + UBOForwardLight::LIGHT_BOUNDING_SIZE_VS_OFFSET + 3] = 0.0F;
} break;
default:
break;
}
}
if (validLightCount > 0) {
// the count of lights is set to cc_lightDir[0].w
_lightBufferData[3 * 4 + 3] = static_cast<float>(validLightCount);
}
}
void ClusterLightCulling::initBuildingSatge() {
ShaderStrings sources;
sources.glsl4 = StringUtil::format(
R"(
#define CLUSTERS_X 16
#define CLUSTERS_Y 8
layout(set=0, binding=0, std140) uniform CCConst {
vec4 cc_nearFar;
vec4 cc_viewPort;
mat4 cc_matView;
mat4 cc_matProjInv;
};
layout(set=0, binding=1, std430) buffer b_clustersBuffer { vec4 b_clusters[]; };
vec4 screen2Eye(vec4 coord) {
vec3 ndc = vec3(
2.0 * (coord.x - cc_viewPort.x) / cc_viewPort.z - 1.0,
2.0 * (coord.y - cc_viewPort.y) / cc_viewPort.w - 1.0,
2.0 * coord.z - 1.0);
vec4 eye = ((cc_matProjInv) * (vec4(ndc, 1.0)));
eye = eye / eye.w;
return eye;
}
layout(local_size_x=16, local_size_y=8, local_size_z=%d) in;
void main() {
uint32_t clusterIndex = gl_GlobalInvocationID.z * uvec3(16, 8, %d).x * uvec3(16, 8, %d).y +
gl_GlobalInvocationID.y * uvec3(16, 8, %d).x + gl_GlobalInvocationID.x;
float clusterSizeX = ceil(cc_viewPort.z / float(CLUSTERS_X));
float clusterSizeY = ceil(cc_viewPort.w / float(CLUSTERS_Y));
vec4 minScreen = vec4(vec2(gl_GlobalInvocationID.xy) * vec2(clusterSizeX, clusterSizeY), 1.0, 1.0);
vec4 maxScreen = vec4(vec2(gl_GlobalInvocationID.xy + uvec2(1, 1)) * vec2(clusterSizeX, clusterSizeY), 1.0, 1.0);
vec3 minEye = screen2Eye(minScreen).xyz;
vec3 maxEye = screen2Eye(maxScreen).xyz;
float clusterNear = -cc_nearFar.x * pow(cc_nearFar.y / cc_nearFar.x, float(gl_GlobalInvocationID.z) / float(24));
float clusterFar = -cc_nearFar.x * pow(cc_nearFar.y / cc_nearFar.x, float(gl_GlobalInvocationID.z + 1u) / float(24));
vec3 minNear = minEye * clusterNear / minEye.z;
vec3 minFar = minEye * clusterFar / minEye.z;
vec3 maxNear = maxEye * clusterNear / maxEye.z;
vec3 maxFar = maxEye * clusterFar / maxEye.z;
vec3 minBounds = min(min(minNear, minFar), min(maxNear, maxFar));
vec3 maxBounds = max(max(minNear, minFar), max(maxNear, maxFar));
b_clusters[2u * clusterIndex + 0u] = vec4(minBounds, 1.0);
b_clusters[2u * clusterIndex + 1u] = vec4(maxBounds, 1.0);
})",
clusterZThreads, clusterZThreads, clusterZThreads, clusterZThreads);
sources.glsl3 = StringUtil::format(
R"(
#define CLUSTERS_X 16
#define CLUSTERS_Y 8
layout(std140) uniform CCConst {
vec4 cc_nearFar;
vec4 cc_viewPort;
mat4 cc_matView;
mat4 cc_matProjInv;
};
layout(std430, binding=1) buffer b_clustersBuffer { vec4 b_clusters[]; };
vec4 screen2Eye(vec4 coord) {
vec3 ndc = vec3(
2.0 * (coord.x - cc_viewPort.x) / cc_viewPort.z - 1.0,
2.0 * (coord.y - cc_viewPort.y) / cc_viewPort.w - 1.0,
2.0 * coord.z - 1.0);
vec4 eye = ((cc_matProjInv) * (vec4(ndc, 1.0)));
eye = eye / eye.w;
return eye;
}
layout(local_size_x=16, local_size_y=8, local_size_z=%d) in;
void main() {
uint32_t clusterIndex = gl_GlobalInvocationID.z * uvec3(16, 8, %d).x * uvec3(16, 8, %d).y +
gl_GlobalInvocationID.y * uvec3(16, 8, %d).x + gl_GlobalInvocationID.x;
float clusterSizeX = ceil(cc_viewPort.z / float(CLUSTERS_X));
float clusterSizeY = ceil(cc_viewPort.w / float(CLUSTERS_Y));
vec4 minScreen = vec4(vec2(gl_GlobalInvocationID.xy) * vec2(clusterSizeX, clusterSizeY), 1.0, 1.0);
vec4 maxScreen = vec4(vec2(gl_GlobalInvocationID.xy + uvec2(1, 1)) * vec2(clusterSizeX, clusterSizeY), 1.0, 1.0);
vec3 minEye = screen2Eye(minScreen).xyz;
vec3 maxEye = screen2Eye(maxScreen).xyz;
float clusterNear = -cc_nearFar.x * pow(cc_nearFar.y / cc_nearFar.x, float(gl_GlobalInvocationID.z) / float(24));
float clusterFar = -cc_nearFar.x * pow(cc_nearFar.y / cc_nearFar.x, float(gl_GlobalInvocationID.z + 1u) / float(24));
vec3 minNear = minEye * clusterNear / minEye.z;
vec3 minFar = minEye * clusterFar / minEye.z;
vec3 maxNear = maxEye * clusterNear / maxEye.z;
vec3 maxFar = maxEye * clusterFar / maxEye.z;
vec3 minBounds = min(min(minNear, minFar), min(maxNear, maxFar));
vec3 maxBounds = max(max(minNear, minFar), max(maxNear, maxFar));
b_clusters[2u * clusterIndex + 0u] = vec4(minBounds, 1.0);
b_clusters[2u * clusterIndex + 1u] = vec4(maxBounds, 1.0);
})",
clusterZThreads, clusterZThreads, clusterZThreads, clusterZThreads);
// no compute support in GLES2
gfx::ShaderInfo shaderInfo;
shaderInfo.name = "Compute ";
shaderInfo.stages = {{gfx::ShaderStageFlagBit::COMPUTE, getShaderSource(sources)}};
shaderInfo.blocks = {
{0, 0, "CCConst", {{"cc_nearFar", gfx::Type::FLOAT4, 1}, {"cc_viewPort", gfx::Type::FLOAT4, 1}, {"cc_matView", gfx::Type::MAT4, 1}, {"cc_matProjInv", gfx::Type::MAT4, 1}}, 1},
};
shaderInfo.buffers = {{0, 1, "b_clustersBuffer", 1, gfx::MemoryAccessBit::WRITE_ONLY}};
_buildingShader = _device->createShader(shaderInfo);
gfx::DescriptorSetLayoutInfo dslInfo;
dslInfo.bindings.push_back({0, gfx::DescriptorType::UNIFORM_BUFFER, 1, gfx::ShaderStageFlagBit::COMPUTE});
dslInfo.bindings.push_back({1, gfx::DescriptorType::STORAGE_BUFFER, 1, gfx::ShaderStageFlagBit::COMPUTE});
_buildingDescriptorSetLayout = _device->createDescriptorSetLayout(dslInfo);
_buildingDescriptorSet = _device->createDescriptorSet({_buildingDescriptorSetLayout});
_buildingPipelineLayout = _device->createPipelineLayout({{_buildingDescriptorSetLayout}});
gfx::PipelineStateInfo pipelineInfo;
pipelineInfo.shader = _buildingShader;
pipelineInfo.pipelineLayout = _buildingPipelineLayout;
pipelineInfo.bindPoint = gfx::PipelineBindPoint::COMPUTE;
_buildingPipelineState = _device->createPipelineState(pipelineInfo);
}
void ClusterLightCulling::initResetStage() {
ShaderStrings sources;
sources.glsl4 = StringUtil::format(
R"(
layout(std430, binding = 0) buffer b_globalIndexBuffer { uint32_t b_globalIndex[]; };
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main()
{
if (gl_GlobalInvocationID.x == 0u) {
b_globalIndex[0] = 0u;
}
}
)");
sources.glsl3 = StringUtil::format(
R"(
layout(std430, binding = 0) buffer b_globalIndexBuffer { uint32_t b_globalIndex[]; };
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main()
{
if (gl_GlobalInvocationID.x == 0u) {
b_globalIndex[0] = 0u;
}
}
)");
// no compute support in GLES2
gfx::ShaderInfo shaderInfo;
shaderInfo.name = "Compute ";
shaderInfo.stages = {{gfx::ShaderStageFlagBit::COMPUTE, getShaderSource(sources)}};
shaderInfo.buffers = {{0, 0, "b_globalIndexBuffer", 1, gfx::MemoryAccessBit::WRITE_ONLY}};
_resetCounterShader = _device->createShader(shaderInfo);
gfx::DescriptorSetLayoutInfo dslInfo;
dslInfo.bindings.push_back({0, gfx::DescriptorType::STORAGE_BUFFER, 1, gfx::ShaderStageFlagBit::COMPUTE});
_resetCounterDescriptorSetLayout = _device->createDescriptorSetLayout(dslInfo);
_resetCounterDescriptorSet = _device->createDescriptorSet({_resetCounterDescriptorSetLayout});
_resetCounterPipelineLayout = _device->createPipelineLayout({{_resetCounterDescriptorSetLayout}});
gfx::PipelineStateInfo pipelineInfo;
pipelineInfo.shader = _resetCounterShader;
pipelineInfo.pipelineLayout = _resetCounterPipelineLayout;
pipelineInfo.bindPoint = gfx::PipelineBindPoint::COMPUTE;
_resetCounterPipelineState = _device->createPipelineState(pipelineInfo);
}
void ClusterLightCulling::initCullingStage() {
ShaderStrings sources;
sources.glsl4 = StringUtil::format(
R"(
layout(set=0, binding=0, std140) uniform CCConst {
vec4 cc_nearFar;
vec4 cc_viewPort;
mat4 cc_matView;
mat4 cc_matProjInv;
};
layout(set=0, binding=1, std430) readonly buffer b_ccLightsBuffer { vec4 b_ccLights[]; };
layout(set=0, binding=2, std430) buffer b_clusterLightIndicesBuffer { uint32_t b_clusterLightIndices[]; };
layout(set=0, binding=3, std430) buffer b_clusterLightGridBuffer { uvec4 b_clusterLightGrid[]; };
layout(set=0, binding=4, std430) buffer b_clustersBuffer { vec4 b_clusters[]; };
layout(set=0, binding=5, std430) buffer b_globalIndexBuffer { uint32_t b_globalIndex[]; };
struct CCLight {
vec4 cc_lightPos;
vec4 cc_lightColor;
vec4 cc_lightSizeRangeAngle;
vec4 cc_lightDir;
};
uint32_t ccLightCount()
{
return uint32_t(b_ccLights[3].w);
}
CCLight getCCLight(uint32_t i)
{
CCLight light;
light.cc_lightPos = b_ccLights[4u * i + 0u];
light.cc_lightColor = b_ccLights[4u * i + 1u];
light.cc_lightSizeRangeAngle = b_ccLights[4u * i + 2u];
light.cc_lightDir = b_ccLights[4u * i + 3u];
return light;
}
struct Cluster {
vec3 minBounds;
vec3 maxBounds;
};
struct LightGrid {
uint32_t offset;
uint32_t ccLights;
};
Cluster getCluster(uint32_t index)
{
Cluster cluster;
cluster.minBounds = b_clusters[2u * index + 0u].xyz;
cluster.maxBounds = b_clusters[2u * index + 1u].xyz;
return cluster;
}
bool ccLightIntersectsCluster(CCLight light, Cluster cluster)
{
if (light.cc_lightPos.w > 0.0) {
vec3 halfExtents = (cluster.maxBounds - cluster.minBounds) * 0.5;
vec3 center = (cluster.minBounds + cluster.maxBounds) * 0.5;
float sphereRadius = sqrt(dot(halfExtents, halfExtents));
light.cc_lightDir = ((cc_matView) * (vec4(light.cc_lightDir.xyz, 1.0)));
light.cc_lightDir.xyz = normalize((light.cc_lightDir - ((cc_matView) * (vec4(0,0,0, 1.0)))).xyz).xyz;
vec3 v = center - light.cc_lightPos.xyz;
float lenSq = dot(v, v);
float v1Len = dot(v, light.cc_lightDir.xyz);
float cosAngle = light.cc_lightSizeRangeAngle.z;
float sinAngle = sqrt(1.0 - cosAngle * cosAngle);
float distanceClosestPoint = cosAngle * sqrt(lenSq - v1Len * v1Len) - v1Len * sinAngle;
bool angleCull = distanceClosestPoint > sphereRadius;
bool frontCull = v1Len > sphereRadius + light.cc_lightSizeRangeAngle.y;
bool backCull = v1Len < -sphereRadius;
return !(angleCull || frontCull || backCull);
}
vec3 closest = max(cluster.minBounds, min(light.cc_lightPos.xyz, cluster.maxBounds));
vec3 dist = closest - light.cc_lightPos.xyz;
return dot(dist, dist) <= (light.cc_lightSizeRangeAngle.y * light.cc_lightSizeRangeAngle.y);
}
shared CCLight lights[(16 * 8 * %d)];
layout(local_size_x = 16, local_size_y = 8, local_size_z = %d) in;
void main()
{
uint32_t visibleLights[100];
uint32_t visibleCount = 0u;
uint32_t clusterIndex = gl_GlobalInvocationID.z * uvec3(16, 8, %d).x * uvec3(16, 8, %d).y +
gl_GlobalInvocationID.y * uvec3(16, 8, %d).x + gl_GlobalInvocationID.x;
Cluster cluster = getCluster(clusterIndex);
uint32_t lightCount = ccLightCount();
uint32_t lightOffset = 0u;
while (lightOffset < lightCount) {
uint32_t batchSize = min((16u * 8u * %du), lightCount - lightOffset);
if (uint32_t(gl_LocalInvocationIndex) < batchSize) {
uint32_t lightIndex = lightOffset + gl_LocalInvocationIndex;
CCLight light = getCCLight(lightIndex);
light.cc_lightPos.xyz = ((cc_matView) * (vec4(light.cc_lightPos.xyz, 1.0))).xyz;
lights[gl_LocalInvocationIndex] = light;
}
barrier();
for (uint32_t i = 0u; i < batchSize; i++) {
if (visibleCount < 100u && ccLightIntersectsCluster(lights[i], cluster)) {
visibleLights[visibleCount] = lightOffset + i;
visibleCount++;
}
}
lightOffset += batchSize;
}
barrier();
uint32_t offset = 0u;
offset = atomicAdd(b_globalIndex[0], visibleCount);
for (uint32_t i = 0u; i < visibleCount; i++) {
b_clusterLightIndices[offset + i] = visibleLights[i];
}
b_clusterLightGrid[clusterIndex] = uvec4(offset, visibleCount, 0, 0);
})",
clusterZThreads, clusterZThreads, clusterZThreads, clusterZThreads, clusterZThreads, clusterZThreads);
sources.glsl3 = StringUtil::format(
R"(
layout(std140) uniform CCConst {
vec4 cc_nearFar;
vec4 cc_viewPort;
mat4 cc_matView;
mat4 cc_matProjInv;
};
layout(std430, binding=1) readonly buffer b_ccLightsBuffer { vec4 b_ccLights[]; };
layout(std430, binding=2) buffer b_clusterLightIndicesBuffer { uint32_t b_clusterLightIndices[]; };
layout(std430, binding=3) buffer b_clusterLightGridBuffer { uvec4 b_clusterLightGrid[]; };
layout(std430, binding=4) buffer b_clustersBuffer { vec4 b_clusters[]; };
layout(std430, binding=5) buffer b_globalIndexBuffer { uint32_t b_globalIndex[]; };
struct CCLight {
vec4 cc_lightPos;
vec4 cc_lightColor;
vec4 cc_lightSizeRangeAngle;
vec4 cc_lightDir;
};
uint32_t ccLightCount()
{
return uint32_t(b_ccLights[3].w);
}
CCLight getCCLight(uint32_t i)
{
CCLight light;
light.cc_lightPos = b_ccLights[4u * i + 0u];
light.cc_lightColor = b_ccLights[4u * i + 1u];
light.cc_lightSizeRangeAngle = b_ccLights[4u * i + 2u];
light.cc_lightDir = b_ccLights[4u * i + 3u];
return light;
}
struct Cluster {
vec3 minBounds;
vec3 maxBounds;
};
struct LightGrid {
uint32_t offset;
uint32_t ccLights;
};
Cluster getCluster(uint32_t index)
{
Cluster cluster;
cluster.minBounds = b_clusters[2u * index + 0u].xyz;
cluster.maxBounds = b_clusters[2u * index + 1u].xyz;
return cluster;
}
bool ccLightIntersectsCluster(CCLight light, Cluster cluster)
{
if (light.cc_lightPos.w > 0.0) {
vec3 halfExtents = (cluster.maxBounds - cluster.minBounds) * 0.5;
vec3 center = (cluster.minBounds + cluster.maxBounds) * 0.5;
float sphereRadius = sqrt(dot(halfExtents, halfExtents));
light.cc_lightDir = ((cc_matView) * (vec4(light.cc_lightDir.xyz, 1.0)));
light.cc_lightDir.xyz = normalize((light.cc_lightDir - ((cc_matView) * (vec4(0,0,0, 1.0)))).xyz).xyz;
vec3 v = center - light.cc_lightPos.xyz;
float lenSq = dot(v, v);
float v1Len = dot(v, light.cc_lightDir.xyz);
float cosAngle = light.cc_lightSizeRangeAngle.z;
float sinAngle = sqrt(1.0 - cosAngle * cosAngle);
float distanceClosestPoint = cosAngle * sqrt(lenSq - v1Len * v1Len) - v1Len * sinAngle;
bool angleCull = distanceClosestPoint > sphereRadius;
bool frontCull = v1Len > sphereRadius + light.cc_lightSizeRangeAngle.y;
bool backCull = v1Len < -sphereRadius;
return !(angleCull || frontCull || backCull);
}
vec3 closest = max(cluster.minBounds, min(light.cc_lightPos.xyz, cluster.maxBounds));
vec3 dist = closest - light.cc_lightPos.xyz;
return dot(dist, dist) <= (light.cc_lightSizeRangeAngle.y * light.cc_lightSizeRangeAngle.y);
}
shared CCLight lights[(16 * 8 * %d)];
layout(local_size_x = 16, local_size_y = 8, local_size_z = %d) in;
void main()
{
uint32_t visibleLights[100];
uint32_t visibleCount = 0u;
uint32_t clusterIndex = gl_GlobalInvocationID.z * uvec3(16, 8, %d).x * uvec3(16, 8, %d).y +
gl_GlobalInvocationID.y * uvec3(16, 8, %d).x + gl_GlobalInvocationID.x;
Cluster cluster = getCluster(clusterIndex);
uint32_t lightCount = ccLightCount();
uint32_t lightOffset = 0u;
while (lightOffset < lightCount) {
uint32_t batchSize = min((16u * 8u * %du), lightCount - lightOffset);
if (uint32_t(gl_LocalInvocationIndex) < batchSize) {
uint32_t lightIndex = lightOffset + gl_LocalInvocationIndex;
CCLight light = getCCLight(lightIndex);
light.cc_lightPos.xyz = ((cc_matView) * (vec4(light.cc_lightPos.xyz, 1.0))).xyz;
lights[gl_LocalInvocationIndex] = light;
}
barrier();
for (uint32_t i = 0u; i < batchSize; i++) {
if (visibleCount < 100u && ccLightIntersectsCluster(lights[i], cluster)) {
visibleLights[visibleCount] = lightOffset + i;
visibleCount++;
}
}
lightOffset += batchSize;
}
barrier();
uint32_t offset = 0u;
offset = atomicAdd(b_globalIndex[0], visibleCount);
for (uint32_t i = 0u; i < visibleCount; i++) {
b_clusterLightIndices[offset + i] = visibleLights[i];
}
b_clusterLightGrid[clusterIndex] = uvec4(offset, visibleCount, 0, 0);
})",
clusterZThreads, clusterZThreads, clusterZThreads, clusterZThreads, clusterZThreads, clusterZThreads);
// no compute support in GLES2
gfx::ShaderInfo shaderInfo;
shaderInfo.name = "Compute ";
shaderInfo.stages = {{gfx::ShaderStageFlagBit::COMPUTE, getShaderSource(sources)}};
shaderInfo.blocks = {
{0, 0, "CCConst", {{"cc_nearFar", gfx::Type::FLOAT4, 1}, {"cc_viewPort", gfx::Type::FLOAT4, 1}, {"cc_matView", gfx::Type::MAT4, 1}, {"cc_matProjInv", gfx::Type::MAT4, 1}}, 1},
};
shaderInfo.buffers = {{0, 1, "b_ccLightsBuffer", 1, gfx::MemoryAccessBit::READ_ONLY},
{0, 2, "b_clusterLightIndicesBuffer", 1, gfx::MemoryAccessBit::WRITE_ONLY},
{0, 3, "b_clusterLightGridBuffer", 1, gfx::MemoryAccessBit::WRITE_ONLY},
{0, 4, "b_clustersBuffer", 1, gfx::MemoryAccessBit::READ_ONLY},
{0, 5, "b_globalIndexBuffer", 1, gfx::MemoryAccessBit::READ_WRITE}};
_cullingShader = _device->createShader(shaderInfo);
gfx::DescriptorSetLayoutInfo dslInfo;
dslInfo.bindings.push_back({0, gfx::DescriptorType::UNIFORM_BUFFER, 1, gfx::ShaderStageFlagBit::COMPUTE});
dslInfo.bindings.push_back({1, gfx::DescriptorType::STORAGE_BUFFER, 1, gfx::ShaderStageFlagBit::COMPUTE});
dslInfo.bindings.push_back({2, gfx::DescriptorType::STORAGE_BUFFER, 1, gfx::ShaderStageFlagBit::COMPUTE});
dslInfo.bindings.push_back({3, gfx::DescriptorType::STORAGE_BUFFER, 1, gfx::ShaderStageFlagBit::COMPUTE});
dslInfo.bindings.push_back({4, gfx::DescriptorType::STORAGE_BUFFER, 1, gfx::ShaderStageFlagBit::COMPUTE});
dslInfo.bindings.push_back({5, gfx::DescriptorType::STORAGE_BUFFER, 1, gfx::ShaderStageFlagBit::COMPUTE});
_cullingDescriptorSetLayout = _device->createDescriptorSetLayout(dslInfo);
_cullingDescriptorSet = _device->createDescriptorSet({_cullingDescriptorSetLayout});
_cullingPipelineLayout = _device->createPipelineLayout({{_cullingDescriptorSetLayout}});
gfx::PipelineStateInfo pipelineInfo;
pipelineInfo.shader = _cullingShader;
pipelineInfo.pipelineLayout = _cullingPipelineLayout;
pipelineInfo.bindPoint = gfx::PipelineBindPoint::COMPUTE;
_cullingPipelineState = _device->createPipelineState(pipelineInfo);
}
void ClusterLightCulling::clusterLightCulling(scene::Camera *camera) {
if (!_initialized || _pipeline->getPipelineUBO()->getCurrentCameraUBOOffset() != 0) return;
_camera = camera;
update(); // update ubo and light data
if (_validLights.empty()) return;
struct DataClusterBuild {
framegraph::BufferHandle clusterBuffer; // cluster build storage buffer
framegraph::BufferHandle globalIndexBuffer; // global light index storage buffer
};
auto clusterBuildSetup = [&](framegraph::PassNodeBuilder &builder, DataClusterBuild &data) {
data.clusterBuffer = framegraph::BufferHandle(builder.readFromBlackboard(fgStrHandleClusterBuffer));
if (!data.clusterBuffer.isValid()) {
// each cluster has 2 vec4, min + max position for AABB
uint32_t clusterBufferSize = 2 * sizeof(Vec4) * CLUSTER_COUNT;
framegraph::Buffer::Descriptor bufferInfo;
bufferInfo.usage = gfx::BufferUsageBit::STORAGE;
bufferInfo.memUsage = gfx::MemoryUsageBit::DEVICE;
bufferInfo.size = clusterBufferSize;
bufferInfo.stride = clusterBufferSize;
bufferInfo.flags = gfx::BufferFlagBit::NONE;
data.clusterBuffer = builder.create(fgStrHandleClusterBuffer, bufferInfo);
builder.writeToBlackboard(fgStrHandleClusterBuffer, data.clusterBuffer);
}
// only rebuild cluster necceray
if (_rebuildClusters) {
data.clusterBuffer = builder.write(data.clusterBuffer);
builder.writeToBlackboard(fgStrHandleClusterBuffer, data.clusterBuffer);
}
data.globalIndexBuffer = framegraph::BufferHandle(builder.readFromBlackboard(fgStrHandleClusterGlobalIndexBuffer));
if (!data.globalIndexBuffer.isValid()) {
uint32_t atomicIndexBufferSize = sizeof(uint32_t);
framegraph::Buffer::Descriptor bufferInfo;
bufferInfo.usage = gfx::BufferUsageBit::STORAGE;
bufferInfo.memUsage = gfx::MemoryUsageBit::DEVICE;
bufferInfo.size = atomicIndexBufferSize;
bufferInfo.stride = atomicIndexBufferSize;
bufferInfo.flags = gfx::BufferFlagBit::NONE;
data.globalIndexBuffer = builder.create(fgStrHandleClusterGlobalIndexBuffer, bufferInfo);
builder.writeToBlackboard(fgStrHandleClusterGlobalIndexBuffer, data.globalIndexBuffer);
}
// atomic counter for building the light grid
// must be reset to 0 every frame
data.globalIndexBuffer = builder.write(data.globalIndexBuffer);
builder.writeToBlackboard(fgStrHandleClusterGlobalIndexBuffer, data.globalIndexBuffer);
};
auto clusterBuildExec = [&](DataClusterBuild const &data, const framegraph::DevicePassResourceTable &table) {
auto *cmdBuff = _pipeline->getCommandBuffers()[0];
if (_rebuildClusters) {
// building cluster
_buildingDescriptorSet->bindBuffer(0, _constantsBuffer);
_buildingDescriptorSet->bindBuffer(1, table.getWrite(data.clusterBuffer));
_buildingDescriptorSet->update();
cmdBuff->bindPipelineState(const_cast<gfx::PipelineState *>(_buildingPipelineState.get()));
cmdBuff->bindDescriptorSet(0, const_cast<gfx::DescriptorSet *>(_buildingDescriptorSet.get()));
cmdBuff->dispatch(_buildingDispatchInfo);
}
// reset global index
_resetCounterDescriptorSet->bindBuffer(0, table.getWrite(data.globalIndexBuffer));
_resetCounterDescriptorSet->update();
cmdBuff->bindPipelineState(const_cast<gfx::PipelineState *>(_resetCounterPipelineState.get()));
cmdBuff->bindDescriptorSet(0, const_cast<gfx::DescriptorSet *>(_resetCounterDescriptorSet.get()));
cmdBuff->dispatch(_resetDispatchInfo);
cmdBuff->pipelineBarrier(_resetBarrier);
};
struct DataLightCulling {
framegraph::BufferHandle lightBuffer; // light storage buffer
framegraph::BufferHandle lightIndexBuffer; // light index storage buffer
framegraph::BufferHandle lightGridBuffer; // light grid storage buffer
framegraph::BufferHandle clusterBuffer; // cluster storage buffer
framegraph::BufferHandle globalIndexBuffer; // global light index storage buffer
};
auto lightCullingSetup = [&](framegraph::PassNodeBuilder &builder, DataLightCulling &data) {
data.lightBuffer = framegraph::BufferHandle(builder.readFromBlackboard(fgStrHandleClusterLightBuffer));
if (!data.lightBuffer.isValid() || _lightBufferResized) {
framegraph::Buffer::Descriptor bufferInfo;
bufferInfo.usage = gfx::BufferUsageBit::STORAGE;
bufferInfo.memUsage = gfx::MemoryUsageBit::HOST | gfx::MemoryUsageBit::DEVICE;
bufferInfo.size = _lightBufferStride * _lightBufferCount;
bufferInfo.stride = _lightBufferStride;
bufferInfo.flags = gfx::BufferFlagBit::NONE;
data.lightBuffer = builder.create(fgStrHandleClusterLightBuffer, bufferInfo);
builder.writeToBlackboard(fgStrHandleClusterLightBuffer, data.lightBuffer);
_lightBufferResized = false;
}
data.lightBuffer = builder.read(data.lightBuffer);
builder.writeToBlackboard(fgStrHandleClusterLightBuffer, data.lightBuffer);
data.lightIndexBuffer = framegraph::BufferHandle(builder.readFromBlackboard(fgStrHandleClusterLightIndexBuffer));
if (!data.lightIndexBuffer.isValid()) {
// light indices belonging to clusters
uint32_t lightIndicesBufferSize = MAX_LIGHTS_PER_CLUSTER * CLUSTER_COUNT * sizeof(int);
framegraph::Buffer::Descriptor bufferInfo;
bufferInfo.usage = gfx::BufferUsageBit::STORAGE;
bufferInfo.memUsage = gfx::MemoryUsageBit::DEVICE;
bufferInfo.size = lightIndicesBufferSize;
bufferInfo.stride = lightIndicesBufferSize;
bufferInfo.flags = gfx::BufferFlagBit::NONE;
data.lightIndexBuffer = builder.create(fgStrHandleClusterLightIndexBuffer, bufferInfo);
builder.writeToBlackboard(fgStrHandleClusterLightIndexBuffer, data.lightIndexBuffer);
}
data.lightIndexBuffer = builder.write(data.lightIndexBuffer);
builder.writeToBlackboard(fgStrHandleClusterLightIndexBuffer, data.lightIndexBuffer);
data.lightGridBuffer = framegraph::BufferHandle(builder.readFromBlackboard(fgStrHandleClusterLightGridBuffer));
if (!data.lightGridBuffer.isValid()) {
// for each cluster: (start index in b_clusterLightIndices, number of point lights, empty, empty)
uint32_t lightGridBufferSize = CLUSTER_COUNT * 4 * sizeof(uint32_t);
framegraph::Buffer::Descriptor bufferInfo;
bufferInfo.usage = gfx::BufferUsageBit::STORAGE;
bufferInfo.memUsage = gfx::MemoryUsageBit::DEVICE;
bufferInfo.size = lightGridBufferSize;
bufferInfo.stride = lightGridBufferSize;
bufferInfo.flags = gfx::BufferFlagBit::NONE;
data.lightGridBuffer = builder.create(fgStrHandleClusterLightGridBuffer, bufferInfo);
builder.writeToBlackboard(fgStrHandleClusterLightGridBuffer, data.lightGridBuffer);
}
data.lightGridBuffer = builder.write(data.lightGridBuffer);
builder.writeToBlackboard(fgStrHandleClusterLightGridBuffer, data.lightGridBuffer);
data.clusterBuffer = framegraph::BufferHandle(builder.readFromBlackboard(fgStrHandleClusterBuffer));
data.clusterBuffer = builder.read(data.clusterBuffer);
builder.writeToBlackboard(fgStrHandleClusterBuffer, data.clusterBuffer);
data.globalIndexBuffer = framegraph::BufferHandle(builder.readFromBlackboard(fgStrHandleClusterGlobalIndexBuffer));
// atomic read and write in a pass
data.globalIndexBuffer = builder.read(data.globalIndexBuffer);
builder.writeToBlackboard(fgStrHandleClusterGlobalIndexBuffer, data.globalIndexBuffer);
};
auto lightCullingExec = [&](DataLightCulling const &data, const framegraph::DevicePassResourceTable &table) {
auto *cmdBuff = _pipeline->getCommandBuffers()[0];
cmdBuff->updateBuffer(table.getRead(data.lightBuffer), _lightBufferData.data(),
static_cast<uint32_t>(_lightBufferData.size() * sizeof(float)));
_cullingDescriptorSet->bindBuffer(0, _constantsBuffer);
_cullingDescriptorSet->bindBuffer(1, table.getRead(data.lightBuffer));
_cullingDescriptorSet->bindBuffer(2, table.getWrite(data.lightIndexBuffer));
_cullingDescriptorSet->bindBuffer(3, table.getWrite(data.lightGridBuffer));
_cullingDescriptorSet->bindBuffer(4, table.getRead(data.clusterBuffer));
_cullingDescriptorSet->bindBuffer(5, table.getRead(data.globalIndexBuffer));
_cullingDescriptorSet->update();
// light culling
cmdBuff->bindPipelineState(const_cast<gfx::PipelineState *>(_cullingPipelineState.get()));
cmdBuff->bindDescriptorSet(0, const_cast<gfx::DescriptorSet *>(_cullingDescriptorSet.get()));
cmdBuff->dispatch(_cullingDispatchInfo);
};
auto *pipeline = static_cast<DeferredPipeline *>(_pipeline);
auto insertPoint = static_cast<uint32_t>(DeferredInsertPoint::DIP_CLUSTER);
pipeline->getFrameGraph().addPass<DataClusterBuild>(insertPoint++, fgStrHandleClusterBuildPass, clusterBuildSetup, clusterBuildExec);
pipeline->getFrameGraph().addPass<DataLightCulling>(insertPoint++, fgStrHandleClusterCullingPass, lightCullingSetup, lightCullingExec);
}
ccstd::string &ClusterLightCulling::getShaderSource(ShaderStrings &sources) {
switch (_device->getGfxAPI()) {
case gfx::API::GLES2:
return sources.glsl1;
case gfx::API::GLES3:
return sources.glsl3;
case gfx::API::METAL:
case gfx::API::VULKAN:
return sources.glsl4;
default: break;
}
return sources.glsl4;
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,143 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "cocos/renderer/gfx-base/GFXDef.h"
#include "cocos/scene/Pass.h"
#include "cocos/scene/RenderScene.h"
namespace cc {
namespace pipeline {
class RenderPipeline;
struct ShaderStrings {
ccstd::string glsl4;
ccstd::string glsl3;
ccstd::string glsl1;
};
class ClusterLightCulling {
public:
explicit ClusterLightCulling(RenderPipeline *pipeline);
~ClusterLightCulling();
static constexpr uint32_t CLUSTERS_X = 16;
static constexpr uint32_t CLUSTERS_Y = 8;
static constexpr uint32_t CLUSTERS_Z = 24;
// z threads varies to meet limit number of threads
static constexpr uint32_t CLUSTERS_X_THREADS = 16;
static constexpr uint32_t CLUSTERS_Y_THREADS = 8;
uint32_t clusterZThreads = 1;
static constexpr uint32_t CLUSTER_COUNT = CLUSTERS_X * CLUSTERS_Y * CLUSTERS_Z;
static constexpr uint32_t MAX_LIGHTS_PER_CLUSTER = 200;
static constexpr uint32_t MAX_LIGHTS_GLOBAL = 1000;
void initialize(gfx::Device *dev);
void clusterLightCulling(scene::Camera *camera);
private:
ccstd::string &getShaderSource(ShaderStrings &sources);
void initBuildingSatge();
void initResetStage();
void initCullingStage();
void update();
void updateLights();
static bool isProjMatChange(const Mat4 &curProj, const Mat4 &oldProj) {
for (uint32_t i = 0; i < sizeof(curProj.m) / sizeof(float); i++) {
if (math::isNotEqualF(curProj.m[i], oldProj.m[i])) {
return true;
}
}
return false;
}
// weak reference
gfx::Device *_device{nullptr};
IntrusivePtr<scene::Camera> _camera;
// weak reference
RenderPipeline *_pipeline{nullptr};
IntrusivePtr<gfx::Shader> _buildingShader;
IntrusivePtr<gfx::DescriptorSetLayout> _buildingDescriptorSetLayout;
IntrusivePtr<gfx::PipelineLayout> _buildingPipelineLayout;
IntrusivePtr<gfx::PipelineState> _buildingPipelineState;
IntrusivePtr<gfx::DescriptorSet> _buildingDescriptorSet;
IntrusivePtr<gfx::Shader> _resetCounterShader;
IntrusivePtr<gfx::DescriptorSetLayout> _resetCounterDescriptorSetLayout;
IntrusivePtr<gfx::PipelineLayout> _resetCounterPipelineLayout;
IntrusivePtr<gfx::PipelineState> _resetCounterPipelineState;
IntrusivePtr<gfx::DescriptorSet> _resetCounterDescriptorSet;
IntrusivePtr<gfx::Shader> _cullingShader;
IntrusivePtr<gfx::DescriptorSetLayout> _cullingDescriptorSetLayout;
IntrusivePtr<gfx::PipelineLayout> _cullingPipelineLayout;
IntrusivePtr<gfx::PipelineState> _cullingPipelineState;
IntrusivePtr<gfx::DescriptorSet> _cullingDescriptorSet;
static constexpr uint32_t NEAR_FAR_OFFSET = 0;
static constexpr uint32_t VIEW_PORT_OFFSET = 4;
static constexpr uint32_t MAT_VIEW_OFFSET = 8;
static constexpr uint32_t MAT_PROJ_INV_OFFSET = 24;
ccstd::array<float, (2 * sizeof(Vec4) + 2 * sizeof(Mat4)) / sizeof(float)> _constants{};
IntrusivePtr<gfx::Buffer> _constantsBuffer;
// weak reference
ccstd::vector<scene::Light *> _validLights;
ccstd::vector<float> _lightBufferData;
// weak reference
gfx::GeneralBarrier *_resetBarrier{nullptr};
gfx::DispatchInfo _buildingDispatchInfo;
gfx::DispatchInfo _resetDispatchInfo;
gfx::DispatchInfo _cullingDispatchInfo;
bool _lightBufferResized{false};
uint32_t _lightBufferStride{0};
uint32_t _lightBufferCount{0};
float _lightMeterScale{10000.0F};
// only rebuild clusters when camera project matrix changed
bool _rebuildClusters{false};
ccstd::vector<Mat4> _oldCamProjMats;
bool _initialized{false};
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,67 @@
/****************************************************************************
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "DebugView.h"
#include "custom/RenderInterfaceTypes.h"
#include "RenderPipeline.h"
#include "core/Root.h"
namespace cc {
namespace pipeline {
void DebugView::activate() {
_singleMode = DebugViewSingleType::NONE;
enableAllCompositeModeValue(true);
_lightingWithAlbedo = true;
_csmLayerColoration = false;
}
void DebugView::updatePipeline() {
Root *root = Root::getInstance();
auto *pipeline = root->getPipeline();
auto useDebugViewValue = static_cast<int32_t>(getType());
bool valueChanged = false;
auto iter = pipeline->getMacros().find("CC_USE_DEBUG_VIEW");
if (iter != pipeline->getMacros().end()) {
const MacroValue &macroValue = iter->second;
const int32_t *macroPtr = ccstd::get_if<int32_t>(&macroValue);
if (macroPtr != nullptr && (*macroPtr != useDebugViewValue)) {
pipeline->setValue("CC_USE_DEBUG_VIEW", useDebugViewValue);
valueChanged = true;
}
} else {
pipeline->setValue("CC_USE_DEBUG_VIEW", useDebugViewValue);
valueChanged = true;
}
if (valueChanged) {
root->onGlobalPipelineStateChanged();
}
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,260 @@
/*
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
#include "base/TypeDef.h"
namespace cc {
namespace pipeline {
enum class RenderingDebugViewType {
NONE,
SINGLE,
COMPOSITE_AND_MISC,
};
/**
* @zh
* 渲染单项调试模式
* @en
* Rendering single debug mode
* @readonly
*/
enum class DebugViewSingleType {
NONE,
VERTEX_COLOR,
VERTEX_NORMAL,
VERTEX_TANGENT,
WORLD_POS,
VERTEX_MIRROR,
FACE_SIDE,
UV0,
UV1,
UV_LIGHTMAP,
PROJ_DEPTH,
LINEAR_DEPTH,
FRAGMENT_NORMAL,
FRAGMENT_TANGENT,
FRAGMENT_BINORMAL,
BASE_COLOR,
DIFFUSE_COLOR,
SPECULAR_COLOR,
TRANSPARENCY,
METALLIC,
ROUGHNESS,
SPECULAR_INTENSITY,
IOR,
DIRECT_DIFFUSE,
DIRECT_SPECULAR,
DIRECT_ALL,
ENV_DIFFUSE,
ENV_SPECULAR,
ENV_ALL,
EMISSIVE,
LIGHT_MAP,
SHADOW,
AO,
FRESNEL,
DIRECT_TRANSMIT_DIFFUSE,
DIRECT_TRANSMIT_SPECULAR,
ENV_TRANSMIT_DIFFUSE,
ENV_TRANSMIT_SPECULAR,
TRANSMIT_ALL,
DIRECT_TRT,
ENV_TRT,
TRT_ALL,
FOG,
};
/**
* @zh
* 渲染组合调试模式
* @en
* Rendering composite debug mode
* @readonly
*/
enum class DebugViewCompositeType {
DIRECT_DIFFUSE = 0,
DIRECT_SPECULAR,
ENV_DIFFUSE,
ENV_SPECULAR,
EMISSIVE,
LIGHT_MAP,
SHADOW,
AO,
NORMAL_MAP,
FOG,
TONE_MAPPING,
GAMMA_CORRECTION,
FRESNEL,
TRANSMIT_DIFFUSE,
TRANSMIT_SPECULAR,
TRT,
MAX_BIT_COUNT
};
/**
* @en Rendering debug view control class
* @zh 渲染调试控制类
*/
// @ccclass('cc.DebugView')
// @help('i18n:cc.DebugView')
class DebugView final {
public:
DebugView() {
activate();
}
~DebugView() = default;
/**
* @en Toggle rendering single debug mode.
* @zh 设置渲染单项调试模式。
*/
inline DebugViewSingleType getSingleMode() const { return _singleMode; }
inline void setSingleMode(DebugViewSingleType val) {
_singleMode = val;
updatePipeline();
}
/**
* @en Toggle normal / pure lighting mode.
* @zh 切换正常光照和仅光照模式。
*/
inline bool isLightingWithAlbedo() const { return _lightingWithAlbedo; }
inline void setLightingWithAlbedo(bool val) {
_lightingWithAlbedo = val;
updatePipeline();
}
/**
* @en Toggle CSM layer coloration mode.
* @zh 切换级联阴影染色调试模式。
*/
inline bool isCsmLayerColoration() const { return _csmLayerColoration; }
inline void setCsmLayerColoration(bool val) {
_csmLayerColoration = val;
updatePipeline();
}
/**
* @en Whether enabled with specified rendering composite debug mode.
* @zh 获取指定的渲染组合调试模式是否开启。
* @param Specified composite type.
*/
inline bool isCompositeModeEnabled (uint32_t val) const {
uint32_t mode = _compositeModeValue & (1 << val);
return mode != 0;
}
/**
* @en Toggle specified rendering composite debug mode.
* @zh 开关指定的渲染组合调试模式。
* @param Specified composite type, enable or disable.
*/
inline void enableCompositeMode (DebugViewCompositeType val, bool enable) {
enableCompositeModeValue(val, enable);
updatePipeline();
}
/**
* @en Toggle all rendering composite debug mode.
* @zh 开关所有的渲染组合调试模式。
*/
inline void enableAllCompositeMode (bool enable) {
enableAllCompositeModeValue(enable);
updatePipeline();
}
/**
* @en Get rendering debug view on / off state.
* @zh 查询当前是否开启了渲染调试模式。
*/
inline bool isEnabled() const {
return getType() != RenderingDebugViewType::NONE;
}
/**
* @en Disable all debug view modes, reset to standard rendering mode.
* @zh 关闭所有的渲染调试模式,恢复到正常渲染。
*/
void reset () {
activate();
updatePipeline();
}
protected:
void activate();
void updatePipeline();
private:
inline void enableCompositeModeValue(DebugViewCompositeType val, bool enable) {
if (enable) {
_compositeModeValue |= (1 << static_cast<uint32_t>(val));
} else {
_compositeModeValue &= (~(1 << static_cast<uint32_t>(val)));
}
}
inline void enableAllCompositeModeValue(bool enable) {
for (int i = 0; i < static_cast<int>(DebugViewCompositeType::MAX_BIT_COUNT); ++i) {
if (enable) {
_compositeModeValue |= (1 << i);
} else {
_compositeModeValue &= (~(1 << i));
}
}
}
inline RenderingDebugViewType getType () const {
if (_singleMode != DebugViewSingleType::NONE) {
return RenderingDebugViewType::SINGLE;
} else if (!_lightingWithAlbedo || _csmLayerColoration) {
return RenderingDebugViewType::COMPOSITE_AND_MISC;
} else {
for (int i = 0; i < static_cast<int>(DebugViewCompositeType::MAX_BIT_COUNT); ++i) {
if (!isCompositeModeEnabled(i)) {
return RenderingDebugViewType::COMPOSITE_AND_MISC;
}
}
}
return RenderingDebugViewType::NONE;
}
private:
DebugViewSingleType _singleMode{DebugViewSingleType::NONE};
uint32_t _compositeModeValue{0};
bool _lightingWithAlbedo{true};
bool _csmLayerColoration{false};
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,694 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "Define.h"
#include "bindings/jswrapper/SeApi.h"
#include "gfx-base/GFXDevice.h"
#include "scene/Light.h"
namespace cc {
namespace pipeline {
static uint32_t globalUBOCount = static_cast<uint32_t>(PipelineGlobalBindings::SAMPLER_SHADOWMAP);
static uint32_t globalSamplerCount = static_cast<uint32_t>(PipelineGlobalBindings::COUNT) - globalUBOCount;
static uint32_t localUBOCount = static_cast<uint32_t>(ModelLocalBindings::SAMPLER_JOINTS);
static uint32_t localSamplerCount = static_cast<uint32_t>(ModelLocalBindings::STORAGE_REFLECTION) - localUBOCount;
static uint32_t localStorageImageCount = static_cast<uint32_t>(ModelLocalBindings::COUNT) - localUBOCount - localSamplerCount;
uint32_t globalSet = static_cast<uint32_t>(SetIndex::GLOBAL);
uint32_t materialSet = static_cast<uint32_t>(SetIndex::MATERIAL);
uint32_t localSet = static_cast<uint32_t>(SetIndex::LOCAL);
gfx::BindingMappingInfo bindingMappingInfo = {
{globalUBOCount, 0, localUBOCount, 0}, // Uniform Buffer Counts
{globalSamplerCount, 0, localSamplerCount, 0}, // Combined Sampler Texture Counts
{0, 0, 0, 0}, // Sampler Counts
{0, 0, 0, 0}, // Texture Counts
{0, 0, 0, 0}, // Storage Buffer Counts
{0, 0, localStorageImageCount, 0}, // Storage Image Counts
{0, 0, 0, 0}, // Subpass Input Counts
{0, 2, 1, 3}, // Set Order Indices
};
DescriptorSetLayoutInfos globalDescriptorSetLayout;
DescriptorSetLayoutInfos localDescriptorSetLayout;
const ccstd::string UBOGlobal::NAME = "CCGlobal";
const gfx::DescriptorSetLayoutBinding UBOGlobal::DESCRIPTOR = {
UBOGlobal::BINDING,
gfx::DescriptorType::UNIFORM_BUFFER,
1,
gfx::ShaderStageFlagBit::ALL,
{},
};
const gfx::UniformBlock UBOGlobal::LAYOUT = {
globalSet,
UBOGlobal::BINDING,
UBOGlobal::NAME,
{
{"cc_time", gfx::Type::FLOAT4, 1},
{"cc_screenSize", gfx::Type::FLOAT4, 1},
{"cc_nativeSize", gfx::Type::FLOAT4, 1},
{"cc_probeInfo", gfx::Type::FLOAT4, 1},
{"cc_debug_view_mode", gfx::Type::FLOAT4, 1},
},
1,
};
const ccstd::string UBOLocalBatched::NAME = "CCLocalBatched";
const gfx::DescriptorSetLayoutBinding UBOLocalBatched::DESCRIPTOR = {
UBOLocalBatched::BINDING,
gfx::DescriptorType::UNIFORM_BUFFER,
1,
gfx::ShaderStageFlagBit::VERTEX,
{},
};
const gfx::UniformBlock UBOLocalBatched::LAYOUT = {
localSet,
UBOLocalBatched::BINDING,
UBOLocalBatched::NAME,
{
{"cc_matWorlds", gfx::Type::MAT4, static_cast<uint32_t>(UBOLocalBatched::BATCHING_COUNT)},
},
1,
};
const ccstd::string UBOCamera::NAME = "CCCamera";
const gfx::DescriptorSetLayoutBinding UBOCamera::DESCRIPTOR = {
UBOCamera::BINDING,
gfx::DescriptorType::DYNAMIC_UNIFORM_BUFFER,
1,
gfx::ShaderStageFlagBit::ALL,
{},
};
const gfx::UniformBlock UBOCamera::LAYOUT = {
globalSet,
UBOCamera::BINDING,
UBOCamera::NAME,
{
{"cc_matView", gfx::Type::MAT4, 1},
{"cc_matViewInv", gfx::Type::MAT4, 1},
{"cc_matProj", gfx::Type::MAT4, 1},
{"cc_matProjInv", gfx::Type::MAT4, 1},
{"cc_matViewProj", gfx::Type::MAT4, 1},
{"cc_matViewProjInv", gfx::Type::MAT4, 1},
{"cc_cameraPos", gfx::Type::FLOAT4, 1},
{"cc_surfaceTransform", gfx::Type::FLOAT4, 1},
{"cc_screenScale", gfx::Type::FLOAT4, 1},
{"cc_exposure", gfx::Type::FLOAT4, 1},
{"cc_mainLitDir", gfx::Type::FLOAT4, 1},
{"cc_mainLitColor", gfx::Type::FLOAT4, 1},
{"cc_ambientSky", gfx::Type::FLOAT4, 1},
{"cc_ambientGround", gfx::Type::FLOAT4, 1},
{"cc_fogColor", gfx::Type::FLOAT4, 1},
{"cc_fogBase", gfx::Type::FLOAT4, 1},
{"cc_fogAdd", gfx::Type::FLOAT4, 1},
{"cc_nearFar", gfx::Type::FLOAT4, 1},
{"cc_viewPort", gfx::Type::FLOAT4, 1},
},
1,
};
const ccstd::string UBOShadow::NAME = "CCShadow";
const gfx::DescriptorSetLayoutBinding UBOShadow::DESCRIPTOR = {
UBOShadow::BINDING,
gfx::DescriptorType::UNIFORM_BUFFER,
1,
gfx::ShaderStageFlagBit::ALL,
{},
};
const gfx::UniformBlock UBOShadow::LAYOUT = {
globalSet,
UBOShadow::BINDING,
UBOShadow::NAME,
{
{"cc_matLightView", gfx::Type::MAT4, 1},
{"cc_matLightViewProj", gfx::Type::MAT4, 1},
{"cc_shadowInvProjDepthInfo", gfx::Type::FLOAT4, 1},
{"cc_shadowProjDepthInfo", gfx::Type::FLOAT4, 1},
{"cc_shadowProjInfo", gfx::Type::FLOAT4, 1},
{"cc_shadowNFLSInfo", gfx::Type::FLOAT4, 1},
{"cc_shadowWHPBInfo", gfx::Type::FLOAT4, 1},
{"cc_shadowLPNNInfo", gfx::Type::FLOAT4, 1},
{"cc_shadowColor", gfx::Type::FLOAT4, 1},
{"cc_planarNDInfo", gfx::Type::FLOAT4, 1},
},
1,
};
const ccstd::string UBOCSM::NAME = "CCCSM";
const gfx::DescriptorSetLayoutBinding UBOCSM::DESCRIPTOR = {
UBOCSM::BINDING,
gfx::DescriptorType::UNIFORM_BUFFER,
1,
gfx::ShaderStageFlagBit::FRAGMENT,
{},
};
const gfx::UniformBlock UBOCSM::LAYOUT = {
globalSet,
UBOCSM::BINDING,
UBOCSM::NAME,
{
{"cc_csmViewDir0", gfx::Type::FLOAT4, UBOCSM::CSM_LEVEL_COUNT},
{"cc_csmViewDir1", gfx::Type::FLOAT4, UBOCSM::CSM_LEVEL_COUNT},
{"cc_csmViewDir2", gfx::Type::FLOAT4, UBOCSM::CSM_LEVEL_COUNT},
{"cc_csmAtlas", gfx::Type::FLOAT4, UBOCSM::CSM_LEVEL_COUNT},
{"cc_matCSMViewProj", gfx::Type::MAT4, UBOCSM::CSM_LEVEL_COUNT},
{"cc_csmProjDepthInfo", gfx::Type::FLOAT4, UBOCSM::CSM_LEVEL_COUNT},
{"cc_csmProjInfo", gfx::Type::FLOAT4, UBOCSM::CSM_LEVEL_COUNT},
{"cc_csmSplitsInfo", gfx::Type::FLOAT4, 1},
},
1,
};
const ccstd::string UBOLocal::NAME = "CCLocal";
const gfx::DescriptorSetLayoutBinding UBOLocal::DESCRIPTOR = {
UBOLocal::BINDING,
gfx::DescriptorType::UNIFORM_BUFFER,
1,
gfx::ShaderStageFlagBit::VERTEX | gfx::ShaderStageFlagBit::FRAGMENT | gfx::ShaderStageFlagBit::COMPUTE,
{},
};
const gfx::UniformBlock UBOLocal::LAYOUT = {
localSet,
UBOLocal::BINDING,
UBOLocal::NAME,
{
{"cc_matWorld", gfx::Type::MAT4, 1},
{"cc_matWorldIT", gfx::Type::MAT4, 1},
{"cc_lightingMapUVParam", gfx::Type::FLOAT4, 1},
{"cc_localShadowBias", gfx::Type::FLOAT4, 1},
{"cc_reflectionProbeData1", gfx::Type::FLOAT4, 1},
{"cc_reflectionProbeData2", gfx::Type::FLOAT4, 1},
{"cc_reflectionProbeBlendData1", gfx::Type::FLOAT4, 1},
{"cc_reflectionProbeBlendData1", gfx::Type::FLOAT4, 1},
},
1,
};
const ccstd::string UBOWorldBound::NAME = "CCWorldBound";
const gfx::DescriptorSetLayoutBinding UBOWorldBound::DESCRIPTOR = {
UBOWorldBound::BINDING,
gfx::DescriptorType::UNIFORM_BUFFER,
1,
gfx::ShaderStageFlagBit::VERTEX | gfx::ShaderStageFlagBit::FRAGMENT | gfx::ShaderStageFlagBit::COMPUTE,
{},
};
const gfx::UniformBlock UBOWorldBound::LAYOUT = {
localSet,
UBOWorldBound::BINDING,
UBOWorldBound::NAME,
{
{"cc_worldBoundCenter", gfx::Type::FLOAT4, 1},
{"cc_worldBoundHalfExtents", gfx::Type::FLOAT4, 1},
},
1,
};
const ccstd::string UBOForwardLight::NAME = "CCForwardLight";
const gfx::DescriptorSetLayoutBinding UBOForwardLight::DESCRIPTOR = {
UBOForwardLight::BINDING,
gfx::DescriptorType::DYNAMIC_UNIFORM_BUFFER,
1,
gfx::ShaderStageFlagBit::FRAGMENT,
{},
};
const gfx::UniformBlock UBOForwardLight::LAYOUT = {
localSet,
UBOForwardLight::BINDING,
UBOForwardLight::NAME,
{
{"cc_lightPos", gfx::Type::FLOAT4, static_cast<uint32_t>(UBOForwardLight::LIGHTS_PER_PASS)},
{"cc_lightColor", gfx::Type::FLOAT4, static_cast<uint32_t>(UBOForwardLight::LIGHTS_PER_PASS)},
{"cc_lightSizeRangeAngle", gfx::Type::FLOAT4, static_cast<uint32_t>(UBOForwardLight::LIGHTS_PER_PASS)},
{"cc_lightDir", gfx::Type::FLOAT4, static_cast<uint32_t>(UBOForwardLight::LIGHTS_PER_PASS)},
{"cc_lightBoundingSizeVS", gfx::Type::FLOAT4, static_cast<uint32_t>(UBOForwardLight::LIGHTS_PER_PASS)},
},
1,
};
const ccstd::string UBOSkinningTexture::NAME = "CCSkinningTexture";
const gfx::DescriptorSetLayoutBinding UBOSkinningTexture::DESCRIPTOR = {
UBOSkinningTexture::BINDING,
gfx::DescriptorType::UNIFORM_BUFFER,
1,
gfx::ShaderStageFlagBit::VERTEX,
{},
};
const gfx::UniformBlock UBOSkinningTexture::LAYOUT = {
localSet,
UBOSkinningTexture::BINDING,
UBOSkinningTexture::NAME,
{
{"cc_jointTextureInfo", gfx::Type::FLOAT4, 1},
},
1,
};
const ccstd::string UBOSkinningAnimation::NAME = "CCSkinningAnimation";
const gfx::DescriptorSetLayoutBinding UBOSkinningAnimation::DESCRIPTOR = {
UBOSkinningAnimation::BINDING,
gfx::DescriptorType::UNIFORM_BUFFER,
1,
gfx::ShaderStageFlagBit::VERTEX,
{},
};
const gfx::UniformBlock UBOSkinningAnimation::LAYOUT = {
localSet,
UBOSkinningAnimation::BINDING,
UBOSkinningAnimation::NAME,
{
{"cc_jointAnimInfo", gfx::Type::FLOAT4, 1},
},
1,
};
uint SkinningJointCapacity::jointUniformCapacity = 0;
uint32_t UBOSkinning::count = 0;
uint32_t UBOSkinning::size = 0;
const ccstd::string UBOSkinning::NAME = "CCSkinning";
const gfx::DescriptorSetLayoutBinding UBOSkinning::DESCRIPTOR = {
UBOSkinning::BINDING,
gfx::DescriptorType::UNIFORM_BUFFER,
1,
gfx::ShaderStageFlagBit::VERTEX,
{},
};
gfx::UniformBlock UBOSkinning::layout = {
localSet,
UBOSkinning::BINDING,
UBOSkinning::NAME,
{
{"cc_joints", gfx::Type::FLOAT4, 0},
},
1,
};
void UBOSkinning::initLayout(uint32_t capacity) {
UBOSkinning::count = capacity * 12;
UBOSkinning::size = UBOSkinning::count * sizeof(float);
UBOSkinning::layout.members[0].count = capacity * 3;
}
const uint32_t UBOMorph::COUNT_BASE_4_BYTES = static_cast<uint32_t>(4 * std::ceil(UBOMorph::MAX_MORPH_TARGET_COUNT / 4) + 4);
const uint32_t UBOMorph::SIZE = UBOMorph::COUNT_BASE_4_BYTES * 4;
const ccstd::string UBOMorph::NAME = "CCMorph";
const gfx::DescriptorSetLayoutBinding UBOMorph::DESCRIPTOR = {
UBOMorph::BINDING,
gfx::DescriptorType::UNIFORM_BUFFER,
1,
gfx::ShaderStageFlagBit::VERTEX,
{},
};
const gfx::UniformBlock UBOMorph::LAYOUT = {
localSet,
UBOMorph::BINDING,
UBOMorph::NAME,
{
{"cc_displacementWeights", gfx::Type::FLOAT4, static_cast<uint32_t>(UBOMorph::MAX_MORPH_TARGET_COUNT / 4)},
{"cc_displacementTextureInfo", gfx::Type::FLOAT4, 1},
},
1,
};
const ccstd::string UBOUILocal::NAME = "CCUILocal";
const gfx::DescriptorSetLayoutBinding UBOUILocal::DESCRIPTOR = {
UBOUILocal::BINDING,
gfx::DescriptorType::DYNAMIC_UNIFORM_BUFFER,
1,
gfx::ShaderStageFlagBit::VERTEX,
};
const gfx::UniformBlock UBOUILocal::LAYOUT = {
localSet,
UBOUILocal::BINDING,
UBOUILocal::NAME,
{
{"cc_local_data", gfx::Type::FLOAT4, 1},
},
1,
};
const ccstd::string UBOSH::NAME = "CCSH";
const gfx::DescriptorSetLayoutBinding UBOSH::DESCRIPTOR = {
UBOSH::BINDING,
gfx::DescriptorType::UNIFORM_BUFFER,
1,
gfx::ShaderStageFlagBit::FRAGMENT,
{},
};
const gfx::UniformBlock UBOSH::LAYOUT = {
localSet,
UBOSH::BINDING,
UBOSH::NAME,
{
{"cc_sh_linear_const_r", gfx::Type::FLOAT4, 1},
{"cc_sh_linear_const_g", gfx::Type::FLOAT4, 1},
{"cc_sh_linear_const_b", gfx::Type::FLOAT4, 1},
{"cc_sh_quadratic_r", gfx::Type::FLOAT4, 1},
{"cc_sh_quadratic_g", gfx::Type::FLOAT4, 1},
{"cc_sh_quadratic_b", gfx::Type::FLOAT4, 1},
{"cc_sh_quadratic_a", gfx::Type::FLOAT4, 1},
},
1,
};
const ccstd::string SHADOWMAP::NAME = "cc_shadowMap";
const gfx::DescriptorSetLayoutBinding SHADOWMAP::DESCRIPTOR = {
SHADOWMAP::BINDING,
gfx::DescriptorType::SAMPLER_TEXTURE,
1,
gfx::ShaderStageFlagBit::FRAGMENT,
{},
};
const gfx::UniformSamplerTexture SHADOWMAP::LAYOUT = {
globalSet,
SHADOWMAP::BINDING,
SHADOWMAP::NAME,
gfx::Type::SAMPLER2D,
1,
};
const ccstd::string ENVIRONMENT::NAME = "cc_environment";
const gfx::DescriptorSetLayoutBinding ENVIRONMENT::DESCRIPTOR = {
ENVIRONMENT::BINDING,
gfx::DescriptorType::SAMPLER_TEXTURE,
1,
gfx::ShaderStageFlagBit::FRAGMENT,
{},
};
const gfx::UniformSamplerTexture ENVIRONMENT::LAYOUT = {
globalSet,
ENVIRONMENT::BINDING,
ENVIRONMENT::NAME,
gfx::Type::SAMPLER_CUBE,
1,
};
const ccstd::string SPOTSHADOWMAP::NAME = "cc_spotShadowMap";
const gfx::DescriptorSetLayoutBinding SPOTSHADOWMAP::DESCRIPTOR = {
SPOTSHADOWMAP::BINDING,
gfx::DescriptorType::SAMPLER_TEXTURE,
1,
gfx::ShaderStageFlagBit::FRAGMENT,
{},
};
const gfx::UniformSamplerTexture SPOTSHADOWMAP::LAYOUT = {
globalSet,
SPOTSHADOWMAP::BINDING,
SPOTSHADOWMAP::NAME,
gfx::Type::SAMPLER2D,
1,
};
const ccstd::string DIFFUSEMAP::NAME = "cc_diffuseMap";
const gfx::DescriptorSetLayoutBinding DIFFUSEMAP::DESCRIPTOR = {
DIFFUSEMAP::BINDING,
gfx::DescriptorType::SAMPLER_TEXTURE,
1,
gfx::ShaderStageFlagBit::FRAGMENT,
{},
};
const gfx::UniformSamplerTexture DIFFUSEMAP::LAYOUT = {
globalSet,
DIFFUSEMAP::BINDING,
DIFFUSEMAP::NAME,
gfx::Type::SAMPLER_CUBE,
1,
};
const ccstd::string JOINTTEXTURE::NAME = "cc_jointTexture";
const gfx::DescriptorSetLayoutBinding JOINTTEXTURE::DESCRIPTOR = {
JOINTTEXTURE::BINDING,
gfx::DescriptorType::SAMPLER_TEXTURE,
1,
gfx::ShaderStageFlagBit::VERTEX,
{},
};
const gfx::UniformSamplerTexture JOINTTEXTURE::LAYOUT = {
localSet,
JOINTTEXTURE::BINDING,
JOINTTEXTURE::NAME,
gfx::Type::SAMPLER2D,
1,
};
const ccstd::string REALTIMEJOINTTEXTURE::NAME = "cc_realtimeJoint";
const gfx::DescriptorSetLayoutBinding REALTIMEJOINTTEXTURE::DESCRIPTOR = {
REALTIMEJOINTTEXTURE::BINDING,
gfx::DescriptorType::SAMPLER_TEXTURE,
1,
gfx::ShaderStageFlagBit::VERTEX,
{},
};
const gfx::UniformSamplerTexture REALTIMEJOINTTEXTURE::LAYOUT = {
localSet,
REALTIMEJOINTTEXTURE::BINDING,
REALTIMEJOINTTEXTURE::NAME,
gfx::Type::SAMPLER2D,
1,
};
const ccstd::string POSITIONMORPH::NAME = "cc_PositionDisplacements";
const gfx::DescriptorSetLayoutBinding POSITIONMORPH::DESCRIPTOR = {
POSITIONMORPH::BINDING,
gfx::DescriptorType::SAMPLER_TEXTURE,
1,
gfx::ShaderStageFlagBit::VERTEX,
{},
};
const gfx::UniformSamplerTexture POSITIONMORPH::LAYOUT = {
localSet,
POSITIONMORPH::BINDING,
POSITIONMORPH::NAME,
gfx::Type::SAMPLER2D,
1,
};
const ccstd::string NORMALMORPH::NAME = "cc_NormalDisplacements";
const gfx::DescriptorSetLayoutBinding NORMALMORPH::DESCRIPTOR = {
NORMALMORPH::BINDING,
gfx::DescriptorType::SAMPLER_TEXTURE,
1,
gfx::ShaderStageFlagBit::VERTEX,
{},
};
const gfx::UniformSamplerTexture NORMALMORPH::LAYOUT = {
localSet,
NORMALMORPH::BINDING,
NORMALMORPH::NAME,
gfx::Type::SAMPLER2D,
1,
};
const ccstd::string TANGENTMORPH::NAME = "cc_TangentDisplacements";
const gfx::DescriptorSetLayoutBinding TANGENTMORPH::DESCRIPTOR = {
TANGENTMORPH::BINDING,
gfx::DescriptorType::SAMPLER_TEXTURE,
1,
gfx::ShaderStageFlagBit::VERTEX,
{},
};
const gfx::UniformSamplerTexture TANGENTMORPH::LAYOUT = {
localSet,
TANGENTMORPH::BINDING,
TANGENTMORPH::NAME,
gfx::Type::SAMPLER2D,
1,
};
const ccstd::string LIGHTMAPTEXTURE::NAME = "cc_lightingMap";
const gfx::DescriptorSetLayoutBinding LIGHTMAPTEXTURE::DESCRIPTOR = {
LIGHTMAPTEXTURE::BINDING,
gfx::DescriptorType::SAMPLER_TEXTURE,
1,
gfx::ShaderStageFlagBit::FRAGMENT,
{},
};
const gfx::UniformSamplerTexture LIGHTMAPTEXTURE::LAYOUT = {
localSet,
LIGHTMAPTEXTURE::BINDING,
LIGHTMAPTEXTURE::NAME,
gfx::Type::SAMPLER2D,
1,
};
const ccstd::string SPRITETEXTURE::NAME = "cc_spriteTexture";
const gfx::DescriptorSetLayoutBinding SPRITETEXTURE::DESCRIPTOR = {
SPRITETEXTURE::BINDING,
gfx::DescriptorType::SAMPLER_TEXTURE,
1,
gfx::ShaderStageFlagBit::FRAGMENT,
{},
};
const gfx::UniformSamplerTexture SPRITETEXTURE::LAYOUT = {
localSet,
static_cast<uint32_t>(ModelLocalBindings::SAMPLER_SPRITE),
"cc_spriteTexture",
gfx::Type::SAMPLER2D,
1,
};
const ccstd::string REFLECTIONTEXTURE::NAME = "cc_reflectionTexture";
const gfx::DescriptorSetLayoutBinding REFLECTIONTEXTURE::DESCRIPTOR = {
REFLECTIONTEXTURE::BINDING,
gfx::DescriptorType::SAMPLER_TEXTURE,
1,
gfx::ShaderStageFlagBit::FRAGMENT,
{},
};
const gfx::UniformSamplerTexture REFLECTIONTEXTURE::LAYOUT = {
localSet,
static_cast<uint32_t>(ModelLocalBindings::SAMPLER_REFLECTION),
"cc_reflectionTexture",
gfx::Type::SAMPLER2D,
1,
};
const ccstd::string REFLECTIONSTORAGE::NAME = "cc_reflectionStorage";
const gfx::DescriptorSetLayoutBinding REFLECTIONSTORAGE::DESCRIPTOR = {
REFLECTIONSTORAGE::BINDING,
gfx::DescriptorType::STORAGE_IMAGE,
1,
gfx::ShaderStageFlagBit::COMPUTE,
{},
};
const gfx::UniformStorageImage REFLECTIONSTORAGE::LAYOUT = {
localSet,
static_cast<uint32_t>(ModelLocalBindings::STORAGE_REFLECTION),
"cc_reflectionStorage",
gfx::Type::IMAGE2D,
1,
};
const ccstd::string REFLECTIONPROBECUBEMAP::NAME = "cc_reflectionProbeCubemap";
const gfx::DescriptorSetLayoutBinding REFLECTIONPROBECUBEMAP::DESCRIPTOR = {
REFLECTIONPROBECUBEMAP::BINDING,
gfx::DescriptorType::SAMPLER_TEXTURE,
1,
gfx::ShaderStageFlagBit::FRAGMENT,
{},
};
const gfx::UniformSamplerTexture REFLECTIONPROBECUBEMAP::LAYOUT = {
localSet,
REFLECTIONPROBECUBEMAP::BINDING,
REFLECTIONPROBECUBEMAP::NAME,
gfx::Type::SAMPLER_CUBE,
1,
};
const ccstd::string REFLECTIONPROBEPLANARMAP::NAME = "cc_reflectionProbePlanarMap";
const gfx::DescriptorSetLayoutBinding REFLECTIONPROBEPLANARMAP::DESCRIPTOR = {
REFLECTIONPROBEPLANARMAP::BINDING,
gfx::DescriptorType::SAMPLER_TEXTURE,
1,
gfx::ShaderStageFlagBit::FRAGMENT,
{},
};
const gfx::UniformSamplerTexture REFLECTIONPROBEPLANARMAP::LAYOUT = {
localSet,
REFLECTIONPROBEPLANARMAP::BINDING,
REFLECTIONPROBEPLANARMAP::NAME,
gfx::Type::SAMPLER2D,
1,
};
const ccstd::string REFLECTIONPROBEDATAMAP::NAME = "cc_reflectionProbeDataMap";
const gfx::DescriptorSetLayoutBinding REFLECTIONPROBEDATAMAP::DESCRIPTOR = {
REFLECTIONPROBEDATAMAP::BINDING,
gfx::DescriptorType::SAMPLER_TEXTURE,
1,
gfx::ShaderStageFlagBit::FRAGMENT,
{},
};
const gfx::UniformSamplerTexture REFLECTIONPROBEDATAMAP::LAYOUT = {
localSet,
REFLECTIONPROBEDATAMAP::BINDING,
REFLECTIONPROBEDATAMAP::NAME,
gfx::Type::SAMPLER2D,
1,
};
const ccstd::string REFLECTIONPROBEBLENDCUBEMAP::NAME = "cc_reflectionProbeBlendCubemap";
const gfx::DescriptorSetLayoutBinding REFLECTIONPROBEBLENDCUBEMAP::DESCRIPTOR = {
REFLECTIONPROBEBLENDCUBEMAP::BINDING,
gfx::DescriptorType::SAMPLER_TEXTURE,
1,
gfx::ShaderStageFlagBit::FRAGMENT,
{},
};
const gfx::UniformSamplerTexture REFLECTIONPROBEBLENDCUBEMAP::LAYOUT = {
localSet,
REFLECTIONPROBEBLENDCUBEMAP::BINDING,
REFLECTIONPROBEBLENDCUBEMAP::NAME,
gfx::Type::SAMPLER_CUBE,
1,
};
uint32_t skyboxFlag = static_cast<uint32_t>(gfx::ClearFlagBit::STENCIL) << 1;
uint32_t nextPow2(uint32_t val) {
--val;
val |= (val >> 1);
val |= (val >> 2);
val |= (val >> 4);
val |= (val >> 8);
val |= (val >> 16);
++val;
return val;
}
bool supportsR16HalfFloatTexture(const gfx::Device* device) {
return hasAllFlags(device->getFormatFeatures(gfx::Format::R16F), gfx::FormatFeature::RENDER_TARGET | gfx::FormatFeature::SAMPLED_TEXTURE);
}
bool supportsRGBA16HalfFloatTexture(const gfx::Device* device) {
return hasAllFlags(device->getFormatFeatures(gfx::Format::RGBA16F), gfx::FormatFeature::RENDER_TARGET | gfx::FormatFeature::SAMPLED_TEXTURE);
}
bool supportsR32FloatTexture(const gfx::Device* device) {
return hasAllFlags(device->getFormatFeatures(gfx::Format::R32F), gfx::FormatFeature::RENDER_TARGET | gfx::FormatFeature::SAMPLED_TEXTURE);
}
bool supportsRGBA32FloatTexture(const gfx::Device* device) {
return hasAllFlags(device->getFormatFeatures(gfx::Format::RGBA32F), gfx::FormatFeature::RENDER_TARGET | gfx::FormatFeature::SAMPLED_TEXTURE);
}
static ccstd::unordered_map<ccstd::string, uint32_t> phases; //cjh how to clear this global variable when exiting game?
static uint32_t phaseNum = 0;
uint32_t getPhaseID(const ccstd::string& phaseName) {
const auto iter = phases.find(phaseName);
if (iter == phases.end()) {
phases.emplace(phaseName, 1 << phaseNum);
++phaseNum;
}
return phases.at(phaseName);
}
void localDescriptorSetLayoutResizeMaxJoints(uint32_t maxCount) {
UBOSkinning::initLayout(maxCount);
localDescriptorSetLayout.blocks[UBOSkinning::NAME] = UBOSkinning::layout;
localDescriptorSetLayout.bindings[UBOSkinning::BINDING] = UBOSkinning::DESCRIPTOR;
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,693 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include <functional>
#include "base/Ptr.h"
#include "base/RefCounted.h"
#include "base/TypeDef.h"
#include "base/Value.h"
#include "renderer/gfx-base/GFXDef.h"
namespace cc {
namespace scene {
class Model;
class SubModel;
class Light;
} // namespace scene
namespace pipeline {
class RenderStage;
class RenderFlow;
// The actual uniform vectors used is JointUniformCapacity * 3.
// We think this is a reasonable default capacity considering MAX_VERTEX_UNIFORM_VECTORS in WebGL spec is just 128.
// Skinning models with number of bones more than this capacity will be automatically switched to texture skinning.
// But still, you can tweak this for your own need by changing the number below
// and the JOINT_UNIFORM_CAPACITY macro in cc-skinning shader header.
class CC_DLL SkinningJointCapacity {
public:
static uint32_t jointUniformCapacity;
};
constexpr float SHADOW_CAMERA_MAX_FAR = 2000.0F;
const float COEFFICIENT_OF_EXPANSION = 2.0F * sqrtf(3.0F);
struct CC_DLL RenderObject {
float depth = 0.0F;
const scene::Model *model = nullptr;
};
using RenderObjectList = ccstd::vector<struct RenderObject>;
struct CC_DLL RenderTargetInfo {
uint32_t width = 0;
uint32_t height = 0;
};
struct CC_DLL RenderPass {
uint32_t priority = 0;
uint32_t hash = 0;
float depth = 0.0F;
uint32_t shaderID = 0;
uint32_t passIndex = 0;
const scene::SubModel *subModel = nullptr;
};
using RenderPassList = ccstd::vector<RenderPass>;
using ColorDesc = gfx::ColorAttachment;
using ColorDescList = ccstd::vector<ColorDesc>;
using DepthStencilDesc = gfx::DepthStencilAttachment;
struct CC_DLL RenderPassDesc {
uint32_t index = 0;
ColorDescList colorAttachments;
DepthStencilDesc depthStencilAttachment;
};
using RenderPassDescList = ccstd::vector<RenderPassDesc>;
struct CC_DLL RenderTextureDesc {
ccstd::string name;
gfx::TextureType type = gfx::TextureType::TEX2D;
gfx::TextureUsage usage = gfx::TextureUsage::COLOR_ATTACHMENT;
gfx::Format format = gfx::Format::UNKNOWN;
int width = -1;
int height = -1;
};
using RenderTextureDescList = ccstd::vector<RenderTextureDesc>;
struct CC_DLL FrameBufferDesc {
ccstd::string name;
uint32_t renderPass = 0;
ccstd::vector<ccstd::string> colorTextures;
ccstd::string depthStencilTexture;
};
using FrameBufferDescList = ccstd::vector<FrameBufferDesc>;
enum class RenderFlowType : uint8_t {
SCENE,
POSTPROCESS,
UI,
};
CC_ENUM_CONVERSION_OPERATOR(RenderFlowType)
using RenderStageList = ccstd::vector<IntrusivePtr<RenderStage>>;
using RenderFlowList = ccstd::vector<IntrusivePtr<RenderFlow>>;
using LightList = ccstd::vector<scene::Light *>;
using UintList = ccstd::vector<uint32_t>;
enum class CC_DLL RenderPassStage {
DEFAULT = 100,
UI = 200,
};
CC_ENUM_CONVERSION_OPERATOR(RenderPassStage)
struct CC_DLL InternalBindingDesc {
gfx::DescriptorType type;
gfx::UniformBlock blockInfo;
gfx::UniformSamplerTexture samplerInfo;
Value defaultValue;
};
struct CC_DLL InternalBindingInst : public InternalBindingDesc {
gfx::Buffer *buffer = nullptr;
gfx::Sampler *sampler = nullptr;
gfx::Texture *texture = nullptr;
};
struct CC_DLL RenderQueueCreateInfo {
bool isTransparent = false;
uint32_t phases = 0;
std::function<bool(const RenderPass &a, const RenderPass &b)> sortFunc;
};
enum class CC_DLL RenderPriority {
MIN = 0,
MAX = 0xff,
DEFAULT = 0x80,
};
CC_ENUM_CONVERSION_OPERATOR(RenderPriority)
enum class CC_DLL RenderQueueSortMode {
FRONT_TO_BACK,
BACK_TO_FRONT,
};
CC_ENUM_CONVERSION_OPERATOR(RenderQueueSortMode)
class CC_DLL RenderQueueDesc : public RefCounted {
public:
RenderQueueDesc() = default;
RenderQueueDesc(bool isTransparent, RenderQueueSortMode sortMode, const ccstd::vector<ccstd::string> &stages) // NOLINT
: isTransparent(isTransparent), sortMode(sortMode), stages(stages) {}
bool isTransparent = false;
RenderQueueSortMode sortMode = RenderQueueSortMode::FRONT_TO_BACK;
ccstd::vector<ccstd::string> stages;
};
using RenderQueueDescList = ccstd::vector<IntrusivePtr<RenderQueueDesc>>;
uint32_t getPhaseID(const ccstd::string &phase);
inline bool opaqueCompareFn(const RenderPass &a, const RenderPass &b) {
if (a.hash != b.hash) {
return a.hash < b.hash;
}
if (math::isNotEqualF(a.depth, b.depth)) {
return a.depth < b.depth;
}
return a.shaderID < b.shaderID;
}
inline bool transparentCompareFn(const RenderPass &a, const RenderPass &b) {
if (a.priority != b.priority) {
return a.priority < b.priority;
}
if (a.hash != b.hash) {
return a.hash < b.hash;
}
if (math::isNotEqualF(a.depth, b.depth)) {
return b.depth < a.depth;
}
return a.shaderID < b.shaderID;
}
inline uint32_t convertPhase(const ccstd::vector<ccstd::string> &stages) {
uint32_t phase = 0;
for (const auto &stage : stages) {
phase |= getPhaseID(stage);
}
return phase;
}
using RenderQueueSortFunc = std::function<int(const RenderPass &, const RenderPass &)>;
inline RenderQueueSortFunc convertQueueSortFunc(const RenderQueueSortMode &mode) {
std::function<int(const RenderPass &, const RenderPass &)> sortFunc = opaqueCompareFn;
switch (mode) {
case RenderQueueSortMode::BACK_TO_FRONT:
sortFunc = transparentCompareFn;
break;
case RenderQueueSortMode::FRONT_TO_BACK:
sortFunc = opaqueCompareFn;
break;
default:
break;
}
return sortFunc;
}
enum class CC_DLL PipelineGlobalBindings {
UBO_GLOBAL,
UBO_CAMERA,
UBO_SHADOW,
UBO_CSM, // should reserve slot for this optional ubo
SAMPLER_SHADOWMAP,
SAMPLER_ENVIRONMENT,
SAMPLER_SPOT_SHADOW_MAP,
SAMPLER_DIFFUSEMAP,
COUNT,
};
CC_ENUM_CONVERSION_OPERATOR(PipelineGlobalBindings)
enum class CC_DLL ModelLocalBindings {
UBO_LOCAL,
UBO_FORWARD_LIGHTS,
UBO_SKINNING_ANIMATION,
UBO_SKINNING_TEXTURE,
UBO_MORPH,
UBO_UI_LOCAL,
UBO_SH,
SAMPLER_JOINTS,
SAMPLER_MORPH_POSITION,
SAMPLER_MORPH_NORMAL,
SAMPLER_MORPH_TANGENT,
SAMPLER_LIGHTMAP,
SAMPLER_SPRITE,
SAMPLER_REFLECTION,
STORAGE_REFLECTION,
SAMPLER_REFLECTION_PROBE_CUBE,
SAMPLER_REFLECTION_PROBE_PLANAR,
SAMPLER_REFLECTION_PROBE_DATA_MAP,
SAMPLER_REFLECTION_PROBE_BLEND_CUBE,
COUNT,
};
CC_ENUM_CONVERSION_OPERATOR(ModelLocalBindings)
enum class CC_DLL SetIndex {
GLOBAL,
MATERIAL,
LOCAL,
COUNT,
};
CC_ENUM_CONVERSION_OPERATOR(SetIndex)
extern CC_DLL uint32_t globalSet;
extern CC_DLL uint32_t materialSet;
extern CC_DLL uint32_t localSet;
extern CC_DLL gfx::BindingMappingInfo bindingMappingInfo;
struct CC_DLL UBOLocalBatched {
static constexpr uint32_t BATCHING_COUNT = 10;
static constexpr uint32_t MAT_WORLDS_OFFSET = 0;
static constexpr uint32_t COUNT = 16 * UBOLocalBatched::BATCHING_COUNT;
static constexpr uint32_t SIZE = UBOLocalBatched::COUNT * 4;
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::UBO_LOCAL);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformBlock LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL UBOLocal {
static constexpr uint32_t MAT_WORLD_OFFSET = 0;
static constexpr uint32_t MAT_WORLD_IT_OFFSET = UBOLocal::MAT_WORLD_OFFSET + 16;
static constexpr uint32_t LIGHTINGMAP_UVPARAM = UBOLocal::MAT_WORLD_IT_OFFSET + 16;
static constexpr uint32_t LOCAL_SHADOW_BIAS = UBOLocal::LIGHTINGMAP_UVPARAM + 4;
static constexpr uint32_t REFLECTION_PROBE_DATA1 = UBOLocal::LOCAL_SHADOW_BIAS + 4;
static constexpr uint32_t REFLECTION_PROBE_DATA2 = UBOLocal::REFLECTION_PROBE_DATA1 + 4;
static constexpr uint32_t REFLECTION_PROBE_BLEND_DATA1 = UBOLocal::REFLECTION_PROBE_DATA2 + 4;
static constexpr uint32_t REFLECTION_PROBE_BLEND_DATA2 = UBOLocal::REFLECTION_PROBE_BLEND_DATA1 + 4;
static constexpr uint32_t COUNT = UBOLocal::REFLECTION_PROBE_BLEND_DATA2 + 4;
static constexpr uint32_t SIZE = UBOLocal::COUNT * 4;
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::UBO_LOCAL);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformBlock LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL UBOWorldBound {
static constexpr uint32_t WORLD_BOUND_CENTER = 0;
static constexpr uint32_t WORLD_BOUND_HALF_EXTENTS = UBOWorldBound::WORLD_BOUND_CENTER + 4;
static constexpr uint32_t COUNT = UBOWorldBound::WORLD_BOUND_HALF_EXTENTS + 4;
static constexpr uint32_t SIZE = UBOWorldBound::COUNT * 4;
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::UBO_LOCAL);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformBlock LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL UBOForwardLight {
static constexpr uint32_t LIGHTS_PER_PASS = 1;
static constexpr uint32_t LIGHT_POS_OFFSET = 0;
static constexpr uint32_t LIGHT_COLOR_OFFSET = UBOForwardLight::LIGHT_POS_OFFSET + UBOForwardLight::LIGHTS_PER_PASS * 4;
static constexpr uint32_t LIGHT_SIZE_RANGE_ANGLE_OFFSET = UBOForwardLight::LIGHT_COLOR_OFFSET + UBOForwardLight::LIGHTS_PER_PASS * 4;
static constexpr uint32_t LIGHT_DIR_OFFSET = UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + UBOForwardLight::LIGHTS_PER_PASS * 4;
static constexpr uint32_t LIGHT_BOUNDING_SIZE_VS_OFFSET = UBOForwardLight::LIGHT_DIR_OFFSET + UBOForwardLight::LIGHTS_PER_PASS * 4;
static constexpr uint32_t COUNT = UBOForwardLight::LIGHT_BOUNDING_SIZE_VS_OFFSET + UBOForwardLight::LIGHTS_PER_PASS * 4;
static constexpr uint32_t SIZE = UBOForwardLight::COUNT * 4;
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::UBO_FORWARD_LIGHTS);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformBlock LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL UBODeferredLight {
static constexpr uint32_t LIGHTS_PER_PASS = 10;
};
struct CC_DLL UBOSkinningTexture {
static constexpr uint32_t JOINTS_TEXTURE_INFO_OFFSET = 0;
static constexpr uint32_t COUNT = UBOSkinningTexture::JOINTS_TEXTURE_INFO_OFFSET + 4;
static constexpr uint32_t SIZE = UBOSkinningTexture::COUNT * 4;
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::UBO_SKINNING_TEXTURE);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformBlock LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL UBOSkinningAnimation {
static constexpr uint32_t JOINTS_ANIM_INFO_OFFSET = 0;
static constexpr uint32_t COUNT = UBOSkinningAnimation::JOINTS_ANIM_INFO_OFFSET + 4;
static constexpr uint32_t SIZE = UBOSkinningAnimation::COUNT * 4;
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::UBO_SKINNING_ANIMATION);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformBlock LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL UBOSkinning {
static uint32_t count;
static uint32_t size;
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::UBO_SKINNING_TEXTURE);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static gfx::UniformBlock layout;
static const ccstd::string NAME;
static void initLayout(uint capacity);
};
struct CC_DLL UBOMorph {
static constexpr uint32_t MAX_MORPH_TARGET_COUNT = 60;
static constexpr uint32_t OFFSET_OF_WEIGHTS = 0;
static constexpr uint32_t OFFSET_OF_DISPLACEMENT_TEXTURE_WIDTH = 4 * MAX_MORPH_TARGET_COUNT;
static constexpr uint32_t OFFSET_OF_DISPLACEMENT_TEXTURE_HEIGHT = OFFSET_OF_DISPLACEMENT_TEXTURE_WIDTH + 4;
static constexpr uint32_t OFFSET_OF_VERTICES_COUNT = OFFSET_OF_DISPLACEMENT_TEXTURE_HEIGHT + 4;
static const uint32_t COUNT_BASE_4_BYTES;
static const uint32_t SIZE;
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::UBO_MORPH);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformBlock LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL UBOUILocal {
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::UBO_UI_LOCAL);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformBlock LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL UBOSH {
static constexpr uint32_t SH_LINEAR_CONST_R_OFFSET = 0;
static constexpr uint32_t SH_LINEAR_CONST_G_OFFSET = UBOSH::SH_LINEAR_CONST_R_OFFSET + 4;
static constexpr uint32_t SH_LINEAR_CONST_B_OFFSET = UBOSH::SH_LINEAR_CONST_G_OFFSET + 4;
static constexpr uint32_t SH_QUADRATIC_R_OFFSET = UBOSH::SH_LINEAR_CONST_B_OFFSET + 4;
static constexpr uint32_t SH_QUADRATIC_G_OFFSET = UBOSH::SH_QUADRATIC_R_OFFSET + 4;
static constexpr uint32_t SH_QUADRATIC_B_OFFSET = UBOSH::SH_QUADRATIC_G_OFFSET + 4;
static constexpr uint32_t SH_QUADRATIC_A_OFFSET = UBOSH::SH_QUADRATIC_B_OFFSET + 4;
static constexpr uint32_t COUNT = UBOSH::SH_QUADRATIC_A_OFFSET + 4;
static constexpr uint32_t SIZE = UBOSH::COUNT * 4;
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::UBO_SH);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformBlock LAYOUT;
static const ccstd::string NAME;
};
enum class CC_DLL ForwardStagePriority {
AR = 5,
FORWARD = 10,
UI = 20
};
CC_ENUM_CONVERSION_OPERATOR(ForwardStagePriority)
enum class CC_DLL ForwardFlowPriority {
SHADOW = 0,
FORWARD = 1,
UI = 10,
};
CC_ENUM_CONVERSION_OPERATOR(ForwardFlowPriority)
enum class CC_DLL RenderFlowTag {
SCENE,
POSTPROCESS,
UI,
};
CC_ENUM_CONVERSION_OPERATOR(RenderFlowTag)
enum class CC_DLL DeferredStagePriority {
GBUFFER = 10,
LIGHTING = 15,
TRANSPARANT = 18,
BLOOM = 19,
POSTPROCESS = 20,
UI = 30
};
CC_ENUM_CONVERSION_OPERATOR(DeferredStagePriority)
enum class CC_DLL DeferredFlowPriority {
SHADOW = 0,
MAIN = 1,
UI = 10
};
CC_ENUM_CONVERSION_OPERATOR(DeferredFlowPriority)
struct CC_DLL UBOGlobal {
static constexpr uint32_t TIME_OFFSET = 0;
static constexpr uint32_t SCREEN_SIZE_OFFSET = UBOGlobal::TIME_OFFSET + 4;
static constexpr uint32_t NATIVE_SIZE_OFFSET = UBOGlobal::SCREEN_SIZE_OFFSET + 4;
static constexpr uint32_t PROBE_INFO_OFFSET = UBOGlobal::NATIVE_SIZE_OFFSET + 4;
static constexpr uint32_t DEBUG_VIEW_MODE_OFFSET = UBOGlobal::PROBE_INFO_OFFSET + 4;
static constexpr uint32_t COUNT = UBOGlobal::DEBUG_VIEW_MODE_OFFSET + 4;
static constexpr uint32_t SIZE = UBOGlobal::COUNT * 4;
static constexpr uint32_t BINDING = static_cast<uint32_t>(PipelineGlobalBindings::UBO_GLOBAL);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformBlock LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL UBOCamera {
static constexpr uint32_t MAT_VIEW_OFFSET = 0;
static constexpr uint32_t MAT_VIEW_INV_OFFSET = UBOCamera::MAT_VIEW_OFFSET + 16;
static constexpr uint32_t MAT_PROJ_OFFSET = UBOCamera::MAT_VIEW_INV_OFFSET + 16;
static constexpr uint32_t MAT_PROJ_INV_OFFSET = UBOCamera::MAT_PROJ_OFFSET + 16;
static constexpr uint32_t MAT_VIEW_PROJ_OFFSET = UBOCamera::MAT_PROJ_INV_OFFSET + 16;
static constexpr uint32_t MAT_VIEW_PROJ_INV_OFFSET = UBOCamera::MAT_VIEW_PROJ_OFFSET + 16;
static constexpr uint32_t CAMERA_POS_OFFSET = UBOCamera::MAT_VIEW_PROJ_INV_OFFSET + 16;
static constexpr uint32_t SURFACE_TRANSFORM_OFFSET = UBOCamera::CAMERA_POS_OFFSET + 4;
static constexpr uint32_t SCREEN_SCALE_OFFSET = UBOCamera::SURFACE_TRANSFORM_OFFSET + 4;
static constexpr uint32_t EXPOSURE_OFFSET = UBOCamera::SCREEN_SCALE_OFFSET + 4;
static constexpr uint32_t MAIN_LIT_DIR_OFFSET = UBOCamera::EXPOSURE_OFFSET + 4;
static constexpr uint32_t MAIN_LIT_COLOR_OFFSET = UBOCamera::MAIN_LIT_DIR_OFFSET + 4;
static constexpr uint32_t AMBIENT_SKY_OFFSET = UBOCamera::MAIN_LIT_COLOR_OFFSET + 4;
static constexpr uint32_t AMBIENT_GROUND_OFFSET = UBOCamera::AMBIENT_SKY_OFFSET + 4;
static constexpr uint32_t GLOBAL_FOG_COLOR_OFFSET = UBOCamera::AMBIENT_GROUND_OFFSET + 4;
static constexpr uint32_t GLOBAL_FOG_BASE_OFFSET = UBOCamera::GLOBAL_FOG_COLOR_OFFSET + 4;
static constexpr uint32_t GLOBAL_FOG_ADD_OFFSET = UBOCamera::GLOBAL_FOG_BASE_OFFSET + 4;
static constexpr uint32_t GLOBAL_NEAR_FAR_OFFSET = UBOCamera::GLOBAL_FOG_ADD_OFFSET + 4;
static constexpr uint32_t GLOBAL_VIEW_PORT_OFFSET = UBOCamera::GLOBAL_NEAR_FAR_OFFSET + 4;
static constexpr uint32_t COUNT = UBOCamera::GLOBAL_VIEW_PORT_OFFSET + 4;
static constexpr uint32_t SIZE = UBOCamera::COUNT * 4;
static constexpr uint32_t BINDING = static_cast<uint32_t>(PipelineGlobalBindings::UBO_CAMERA);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformBlock LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL UBOShadow {
static constexpr uint32_t MAT_LIGHT_VIEW_OFFSET = 0;
static constexpr uint32_t MAT_LIGHT_VIEW_PROJ_OFFSET = UBOShadow::MAT_LIGHT_VIEW_OFFSET + 16;
static constexpr uint32_t SHADOW_INV_PROJ_DEPTH_INFO_OFFSET = UBOShadow::MAT_LIGHT_VIEW_PROJ_OFFSET + 16;
static constexpr uint32_t SHADOW_PROJ_DEPTH_INFO_OFFSET = UBOShadow::SHADOW_INV_PROJ_DEPTH_INFO_OFFSET + 4;
static constexpr uint32_t SHADOW_PROJ_INFO_OFFSET = UBOShadow::SHADOW_PROJ_DEPTH_INFO_OFFSET + 4;
static constexpr uint32_t SHADOW_NEAR_FAR_LINEAR_SATURATION_INFO_OFFSET = UBOShadow::SHADOW_PROJ_INFO_OFFSET + 4;
static constexpr uint32_t SHADOW_WIDTH_HEIGHT_PCF_BIAS_INFO_OFFSET = UBOShadow::SHADOW_NEAR_FAR_LINEAR_SATURATION_INFO_OFFSET + 4;
static constexpr uint32_t SHADOW_LIGHT_PACKING_NBIAS_NULL_INFO_OFFSET = UBOShadow::SHADOW_WIDTH_HEIGHT_PCF_BIAS_INFO_OFFSET + 4;
static constexpr uint32_t SHADOW_COLOR_OFFSET = UBOShadow::SHADOW_LIGHT_PACKING_NBIAS_NULL_INFO_OFFSET + 4;
static constexpr uint32_t PLANAR_NORMAL_DISTANCE_INFO_OFFSET = UBOShadow::SHADOW_COLOR_OFFSET + 4;
static constexpr uint32_t COUNT = UBOShadow::PLANAR_NORMAL_DISTANCE_INFO_OFFSET + 4;
static constexpr uint32_t SIZE = UBOShadow::COUNT * 4;
static constexpr uint32_t BINDING = static_cast<uint32_t>(PipelineGlobalBindings::UBO_SHADOW);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformBlock LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL UBOCSM {
static constexpr uint32_t CSM_LEVEL_COUNT = 4;
static constexpr uint32_t CSM_VIEW_DIR_0_OFFSET = 0;
static constexpr uint32_t CSM_VIEW_DIR_1_OFFSET = UBOCSM::CSM_VIEW_DIR_0_OFFSET + 4 * UBOCSM::CSM_LEVEL_COUNT;
static constexpr uint32_t CSM_VIEW_DIR_2_OFFSET = UBOCSM::CSM_VIEW_DIR_1_OFFSET + 4 * UBOCSM::CSM_LEVEL_COUNT;
static constexpr uint32_t CSM_ATLAS_OFFSET = UBOCSM::CSM_VIEW_DIR_2_OFFSET + 4 * UBOCSM::CSM_LEVEL_COUNT;
static constexpr uint32_t MAT_CSM_VIEW_PROJ_LEVELS_OFFSET = UBOCSM::CSM_ATLAS_OFFSET + 4 * UBOCSM::CSM_LEVEL_COUNT;
static constexpr uint32_t CSM_PROJ_DEPTH_INFO_LEVELS_OFFSET = UBOCSM::MAT_CSM_VIEW_PROJ_LEVELS_OFFSET + 16 * UBOCSM::CSM_LEVEL_COUNT;
static constexpr uint32_t CSM_PROJ_INFO_LEVELS_OFFSET = UBOCSM::CSM_PROJ_DEPTH_INFO_LEVELS_OFFSET + 4 * UBOCSM::CSM_LEVEL_COUNT;
static constexpr uint32_t CSM_SPLITS_INFO_OFFSET = UBOCSM::CSM_PROJ_INFO_LEVELS_OFFSET + 4 * UBOCSM::CSM_LEVEL_COUNT;
static constexpr uint32_t COUNT = UBOCSM::CSM_SPLITS_INFO_OFFSET + 4;
static constexpr uint32_t SIZE = UBOCSM::COUNT * 4;
static constexpr uint32_t BINDING = static_cast<uint32_t>(PipelineGlobalBindings::UBO_CSM);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformBlock LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL DescriptorSetLayoutInfos {
gfx::DescriptorSetLayoutBindingList bindings;
ccstd::unordered_map<ccstd::string, gfx::UniformBlock> blocks;
ccstd::unordered_map<ccstd::string, gfx::UniformSamplerTexture> samplers;
ccstd::unordered_map<ccstd::string, gfx::UniformStorageImage> storeImages;
};
extern CC_DLL DescriptorSetLayoutInfos globalDescriptorSetLayout;
extern CC_DLL DescriptorSetLayoutInfos localDescriptorSetLayout;
enum class LayerList : uint32_t {
NONE = 0,
IGNORE_RAYCAST = (1 << 20),
GIZMOS = (1 << 21),
EDITOR = (1 << 22),
UI_3D = (1 << 23),
SCENE_GIZMO = (1 << 24),
UI_2D = (1 << 25),
PROFILER = (1 << 28),
DEFAULT = (1 << 30),
ALL = 0xffffffff,
};
CC_ENUM_CONVERSION_OPERATOR(LayerList)
const uint32_t CAMERA_DEFAULT_MASK = ~static_cast<uint32_t>(LayerList::UI_2D) & ~static_cast<uint32_t>(LayerList::PROFILER);
// constexpr CAMERA_DEFAULT_MASK = Layers.makeMaskExclude([Layers.BitMask.UI_2D, Layers.BitMask.GIZMOS, Layers.BitMask.EDITOR,
// Layers.BitMask.SCENE_GIZMO, Layers.BitMask.PROFILER]);
uint32_t nextPow2(uint32_t val);
bool supportsR16HalfFloatTexture(const gfx::Device *device);
bool supportsRGBA16HalfFloatTexture(const gfx::Device *device);
bool supportsR32FloatTexture(const gfx::Device *device);
bool supportsRGBA32FloatTexture(const gfx::Device *device);
extern CC_DLL uint32_t skyboxFlag;
struct CC_DLL SHADOWMAP {
static constexpr uint32_t BINDING = static_cast<uint32_t>(PipelineGlobalBindings::SAMPLER_SHADOWMAP);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformSamplerTexture LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL ENVIRONMENT {
static constexpr uint32_t BINDING = static_cast<uint32_t>(PipelineGlobalBindings::SAMPLER_ENVIRONMENT);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformSamplerTexture LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL SPOTSHADOWMAP {
static constexpr uint32_t BINDING = static_cast<uint32_t>(PipelineGlobalBindings::SAMPLER_SPOT_SHADOW_MAP);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformSamplerTexture LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL DIFFUSEMAP {
static constexpr uint32_t BINDING = static_cast<uint32_t>(PipelineGlobalBindings::SAMPLER_DIFFUSEMAP);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformSamplerTexture LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL JOINTTEXTURE {
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::SAMPLER_JOINTS);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformSamplerTexture LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL REALTIMEJOINTTEXTURE {
static constexpr uint BINDING = static_cast<uint>(ModelLocalBindings::SAMPLER_JOINTS);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformSamplerTexture LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL POSITIONMORPH {
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::SAMPLER_MORPH_POSITION);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformSamplerTexture LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL NORMALMORPH {
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::SAMPLER_MORPH_NORMAL);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformSamplerTexture LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL TANGENTMORPH {
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::SAMPLER_MORPH_TANGENT);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformSamplerTexture LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL LIGHTMAPTEXTURE {
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::SAMPLER_LIGHTMAP);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformSamplerTexture LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL SPRITETEXTURE {
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::SAMPLER_SPRITE);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformSamplerTexture LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL REFLECTIONTEXTURE {
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::SAMPLER_REFLECTION);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformSamplerTexture LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL REFLECTIONSTORAGE {
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::STORAGE_REFLECTION);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformStorageImage LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL REFLECTIONPROBECUBEMAP {
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::SAMPLER_REFLECTION_PROBE_CUBE);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformSamplerTexture LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL REFLECTIONPROBEPLANARMAP {
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::SAMPLER_REFLECTION_PROBE_PLANAR);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformSamplerTexture LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL REFLECTIONPROBEDATAMAP {
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::SAMPLER_REFLECTION_PROBE_DATA_MAP);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformSamplerTexture LAYOUT;
static const ccstd::string NAME;
};
struct CC_DLL REFLECTIONPROBEBLENDCUBEMAP {
static constexpr uint32_t BINDING = static_cast<uint32_t>(ModelLocalBindings::SAMPLER_REFLECTION_PROBE_BLEND_CUBE);
static const gfx::DescriptorSetLayoutBinding DESCRIPTOR;
static const gfx::UniformSamplerTexture LAYOUT;
static const ccstd::string NAME;
};
static constexpr uint32_t CLUSTER_LIGHT_BINDING = 4;
static constexpr uint32_t CLUSTER_LIGHT_INDEX_BINDING = 5;
static constexpr uint32_t CLUSTER_LIGHT_GRID_BINDING = 6;
void localDescriptorSetLayoutResizeMaxJoints(uint32_t maxCount);
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,45 @@
/****************************************************************************
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
enum class CommonInsertPoint {
DIP_AR_BACKGROUND = 90,
DIP_BLOOM = 350,
DIP_POSTPROCESS = 400,
};
enum class DeferredInsertPoint {
DIP_CLUSTER = 80,
DIP_GBUFFER = 100,
DIP_LIGHTING = 200,
DIP_TRANSPARENT = 220,
DIP_SSPR = 300,
DIP_INVALID
};
enum class ForwardInsertPoint {
IP_FORWARD = 100,
IP_INVALID
};

View File

@@ -0,0 +1,879 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "GeometryRenderer.h"
#include <algorithm>
#include <cmath>
#include "Define.h"
#include "PipelineSceneData.h"
#include "PipelineStateManager.h"
#include "RenderPipeline.h"
#include "base/Log.h"
#include "base/std/container/array.h"
#include "core/geometry/AABB.h"
#include "core/geometry/Frustum.h"
#include "core/geometry/Spline.h"
#include "math/Mat4.h"
#include "math/Math.h"
#include "profiler/Profiler.h"
#include "scene/Camera.h"
#include "scene/Pass.h"
#include "scene/RenderWindow.h"
namespace cc {
namespace pipeline {
/**
* GEOMETRY_DEPTH_TYPE_COUNT:
* [0]: no depthTest
* [1]: depthTest
*/
constexpr uint32_t GEOMETRY_DEPTH_TYPE_COUNT = 2U;
constexpr uint32_t GEOMETRY_NO_DEPTH_TEST_PASS_NUM = 1U;
constexpr uint32_t GEOMETRY_DEPTH_TEST_PASS_NUM = 2U;
constexpr uint32_t GEOMETRY_VERTICES_PER_LINE = 2U;
constexpr uint32_t GEOMETRY_VERTICES_PER_TRIANGLE = 3U;
constexpr uint32_t GEOMETRY_MAX_LINES = 30000U;
constexpr uint32_t GEOMETRY_MAX_DASHED_LINES = 10000U;
constexpr uint32_t GEOMETRY_MAX_TRIANGLES = 10000U;
enum class GeometryType {
LINE = 0,
DASHED_LINE = 1,
TRIANGLE = 2,
};
struct PosColorVertex {
PosColorVertex() = default;
PosColorVertex(const Vec3 &pos, gfx::Color clr)
: position(pos), color(clr) {}
Vec3 position;
gfx::Color color;
};
struct PosNormColorVertex {
PosNormColorVertex() = default;
PosNormColorVertex(const Vec3 &pos, const Vec4 &norm, gfx::Color clr)
: position(pos), normal(norm), color(clr) {}
Vec3 position;
Vec4 normal; // xyz: normal, w:unlit
gfx::Color color;
};
template <typename T>
class GeometryVertexBuffer {
private:
inline void init(gfx::Device *device, uint32_t maxVertices, const gfx::AttributeList &attributes) {
_maxVertices = maxVertices;
_buffer = device->createBuffer({gfx::BufferUsageBit::VERTEX | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::DEVICE,
static_cast<uint32_t>(maxVertices * sizeof(T)),
static_cast<uint32_t>(sizeof(T))});
gfx::InputAssemblerInfo info;
info.attributes = attributes;
info.vertexBuffers.push_back(_buffer);
_inputAssembler = device->createInputAssembler(info);
CC_PROFILE_MEMORY_INC(GeometryVertexBuffer, static_cast<uint32_t>(_maxVertices * sizeof(T)));
}
inline uint32_t getCount() const { return std::min(static_cast<uint32_t>(_vertices.size()), _maxVertices); }
inline bool empty() const { return _vertices.empty(); }
inline void reset() { _vertices.clear(); }
inline void update() {
if (!empty()) {
const auto count = getCount();
const auto size = static_cast<uint32_t>(count * sizeof(T));
_buffer->update(&_vertices[0], size);
}
}
inline void destroy() {
_vertices.clear();
CC_SAFE_DESTROY_AND_DELETE(_buffer);
CC_SAFE_DESTROY_AND_DELETE(_inputAssembler);
CC_PROFILE_MEMORY_DEC(GeometryVertexBuffer, static_cast<uint32_t>(_maxVertices * sizeof(T)));
}
uint32_t _maxVertices{0};
ccstd::vector<T> _vertices;
gfx::Buffer *_buffer{nullptr};
gfx::InputAssembler *_inputAssembler{nullptr};
friend class GeometryRenderer;
};
struct GeometryVertexBuffers {
ccstd::array<GeometryVertexBuffer<PosColorVertex>, GEOMETRY_DEPTH_TYPE_COUNT> lines;
ccstd::array<GeometryVertexBuffer<PosColorVertex>, GEOMETRY_DEPTH_TYPE_COUNT> dashedLines;
ccstd::array<GeometryVertexBuffer<PosNormColorVertex>, GEOMETRY_DEPTH_TYPE_COUNT> triangles;
};
GeometryRendererInfo::GeometryRendererInfo()
: maxLines{GEOMETRY_MAX_LINES}, maxDashedLines{GEOMETRY_MAX_DASHED_LINES}, maxTriangles{GEOMETRY_MAX_TRIANGLES} {
}
GeometryRenderer::GeometryRenderer() {
_buffers = ccnew GeometryVertexBuffers();
}
GeometryRenderer::~GeometryRenderer() {
CC_SAFE_DELETE(_buffers);
}
void GeometryRenderer::activate(gfx::Device *device, const GeometryRendererInfo &info) {
_device = device;
static const gfx::AttributeList POS_COLOR_ATTRIBUTES = {
{"a_position", gfx::Format::RGB32F},
{"a_color", gfx::Format::RGBA32F}};
static const gfx::AttributeList POS_NORM_COLOR_ATTRIBUTES = {
{"a_position", gfx::Format::RGB32F},
{"a_normal", gfx::Format::RGBA32F},
{"a_color", gfx::Format::RGBA32F}};
for (auto i = 0U; i < GEOMETRY_DEPTH_TYPE_COUNT; i++) {
_buffers->lines[i].init(_device, info.maxLines * GEOMETRY_VERTICES_PER_LINE, POS_COLOR_ATTRIBUTES);
_buffers->dashedLines[i].init(_device, info.maxDashedLines * GEOMETRY_VERTICES_PER_LINE, POS_COLOR_ATTRIBUTES);
_buffers->triangles[i].init(_device, info.maxTriangles * GEOMETRY_VERTICES_PER_TRIANGLE, POS_NORM_COLOR_ATTRIBUTES);
}
}
void GeometryRenderer::render(gfx::RenderPass *renderPass, gfx::CommandBuffer *cmdBuff, PipelineSceneData *sceneData) {
const auto &passes = sceneData->getGeometryRendererPasses();
const auto &shaders = sceneData->getGeometryRendererShaders();
uint32_t offset = 0U;
const uint32_t passCount[GEOMETRY_DEPTH_TYPE_COUNT] = {GEOMETRY_NO_DEPTH_TEST_PASS_NUM, GEOMETRY_DEPTH_TEST_PASS_NUM};
/**
* passes:
* 0 : no depthTest line pass
* 1,2: depthTest line pass
* 3 : no depthTest dashed line pass
* 4,5: depthTest dashed line pass
* 6 : no depthTest triangle pass
* 7,8: depthTest triangle pass
*/
for (auto i = 0U; i < GEOMETRY_DEPTH_TYPE_COUNT; i++) {
auto &lines = _buffers->lines[i];
if (!lines.empty()) {
gfx::DrawInfo drawInfo;
drawInfo.vertexCount = lines.getCount();
for (auto p = 0U; p < passCount[i]; p++) {
auto *pass = passes[offset + p];
auto *shader = shaders[offset + p];
auto *pso = PipelineStateManager::getOrCreatePipelineState(pass, shader, lines._inputAssembler, renderPass);
cmdBuff->bindPipelineState(pso);
cmdBuff->bindDescriptorSet(materialSet, pass->getDescriptorSet());
cmdBuff->bindInputAssembler(lines._inputAssembler);
cmdBuff->draw(drawInfo);
}
}
offset += passCount[i];
}
for (auto i = 0U; i < GEOMETRY_DEPTH_TYPE_COUNT; i++) {
auto &dashedLines = _buffers->dashedLines[i];
if (!dashedLines.empty()) {
gfx::DrawInfo drawInfo;
drawInfo.vertexCount = dashedLines.getCount();
for (auto p = 0U; p < passCount[i]; p++) {
auto *pass = passes[offset + p];
auto *shader = shaders[offset + p];
auto *pso = PipelineStateManager::getOrCreatePipelineState(pass, shader, dashedLines._inputAssembler, renderPass);
cmdBuff->bindPipelineState(pso);
cmdBuff->bindDescriptorSet(materialSet, pass->getDescriptorSet());
cmdBuff->bindInputAssembler(dashedLines._inputAssembler);
cmdBuff->draw(drawInfo);
}
}
offset += passCount[i];
}
for (auto i = 0U; i < GEOMETRY_DEPTH_TYPE_COUNT; i++) {
auto &triangles = _buffers->triangles[i];
if (!triangles.empty()) {
gfx::DrawInfo drawInfo;
drawInfo.vertexCount = triangles.getCount();
for (auto p = 0U; p < passCount[i]; p++) {
auto *pass = passes[offset + p];
auto *shader = shaders[offset + p];
auto *pso = PipelineStateManager::getOrCreatePipelineState(pass, shader, triangles._inputAssembler, renderPass);
cmdBuff->bindPipelineState(pso);
cmdBuff->bindDescriptorSet(materialSet, pass->getDescriptorSet());
cmdBuff->bindInputAssembler(triangles._inputAssembler);
cmdBuff->draw(drawInfo);
}
}
offset += passCount[i];
}
// reset all geometry data for next frame
reset();
}
void GeometryRenderer::destroy() {
for (auto i = 0U; i < GEOMETRY_DEPTH_TYPE_COUNT; i++) {
_buffers->lines[i].destroy();
_buffers->dashedLines[i].destroy();
_buffers->triangles[i].destroy();
}
}
bool GeometryRenderer::empty() const {
for (auto i = 0U; i < GEOMETRY_DEPTH_TYPE_COUNT; i++) {
if (!_buffers->lines[i].empty() ||
!_buffers->dashedLines[i].empty() ||
!_buffers->triangles[i].empty()) {
return false;
}
}
return true;
}
void GeometryRenderer::update() {
for (auto i = 0U; i < GEOMETRY_DEPTH_TYPE_COUNT; i++) {
_buffers->lines[i].update();
_buffers->dashedLines[i].update();
_buffers->triangles[i].update();
}
}
void GeometryRenderer::reset() {
for (auto i = 0U; i < GEOMETRY_DEPTH_TYPE_COUNT; i++) {
_buffers->lines[i].reset();
_buffers->dashedLines[i].reset();
_buffers->triangles[i].reset();
}
}
void GeometryRenderer::addDashedLine(const Vec3 &v0, const Vec3 &v1, gfx::Color color, bool depthTest) {
auto &dashedLines = _buffers->dashedLines[depthTest ? 1 : 0];
if (dashedLines._vertices.size() + GEOMETRY_VERTICES_PER_LINE > dashedLines._maxVertices) {
CC_LOG_WARNING("GeometryRenderer: too many lines.");
return;
}
dashedLines._vertices.emplace_back(v0, color);
dashedLines._vertices.emplace_back(v1, color);
}
void GeometryRenderer::addLine(const Vec3 &v0, const Vec3 &v1, gfx::Color color, bool depthTest) {
auto &lines = _buffers->lines[depthTest ? 1 : 0];
if (lines._vertices.size() + GEOMETRY_VERTICES_PER_LINE > lines._maxVertices) {
CC_LOG_WARNING("GeometryRenderer: too many lines.");
return;
}
lines._vertices.emplace_back(v0, color);
lines._vertices.emplace_back(v1, color);
}
void GeometryRenderer::addTriangle(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2, gfx::Color color, bool wireframe, bool depthTest, bool unlit) {
if (wireframe) {
addLine(v0, v1, color, depthTest);
addLine(v1, v2, color, depthTest);
addLine(v2, v0, color, depthTest);
return;
}
auto &triangles = _buffers->triangles[depthTest ? 1 : 0];
if (triangles._vertices.size() + GEOMETRY_VERTICES_PER_TRIANGLE > triangles._maxVertices) {
CC_LOG_WARNING("GeometryRenderer: too many triangles.");
return;
}
Vec4 normal{0.0F, 0.0F, 0.0F, 0.0F};
if (!unlit) {
const Vec3 dist1 = v1 - v0;
const Vec3 dist2 = v2 - v0;
Vec3 norm;
Vec3::cross(dist1, dist2, &norm);
norm.normalize();
normal.set(norm.x, norm.y, norm.z, 1.0F);
}
triangles._vertices.emplace_back(v0, normal, color);
triangles._vertices.emplace_back(v1, normal, color);
triangles._vertices.emplace_back(v2, normal, color);
}
void GeometryRenderer::addQuad(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2, const Vec3 &v3, gfx::Color color, bool wireframe, bool depthTest, bool unlit) {
/**
* 3---2
* | |
* 0---1
*/
if (wireframe) {
addLine(v0, v1, color, depthTest);
addLine(v1, v2, color, depthTest);
addLine(v2, v3, color, depthTest);
addLine(v3, v0, color, depthTest);
} else {
addTriangle(v0, v1, v2, color, wireframe, depthTest, unlit);
addTriangle(v0, v2, v3, color, wireframe, depthTest, unlit);
}
}
void GeometryRenderer::addBoundingBox(const geometry::AABB &aabb, gfx::Color color, bool wireframe, bool depthTest, bool unlit, bool useTransform, const Mat4 &transform) {
/**
* 2---3
* / /
* 6---7
* 0---1
* / /
* 4---5
*
*/
const Vec3 min = aabb.getCenter() - aabb.getHalfExtents();
const Vec3 max = aabb.getCenter() + aabb.getHalfExtents();
Vec3 v0{min.x, min.y, min.z};
Vec3 v1{max.x, min.y, min.z};
Vec3 v2{min.x, max.y, min.z};
Vec3 v3{max.x, max.y, min.z};
Vec3 v4{min.x, min.y, max.z};
Vec3 v5{max.x, min.y, max.z};
Vec3 v6{min.x, max.y, max.z};
Vec3 v7{max.x, max.y, max.z};
if (useTransform) {
v0.transformMat4(transform);
v1.transformMat4(transform);
v2.transformMat4(transform);
v3.transformMat4(transform);
v4.transformMat4(transform);
v5.transformMat4(transform);
v6.transformMat4(transform);
v7.transformMat4(transform);
}
if (wireframe) {
addLine(v6, v7, color, depthTest);
addLine(v7, v3, color, depthTest);
addLine(v3, v2, color, depthTest);
addLine(v2, v6, color, depthTest);
addLine(v4, v5, color, depthTest);
addLine(v5, v1, color, depthTest);
addLine(v1, v0, color, depthTest);
addLine(v0, v4, color, depthTest);
addLine(v6, v4, color, depthTest);
addLine(v7, v5, color, depthTest);
addLine(v3, v1, color, depthTest);
addLine(v2, v0, color, depthTest);
} else {
addQuad(v4, v5, v7, v6, color, wireframe, depthTest, unlit);
addQuad(v5, v1, v3, v7, color, wireframe, depthTest, unlit);
addQuad(v1, v0, v2, v3, color, wireframe, depthTest, unlit);
addQuad(v0, v4, v6, v2, color, wireframe, depthTest, unlit);
addQuad(v6, v7, v3, v2, color, wireframe, depthTest, unlit);
addQuad(v0, v1, v5, v4, color, wireframe, depthTest, unlit);
}
}
void GeometryRenderer::addCross(const Vec3 &center, float size, gfx::Color color, bool depthTest) {
float halfSize = size * 0.5F;
addLine(Vec3(center.x - halfSize, center.y, center.z), Vec3(center.x + halfSize, center.y, center.z), color, depthTest);
addLine(Vec3(center.x, center.y - halfSize, center.z), Vec3(center.x, center.y + halfSize, center.z), color, depthTest);
addLine(Vec3(center.x, center.y, center.z - halfSize), Vec3(center.x, center.y, center.z + halfSize), color, depthTest);
}
void GeometryRenderer::addFrustum(const geometry::Frustum &frustum, gfx::Color color, bool depthTest) {
const auto &vertices = frustum.vertices;
addLine(vertices[0], vertices[1], color, depthTest);
addLine(vertices[1], vertices[2], color, depthTest);
addLine(vertices[2], vertices[3], color, depthTest);
addLine(vertices[3], vertices[0], color, depthTest);
addLine(vertices[4], vertices[5], color, depthTest);
addLine(vertices[5], vertices[6], color, depthTest);
addLine(vertices[6], vertices[7], color, depthTest);
addLine(vertices[7], vertices[4], color, depthTest);
addLine(vertices[0], vertices[4], color, depthTest);
addLine(vertices[1], vertices[5], color, depthTest);
addLine(vertices[2], vertices[6], color, depthTest);
addLine(vertices[3], vertices[7], color, depthTest);
}
void GeometryRenderer::addCapsule(const Vec3 &center, float radius, float height, gfx::Color color, uint32_t segmentsU, uint32_t hemiSegmentsV, bool wireframe, bool depthTest, bool unlit, bool useTransform, const Mat4 &transform) {
const auto deltaPhi = math::PI_2 / static_cast<float>(segmentsU);
const auto deltaTheta = math::PI_DIV2 / static_cast<float>(hemiSegmentsV);
Vec3 bottomCenter{center.x, center.y - height / 2.0F, center.z};
Vec3 topCenter{center.x, center.y + height / 2.0F, center.z};
using CircleList = ccstd::vector<Vec3>;
ccstd::vector<CircleList> bottomPoints;
ccstd::vector<CircleList> topPoints;
for (auto i = 0U; i < hemiSegmentsV + 1; i++) {
CircleList bottomList;
CircleList topList;
float theta = static_cast<float>(i) * deltaTheta;
float sinTheta = sinf(theta);
float cosTheta = cosf(theta);
for (auto j = 0U; j < segmentsU + 1; j++) {
float phi = static_cast<float>(j) * deltaPhi;
float sinPhi = sinf(phi);
float cosPhi = cosf(phi);
Vec3 p{radius * sinTheta * cosPhi, radius * cosTheta, radius * sinTheta * sinPhi};
bottomList.emplace_back(bottomCenter + Vec3(p.x, -p.y, p.z));
topList.emplace_back(topCenter + p);
}
bottomPoints.emplace_back(bottomList);
topPoints.emplace_back(topList);
}
if (useTransform) {
for (auto i = 0U; i < hemiSegmentsV + 1; i++) {
for (auto j = 0U; j < segmentsU + 1; j++) {
bottomPoints[i][j].transformMat4(transform);
topPoints[i][j].transformMat4(transform);
}
}
}
for (auto i = 0U; i < hemiSegmentsV; i++) {
for (auto j = 0U; j < segmentsU; j++) {
addTriangle(bottomPoints[i + 1][j], bottomPoints[i][j + 1], bottomPoints[i][j], color, wireframe, depthTest, unlit);
addTriangle(bottomPoints[i + 1][j], bottomPoints[i + 1][j + 1], bottomPoints[i][j + 1], color, wireframe, depthTest, unlit);
addTriangle(topPoints[i][j], topPoints[i + 1][j + 1], topPoints[i + 1][j], color, wireframe, depthTest, unlit);
addTriangle(topPoints[i][j], topPoints[i][j + 1], topPoints[i + 1][j + 1], color, wireframe, depthTest, unlit);
}
}
CircleList &bottomCircle = bottomPoints[hemiSegmentsV];
CircleList &topCircle = topPoints[hemiSegmentsV];
for (auto j = 0U; j < segmentsU; j++) {
addTriangle(topCircle[j], bottomCircle[j + 1], bottomCircle[j], color, wireframe, depthTest, unlit);
addTriangle(topCircle[j], topCircle[j + 1], bottomCircle[j + 1], color, wireframe, depthTest, unlit);
}
}
void GeometryRenderer::addCylinder(const Vec3 &center, float radius, float height, gfx::Color color, uint32_t segments, bool wireframe, bool depthTest, bool unlit, bool useTransform, const Mat4 &transform) {
const auto deltaPhi = math::PI_2 / static_cast<float>(segments);
Vec3 bottomCenter{center.x, center.y - height / 2.0F, center.z};
Vec3 topCenter{center.x, center.y + height / 2.0F, center.z};
ccstd::vector<Vec3> bottomPoints;
ccstd::vector<Vec3> topPoints;
for (auto i = 0U; i < segments + 1; i++) {
float phi = static_cast<float>(i) * deltaPhi;
Vec3 p{radius * cosf(phi), 0.0F, radius * sinf(phi)};
bottomPoints.emplace_back(p + bottomCenter);
topPoints.emplace_back(p + topCenter);
}
if (useTransform) {
bottomCenter.transformMat4(transform);
topCenter.transformMat4(transform);
for (auto i = 0U; i < segments + 1; i++) {
bottomPoints[i].transformMat4(transform);
topPoints[i].transformMat4(transform);
}
}
for (auto i = 0U; i < segments; i++) {
addTriangle(topCenter, topPoints[i + 1], topPoints[i], color, wireframe, depthTest, unlit);
addTriangle(bottomCenter, bottomPoints[i], bottomPoints[i + 1], color, wireframe, depthTest, unlit);
addTriangle(topPoints[i], bottomPoints[i + 1], bottomPoints[i], color, wireframe, depthTest, unlit);
addTriangle(topPoints[i], topPoints[i + 1], bottomPoints[i + 1], color, wireframe, depthTest, unlit);
}
}
void GeometryRenderer::addCone(const Vec3 &center, float radius, float height, gfx::Color color, uint32_t segments, bool wireframe, bool depthTest, bool unlit, bool useTransform, const Mat4 &transform) {
const auto deltaPhi = math::PI_2 / static_cast<float>(segments);
Vec3 bottomCenter{center.x, center.y - height / 2.0F, center.z};
Vec3 topCenter{center.x, center.y + height / 2.0F, center.z};
ccstd::vector<Vec3> bottomPoints;
for (auto i = 0U; i < segments + 1; i++) {
Vec3 point{radius * cosf(static_cast<float>(i) * deltaPhi), 0.0F, radius * sinf(static_cast<float>(i) * deltaPhi)};
bottomPoints.emplace_back(point + bottomCenter);
}
if (useTransform) {
bottomCenter.transformMat4(transform);
topCenter.transformMat4(transform);
for (auto i = 0U; i < segments + 1; i++) {
bottomPoints[i].transformMat4(transform);
}
}
for (auto i = 0U; i < segments; i++) {
addTriangle(topCenter, bottomPoints[i + 1], bottomPoints[i], color, wireframe, depthTest, unlit);
addTriangle(bottomCenter, bottomPoints[i], bottomPoints[i + 1], color, wireframe, depthTest, unlit);
}
}
void GeometryRenderer::addCircle(const Vec3 &center, float radius, gfx::Color color, uint32_t segments, bool depthTest, bool useTransform, const Mat4 &transform) {
const auto deltaPhi = math::PI_2 / static_cast<float>(segments);
ccstd::vector<Vec3> points;
for (auto i = 0U; i < segments + 1; i++) {
Vec3 point{radius * cosf(static_cast<float>(i) * deltaPhi), 0.0F, radius * sinf(static_cast<float>(i) * deltaPhi)};
points.emplace_back(point + center);
}
if (useTransform) {
for (auto i = 0U; i < segments + 1; i++) {
points[i].transformMat4(transform);
}
}
for (auto i = 0U; i < segments; i++) {
addLine(points[i], points[i + 1], color, depthTest);
}
}
void GeometryRenderer::addArc(const Vec3 &center, float radius, gfx::Color color, float startAngle, float endAngle, uint32_t segments, bool depthTest, bool useTransform, const Mat4 &transform) {
float startRadian = math::DEG_TO_RAD * startAngle;
float endRadian = math::DEG_TO_RAD * endAngle;
const auto deltaPhi = (endRadian - startRadian) / static_cast<float>(segments);
ccstd::vector<Vec3> points;
for (auto i = 0U; i < segments + 1; i++) {
Vec3 point{radius * cosf(static_cast<float>(i) * deltaPhi + startRadian), 0.0F, radius * sinf(static_cast<float>(i) * deltaPhi + startRadian)};
points.emplace_back(point + center);
}
if (useTransform) {
for (auto i = 0U; i < segments + 1; i++) {
points[i].transformMat4(transform);
}
}
for (auto i = 0U; i < segments; i++) {
addLine(points[i], points[i + 1], color, depthTest);
}
}
void GeometryRenderer::addPolygon(const Vec3 &center, float radius, gfx::Color color, uint32_t segments, bool wireframe, bool depthTest, bool unlit, bool useTransform, const Mat4 &transform) {
if (wireframe) {
addCircle(center, radius, color, segments, depthTest, useTransform, transform);
} else {
addDisc(center, radius, color, segments, wireframe, depthTest, unlit, useTransform, transform);
}
}
void GeometryRenderer::addDisc(const Vec3 &center, float radius, gfx::Color color, uint32_t segments, bool wireframe, bool depthTest, bool unlit, bool useTransform, const Mat4 &transform) {
const auto deltaPhi = math::PI_2 / static_cast<float>(segments);
ccstd::vector<Vec3> points;
Vec3 newCenter = center;
for (auto i = 0U; i < segments + 1; i++) {
Vec3 point{radius * cosf(static_cast<float>(i) * deltaPhi), 0.0F, radius * sinf(static_cast<float>(i) * deltaPhi)};
points.emplace_back(point + newCenter);
}
if (useTransform) {
newCenter.transformMat4(transform);
for (auto i = 0U; i < segments + 1; i++) {
points[i].transformMat4(transform);
}
}
for (auto i = 0U; i < segments; i++) {
addTriangle(newCenter, points[i], points[i + 1], color, wireframe, depthTest, unlit);
}
// two sides
if (!wireframe) {
for (auto i = 0U; i < segments; i++) {
addTriangle(newCenter, points[i + 1], points[i], color, wireframe, depthTest, unlit);
}
}
}
void GeometryRenderer::addSector(const Vec3 &center, float radius, gfx::Color color, float startAngle, float endAngle, uint32_t segments, bool wireframe, bool depthTest, bool unlit, bool useTransform, const Mat4 &transform) {
float startRadian = math::DEG_TO_RAD * startAngle;
float endRadian = math::DEG_TO_RAD * endAngle;
const auto deltaPhi = (endRadian - startRadian) / static_cast<float>(segments);
ccstd::vector<Vec3> points;
Vec3 newCenter = center;
for (auto i = 0U; i < segments + 1; i++) {
Vec3 point{radius * cosf(static_cast<float>(i) * deltaPhi), 0.0F, radius * sinf(static_cast<float>(i) * deltaPhi)};
points.emplace_back(point + newCenter);
}
if (useTransform) {
newCenter.transformMat4(transform);
for (auto i = 0U; i < segments + 1; i++) {
points[i].transformMat4(transform);
}
}
for (auto i = 0U; i < segments; i++) {
addTriangle(newCenter, points[i], points[i + 1], color, wireframe, depthTest, unlit);
}
// two sides
if (!wireframe) {
for (auto i = 0U; i < segments; i++) {
addTriangle(newCenter, points[i + 1], points[i], color, wireframe, depthTest, unlit);
}
}
}
void GeometryRenderer::addSphere(const Vec3 &center, float radius, gfx::Color color, uint32_t segmentsU, uint32_t segmentsV, bool wireframe, bool depthTest, bool unlit, bool useTransform, const Mat4 &transform) {
const auto deltaPhi = math::PI_2 / static_cast<float>(segmentsU);
const auto deltaTheta = math::PI / static_cast<float>(segmentsV);
using CircleList = ccstd::vector<Vec3>;
ccstd::vector<CircleList> points;
for (auto i = 0U; i < segmentsV + 1; i++) {
CircleList list;
float theta = static_cast<float>(i) * deltaTheta;
float sinTheta = sinf(theta);
float cosTheta = cosf(theta);
for (auto j = 0U; j < segmentsU + 1; j++) {
float phi = static_cast<float>(j) * deltaPhi;
float sinPhi = sinf(phi);
float cosPhi = cosf(phi);
Vec3 p{radius * sinTheta * cosPhi, radius * cosTheta, radius * sinTheta * sinPhi};
list.emplace_back(center + p);
}
points.emplace_back(list);
}
if (useTransform) {
for (auto i = 0U; i < segmentsV + 1; i++) {
for (auto j = 0U; j < segmentsU + 1; j++) {
points[i][j].transformMat4(transform);
}
}
}
for (auto i = 0U; i < segmentsV; i++) {
for (auto j = 0U; j < segmentsU; j++) {
addTriangle(points[i][j], points[i + 1][j + 1], points[i + 1][j], color, wireframe, depthTest, unlit);
addTriangle(points[i][j], points[i][j + 1], points[i + 1][j + 1], color, wireframe, depthTest, unlit);
}
}
}
void GeometryRenderer::addTorus(const Vec3 &center, float bigRadius, float radius, gfx::Color color, uint32_t segmentsU, uint32_t segmentsV, bool wireframe, bool depthTest, bool unlit, bool useTransform, const Mat4 &transform) {
const auto deltaPhi = math::PI_2 / static_cast<float>(segmentsU);
const auto deltaTheta = math::PI_2 / static_cast<float>(segmentsV);
using CircleList = ccstd::vector<Vec3>;
ccstd::vector<CircleList> points;
for (auto i = 0U; i < segmentsU + 1; i++) {
CircleList list;
float phi = static_cast<float>(i) * deltaPhi;
float sinPhi = sinf(phi);
float cosPhi = cosf(phi);
for (auto j = 0U; j < segmentsV + 1; j++) {
float theta = static_cast<float>(j) * deltaTheta;
float sinTheta = sinf(theta);
float cosTheta = cosf(theta);
Vec3 p{(bigRadius + radius * cosTheta) * cosPhi, radius * sinTheta, (bigRadius + radius * cosTheta) * sinPhi};
list.emplace_back(center + p);
}
points.emplace_back(list);
}
if (useTransform) {
for (auto i = 0U; i < segmentsU + 1; i++) {
for (auto j = 0U; j < segmentsV + 1; j++) {
points[i][j].transformMat4(transform);
}
}
}
for (auto i = 0U; i < segmentsU; i++) {
for (auto j = 0U; j < segmentsV; j++) {
addTriangle(points[i][j + 1], points[i + 1][j], points[i][j], color, wireframe, depthTest, unlit);
addTriangle(points[i][j + 1], points[i + 1][j + 1], points[i + 1][j], color, wireframe, depthTest, unlit);
}
}
}
void GeometryRenderer::addOctahedron(const Vec3 &center, float radius, gfx::Color color, bool wireframe, bool depthTest, bool unlit, bool useTransform, const Mat4 &transform) {
ccstd::vector<Vec3> points;
points.emplace_back(Vec3(radius, 0.0F, 0.0F) + center);
points.emplace_back(Vec3(0.0F, 0.0F, -radius) + center);
points.emplace_back(Vec3(-radius, 0.0F, 0.0F) + center);
points.emplace_back(Vec3(0.0F, 0.0F, radius) + center);
points.emplace_back(Vec3(0.0F, radius, 0.0F) + center);
points.emplace_back(Vec3(0.0F, -radius, 0.0F) + center);
if (useTransform) {
for (auto &point : points) {
point.transformMat4(transform);
}
}
if (wireframe) {
addLine(points[0], points[1], color, depthTest);
addLine(points[1], points[2], color, depthTest);
addLine(points[2], points[3], color, depthTest);
addLine(points[3], points[0], color, depthTest);
addLine(points[0], points[4], color, depthTest);
addLine(points[1], points[4], color, depthTest);
addLine(points[2], points[4], color, depthTest);
addLine(points[3], points[4], color, depthTest);
addLine(points[0], points[5], color, depthTest);
addLine(points[1], points[5], color, depthTest);
addLine(points[2], points[5], color, depthTest);
addLine(points[3], points[5], color, depthTest);
} else {
addTriangle(points[0], points[1], points[4], color, wireframe, depthTest, unlit);
addTriangle(points[1], points[2], points[4], color, wireframe, depthTest, unlit);
addTriangle(points[2], points[3], points[4], color, wireframe, depthTest, unlit);
addTriangle(points[3], points[0], points[4], color, wireframe, depthTest, unlit);
addTriangle(points[0], points[3], points[5], color, wireframe, depthTest, unlit);
addTriangle(points[3], points[2], points[5], color, wireframe, depthTest, unlit);
addTriangle(points[2], points[1], points[5], color, wireframe, depthTest, unlit);
addTriangle(points[1], points[0], points[5], color, wireframe, depthTest, unlit);
}
}
void GeometryRenderer::addBezier(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2, const Vec3 &v3, gfx::Color color, uint32_t segments, bool depthTest, bool useTransform, const Mat4 &transform) {
const auto deltaT = 1.0F / static_cast<float>(segments);
ccstd::vector<Vec3> points;
Vec3 newV0 = v0;
Vec3 newV1 = v1;
Vec3 newV2 = v2;
Vec3 newV3 = v3;
if (useTransform) {
newV0.transformMat4(transform);
newV1.transformMat4(transform);
newV2.transformMat4(transform);
newV3.transformMat4(transform);
}
for (auto i = 0U; i < segments + 1; i++) {
float t = static_cast<float>(i) * deltaT;
float a = (1.0F - t) * (1.0F - t) * (1.0F - t);
float b = 3.0F * t * (1.0F - t) * (1.0F - t);
float c = 3.0F * t * t * (1.0F - t);
float d = t * t * t;
points.emplace_back(a * newV0 + b * newV1 + c * newV2 + d * newV3);
}
for (auto i = 0U; i < segments; i++) {
addLine(points[i], points[i + 1], color, depthTest);
}
}
void GeometryRenderer::addSpline(const geometry::Spline &spline, gfx::Color color, uint32_t index, float knotSize, uint32_t segments, bool depthTest) {
const auto numPoints = segments + 1;
auto points = spline.getPoints(numPoints, index);
for (auto i = 0U; i < segments; i++) {
addLine(points[i], points[i + 1], color, depthTest);
}
if (knotSize > 0.0F && index == geometry::SPLINE_WHOLE_INDEX) {
const gfx::Color crossColor{1.0F - color.x, 1.0F - color.y, 1.0F - color.z, color.w};
const auto numKnots = spline.getKnotCount();
const auto &knots = spline.getKnots();
for (auto i = 0U; i < numKnots; i++) {
addCross(knots[i], knotSize, crossColor, depthTest);
}
}
}
void GeometryRenderer::addMesh(const Vec3 &center, const ccstd::vector<Vec3> &vertices, gfx::Color color, bool depthTest, bool useTransform, const Mat4 &transform) {
for (auto i = 0U; i < vertices.size(); i += 3) {
Vec3 v0 = center + vertices[i];
Vec3 v1 = center + vertices[i + 1];
Vec3 v2 = center + vertices[i + 2];
if (useTransform) {
v0.transformMat4(transform);
v1.transformMat4(transform);
v2.transformMat4(transform);
}
addLine(v0, v1, color, depthTest);
addLine(v1, v2, color, depthTest);
addLine(v2, v0, color, depthTest);
}
}
void GeometryRenderer::addIndexedMesh(const Vec3 &center, const ccstd::vector<Vec3> &vertices, const ccstd::vector<uint32_t> &indices, gfx::Color color, bool depthTest, bool useTransform, const Mat4 &transform) {
for (auto i = 0U; i < indices.size(); i += 3) {
Vec3 v0 = center + vertices[indices[i]];
Vec3 v1 = center + vertices[indices[i + 1]];
Vec3 v2 = center + vertices[indices[i + 2]];
if (useTransform) {
v0.transformMat4(transform);
v1.transformMat4(transform);
v2.transformMat4(transform);
}
addLine(v0, v1, color, depthTest);
addLine(v1, v2, color, depthTest);
addLine(v2, v0, color, depthTest);
}
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,117 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
// NOTE: Still need to wrap all code in CC_USE_GEOMETRY_RENDERER block
// since auto-generated binding code will include GeometryRenderer.h
#if CC_USE_GEOMETRY_RENDERER
#include "base/Macros.h"
#include "base/RefCounted.h"
#include "gfx-base/GFXDef-common.h"
#include "math/Vec2.h"
#include "math/Vec3.h"
#include "math/Vec4.h"
namespace cc {
class Mat4;
namespace gfx {
class Device;
class RenderPass;
class CommandBuffer;
} // namespace gfx
namespace geometry {
class AABB;
class Frustum;
class Spline;
} // namespace geometry
namespace scene {
class Pass;
} // namespace scene
namespace pipeline {
class PipelineSceneData;
struct GeometryVertexBuffers;
struct GeometryRendererInfo {
GeometryRendererInfo();
uint32_t maxLines{0U};
uint32_t maxDashedLines{0U};
uint32_t maxTriangles{0U};
};
class GeometryRenderer : public RefCounted {
public:
GeometryRenderer();
~GeometryRenderer() override;
GeometryRenderer(const GeometryRenderer &) = delete;
GeometryRenderer(GeometryRenderer &&) = delete;
GeometryRenderer &operator=(const GeometryRenderer &) = delete;
GeometryRenderer &operator=(GeometryRenderer &&) = delete;
void activate(gfx::Device *device, const GeometryRendererInfo &info = GeometryRendererInfo());
void render(gfx::RenderPass *renderPass, gfx::CommandBuffer *cmdBuff, PipelineSceneData *sceneData);
void destroy();
bool empty() const;
void update();
void addDashedLine(const Vec3 &v0, const Vec3 &v1, gfx::Color color, bool depthTest = true);
void addLine(const Vec3 &v0, const Vec3 &v1, gfx::Color color, bool depthTest = true);
void addTriangle(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2, gfx::Color color, bool wireframe = true, bool depthTest = true, bool unlit = false); // counterclockwise
void addQuad(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2, const Vec3 &v3, gfx::Color color, bool wireframe = true, bool depthTest = true, bool unlit = false); // counterclockwise
void addBoundingBox(const geometry::AABB &aabb, gfx::Color color, bool wireframe = true, bool depthTest = true, bool unlit = false, bool useTransform = false, const Mat4 &transform = Mat4());
void addCross(const Vec3 &center, float size, gfx::Color color, bool depthTest = true);
void addFrustum(const geometry::Frustum &frustum, gfx::Color color, bool depthTest = true);
void addCapsule(const Vec3 &center, float radius, float height, gfx::Color color, uint32_t segmentsU = 32U, uint32_t hemiSegmentsV = 8U, bool wireframe = true, bool depthTest = true, bool unlit = false, bool useTransform = false, const Mat4 &transform = Mat4());
void addCylinder(const Vec3 &center, float radius, float height, gfx::Color color, uint32_t segments = 32U, bool wireframe = true, bool depthTest = true, bool unlit = false, bool useTransform = false, const Mat4 &transform = Mat4());
void addCone(const Vec3 &center, float radius, float height, gfx::Color color, uint32_t segments = 32U, bool wireframe = true, bool depthTest = true, bool unlit = false, bool useTransform = false, const Mat4 &transform = Mat4());
void addCircle(const Vec3 &center, float radius, gfx::Color color, uint32_t segments = 32U, bool depthTest = true, bool useTransform = false, const Mat4 &transform = Mat4());
void addArc(const Vec3 &center, float radius, gfx::Color color, float startAngle, float endAngle, uint32_t segments = 32U, bool depthTest = true, bool useTransform = false, const Mat4 &transform = Mat4());
void addPolygon(const Vec3 &center, float radius, gfx::Color color, uint32_t segments = 6U, bool wireframe = true, bool depthTest = true, bool unlit = false, bool useTransform = false, const Mat4 &transform = Mat4());
void addDisc(const Vec3 &center, float radius, gfx::Color color, uint32_t segments = 32U, bool wireframe = true, bool depthTest = true, bool unlit = false, bool useTransform = false, const Mat4 &transform = Mat4());
void addSector(const Vec3 &center, float radius, gfx::Color color, float startAngle, float endAngle, uint32_t segments = 32U, bool wireframe = true, bool depthTest = true, bool unlit = false, bool useTransform = false, const Mat4 &transform = Mat4());
void addSphere(const Vec3 &center, float radius, gfx::Color color, uint32_t segmentsU = 32U, uint32_t segmentsV = 16U, bool wireframe = true, bool depthTest = true, bool unlit = false, bool useTransform = false, const Mat4 &transform = Mat4());
void addTorus(const Vec3 &center, float bigRadius, float radius, gfx::Color color, uint32_t segmentsU = 32U, uint32_t segmentsV = 32U, bool wireframe = true, bool depthTest = true, bool unlit = false, bool useTransform = false, const Mat4 &transform = Mat4());
void addOctahedron(const Vec3 &center, float radius, gfx::Color color, bool wireframe = true, bool depthTest = true, bool unlit = false, bool useTransform = false, const Mat4 &transform = Mat4());
void addBezier(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2, const Vec3 &v3, gfx::Color color, uint32_t segments = 32U, bool depthTest = true, bool useTransform = false, const Mat4 &transform = Mat4());
void addSpline(const geometry::Spline &spline, gfx::Color color, uint32_t index = 0xffffffff, float knotSize = 0.5F, uint32_t segments = 32U, bool depthTest = true);
void addMesh(const Vec3 &center, const ccstd::vector<Vec3> &vertices, gfx::Color color, bool depthTest = true, bool useTransform = false, const Mat4 &transform = Mat4());
void addIndexedMesh(const Vec3 &center, const ccstd::vector<Vec3> &vertices, const ccstd::vector<uint32_t> &indices, gfx::Color color, bool depthTest = true, bool useTransform = false, const Mat4 &transform = Mat4());
private:
void reset();
gfx::Device *_device{nullptr};
GeometryVertexBuffers *_buffers{nullptr};
};
} // namespace pipeline
} // namespace cc
#endif // #if CC_USE_GEOMETRY_RENDERER

View File

@@ -0,0 +1,245 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "GlobalDescriptorSetManager.h"
#include "Define.h"
#include "RenderInstancedQueue.h"
#include "gfx-base/GFXDevice.h"
#include "scene/Light.h"
namespace cc {
namespace pipeline {
void GlobalDSManager::activate(gfx::Device *device) {
_device = device;
_linearSampler = device->getSampler({
gfx::Filter::LINEAR,
gfx::Filter::LINEAR,
gfx::Filter::NONE,
gfx::Address::CLAMP,
gfx::Address::CLAMP,
gfx::Address::CLAMP,
});
_pointSampler = device->getSampler({
gfx::Filter::POINT,
gfx::Filter::POINT,
gfx::Filter::NONE,
gfx::Address::CLAMP,
gfx::Address::CLAMP,
gfx::Address::CLAMP,
});
//tips: for compatibility with old version, when maxVertexUniformVectors is 128, maxJoints = 30
uint maxJoints = (_device->getCapabilities().maxVertexUniformVectors - 38) / 3;
maxJoints = maxJoints < 256 ? maxJoints : 256;
SkinningJointCapacity::jointUniformCapacity = maxJoints;
UBOSkinning::initLayout(maxJoints);
_defaultTexture = _device->createTexture({gfx::TextureType::TEX2D,
gfx::TextureUsageBit::SAMPLED,
gfx::Format::RGBA8,
2,
2});
setDescriptorSetLayout();
_descriptorSetLayout = device->createDescriptorSetLayout({globalDescriptorSetLayout.bindings});
_globalDescriptorSet = device->createDescriptorSet({_descriptorSetLayout});
}
void GlobalDSManager::bindBuffer(uint32_t binding, gfx::Buffer *buffer) {
if (_globalDescriptorSet != nullptr) {
_globalDescriptorSet->bindBuffer(binding, buffer);
}
for (const auto &pair : _descriptorSetMap) {
if (pair.second != nullptr) {
pair.second->bindBuffer(binding, buffer);
}
}
}
void GlobalDSManager::bindSampler(uint32_t binding, gfx::Sampler *sampler) {
if (_globalDescriptorSet != nullptr) {
_globalDescriptorSet->bindSampler(binding, sampler);
}
for (const auto &pair : _descriptorSetMap) {
if (pair.second != nullptr) {
pair.second->bindSampler(binding, sampler);
}
}
}
void GlobalDSManager::bindTexture(uint32_t binding, gfx::Texture *texture) {
if (!texture) {
texture = _defaultTexture.get();
}
if (_globalDescriptorSet != nullptr) {
_globalDescriptorSet->bindTexture(binding, texture);
}
for (const auto &pair : _descriptorSetMap) {
if (pair.second != nullptr) {
pair.second->bindTexture(binding, texture);
}
}
}
void GlobalDSManager::update() {
if (_globalDescriptorSet != nullptr) {
_globalDescriptorSet->update();
}
for (const auto &pair : _descriptorSetMap) {
if (pair.second != nullptr) {
pair.second->update();
}
}
}
gfx::DescriptorSet *GlobalDSManager::getOrCreateDescriptorSet(const scene::Light *light) {
CC_ASSERT(light);
// The global descriptorSet is managed by the pipeline and binds the buffer
if (_descriptorSetMap.count(light) == 0 || (_descriptorSetMap.at(light) == nullptr)) {
auto *descriptorSet = _device->createDescriptorSet({_descriptorSetLayout});
_descriptorSetMap[light] = descriptorSet;
const auto begin = static_cast<uint32_t>(PipelineGlobalBindings::UBO_GLOBAL);
const auto end = static_cast<uint32_t>(PipelineGlobalBindings::COUNT);
for (uint32_t i = begin; i < end; ++i) {
auto *const buffer = _globalDescriptorSet->getBuffer(i);
if (buffer != nullptr) {
descriptorSet->bindBuffer(i, buffer);
}
auto *const sampler = _globalDescriptorSet->getSampler(i);
if (sampler != nullptr) {
descriptorSet->bindSampler(i, sampler);
}
auto *const texture = _globalDescriptorSet->getTexture(i);
if (texture != nullptr) {
descriptorSet->bindTexture(i, texture);
}
}
auto *shadowUBO = _device->createBuffer({
gfx::BufferUsageBit::UNIFORM | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::HOST | gfx::MemoryUsageBit::DEVICE,
UBOShadow::SIZE,
UBOShadow::SIZE,
gfx::BufferFlagBit::NONE,
});
_shadowUBOs.emplace_back(shadowUBO);
descriptorSet->bindBuffer(UBOShadow::BINDING, shadowUBO);
descriptorSet->update();
}
return _descriptorSetMap.at(light);
}
void GlobalDSManager::destroy() {
_shadowUBOs.clear();
_descriptorSetMap.clear();
_descriptorSetLayout = nullptr;
_globalDescriptorSet = nullptr;
_linearSampler = nullptr;
_pointSampler = nullptr;
_defaultTexture = nullptr;
}
void GlobalDSManager::setDescriptorSetLayout() {
globalDescriptorSetLayout.bindings.resize(static_cast<size_t>(PipelineGlobalBindings::COUNT));
globalDescriptorSetLayout.blocks[UBOGlobal::NAME] = UBOGlobal::LAYOUT;
globalDescriptorSetLayout.bindings[UBOGlobal::BINDING] = UBOGlobal::DESCRIPTOR;
globalDescriptorSetLayout.blocks[UBOCamera::NAME] = UBOCamera::LAYOUT;
globalDescriptorSetLayout.bindings[UBOCamera::BINDING] = UBOCamera::DESCRIPTOR;
globalDescriptorSetLayout.blocks[UBOShadow::NAME] = UBOShadow::LAYOUT;
globalDescriptorSetLayout.bindings[UBOShadow::BINDING] = UBOShadow::DESCRIPTOR;
globalDescriptorSetLayout.blocks[UBOCSM::NAME] = UBOCSM::LAYOUT;
globalDescriptorSetLayout.bindings[UBOCSM::BINDING] = UBOCSM::DESCRIPTOR;
globalDescriptorSetLayout.samplers[SHADOWMAP::NAME] = SHADOWMAP::LAYOUT;
globalDescriptorSetLayout.bindings[SHADOWMAP::BINDING] = SHADOWMAP::DESCRIPTOR;
globalDescriptorSetLayout.samplers[ENVIRONMENT::NAME] = ENVIRONMENT::LAYOUT;
globalDescriptorSetLayout.bindings[ENVIRONMENT::BINDING] = ENVIRONMENT::DESCRIPTOR;
globalDescriptorSetLayout.samplers[SPOTSHADOWMAP::NAME] = SPOTSHADOWMAP::LAYOUT;
globalDescriptorSetLayout.bindings[SPOTSHADOWMAP::BINDING] = SPOTSHADOWMAP::DESCRIPTOR;
globalDescriptorSetLayout.samplers[DIFFUSEMAP::NAME] = DIFFUSEMAP::LAYOUT;
globalDescriptorSetLayout.bindings[DIFFUSEMAP::BINDING] = DIFFUSEMAP::DESCRIPTOR;
localDescriptorSetLayout.bindings.resize(static_cast<size_t>(ModelLocalBindings::COUNT));
localDescriptorSetLayout.blocks[UBOLocalBatched::NAME] = UBOLocalBatched::LAYOUT;
localDescriptorSetLayout.bindings[UBOLocalBatched::BINDING] = UBOLocalBatched::DESCRIPTOR;
localDescriptorSetLayout.blocks[UBOLocal::NAME] = UBOLocal::LAYOUT;
localDescriptorSetLayout.bindings[UBOLocal::BINDING] = UBOLocal::DESCRIPTOR;
localDescriptorSetLayout.blocks[UBOWorldBound::NAME] = UBOWorldBound::LAYOUT;
localDescriptorSetLayout.bindings[UBOWorldBound::BINDING] = UBOWorldBound::DESCRIPTOR;
localDescriptorSetLayout.blocks[UBOForwardLight::NAME] = UBOForwardLight::LAYOUT;
localDescriptorSetLayout.bindings[UBOForwardLight::BINDING] = UBOForwardLight::DESCRIPTOR;
localDescriptorSetLayout.blocks[UBOSkinningTexture::NAME] = UBOSkinningTexture::LAYOUT;
localDescriptorSetLayout.bindings[UBOSkinningTexture::BINDING] = UBOSkinningTexture::DESCRIPTOR;
localDescriptorSetLayout.blocks[UBOSkinningAnimation::NAME] = UBOSkinningAnimation::LAYOUT;
localDescriptorSetLayout.bindings[UBOSkinningAnimation::BINDING] = UBOSkinningAnimation::DESCRIPTOR;
localDescriptorSetLayout.blocks[UBOSkinning::NAME] = UBOSkinning::layout;
localDescriptorSetLayout.bindings[UBOSkinning::BINDING] = UBOSkinning::DESCRIPTOR;
localDescriptorSetLayout.blocks[UBOMorph::NAME] = UBOMorph::LAYOUT;
localDescriptorSetLayout.bindings[UBOMorph::BINDING] = UBOMorph::DESCRIPTOR;
localDescriptorSetLayout.blocks[UBOUILocal::NAME] = UBOUILocal::LAYOUT;
localDescriptorSetLayout.bindings[UBOUILocal::BINDING] = UBOUILocal::DESCRIPTOR;
localDescriptorSetLayout.blocks[UBOSH::NAME] = UBOSH::LAYOUT;
localDescriptorSetLayout.bindings[UBOSH::BINDING] = UBOSH::DESCRIPTOR;
localDescriptorSetLayout.samplers[JOINTTEXTURE::NAME] = JOINTTEXTURE::LAYOUT;
localDescriptorSetLayout.bindings[JOINTTEXTURE::BINDING] = JOINTTEXTURE::DESCRIPTOR;
localDescriptorSetLayout.samplers[REALTIMEJOINTTEXTURE::NAME] = REALTIMEJOINTTEXTURE::LAYOUT;
localDescriptorSetLayout.bindings[REALTIMEJOINTTEXTURE::BINDING] = REALTIMEJOINTTEXTURE::DESCRIPTOR;
localDescriptorSetLayout.samplers[POSITIONMORPH::NAME] = POSITIONMORPH::LAYOUT;
localDescriptorSetLayout.bindings[POSITIONMORPH::BINDING] = POSITIONMORPH::DESCRIPTOR;
localDescriptorSetLayout.samplers[NORMALMORPH::NAME] = NORMALMORPH::LAYOUT;
localDescriptorSetLayout.bindings[NORMALMORPH::BINDING] = NORMALMORPH::DESCRIPTOR;
localDescriptorSetLayout.samplers[TANGENTMORPH::NAME] = TANGENTMORPH::LAYOUT;
localDescriptorSetLayout.bindings[TANGENTMORPH::BINDING] = TANGENTMORPH::DESCRIPTOR;
localDescriptorSetLayout.samplers[LIGHTMAPTEXTURE::NAME] = LIGHTMAPTEXTURE::LAYOUT;
localDescriptorSetLayout.bindings[LIGHTMAPTEXTURE::BINDING] = LIGHTMAPTEXTURE::DESCRIPTOR;
localDescriptorSetLayout.samplers[SPRITETEXTURE::NAME] = SPRITETEXTURE::LAYOUT;
localDescriptorSetLayout.bindings[SPRITETEXTURE::BINDING] = SPRITETEXTURE::DESCRIPTOR;
localDescriptorSetLayout.samplers[REFLECTIONTEXTURE::NAME] = REFLECTIONTEXTURE::LAYOUT;
localDescriptorSetLayout.bindings[REFLECTIONTEXTURE::BINDING] = REFLECTIONTEXTURE::DESCRIPTOR;
localDescriptorSetLayout.storeImages[REFLECTIONSTORAGE::NAME] = REFLECTIONSTORAGE::LAYOUT;
localDescriptorSetLayout.bindings[REFLECTIONSTORAGE::BINDING] = REFLECTIONSTORAGE::DESCRIPTOR;
localDescriptorSetLayout.samplers[REFLECTIONPROBECUBEMAP::NAME] = REFLECTIONPROBECUBEMAP::LAYOUT;
localDescriptorSetLayout.bindings[REFLECTIONPROBECUBEMAP::BINDING] = REFLECTIONPROBECUBEMAP::DESCRIPTOR;
localDescriptorSetLayout.samplers[REFLECTIONPROBEPLANARMAP::NAME] = REFLECTIONPROBEPLANARMAP::LAYOUT;
localDescriptorSetLayout.bindings[REFLECTIONPROBEPLANARMAP::BINDING] = REFLECTIONPROBEPLANARMAP::DESCRIPTOR;
localDescriptorSetLayout.samplers[REFLECTIONPROBEDATAMAP::NAME] = REFLECTIONPROBEDATAMAP::LAYOUT;
localDescriptorSetLayout.bindings[REFLECTIONPROBEDATAMAP::BINDING] = REFLECTIONPROBEDATAMAP::DESCRIPTOR;
localDescriptorSetLayout.samplers[REFLECTIONPROBEBLENDCUBEMAP::NAME] = REFLECTIONPROBEBLENDCUBEMAP::LAYOUT;
localDescriptorSetLayout.bindings[REFLECTIONPROBEBLENDCUBEMAP::BINDING] = REFLECTIONPROBEBLENDCUBEMAP::DESCRIPTOR;
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,84 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include <cstdint>
#include "base/Ptr.h"
#include "base/std/container/unordered_map.h"
#include "base/std/container/vector.h"
namespace cc {
namespace scene {
class Light;
}
namespace gfx {
class DescriptorSet;
class DescriptorSetLayout;
class Sampler;
class Buffer;
class Texture;
class Device;
} // namespace gfx
namespace pipeline {
class GlobalDSManager final {
public:
GlobalDSManager() = default;
~GlobalDSManager() = default;
inline gfx::Sampler *getLinearSampler() const { return _linearSampler; }
inline gfx::Sampler *getPointSampler() const { return _pointSampler; }
inline gfx::DescriptorSetLayout *getDescriptorSetLayout() const { return _descriptorSetLayout; }
inline gfx::DescriptorSet *getGlobalDescriptorSet() const { return _globalDescriptorSet; }
void activate(gfx::Device *device);
void bindBuffer(uint32_t binding, gfx::Buffer *buffer);
void bindTexture(uint32_t binding, gfx::Texture *texture);
void bindSampler(uint32_t binding, gfx::Sampler *sampler);
void update();
gfx::DescriptorSet *getOrCreateDescriptorSet(const scene::Light *light);
void destroy();
static void setDescriptorSetLayout();
private:
// weak reference
gfx::Device *_device{nullptr};
// Samplers are hold by device
gfx::Sampler *_linearSampler{nullptr};
gfx::Sampler *_pointSampler{nullptr};
IntrusivePtr<gfx::Texture> _defaultTexture;
IntrusivePtr<gfx::DescriptorSetLayout> _descriptorSetLayout;
IntrusivePtr<gfx::DescriptorSet> _globalDescriptorSet;
ccstd::vector<IntrusivePtr<gfx::Buffer>> _shadowUBOs;
// light is weak reference
ccstd::unordered_map<const scene::Light *, IntrusivePtr<gfx::DescriptorSet>> _descriptorSetMap;
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,176 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "InstancedBuffer.h"
#include "Define.h"
#include "gfx-base/GFXBuffer.h"
#include "gfx-base/GFXCommandBuffer.h"
#include "gfx-base/GFXDescriptorSet.h"
#include "gfx-base/GFXDevice.h"
#include "gfx-base/GFXInputAssembler.h"
namespace cc {
namespace pipeline {
InstancedBuffer::InstancedBuffer(const scene::Pass *pass)
: _pass(pass),
_device(gfx::Device::getInstance()) {
}
InstancedBuffer::~InstancedBuffer() {
destroy();
}
void InstancedBuffer::destroy() {
for (auto &instance : _instances) {
CC_SAFE_DESTROY_AND_DELETE(instance.vb);
CC_SAFE_DESTROY_AND_DELETE(instance.ia);
CC_FREE(instance.data);
}
_instances.clear();
}
void InstancedBuffer::merge(scene::SubModel *subModel, uint32_t passIdx) {
merge(subModel, passIdx, nullptr);
}
void InstancedBuffer::merge(scene::SubModel *subModel, uint32_t passIdx, gfx::Shader *shaderImplant) {
auto &attrs = subModel->getInstancedAttributeBlock();
const auto stride = attrs.buffer.length();
if (!stride) return; // we assume per-instance attributes are always present
auto *sourceIA = subModel->getInputAssembler();
auto *descriptorSet = subModel->getDescriptorSet();
auto *lightingMap = descriptorSet->getTexture(LIGHTMAPTEXTURE::BINDING);
auto *reflectionProbeCubemap = descriptorSet->getTexture(REFLECTIONPROBECUBEMAP::BINDING);
auto *reflectionProbePlanarMap = descriptorSet->getTexture(REFLECTIONPROBEPLANARMAP::BINDING);
auto *reflectionProbeBlendCubemap = descriptorSet->getTexture(REFLECTIONPROBEBLENDCUBEMAP::BINDING);
uint32_t reflectionProbeType = subModel->getReflectionProbeType();
auto *shader = shaderImplant;
if (!shader) {
shader = subModel->getShader(passIdx);
}
for (auto &instance : _instances) {
if (instance.ia->getIndexBuffer() != sourceIA->getIndexBuffer() || instance.drawInfo.instanceCount >= MAX_CAPACITY) {
continue;
}
// check same binding
if (instance.lightingMap != lightingMap) {
continue;
}
if (instance.reflectionProbeType != reflectionProbeType) {
continue;
}
if (instance.reflectionProbeCubemap != reflectionProbeCubemap) {
continue;
}
if (instance.reflectionProbePlanarMap != reflectionProbePlanarMap) {
continue;
}
if (instance.reflectionProbeBlendCubemap != reflectionProbeBlendCubemap) {
continue;
}
if (instance.stride != stride) {
continue;
}
if (instance.drawInfo.instanceCount >= instance.capacity) { // resize buffers
instance.capacity <<= 1;
const auto newSize = instance.stride * instance.capacity;
instance.data = static_cast<uint8_t *>(CC_REALLOC(instance.data, newSize));
instance.vb->resize(newSize);
}
if (instance.shader != shader) {
instance.shader = shader;
}
if (instance.descriptorSet != descriptorSet) {
instance.descriptorSet = descriptorSet;
}
memcpy(instance.data + instance.stride * instance.drawInfo.instanceCount++, attrs.buffer.buffer()->getData(), stride);
_hasPendingModels = true;
return;
}
// Create a new instance
const auto newSize = stride * INITIAL_CAPACITY;
auto *vb = _device->createBuffer({
gfx::BufferUsageBit::VERTEX | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::DEVICE,
static_cast<uint32_t>(newSize),
static_cast<uint32_t>(stride),
});
auto vertexBuffers = sourceIA->getVertexBuffers();
auto attributes = sourceIA->getAttributes();
auto *indexBuffer = sourceIA->getIndexBuffer();
for (const auto &attribute : attrs.attributes) {
attributes.emplace_back(gfx::Attribute{
attribute.name,
attribute.format,
attribute.isNormalized,
static_cast<uint32_t>(vertexBuffers.size()), // stream
true,
attribute.location});
}
auto *data = static_cast<uint8_t *>(CC_MALLOC(newSize));
memcpy(data, attrs.buffer.buffer()->getData(), stride);
vertexBuffers.emplace_back(vb);
const gfx::InputAssemblerInfo iaInfo = {attributes, vertexBuffers, indexBuffer};
auto *ia = _device->createInputAssembler(iaInfo);
InstancedItem item = {INITIAL_CAPACITY, vb, data, ia, stride, shader, descriptorSet,
lightingMap, reflectionProbeCubemap, reflectionProbePlanarMap, reflectionProbeType, reflectionProbeBlendCubemap,
ia->getDrawInfo()};
item.drawInfo.instanceCount = 1;
_instances.emplace_back(item);
_hasPendingModels = true;
}
void InstancedBuffer::uploadBuffers(gfx::CommandBuffer *cmdBuff) const {
for (const auto &instance : _instances) {
if (!instance.drawInfo.instanceCount) continue;
cmdBuff->updateBuffer(instance.vb, instance.data, instance.vb->getSize());
instance.ia->setInstanceCount(instance.drawInfo.instanceCount);
}
}
void InstancedBuffer::clear() {
for (auto &instance : _instances) {
instance.drawInfo.instanceCount = 0;
}
_hasPendingModels = false;
}
void InstancedBuffer::setDynamicOffset(uint32_t idx, uint32_t value) {
if (_dynamicOffsets.size() <= idx) _dynamicOffsets.resize(1 + idx);
_dynamicOffsets[idx] = value;
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,90 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "Define.h"
#include "base/RefCounted.h"
#include "base/std/container/unordered_map.h"
#include "scene/Model.h"
#include "scene/Pass.h"
namespace cc {
namespace gfx {
class Device;
}
namespace pipeline {
struct PSOInfo;
struct CC_DLL InstancedItem {
uint32_t capacity = 0;
gfx::Buffer *vb = nullptr;
uint8_t *data = nullptr;
gfx::InputAssembler *ia = nullptr;
uint32_t stride = 0;
gfx::Shader *shader = nullptr;
gfx::DescriptorSet *descriptorSet = nullptr;
gfx::Texture *lightingMap = nullptr;
gfx::Texture *reflectionProbeCubemap = nullptr;
gfx::Texture *reflectionProbePlanarMap = nullptr;
uint32_t reflectionProbeType = 0;
gfx::Texture *reflectionProbeBlendCubemap = nullptr;
gfx::DrawInfo drawInfo;
};
using InstancedItemList = ccstd::vector<InstancedItem>;
using DynamicOffsetList = ccstd::vector<uint32_t>;
class InstancedBuffer : public RefCounted {
public:
static constexpr uint32_t INITIAL_CAPACITY = 32;
static constexpr uint32_t MAX_CAPACITY = 1024;
explicit InstancedBuffer(const scene::Pass *pass);
~InstancedBuffer() override;
void destroy();
void merge(scene::SubModel *, uint32_t);
void merge(scene::SubModel *, uint32_t, gfx::Shader *);
void uploadBuffers(gfx::CommandBuffer *cmdBuff) const;
void clear();
void setDynamicOffset(uint32_t idx, uint32_t value);
inline const InstancedItemList &getInstances() const { return _instances; }
inline const scene::Pass *getPass() const { return _pass; }
inline void setPass(const scene::Pass *pass) noexcept { _pass = pass; }
inline bool hasPendingModels() const { return _hasPendingModels; }
inline const DynamicOffsetList &dynamicOffsets() const { return _dynamicOffsets; }
private:
InstancedItemList _instances;
// weak reference
const scene::Pass *_pass{nullptr};
bool _hasPendingModels{false};
DynamicOffsetList _dynamicOffsets;
// weak reference
gfx::Device *_device{nullptr};
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,188 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "PipelineSceneData.h"
#include <sstream>
#include "core/ArrayBuffer.h"
#include "core/assets/Material.h"
#include "gfx-base/GFXDef-common.h"
#include "gfx-base/GFXDevice.h"
#include "gfx-base/GFXFramebuffer.h"
#include "gi/light-probe/LightProbe.h"
#include "scene/Ambient.h"
#include "scene/Fog.h"
#include "scene/Model.h"
#include "scene/Octree.h"
#include "scene/Pass.h"
#include "scene/Shadow.h"
#include "scene/Skin.h"
#include "scene/Skybox.h"
#include "scene/Model.h"
#include "scene/PostSettings.h"
namespace cc {
namespace pipeline {
PipelineSceneData::PipelineSceneData() {
_fog = ccnew scene::Fog();
_ambient = ccnew scene::Ambient();
_skybox = ccnew scene::Skybox();
_shadow = ccnew scene::Shadows();
_csmLayers = ccnew CSMLayers();
_octree = ccnew scene::Octree();
_lightProbes = ccnew gi::LightProbes();
_skin = ccnew scene::Skin();
_postSettings = ccnew scene ::PostSettings();
}
PipelineSceneData::~PipelineSceneData() {
CC_SAFE_DELETE(_fog);
CC_SAFE_DELETE(_ambient);
CC_SAFE_DELETE(_skybox);
CC_SAFE_DELETE(_shadow);
CC_SAFE_DELETE(_octree);
CC_SAFE_DELETE(_csmLayers);
CC_SAFE_DELETE(_lightProbes);
CC_SAFE_DELETE(_skin);
CC_SAFE_DELETE(_postSettings);
}
void PipelineSceneData::activate(gfx::Device *device) {
_device = device;
#if CC_USE_GEOMETRY_RENDERER
initGeometryRenderer();
#endif
#if CC_USE_DEBUG_RENDERER
initDebugRenderer();
#endif
#if CC_USE_OCCLUSION_QUERY
initOcclusionQuery();
#endif
}
void PipelineSceneData::destroy() {
_shadowFrameBufferMap.clear();
_validPunctualLights.clear();
_occlusionQueryInputAssembler = nullptr;
_occlusionQueryVertexBuffer = nullptr;
_occlusionQueryIndicesBuffer = nullptr;
_standardSkinModel = nullptr;
_skinMaterialModel = nullptr;
}
void PipelineSceneData::initOcclusionQuery() {
CC_ASSERT(!_occlusionQueryInputAssembler);
_occlusionQueryInputAssembler = createOcclusionQueryIA();
if (!_occlusionQueryMaterial) {
_occlusionQueryMaterial = ccnew Material();
_occlusionQueryMaterial->setUuid("default-occlusion-query-material");
IMaterialInfo info;
info.effectName = "internal/builtin-occlusion-query";
_occlusionQueryMaterial->initialize(info);
if (!_occlusionQueryMaterial->getPasses()->empty()) {
_occlusionQueryPass = (*_occlusionQueryMaterial->getPasses())[0];
_occlusionQueryShader = _occlusionQueryPass->getShaderVariant();
}
}
}
void PipelineSceneData::initGeometryRenderer() {
_geometryRendererMaterials.resize(GEOMETRY_RENDERER_TECHNIQUE_COUNT);
_geometryRendererPasses.reserve(GEOMETRY_RENDERER_TECHNIQUE_COUNT);
_geometryRendererShaders.reserve(GEOMETRY_RENDERER_TECHNIQUE_COUNT);
for (uint32_t tech = 0; tech < GEOMETRY_RENDERER_TECHNIQUE_COUNT; tech++) {
_geometryRendererMaterials[tech] = ccnew Material();
std::stringstream ss;
ss << "geometry-renderer-material-" << tech;
_geometryRendererMaterials[tech]->setUuid(ss.str());
IMaterialInfo materialInfo;
materialInfo.effectName = "internal/builtin-geometry-renderer";
materialInfo.technique = tech;
_geometryRendererMaterials[tech]->initialize(materialInfo);
const auto &passes = _geometryRendererMaterials[tech]->getPasses().get();
for (const auto &pass : *passes) {
_geometryRendererPasses.emplace_back(pass);
_geometryRendererShaders.emplace_back(pass->getShaderVariant());
}
}
}
void PipelineSceneData::initDebugRenderer() {
if (!_debugRendererMaterial) {
_debugRendererMaterial = ccnew Material();
_debugRendererMaterial->setUuid("default-debug-renderer-material");
IMaterialInfo info;
info.effectName = "internal/builtin-debug-renderer";
_debugRendererMaterial->initialize(info);
_debugRendererPass = (*_debugRendererMaterial->getPasses())[0];
_debugRendererShader = _debugRendererPass->getShaderVariant();
}
}
gfx::InputAssembler *PipelineSceneData::createOcclusionQueryIA() {
// create vertex buffer
const float vertices[] = {-1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1};
uint32_t vbStride = sizeof(float) * 3;
uint32_t vbSize = vbStride * 8;
_occlusionQueryVertexBuffer = _device->createBuffer(gfx::BufferInfo{
gfx::BufferUsageBit::VERTEX | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::DEVICE, vbSize, vbStride});
_occlusionQueryVertexBuffer->update(vertices);
// create index buffer
const uint16_t indices[] = {0, 2, 1, 1, 2, 3, 4, 5, 6, 5, 7, 6, 1, 3, 7, 1, 7, 5, 0, 4, 6, 0, 6, 2, 0, 1, 5, 0, 5, 4, 2, 6, 7, 2, 7, 3};
uint32_t ibStride = sizeof(uint16_t);
uint32_t ibSize = ibStride * 36;
_occlusionQueryIndicesBuffer = _device->createBuffer(gfx::BufferInfo{
gfx::BufferUsageBit::INDEX | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::DEVICE, ibSize, ibStride});
_occlusionQueryIndicesBuffer->update(indices);
gfx::AttributeList attributes{gfx::Attribute{gfx::ATTR_NAME_POSITION, gfx::Format::RGB32F}};
// create cube input assembler
gfx::InputAssemblerInfo info{attributes, {_occlusionQueryVertexBuffer}, _occlusionQueryIndicesBuffer};
return _device->createInputAssembler(info);
}
void PipelineSceneData::setStandardSkinModel(scene::Model *val) {
_standardSkinModel = val;
}
void PipelineSceneData::setSkinMaterialModel(scene::Model *val) {
_skinMaterialModel = val;
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,159 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "Define.h"
#include "base/RefCounted.h"
#include "core/assets/Material.h"
#include "renderer/gfx-base/GFXFramebuffer.h"
#include "renderer/pipeline/shadow/CSMLayers.h"
namespace cc {
namespace gfx {
class Framebuffer;
}
namespace scene {
class Pass;
class Ambient;
class Shadows;
class Skybox;
class Fog;
class Octree;
class Light;
class Skin;
class PostSettings;
} // namespace scene
namespace gi {
class LightProbes;
}
namespace pipeline {
class CC_DLL PipelineSceneData : public RefCounted {
public:
PipelineSceneData();
~PipelineSceneData() override;
virtual void activate(gfx::Device *device);
void destroy();
virtual void updatePipelineSceneData() {}
inline void setShadowFramebuffer(const scene::Light *light, gfx::Framebuffer *framebuffer) { _shadowFrameBufferMap[light] = framebuffer; }
inline const ccstd::unordered_map<const scene::Light *, IntrusivePtr<gfx::Framebuffer>> &getShadowFramebufferMap() const { return _shadowFrameBufferMap; }
inline const RenderObjectList &getRenderObjects() const { return _renderObjects; }
inline void setRenderObjects(RenderObjectList &&ro) { _renderObjects = std::forward<RenderObjectList>(ro); }
inline const ccstd::vector<const scene::Light *> &getValidPunctualLights() const { return _validPunctualLights; }
inline void setValidPunctualLights(ccstd::vector<const scene::Light *> lights) { _validPunctualLights = std::move(lights); }
inline bool isHDR() const { return _isHDR; }
inline void setHDR(bool val) { _isHDR = val; }
inline scene::Shadows *getShadows() const { return _shadow; }
inline CSMLayers *getCSMLayers() const { return _csmLayers; }
inline scene::Ambient *getAmbient() const { return _ambient; }
inline scene::Skybox *getSkybox() const { return _skybox; }
inline scene::Fog *getFog() const { return _fog; }
inline scene::Octree *getOctree() const { return _octree; }
inline gi::LightProbes *getLightProbes() const { return _lightProbes; }
inline scene::Skin *getSkin() const { return _skin; }
inline scene::PostSettings *getPostSettings() const { return _postSettings; }
inline gfx::InputAssembler *getOcclusionQueryInputAssembler() const { return _occlusionQueryInputAssembler; }
inline scene::Pass *getOcclusionQueryPass() const { return _occlusionQueryPass; }
inline gfx::Shader *getOcclusionQueryShader() const { return _occlusionQueryShader; }
inline const ccstd::vector<IntrusivePtr<Material>> &getGeometryRendererMaterials() const { return _geometryRendererMaterials; }
inline const ccstd::vector<scene::Pass *> &getGeometryRendererPasses() const { return _geometryRendererPasses; }
inline const ccstd::vector<gfx::Shader *> &getGeometryRendererShaders() const { return _geometryRendererShaders; }
inline scene::Pass *getDebugRendererPass() const { return _debugRendererPass; }
inline gfx::Shader *getDebugRendererShader() const { return _debugRendererShader; }
inline void addRenderObject(RenderObject &&obj) { _renderObjects.emplace_back(obj); }
inline void clearRenderObjects() { _renderObjects.clear(); }
inline void addValidPunctualLight(scene::Light *light) { _validPunctualLights.emplace_back(light); }
inline void clearValidPunctualLights() { _validPunctualLights.clear(); }
inline float getShadingScale() const { return _shadingScale; }
inline void setShadingScale(float val) { _shadingScale = val; }
inline bool getCSMSupported() const { return _csmSupported; }
inline void setCSMSupported(bool val) { _csmSupported = val; }
inline scene::Model *getStandardSkinModel() const { return _standardSkinModel.get(); }
void setStandardSkinModel(scene::Model *val);
inline scene::Model *getSkinMaterialModel() const { return _skinMaterialModel.get(); }
void setSkinMaterialModel(scene::Model *val);
protected:
void initOcclusionQuery();
void initGeometryRenderer();
void initDebugRenderer();
gfx::InputAssembler *createOcclusionQueryIA();
static constexpr uint32_t GEOMETRY_RENDERER_TECHNIQUE_COUNT{6};
IntrusivePtr<gfx::Buffer> _occlusionQueryVertexBuffer;
IntrusivePtr<gfx::Buffer> _occlusionQueryIndicesBuffer;
IntrusivePtr<gfx::InputAssembler> _occlusionQueryInputAssembler;
IntrusivePtr<Material> _occlusionQueryMaterial{nullptr};
IntrusivePtr<Material> _debugRendererMaterial{nullptr};
IntrusivePtr<scene::Model> _standardSkinModel;
IntrusivePtr<scene::Model> _skinMaterialModel;
gfx::Shader *_occlusionQueryShader{nullptr}; // weak reference
scene::Pass *_occlusionQueryPass{nullptr}; // weak reference
gfx::Shader *_debugRendererShader{nullptr}; // weak reference
scene::Pass *_debugRendererPass{nullptr}; // weak reference
gfx::Device *_device{nullptr}; // weak reference
// manage memory manually
scene::Fog *_fog{nullptr};
// manage memory manually
scene::Ambient *_ambient{nullptr};
// manage memory manually
scene::Skybox *_skybox{nullptr};
// manage memory manually
scene::Shadows *_shadow{nullptr};
// manage memory manually
scene::Octree *_octree{nullptr};
// manage memory manually
gi::LightProbes *_lightProbes{nullptr};
// manage memory manually
scene::Skin *_skin{nullptr};
// manage memory manually
CSMLayers *_csmLayers{nullptr};
// manage memory manually
scene::PostSettings *_postSettings{nullptr};
bool _isHDR{true};
bool _csmSupported{true};
float _shadingScale{1.0F};
RenderObjectList _renderObjects;
ccstd::vector<IntrusivePtr<Material>> _geometryRendererMaterials;
// `scene::Light *`: weak reference
ccstd::vector<const scene::Light *> _validPunctualLights;
ccstd::vector<scene::Pass *> _geometryRendererPasses; // weak reference
ccstd::vector<gfx::Shader *> _geometryRendererShaders; // weak reference
ccstd::unordered_map<const scene::Light *, IntrusivePtr<gfx::Framebuffer>> _shadowFrameBufferMap;
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,79 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "PipelineStateManager.h"
#include "gfx-base/GFXDef-common.h"
#include "gfx-base/GFXDevice.h"
#include "scene/Pass.h"
namespace cc {
namespace pipeline {
ccstd::unordered_map<ccstd::hash_t, IntrusivePtr<gfx::PipelineState>> PipelineStateManager::psoHashMap;
gfx::PipelineState *PipelineStateManager::getOrCreatePipelineState(const scene::Pass *pass,
gfx::Shader *shader,
gfx::InputAssembler *inputAssembler,
gfx::RenderPass *renderPass,
uint32_t subpass) {
const auto passHash = pass->getHash();
const auto renderPassHash = renderPass->getHash();
const auto iaHash = inputAssembler->getAttributesHash();
const auto shaderID = shader->getTypedID();
auto hash = passHash ^ renderPassHash ^ iaHash ^ shaderID;
if (subpass != 0) {
hash = hash << subpass;
}
auto *pso = psoHashMap[static_cast<ccstd::hash_t>(hash)].get();
if (!pso) {
auto *pipelineLayout = pass->getPipelineLayout();
pso = gfx::Device::getInstance()->createPipelineState({shader,
pipelineLayout,
renderPass,
{inputAssembler->getAttributes()},
*(pass->getRasterizerState()),
*(pass->getDepthStencilState()),
*(pass->getBlendState()),
pass->getPrimitive(),
pass->getDynamicStates(),
gfx::PipelineBindPoint::GRAPHICS,
subpass});
psoHashMap[static_cast<ccstd::hash_t>(hash)] = pso;
}
return pso;
}
void PipelineStateManager::destroyAll() {
for (auto &pair : psoHashMap) {
CC_SAFE_DESTROY_NULL(pair.second);
}
psoHashMap.clear();
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,50 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "cocos/base/Ptr.h"
#include "gfx-base/GFXDef.h"
namespace cc {
namespace scene {
class Pass;
}
namespace pipeline {
class CC_DLL PipelineStateManager {
public:
static gfx::PipelineState *getOrCreatePipelineState(const scene::Pass *pass,
gfx::Shader *shader,
gfx::InputAssembler *inputAssembler,
gfx::RenderPass *renderPass,
uint32_t subpass = 0);
static void destroyAll();
private:
static ccstd::unordered_map<ccstd::hash_t, IntrusivePtr<gfx::PipelineState>> psoHashMap;
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,611 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "PipelineUBO.h"
#include "GlobalDescriptorSetManager.h"
#include "PipelineSceneData.h"
#include "RenderPipeline.h"
#include "SceneCulling.h"
#include "application/ApplicationManager.h"
#include "core/Root.h"
#include "gfx-base/GFXDevice.h"
#include "renderer/pipeline/shadow/CSMLayers.h"
#include "scene/Camera.h"
#include "scene/DirectionalLight.h"
#include "scene/Fog.h"
#include "scene/ReflectionProbeManager.h"
#include "scene/RenderScene.h"
#include "scene/Shadow.h"
#include "scene/Skybox.h"
#include "scene/SpotLight.h"
namespace cc {
namespace pipeline {
#define TO_VEC3(dst, src, offset) \
(dst)[(offset) + 0] = (src).x; \
(dst)[(offset) + 1] = (src).y; \
(dst)[(offset) + 2] = (src).z;
#define TO_VEC4(dst, src, offset) \
(dst)[(offset) + 0] = (src).x; \
(dst)[(offset) + 1] = (src).y; \
(dst)[(offset) + 2] = (src).z; \
(dst)[(offset) + 3] = (src).w;
Mat4 matShadowViewProj;
void PipelineUBO::updateGlobalUBOView(const scene::Camera *camera, ccstd::array<float, UBOGlobal::COUNT> *bufferView) {
const auto *const root = Root::getInstance();
ccstd::array<float, UBOGlobal::COUNT> &uboGlobalView = *bufferView;
const auto shadingWidth = std::floor(camera->getWindow()->getWidth());
const auto shadingHeight = std::floor(camera->getWindow()->getHeight());
// update UBOGlobal
uboGlobalView[UBOGlobal::TIME_OFFSET + 0] = root->getCumulativeTime();
uboGlobalView[UBOGlobal::TIME_OFFSET + 1] = root->getFrameTime();
uboGlobalView[UBOGlobal::TIME_OFFSET + 2] = static_cast<float>(CC_CURRENT_ENGINE()->getTotalFrames());
uboGlobalView[UBOGlobal::TIME_OFFSET + 3] = root->getCumulativeTime() - floorf(root->getFrameTime());
uboGlobalView[UBOGlobal::SCREEN_SIZE_OFFSET + 0] = static_cast<float>(shadingWidth);
uboGlobalView[UBOGlobal::SCREEN_SIZE_OFFSET + 1] = static_cast<float>(shadingHeight);
uboGlobalView[UBOGlobal::SCREEN_SIZE_OFFSET + 2] = 1.0F / uboGlobalView[UBOGlobal::SCREEN_SIZE_OFFSET];
uboGlobalView[UBOGlobal::SCREEN_SIZE_OFFSET + 3] = 1.0F / uboGlobalView[UBOGlobal::SCREEN_SIZE_OFFSET + 1];
uboGlobalView[UBOGlobal::NATIVE_SIZE_OFFSET + 0] = static_cast<float>(shadingWidth);
uboGlobalView[UBOGlobal::NATIVE_SIZE_OFFSET + 1] = static_cast<float>(shadingHeight);
uboGlobalView[UBOGlobal::NATIVE_SIZE_OFFSET + 2] = 1.0F / uboGlobalView[UBOGlobal::NATIVE_SIZE_OFFSET];
uboGlobalView[UBOGlobal::NATIVE_SIZE_OFFSET + 3] = 1.0F / uboGlobalView[UBOGlobal::NATIVE_SIZE_OFFSET + 1];
uboGlobalView[UBOGlobal::PROBE_INFO_OFFSET + 0] = scene::ReflectionProbeManager::getInstance()->getMaxProbeId() + 1;
auto *debugView = root->getDebugView();
uboGlobalView[UBOGlobal::DEBUG_VIEW_MODE_OFFSET] = static_cast<float>(debugView->getSingleMode());
for (int i = 1; i <= 3; ++i) {
uboGlobalView[UBOGlobal::DEBUG_VIEW_MODE_OFFSET + i] = 0.0F;
}
for (int i = 0; i < static_cast<int>(pipeline::DebugViewCompositeType::MAX_BIT_COUNT); ++i) {
int offset = i >> 3;
int bit = i % 8;
uboGlobalView[UBOGlobal::DEBUG_VIEW_MODE_OFFSET + 1 + offset] += (debugView->isCompositeModeEnabled(i) ? 1.0F : 0.0F) * pow(10.0F, static_cast<float>(bit));
}
uboGlobalView[UBOGlobal::DEBUG_VIEW_MODE_OFFSET + 3] += (debugView->isLightingWithAlbedo() ? 1.0F : 0.0F) * pow(10.0F, 6.0F);
uboGlobalView[UBOGlobal::DEBUG_VIEW_MODE_OFFSET + 3] += (debugView->isCsmLayerColoration() ? 1.0F : 0.0F) * pow(10.0F, 7.0F);
}
void PipelineUBO::updateCameraUBOView(const RenderPipeline *pipeline, float *output, const scene::Camera *camera) {
updateCameraUBOView(pipeline, output, camera, camera->getScene());
}
void PipelineUBO::updateCameraUBOView(const RenderPipeline *pipeline, float *output, const scene::Camera *camera, const scene::RenderScene *scene) {
const scene::DirectionalLight *mainLight = scene->getMainLight();
const auto *sceneData = pipeline->getPipelineSceneData();
const scene::Shadows *const shadowInfo = sceneData->getShadows();
const auto *ambient = sceneData->getAmbient();
auto *fog = sceneData->getFog();
const auto isHDR = sceneData->isHDR();
output[UBOCamera::SCREEN_SCALE_OFFSET + 0] = sceneData->getShadingScale();
output[UBOCamera::SCREEN_SCALE_OFFSET + 1] = sceneData->getShadingScale();
output[UBOCamera::SCREEN_SCALE_OFFSET + 2] = 1.0F / output[UBOCamera::SCREEN_SCALE_OFFSET];
output[UBOCamera::SCREEN_SCALE_OFFSET + 3] = 1.0F / output[UBOCamera::SCREEN_SCALE_OFFSET + 1];
const auto exposure = camera->getExposure();
output[UBOCamera::EXPOSURE_OFFSET + 0] = exposure;
output[UBOCamera::EXPOSURE_OFFSET + 1] = 1.0F / exposure;
output[UBOCamera::EXPOSURE_OFFSET + 2] = isHDR ? 1.0F : 0.0F;
output[UBOCamera::EXPOSURE_OFFSET + 3] = 1.0F / scene::Camera::getStandardExposureValue();
if (mainLight) {
const float shadowEnable = (mainLight->isShadowEnabled() && shadowInfo->getType() == scene::ShadowType::SHADOW_MAP) ? 1.0F : 0.0F;
const Vec4 lightDir(mainLight->getDirection().x, mainLight->getDirection().y, mainLight->getDirection().z, shadowEnable);
TO_VEC4(output, lightDir, UBOCamera::MAIN_LIT_DIR_OFFSET)
TO_VEC3(output, mainLight->getColor(), UBOCamera::MAIN_LIT_COLOR_OFFSET)
if (mainLight->isUseColorTemperature()) {
const auto &colorTempRGB = mainLight->getColorTemperatureRGB();
output[UBOCamera::MAIN_LIT_COLOR_OFFSET + 0] *= colorTempRGB.x;
output[UBOCamera::MAIN_LIT_COLOR_OFFSET + 1] *= colorTempRGB.y;
output[UBOCamera::MAIN_LIT_COLOR_OFFSET + 2] *= colorTempRGB.z;
}
if (isHDR) {
output[UBOCamera::MAIN_LIT_COLOR_OFFSET + 3] = mainLight->getIlluminanceHDR() * exposure;
} else {
output[UBOCamera::MAIN_LIT_COLOR_OFFSET + 3] = mainLight->getIlluminanceLDR();
}
} else {
const Vec4 lightDir(0.0F, 0.0F, 1.0F, 0.0F);
TO_VEC4(output, lightDir, UBOCamera::MAIN_LIT_DIR_OFFSET)
TO_VEC4(output, Vec4::ZERO, UBOCamera::MAIN_LIT_COLOR_OFFSET)
}
if (ambient != nullptr) {
auto &skyColor = const_cast<scene::Ambient *>(ambient)->getSkyColor();
if (isHDR) {
skyColor.w = ambient->getSkyIllum() * exposure;
} else {
skyColor.w = ambient->getSkyIllum();
}
output[UBOCamera::AMBIENT_SKY_OFFSET + 0] = skyColor.x;
output[UBOCamera::AMBIENT_SKY_OFFSET + 1] = skyColor.y;
output[UBOCamera::AMBIENT_SKY_OFFSET + 2] = skyColor.z;
output[UBOCamera::AMBIENT_SKY_OFFSET + 3] = skyColor.w;
const auto &groundAlbedo = ambient->getGroundAlbedo();
output[UBOCamera::AMBIENT_GROUND_OFFSET + 0] = groundAlbedo.x;
output[UBOCamera::AMBIENT_GROUND_OFFSET + 1] = groundAlbedo.y;
output[UBOCamera::AMBIENT_GROUND_OFFSET + 2] = groundAlbedo.z;
output[UBOCamera::AMBIENT_GROUND_OFFSET + 3] = ambient->getMipmapCount();
}
// cjh TS doesn't have this logic ? auto *const envmap = descriptorSet->getTexture(static_cast<uint32_t>(PipelineGlobalBindings::SAMPLER_ENVIRONMENT));
// if (envmap != nullptr) {
// output[UBOCamera::AMBIENT_GROUND_OFFSET + 3] = static_cast<float>(envmap->getLevelCount());
// }
memcpy(output + UBOCamera::MAT_VIEW_OFFSET, camera->getMatView().m, sizeof(cc::Mat4));
memcpy(output + UBOCamera::MAT_VIEW_INV_OFFSET, camera->getNode()->getWorldMatrix().m, sizeof(cc::Mat4));
TO_VEC3(output, camera->getPosition(), UBOCamera::CAMERA_POS_OFFSET)
memcpy(output + UBOCamera::MAT_PROJ_OFFSET, camera->getMatProj().m, sizeof(cc::Mat4));
memcpy(output + UBOCamera::MAT_PROJ_INV_OFFSET, camera->getMatProjInv().m, sizeof(cc::Mat4));
memcpy(output + UBOCamera::MAT_VIEW_PROJ_OFFSET, camera->getMatViewProj().m, sizeof(cc::Mat4));
memcpy(output + UBOCamera::MAT_VIEW_PROJ_INV_OFFSET, camera->getMatViewProjInv().m, sizeof(cc::Mat4));
output[UBOCamera::CAMERA_POS_OFFSET + 3] = getCombineSignY();
output[UBOCamera::SURFACE_TRANSFORM_OFFSET + 0] = static_cast<float>(camera->getSurfaceTransform());
output[UBOCamera::SURFACE_TRANSFORM_OFFSET + 1] = static_cast<float>(camera->getCameraUsage());
const float angle = sceneData->getSkybox()->getRotationAngle();
output[UBOCamera::SURFACE_TRANSFORM_OFFSET + 2] = static_cast<float>(cos(mathutils::toRadian(angle)));
output[UBOCamera::SURFACE_TRANSFORM_OFFSET + 3] = static_cast<float>(sin(mathutils::toRadian(angle)));
if (fog != nullptr) {
const auto &colorTempRGB = fog->getColorArray();
output[UBOCamera::GLOBAL_FOG_COLOR_OFFSET] = colorTempRGB.x;
output[UBOCamera::GLOBAL_FOG_COLOR_OFFSET + 1] = colorTempRGB.y;
output[UBOCamera::GLOBAL_FOG_COLOR_OFFSET + 2] = colorTempRGB.z;
output[UBOCamera::GLOBAL_FOG_COLOR_OFFSET + 3] = colorTempRGB.z;
output[UBOCamera::GLOBAL_FOG_BASE_OFFSET + 0] = fog->getFogStart();
output[UBOCamera::GLOBAL_FOG_BASE_OFFSET + 1] = fog->getFogEnd();
output[UBOCamera::GLOBAL_FOG_BASE_OFFSET + 2] = fog->getFogDensity();
output[UBOCamera::GLOBAL_FOG_ADD_OFFSET + 0] = fog->getFogTop();
output[UBOCamera::GLOBAL_FOG_ADD_OFFSET + 1] = fog->getFogRange();
output[UBOCamera::GLOBAL_FOG_ADD_OFFSET + 2] = fog->getFogAtten();
}
output[UBOCamera::GLOBAL_NEAR_FAR_OFFSET + 0] = static_cast<float>(camera->getNearClip());
output[UBOCamera::GLOBAL_NEAR_FAR_OFFSET + 1] = static_cast<float>(camera->getFarClip());
output[UBOCamera::GLOBAL_NEAR_FAR_OFFSET + 2] = static_cast<float>(camera->getClipSpaceMinz());
output[UBOCamera::GLOBAL_VIEW_PORT_OFFSET + 0] = sceneData->getShadingScale() * static_cast<float>(camera->getWindow()->getWidth()) * camera->getViewport().x;
output[UBOCamera::GLOBAL_VIEW_PORT_OFFSET + 1] = sceneData->getShadingScale() * static_cast<float>(camera->getWindow()->getHeight()) * camera->getViewport().y;
output[UBOCamera::GLOBAL_VIEW_PORT_OFFSET + 2] = sceneData->getShadingScale() * static_cast<float>(camera->getWindow()->getWidth()) * camera->getViewport().z;
output[UBOCamera::GLOBAL_VIEW_PORT_OFFSET + 3] = sceneData->getShadingScale() * static_cast<float>(camera->getWindow()->getHeight()) * camera->getViewport().w;
}
void PipelineUBO::updateShadowUBOView(const RenderPipeline *pipeline, ccstd::array<float, UBOShadow::COUNT> *shadowBufferView,
ccstd::array<float, UBOCSM::COUNT> *csmBufferView, const scene::Camera *camera) {
const scene::RenderScene *const scene = camera->getScene();
const scene::DirectionalLight *mainLight = scene->getMainLight();
gfx::Device *device = gfx::Device::getInstance();
const PipelineSceneData *sceneData = pipeline->getPipelineSceneData();
const CSMLayers *csmLayers = sceneData->getCSMLayers();
scene::Shadows *const shadowInfo = sceneData->getShadows();
ccstd::array<float, UBOShadow::COUNT> &sv = *shadowBufferView;
ccstd::array<float, UBOCSM::COUNT> &cv = *csmBufferView;
const bool hFTexture = supportsR32FloatTexture(device);
const float packing = hFTexture ? 0.0F : 1.0F;
const bool csmSupported = sceneData->getCSMSupported();
if (shadowInfo->isEnabled() && mainLight) {
if (shadowInfo->getType() == scene::ShadowType::SHADOW_MAP) {
if (mainLight->isShadowEnabled()) {
if (mainLight->isShadowFixedArea() || mainLight->getCSMLevel() == scene::CSMLevel::LEVEL_1 || !csmSupported) {
const Mat4 &matShadowView = csmLayers->getSpecialLayer()->getMatShadowView();
const Mat4 &matShadowProj = csmLayers->getSpecialLayer()->getMatShadowProj();
const Mat4 &matShadowViewProj = csmLayers->getSpecialLayer()->getMatShadowViewProj();
float levelCount = 0.0F;
float nearClamp = 0.1F;
float farClamp = 0.0F;
if (mainLight->isShadowFixedArea()) {
nearClamp = mainLight->getShadowNear();
farClamp = mainLight->getShadowFar();
levelCount = 0.0F;
} else {
farClamp = csmLayers->getSpecialLayer()->getShadowCameraFar();
levelCount = 1.0F;
}
memcpy(sv.data() + UBOShadow::MAT_LIGHT_VIEW_OFFSET, matShadowView.m, sizeof(matShadowView));
const float shadowProjDepthInfos[4] = {matShadowProj.m[10], matShadowProj.m[14], matShadowProj.m[11], matShadowProj.m[15]};
memcpy(sv.data() + UBOShadow::SHADOW_PROJ_DEPTH_INFO_OFFSET, &shadowProjDepthInfos, sizeof(shadowProjDepthInfos));
const float shadowProjInfos[4] = {matShadowProj.m[00], matShadowProj.m[05], 1.0F / matShadowProj.m[00], 1.0F / matShadowProj.m[05]};
memcpy(sv.data() + UBOShadow::SHADOW_PROJ_INFO_OFFSET, &shadowProjInfos, sizeof(shadowProjInfos));
memcpy(sv.data() + UBOShadow::MAT_LIGHT_VIEW_PROJ_OFFSET, matShadowViewProj.m, sizeof(matShadowViewProj));
const float shadowNFLSInfos[4] = {nearClamp, farClamp, 0.0F, 1.0F - mainLight->getShadowSaturation()};
memcpy(sv.data() + UBOShadow::SHADOW_NEAR_FAR_LINEAR_SATURATION_INFO_OFFSET, &shadowNFLSInfos, sizeof(shadowNFLSInfos));
const float shadowLPNNInfos[4] = {static_cast<float>(scene::LightType::DIRECTIONAL), packing, mainLight->getShadowNormalBias(), levelCount};
memcpy(sv.data() + UBOShadow::SHADOW_LIGHT_PACKING_NBIAS_NULL_INFO_OFFSET, &shadowLPNNInfos, sizeof(shadowLPNNInfos));
} else {
const auto layerThreshold = PipelineUBO::getPCFRadius(shadowInfo, mainLight);
for (uint32_t i = 0; i < static_cast<uint32_t>(mainLight->getCSMLevel()); ++i) {
const auto *layer = csmLayers->getLayers()[i];
const Mat4 &matShadowView = layer->getMatShadowView();
const float csmViewDir0[4] = {matShadowView.m[0], matShadowView.m[4], matShadowView.m[8], layerThreshold};
memcpy(cv.data() + UBOCSM::CSM_VIEW_DIR_0_OFFSET + i * 4, &csmViewDir0, sizeof(csmViewDir0));
const float csmViewDir1[4] = {matShadowView.m[1], matShadowView.m[5], matShadowView.m[9], layer->getSplitCameraNear()};
memcpy(cv.data() + UBOCSM::CSM_VIEW_DIR_1_OFFSET + i * 4, &csmViewDir1, sizeof(csmViewDir1));
const float csmViewDir2[4] = {matShadowView.m[2], matShadowView.m[6], matShadowView.m[10], layer->getSplitCameraFar()};
memcpy(cv.data() + UBOCSM::CSM_VIEW_DIR_2_OFFSET + i * 4, &csmViewDir2, sizeof(csmViewDir2));
const auto &csmAtlas = layer->getCSMAtlas();
const float csmAtlasOffsets[4] = {csmAtlas.x, csmAtlas.y, csmAtlas.z, csmAtlas.w};
memcpy(cv.data() + UBOCSM::CSM_ATLAS_OFFSET + i * 4, &csmAtlasOffsets, sizeof(csmAtlasOffsets));
const Mat4 &matShadowViewProj = layer->getMatShadowViewProj();
memcpy(cv.data() + UBOCSM::MAT_CSM_VIEW_PROJ_LEVELS_OFFSET + i * 16, matShadowViewProj.m, sizeof(matShadowViewProj));
const Mat4 &matShadowProj = layer->getMatShadowProj();
const float shadowProjDepthInfos[4] = {matShadowProj.m[10], matShadowProj.m[14], matShadowProj.m[11], matShadowProj.m[15]};
memcpy(cv.data() + UBOCSM::CSM_PROJ_DEPTH_INFO_LEVELS_OFFSET + i * 4, &shadowProjDepthInfos, sizeof(shadowProjDepthInfos));
const float shadowProjInfos[4] = {matShadowProj.m[00], matShadowProj.m[05], 1.0F / matShadowProj.m[00], 1.0F / matShadowProj.m[05]};
memcpy(cv.data() + UBOCSM::CSM_PROJ_INFO_LEVELS_OFFSET + i * 4, &shadowProjInfos, sizeof(shadowProjInfos));
}
const float csmInfo[4] = {mainLight->getCSMTransitionRange(), 0.0F, 0.0F, 0.0F};
memcpy(cv.data() + UBOCSM::CSM_SPLITS_INFO_OFFSET, &csmInfo, sizeof(csmInfo));
const float shadowNFLSInfos[4] = {0.1F, mainLight->getShadowDistance(), 0.0F, 1.0F - mainLight->getShadowSaturation()};
memcpy(sv.data() + UBOShadow::SHADOW_NEAR_FAR_LINEAR_SATURATION_INFO_OFFSET, &shadowNFLSInfos, sizeof(shadowNFLSInfos));
const float shadowLPNNInfos[4] = {static_cast<float>(scene::LightType::DIRECTIONAL), packing, mainLight->getShadowNormalBias(), static_cast<float>(mainLight->getCSMLevel())};
memcpy(sv.data() + UBOShadow::SHADOW_LIGHT_PACKING_NBIAS_NULL_INFO_OFFSET, &shadowLPNNInfos, sizeof(shadowLPNNInfos));
}
const float shadowWHPBInfos[4] = {shadowInfo->getSize().x, shadowInfo->getSize().y, static_cast<float>(mainLight->getShadowPcf()), mainLight->getShadowBias()};
memcpy(sv.data() + UBOShadow::SHADOW_WIDTH_HEIGHT_PCF_BIAS_INFO_OFFSET, &shadowWHPBInfos, sizeof(shadowWHPBInfos));
}
} else if (mainLight && shadowInfo->getType() == scene::ShadowType::PLANAR) {
PipelineUBO::updatePlanarNormalAndDistance(shadowInfo, shadowBufferView);
const float shadowWHPBInfos[4] = {0, 0, 0, shadowInfo->getPlaneBias()};
memcpy(sv.data() + UBOShadow::SHADOW_WIDTH_HEIGHT_PCF_BIAS_INFO_OFFSET, &shadowWHPBInfos, sizeof(shadowWHPBInfos));
}
memcpy(sv.data() + UBOShadow::SHADOW_COLOR_OFFSET, shadowInfo->getShadowColor4f().data(), sizeof(float) * 4);
}
}
void PipelineUBO::updateShadowUBOLightView(const RenderPipeline *pipeline, ccstd::array<float, UBOShadow::COUNT> *shadowBufferView,
const scene::Light *light, uint32_t level) {
const auto *sceneData = pipeline->getPipelineSceneData();
const CSMLayers *csmLayers = sceneData->getCSMLayers();
const auto *shadowInfo = sceneData->getShadows();
const auto *device = gfx::Device::getInstance();
auto &shadowUBO = *shadowBufferView;
const bool hFTexture = supportsR32FloatTexture(device);
const float packing = hFTexture ? 0.0F : 1.0F;
const auto cap = pipeline->getDevice()->getCapabilities();
const bool csmSupported = sceneData->getCSMSupported();
switch (light->getType()) {
case scene::LightType::DIRECTIONAL: {
const auto *mainLight = static_cast<const scene::DirectionalLight *>(light);
if (shadowInfo->isEnabled() && mainLight && mainLight->isShadowEnabled()) {
if (shadowInfo->getType() == scene::ShadowType::SHADOW_MAP) {
float levelCount = 0.0F;
float nearClamp = 0.1F;
float farClamp = 0.0F;
Mat4 matShadowView;
Mat4 matShadowProj;
Mat4 matShadowViewProj;
if (mainLight->isShadowFixedArea() || mainLight->getCSMLevel() == scene::CSMLevel::LEVEL_1 || !csmSupported) {
matShadowView = csmLayers->getSpecialLayer()->getMatShadowView();
matShadowProj = csmLayers->getSpecialLayer()->getMatShadowProj();
matShadowViewProj = csmLayers->getSpecialLayer()->getMatShadowViewProj();
if (mainLight->isShadowFixedArea()) {
nearClamp = mainLight->getShadowNear();
farClamp = mainLight->getShadowFar();
levelCount = 0.0F;
} else {
nearClamp = 0.1F;
farClamp = csmLayers->getSpecialLayer()->getShadowCameraFar();
levelCount = 1.0F;
}
const float shadowLPNNInfos[4] = {static_cast<float>(scene::LightType::DIRECTIONAL), packing, mainLight->getShadowNormalBias(), 0.0F};
memcpy(shadowUBO.data() + UBOShadow::SHADOW_LIGHT_PACKING_NBIAS_NULL_INFO_OFFSET, &shadowLPNNInfos, sizeof(shadowLPNNInfos));
} else {
const CSMLayerInfo *layer = csmLayers->getLayers()[level];
levelCount = static_cast<float>(mainLight->getCSMLevel());
nearClamp = layer->getSplitCameraNear();
farClamp = layer->getSplitCameraFar();
matShadowView = layer->getMatShadowView();
matShadowProj = layer->getMatShadowProj();
matShadowViewProj = layer->getMatShadowViewProj();
}
memcpy(shadowUBO.data() + UBOShadow::MAT_LIGHT_VIEW_OFFSET, matShadowView.m, sizeof(matShadowView));
const float shadowProjDepthInfos[4] = {matShadowProj.m[10], matShadowProj.m[14], matShadowProj.m[11], matShadowProj.m[15]};
memcpy(shadowUBO.data() + UBOShadow::SHADOW_PROJ_DEPTH_INFO_OFFSET, &shadowProjDepthInfos, sizeof(shadowProjDepthInfos));
const float shadowProjInfos[4] = {matShadowProj.m[00], matShadowProj.m[05], 1.0F / matShadowProj.m[00], 1.0F / matShadowProj.m[05]};
memcpy(shadowUBO.data() + UBOShadow::SHADOW_PROJ_INFO_OFFSET, &shadowProjInfos, sizeof(shadowProjInfos));
memcpy(shadowUBO.data() + UBOShadow::MAT_LIGHT_VIEW_PROJ_OFFSET, matShadowViewProj.m, sizeof(matShadowViewProj));
const float shadowNFLSInfos[4] = {nearClamp, farClamp, 0.0F, 1.0F - mainLight->getShadowSaturation()};
memcpy(shadowUBO.data() + UBOShadow::SHADOW_NEAR_FAR_LINEAR_SATURATION_INFO_OFFSET, &shadowNFLSInfos, sizeof(shadowNFLSInfos));
const float shadowLPNNInfos[4] = {static_cast<float>(scene::LightType::DIRECTIONAL), packing, mainLight->getShadowNormalBias(), levelCount};
memcpy(shadowUBO.data() + UBOShadow::SHADOW_LIGHT_PACKING_NBIAS_NULL_INFO_OFFSET, &shadowLPNNInfos, sizeof(shadowLPNNInfos));
const float shadowWHPBInfos[4] = {shadowInfo->getSize().x, shadowInfo->getSize().y, static_cast<float>(mainLight->getShadowPcf()), mainLight->getShadowBias()};
memcpy(shadowUBO.data() + UBOShadow::SHADOW_WIDTH_HEIGHT_PCF_BIAS_INFO_OFFSET, &shadowWHPBInfos, sizeof(shadowWHPBInfos));
}
}
} break;
case scene::LightType::SPOT: {
const auto *spotLight = static_cast<const scene::SpotLight *>(light);
if (shadowInfo->isEnabled() && spotLight && spotLight->isShadowEnabled()) {
const auto &matShadowCamera = spotLight->getNode()->getWorldMatrix();
const auto matShadowView = matShadowCamera.getInversed();
memcpy(shadowUBO.data() + UBOShadow::MAT_LIGHT_VIEW_OFFSET, matShadowView.m, sizeof(matShadowView));
Mat4::createPerspective(spotLight->getAngle(), 1.0F, 0.001F, spotLight->getRange(), true, cap.clipSpaceMinZ, cap.clipSpaceSignY, 0, &matShadowViewProj);
matShadowViewProj.multiply(matShadowView);
memcpy(shadowUBO.data() + UBOShadow::MAT_LIGHT_VIEW_PROJ_OFFSET, matShadowViewProj.m, sizeof(matShadowViewProj));
const float shadowNFLSInfos[4] = {0.01F, spotLight->getRange(), 0.0F, 0.0F};
memcpy(shadowUBO.data() + UBOShadow::SHADOW_NEAR_FAR_LINEAR_SATURATION_INFO_OFFSET, &shadowNFLSInfos, sizeof(shadowNFLSInfos));
const float shadowLPNNInfos[4] = {static_cast<float>(scene::LightType::SPOT), packing, spotLight->getShadowNormalBias(), 0.0F};
memcpy(shadowUBO.data() + UBOShadow::SHADOW_LIGHT_PACKING_NBIAS_NULL_INFO_OFFSET, &shadowLPNNInfos, sizeof(shadowLPNNInfos));
const float shadowWHPBInfos[4] = {shadowInfo->getSize().x, shadowInfo->getSize().y, spotLight->getShadowPcf(), spotLight->getShadowBias()};
memcpy(shadowUBO.data() + UBOShadow::SHADOW_WIDTH_HEIGHT_PCF_BIAS_INFO_OFFSET, &shadowWHPBInfos, sizeof(shadowWHPBInfos));
}
} break;
case scene::LightType::SPHERE: break;
case scene::LightType::UNKNOWN: break;
default:
break;
}
memcpy(shadowUBO.data() + UBOShadow::SHADOW_COLOR_OFFSET, shadowInfo->getShadowColor4f().data(), sizeof(float) * 4);
}
static uint8_t combineSignY = 0;
uint8_t PipelineUBO::getCombineSignY() {
return combineSignY;
}
float PipelineUBO::getPCFRadius(const scene::Shadows *shadowInfo, const scene::DirectionalLight *dirLight) {
const float shadowMapSize = shadowInfo->getSize().x;
if (dirLight->getShadowPcf() == scene::PCFType::SOFT_4X) { // PCFType.SOFT_4X
return 3.0F / (shadowMapSize * 0.5F);
}
if (dirLight->getShadowPcf() == scene::PCFType::SOFT_2X) { // PCFType.SOFT_2X
return 2.0F / (shadowMapSize * 0.5F);
}
if (dirLight->getShadowPcf() == scene::PCFType::SOFT) { // PCFType.SOFT
return 1.0F / (shadowMapSize * 0.5F);
}
return 0.0F; // PCFType.HARD
}
void PipelineUBO::updatePlanarNormalAndDistance(const scene::Shadows *shadowInfo, ccstd::array<float, UBOShadow::COUNT> *shadowUBO) {
const Vec3 normal = shadowInfo->getNormal().getNormalized();
const float planarNDInfo[4] = {normal.x, normal.y, normal.z, -shadowInfo->getDistance()};
memcpy(shadowUBO->data() + UBOShadow::PLANAR_NORMAL_DISTANCE_INFO_OFFSET, &planarNDInfo, sizeof(planarNDInfo));
}
void PipelineUBO::initCombineSignY() const {
const float screenSpaceSignY = _device->getCapabilities().screenSpaceSignY * 0.5F + 0.5F;
const float clipSpaceSignY = _device->getCapabilities().clipSpaceSignY * 0.5F + 0.5F;
combineSignY = static_cast<uint8_t>(screenSpaceSignY) << 1 | static_cast<uint8_t>(clipSpaceSignY);
}
void PipelineUBO::activate(gfx::Device *device, RenderPipeline *pipeline) {
_device = device;
_pipeline = pipeline;
auto *descriptorSet = pipeline->getDescriptorSet();
initCombineSignY();
auto *globalUBO = _device->createBuffer({
gfx::BufferUsageBit::UNIFORM | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::HOST | gfx::MemoryUsageBit::DEVICE,
UBOGlobal::SIZE,
UBOGlobal::SIZE,
gfx::BufferFlagBit::NONE,
});
descriptorSet->bindBuffer(UBOGlobal::BINDING, globalUBO);
_ubos.push_back(globalUBO);
_alignedCameraUBOSize = utils::alignTo(UBOCamera::SIZE, _device->getCapabilities().uboOffsetAlignment);
_cameraBuffer = _device->createBuffer({
gfx::BufferUsageBit::UNIFORM | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::HOST | gfx::MemoryUsageBit::DEVICE,
_alignedCameraUBOSize,
_alignedCameraUBOSize,
});
_ubos.push_back(_cameraBuffer);
_cameraUBOs.resize(_alignedCameraUBOSize / sizeof(float));
_cameraBufferView = _device->createBuffer({
_cameraBuffer,
0,
UBOCamera::SIZE,
});
descriptorSet->bindBuffer(UBOCamera::BINDING, _cameraBufferView);
_ubos.push_back(_cameraBufferView);
auto *shadowUBO = _device->createBuffer({
gfx::BufferUsageBit::UNIFORM | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::DEVICE,
UBOShadow::SIZE,
UBOShadow::SIZE,
gfx::BufferFlagBit::NONE,
});
descriptorSet->bindBuffer(UBOShadow::BINDING, shadowUBO);
_ubos.push_back(shadowUBO);
auto *csmUBO = _device->createBuffer({
gfx::BufferUsageBit::UNIFORM | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::DEVICE,
UBOCSM::SIZE,
UBOCSM::SIZE,
gfx::BufferFlagBit::NONE,
});
descriptorSet->bindBuffer(UBOCSM::BINDING, csmUBO);
_ubos.push_back(csmUBO);
_shadowUBOUpdated = false;
}
void PipelineUBO::destroy() {
for (auto &ubo : _ubos) {
CC_SAFE_DELETE(ubo)
}
_ubos.clear();
}
void PipelineUBO::updateGlobalUBO(const scene::Camera *camera) {
auto *const globalDSManager = _pipeline->getGlobalDSManager();
auto *const ds = _pipeline->getDescriptorSet();
ds->update();
updateGlobalUBOView(camera, &_globalUBO);
ds->getBuffer(UBOGlobal::BINDING)->update(_globalUBO.data(), UBOGlobal::SIZE);
globalDSManager->bindBuffer(UBOGlobal::BINDING, ds->getBuffer(UBOGlobal::BINDING));
globalDSManager->update();
}
void PipelineUBO::updateCameraUBO(const scene::Camera *camera) {
updateCameraUBO(camera, camera->getScene());
}
void PipelineUBO::updateCameraUBO(const scene::Camera *camera, const scene::RenderScene *scene) {
auto *const cmdBuffer = _pipeline->getCommandBuffers()[0];
updateCameraUBOView(_pipeline, _cameraUBOs.data(), camera, scene);
cmdBuffer->updateBuffer(_cameraBuffer, _cameraUBOs.data());
}
void PipelineUBO::updateMultiCameraUBO(GlobalDSManager *globalDSMgr, const ccstd::vector<scene::Camera *> &cameras) {
const auto cameraCount = cameras.size();
const auto totalUboSize = static_cast<uint32_t>(_alignedCameraUBOSize * cameraCount);
if (_cameraBuffer->getSize() < totalUboSize) {
_cameraBuffer->resize(totalUboSize);
_cameraUBOs.resize(totalUboSize / sizeof(float));
if (_cameraBufferView != nullptr) {
_ubos.erase(std::remove(_ubos.begin(), _ubos.end(), _cameraBufferView), _ubos.end());
CC_SAFE_DELETE(_cameraBufferView);
}
_cameraBufferView = _device->createBuffer({
_cameraBuffer,
0,
UBOCamera::SIZE,
});
globalDSMgr->bindBuffer(UBOCamera::BINDING, _cameraBufferView);
_ubos.push_back(_cameraBufferView);
}
for (uint32_t cameraIdx = 0; cameraIdx < cameraCount; ++cameraIdx) {
const auto *camera = cameras[cameraIdx];
const auto offset = cameraIdx * _alignedCameraUBOSize / sizeof(float);
PipelineUBO::updateCameraUBOView(_pipeline, &_cameraUBOs[offset], camera);
}
_cameraBuffer->update(_cameraUBOs.data());
_currentCameraUBOOffset = 0;
}
void PipelineUBO::updateShadowUBO(const scene::Camera *camera) {
auto *const ds = _pipeline->getDescriptorSet();
auto *const cmdBuffer = _pipeline->getCommandBuffers()[0];
const auto *sceneData = _pipeline->getPipelineSceneData();
const auto *shadowInfo = sceneData->getShadows();
const auto *const scene = camera->getScene();
if (shadowInfo == nullptr || !shadowInfo->isEnabled()) {
// at least update once to avoid crash #10779
if (_shadowUBOUpdated) {
return;
}
}
_shadowUBOUpdated = true;
const auto &shadowFrameBufferMap = sceneData->getShadowFramebufferMap();
const scene::DirectionalLight *mainLight = scene->getMainLight();
if (mainLight && shadowInfo->getType() == scene::ShadowType::SHADOW_MAP) {
if (shadowFrameBufferMap.count(mainLight) > 0) {
auto *texture = shadowFrameBufferMap.at(mainLight)->getColorTextures()[0];
if (texture) {
ds->bindTexture(SHADOWMAP::BINDING, texture);
}
}
}
updateShadowUBOView(_pipeline, &_shadowUBO, &_csmUBO, camera);
ds->update();
cmdBuffer->updateBuffer(ds->getBuffer(UBOShadow::BINDING), _shadowUBO.data(), UBOShadow::SIZE);
cmdBuffer->updateBuffer(ds->getBuffer(UBOCSM::BINDING), _csmUBO.data(), UBOCSM::SIZE);
}
void PipelineUBO::updateShadowUBOLight(gfx::DescriptorSet *globalDS, const scene::Light *light, uint32_t level) {
auto *const cmdBuffer = _pipeline->getCommandBuffers()[0];
updateShadowUBOLightView(_pipeline, &_shadowUBO, light, level);
globalDS->update();
cmdBuffer->updateBuffer(globalDS->getBuffer(UBOShadow::BINDING), _shadowUBO.data(), UBOShadow::SIZE);
}
void PipelineUBO::updateShadowUBORange(uint32_t offset, const Mat4 *data) {
memcpy(_shadowUBO.data() + offset, data->m, sizeof(*data));
}
uint32_t PipelineUBO::getCurrentCameraUBOOffset() const {
return _currentCameraUBOOffset;
}
void PipelineUBO::incCameraUBOOffset() {
_currentCameraUBOOffset += _alignedCameraUBOSize;
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,96 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "Define.h"
#include "base/std/container/array.h"
namespace cc {
class Mat4;
namespace scene {
class Camera;
class Shadows;
class DirectionalLight;
class RenderScene;
} // namespace scene
namespace pipeline {
class RenderPipeline;
class GlobalDSManager;
class CC_DLL PipelineUBO final {
public:
static void updateGlobalUBOView(const scene::Camera *camera, ccstd::array<float, UBOGlobal::COUNT> *bufferView);
static void updateCameraUBOView(const RenderPipeline *pipeline, float *output, const scene::Camera *camera);
static void updateCameraUBOView(const RenderPipeline *pipeline, float *output, const scene::Camera *camera, const scene::RenderScene *renderScene);
static void updateShadowUBOView(const RenderPipeline *pipeline, ccstd::array<float, UBOShadow::COUNT> *shadowBufferView,
ccstd::array<float, UBOCSM::COUNT> *csmBufferView, const scene::Camera *camera);
static void updateShadowUBOLightView(const RenderPipeline *pipeline, ccstd::array<float, UBOShadow::COUNT> *shadowBufferView,
const scene::Light *light, uint32_t level);
static uint8_t getCombineSignY();
static void updatePlanarNormalAndDistance(const ::cc::scene::Shadows *shadowInfo, ccstd::array<float, UBOShadow::COUNT> *shadowUBO);
PipelineUBO() = default;
~PipelineUBO() = default;
void activate(gfx::Device *device, RenderPipeline *pipeline);
void destroy();
void updateGlobalUBO(const scene::Camera *camera);
void updateCameraUBO(const scene::Camera *camera);
void updateCameraUBO(const scene::Camera *camera, const scene::RenderScene *scene);
void updateMultiCameraUBO(GlobalDSManager *globalDSMgr, const ccstd::vector<scene::Camera *> &cameras);
void updateShadowUBO(const scene::Camera *camera);
void updateShadowUBOLight(gfx::DescriptorSet *globalDS, const scene::Light *light, uint32_t level = 0U);
void updateShadowUBORange(uint32_t offset, const Mat4 *data);
uint32_t getCurrentCameraUBOOffset() const;
void incCameraUBOOffset();
private:
static float getPCFRadius(const scene::Shadows *shadowInfo, const scene::DirectionalLight *dirLight);
void initCombineSignY() const;
void resizeCameraBuffer(uint32_t totalSize);
// weak reference
RenderPipeline *_pipeline{nullptr};
// weak reference
gfx::Device *_device{nullptr};
// weak reference, it is recorded in _ubos
gfx::Buffer *_cameraBuffer{nullptr};
gfx::Buffer *_cameraBufferView{nullptr};
uint32_t _currentCameraUBOOffset{0};
uint32_t _alignedCameraUBOSize{0};
bool _shadowUBOUpdated{false};
ccstd::array<float, UBOGlobal::COUNT> _globalUBO;
ccstd::array<float, UBOShadow::COUNT> _shadowUBO;
ccstd::array<float, UBOCSM::COUNT> _csmUBO;
// manage memory manually
ccstd::vector<gfx::Buffer *> _ubos;
ccstd::vector<float> _cameraUBOs;
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,166 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "PlanarShadowQueue.h"
#include "Define.h"
#include "InstancedBuffer.h"
#include "PipelineSceneData.h"
#include "PipelineStateManager.h"
#include "RenderInstancedQueue.h"
#include "RenderPipeline.h"
#include "core/geometry/AABB.h"
#include "gfx-base/GFXDevice.h"
#include "scene/Camera.h"
#include "scene/Model.h"
#include "scene/RenderScene.h"
#include "scene/Shadow.h"
namespace cc {
namespace pipeline {
PlanarShadowQueue::PlanarShadowQueue(RenderPipeline *pipeline)
: _pipeline(pipeline),
_phaseID(getPhaseID("planar-shadow")) {
_instancedQueue = ccnew RenderInstancedQueue;
}
PlanarShadowQueue::~PlanarShadowQueue() {
destroy();
}
void PlanarShadowQueue::gatherShadowPasses(scene::Camera *camera, gfx::CommandBuffer *cmdBuffer) {
clear();
const PipelineSceneData *sceneData = _pipeline->getPipelineSceneData();
scene::Shadows *shadowInfo = sceneData->getShadows();
if (shadowInfo == nullptr || !shadowInfo->isEnabled() || shadowInfo->getType() != scene::ShadowType::PLANAR || shadowInfo->getNormal().length() < 0.000001F) {
return;
}
const auto *scene = camera->getScene();
const bool shadowVisible = camera->getVisibility() & static_cast<uint32_t>(LayerList::DEFAULT);
if (!scene->getMainLight() || !shadowVisible) {
return;
}
const auto &models = scene->getModels();
for (const auto &model : models) {
if (scene->isCulledByLod(camera, model)) {
continue;
}
if (!model->isEnabled() || !model->isCastShadow() || !model->getNode()) {
continue;
}
if (model->getWorldBounds() && model->isCastShadow()) {
_castModels.emplace_back(model);
}
}
geometry::AABB ab;
for (const auto *model : _castModels) {
// frustum culling
model->getWorldBounds()->transform(shadowInfo->getMatLight(), &ab);
if (!ab.aabbFrustum(camera->getFrustum())) {
continue;
}
const auto &subModels = model->getSubModels();
for (const auto &subModel : subModels) {
const auto shadowPassIdx = getShadowPassIndex(subModel);
if (shadowPassIdx == -1) {
_subModelArray.emplace_back(subModel);
_shaderArray.emplace_back(shadowInfo->getPlanarShader(subModel->getPatches()));
_passArray.emplace_back((*shadowInfo->getMaterial()->getPasses())[0]);
continue;
}
auto *const pass = subModel->getPass(shadowPassIdx);
const auto batchingScheme = pass->getBatchingScheme();
if (batchingScheme == scene::BatchingSchemes::INSTANCING) {
auto *instancedBuffer = pass->getInstancedBuffer();
instancedBuffer->merge(subModel, shadowPassIdx);
_instancedQueue->add(instancedBuffer);
} else { // standard draw
_subModelArray.emplace_back(subModel);
_shaderArray.emplace_back(subModel->getShader(shadowPassIdx));
_passArray.emplace_back(pass);
}
}
}
_instancedQueue->uploadBuffers(cmdBuffer);
}
void PlanarShadowQueue::clear() {
_castModels.clear();
_subModelArray.clear();
_shaderArray.clear();
_passArray.clear();
if (_instancedQueue) _instancedQueue->clear();
}
void PlanarShadowQueue::recordCommandBuffer(gfx::Device *device, gfx::RenderPass *renderPass, gfx::CommandBuffer *cmdBuffer, uint32_t subpassID) {
const PipelineSceneData *sceneData = _pipeline->getPipelineSceneData();
const auto *shadowInfo = sceneData->getShadows();
if (shadowInfo == nullptr || !shadowInfo->isEnabled() || shadowInfo->getType() != scene::ShadowType::PLANAR || shadowInfo->getNormal().length() < 0.000001F) {
return;
}
_instancedQueue->recordCommandBuffer(device, renderPass, cmdBuffer);
for (size_t i = 0; i < _subModelArray.size(); ++i) {
const auto *const subModel = _subModelArray[i];
auto *const shader = _shaderArray[i];
const auto *pass = _passArray[i];
auto *const ia = subModel->getInputAssembler();
auto *const pso = PipelineStateManager::getOrCreatePipelineState(pass, shader, ia, renderPass, subpassID);
cmdBuffer->bindPipelineState(pso);
cmdBuffer->bindDescriptorSet(materialSet, pass->getDescriptorSet());
cmdBuffer->bindDescriptorSet(localSet, subModel->getDescriptorSet());
cmdBuffer->bindInputAssembler(ia);
cmdBuffer->draw(ia);
}
}
void PlanarShadowQueue::destroy() {
_pipeline = nullptr;
CC_SAFE_DELETE(_instancedQueue);
_castModels.clear();
_subModelArray.clear();
}
int PlanarShadowQueue::getShadowPassIndex(const scene::SubModel *subModel) const {
int i = 0;
for (const auto &pass : *(subModel->getPasses())) {
if (pass->getPhase() == _phaseID) {
return i;
}
++i;
}
return -1;
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,72 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "scene/Model.h"
namespace cc {
namespace scene {
class Camera;
}
namespace gfx {
class Device;
class RenderPass;
class CommandBuffer;
class Shader;
} // namespace gfx
namespace pipeline {
class RenderPipeline;
class InstanceBuffer;
class RenderInstancedQueue;
class CC_DLL PlanarShadowQueue final {
public:
explicit PlanarShadowQueue(RenderPipeline *pipeline);
~PlanarShadowQueue();
void clear();
void gatherShadowPasses(scene::Camera *camera, gfx::CommandBuffer *cmdBuffer);
void recordCommandBuffer(gfx::Device *, gfx::RenderPass *, gfx::CommandBuffer *, uint32_t subpassID = 0);
void destroy();
int getShadowPassIndex(const scene::SubModel *subModel) const;
private:
// weak reference
RenderPipeline *_pipeline{nullptr};
// manage memory manually
RenderInstancedQueue *_instancedQueue{nullptr};
uint32_t _phaseID = 0;
// weak reference
ccstd::vector<const scene::Model *> _castModels;
// weak reference
ccstd::vector<const scene::SubModel *> _subModelArray;
// weak reference
ccstd::vector<const scene::Pass *> _passArray;
// weak reference
ccstd::vector<gfx::Shader *> _shaderArray;
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,215 @@
/****************************************************************************
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "ReflectionProbeBatchedQueue.h"
#include "Define.h"
#include "InstancedBuffer.h"
#include "PipelineSceneData.h"
#include "PipelineStateManager.h"
#include "RenderInstancedQueue.h"
#include "core/geometry/AABB.h"
#include "core/geometry/Intersect.h"
#include "forward/ForwardPipeline.h"
#include "gfx-base/GFXCommandBuffer.h"
#include "gfx-base/GFXDevice.h"
#include "renderer/core/ProgramLib.h"
#include "scene/Camera.h"
#include "scene/Define.h"
#include "scene/ReflectionProbe.h"
#include "scene/ReflectionProbeManager.h"
#include "scene/Skybox.h"
namespace cc {
namespace pipeline {
const ccstd::string CC_USE_RGBE_OUTPUT = "CC_USE_RGBE_OUTPUT";
const cc::scene::IMacroPatch MACRO_PATCH_RGBE_OUTPUT{CC_USE_RGBE_OUTPUT, true};
ReflectionProbeBatchedQueue::ReflectionProbeBatchedQueue(RenderPipeline *pipeline)
: _phaseID(getPhaseID("default")), _phaseReflectMapID(getPhaseID("reflect-map")) {
_pipeline = pipeline;
_instancedQueue = ccnew RenderInstancedQueue;
}
ReflectionProbeBatchedQueue::~ReflectionProbeBatchedQueue() {
destroy();
}
void ReflectionProbeBatchedQueue::destroy() {
CC_SAFE_DELETE(_instancedQueue)
}
void ReflectionProbeBatchedQueue::gatherRenderObjects(const scene::Camera *camera, gfx::CommandBuffer *cmdBuffer, const scene::ReflectionProbe *probe) {
if (probe == nullptr) {
return;
}
clear();
const PipelineSceneData *sceneData = _pipeline->getPipelineSceneData();
const scene::Skybox *skyBox = sceneData->getSkybox();
const scene::RenderScene *const scene = camera->getScene();
if (static_cast<uint32_t>(probe->getCamera()->getClearFlag()) & skyboxFlag) {
if (skyBox != nullptr && skyBox->isEnabled() && skyBox->getModel()) {
add(skyBox->getModel());
}
}
for (const auto &model : scene->getModels()) {
const auto *node = model->getNode();
const auto *worldBounds = model->getWorldBounds();
if (scene->isCulledByLod(camera, model)) {
continue;
}
if (!node || !model->isEnabled() || !worldBounds || !model->getBakeToReflectionProbe()) continue;
uint32_t visibility = probe->getVisibility();
if (((visibility & node->getLayer()) != node->getLayer()) && (!(visibility & static_cast<uint32_t>(model->getVisFlags())))) {
continue;
}
if (probe->getProbeType() == scene::ReflectionProbe::ProbeType::CUBE) {
if (aabbWithAABB(*worldBounds, *probe->getBoundingBox())) {
add(model);
}
} else {
if (worldBounds->aabbFrustum(probe->getCamera()->getFrustum())) {
add(model);
}
}
}
_instancedQueue->uploadBuffers(cmdBuffer);
}
void ReflectionProbeBatchedQueue::clear() {
_subModels.clear();
_shaders.clear();
_passes.clear();
_rgbeSubModels.clear();
if (_instancedQueue) _instancedQueue->clear();
}
void ReflectionProbeBatchedQueue::add(const scene::Model *model) {
for (const auto &subModel : model->getSubModels()) {
// Filter transparent objects
const bool isTransparent = subModel->getPass(0)->getBlendState()->targets[0].blend;
if (isTransparent) {
continue;
}
auto passIdx = getReflectMapPassIndex(subModel);
bool bUseReflectPass = true;
if (passIdx == -1) {
passIdx = getDefaultPassIndex(subModel);
bUseReflectPass = false;
}
if (passIdx == -1) {
continue;
}
auto *pass = subModel->getPass(passIdx);
const auto batchingScheme = pass->getBatchingScheme();
if (!bUseReflectPass) {
_patches.clear();
for (const auto &patch : subModel->getPatches()) {
_patches.push_back(patch);
}
_patches.emplace_back(MACRO_PATCH_RGBE_OUTPUT);
subModel->onMacroPatchesStateChanged(_patches);
_rgbeSubModels.emplace_back(subModel);
}
if (batchingScheme == scene::BatchingSchemes::INSTANCING) {
auto *instancedBuffer = subModel->getPass(passIdx)->getInstancedBuffer();
instancedBuffer->merge(subModel, passIdx);
_instancedQueue->add(instancedBuffer);
} else { // standard draw
_subModels.emplace_back(subModel);
_shaders.emplace_back(subModel->getShader(passIdx));
_passes.emplace_back(pass);
}
}
}
void ReflectionProbeBatchedQueue::recordCommandBuffer(gfx::Device *device, gfx::RenderPass *renderPass, gfx::CommandBuffer *cmdBuffer) {
_instancedQueue->recordCommandBuffer(device, renderPass, cmdBuffer);
for (size_t i = 0; i < _subModels.size(); i++) {
const auto *const subModel = _subModels[i];
auto *const shader = _shaders[i];
const auto *pass = _passes[i];
auto *const ia = subModel->getInputAssembler();
auto *const pso = PipelineStateManager::getOrCreatePipelineState(pass, shader, ia, renderPass);
cmdBuffer->bindPipelineState(pso);
cmdBuffer->bindDescriptorSet(materialSet, pass->getDescriptorSet());
cmdBuffer->bindDescriptorSet(localSet, subModel->getDescriptorSet());
cmdBuffer->bindInputAssembler(ia);
cmdBuffer->draw(ia);
}
resetMacro();
if (_instancedQueue) _instancedQueue->clear();
}
void ReflectionProbeBatchedQueue::resetMacro() {
for (const auto &subModel : _rgbeSubModels) {
_patches.clear();
for (const auto &patch : subModel->getPatches()) {
_patches.push_back(patch);
}
for (auto iter = _patches.begin(); iter != _patches.end(); iter++) {
if (iter->name == CC_USE_RGBE_OUTPUT) {
_patches.erase(iter);
const_cast<scene::SubModel *>(subModel)->onMacroPatchesStateChanged(_patches);
break;
}
}
}
}
bool ReflectionProbeBatchedQueue::isUseReflectMapPass(const scene::SubModel *subModel) const {
auto passIdx = getReflectMapPassIndex(subModel);
return passIdx != -1;
}
int ReflectionProbeBatchedQueue::getDefaultPassIndex(const scene::SubModel *subModel) const {
int i = 0;
for (const auto &pass : *(subModel->getPasses())) {
if (pass->getPhase() == _phaseID) {
return i;
}
++i;
}
return -1;
}
int ReflectionProbeBatchedQueue::getReflectMapPassIndex(const scene::SubModel *subModel) const {
int i = 0;
for (const auto &pass : *(subModel->getPasses())) {
if (pass->getPhase() == _phaseReflectMapID) {
return i;
}
++i;
}
return -1;
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,79 @@
/****************************************************************************
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "Define.h"
#include "cocos/base/Macros.h"
#include "scene/Define.h"
namespace cc {
namespace scene {
class Camera;
class Pass;
class ReflectionProbe;
} // namespace scene
namespace pipeline {
struct RenderObject;
class RenderInstancedQueue;
class RenderPipeline;
//const uint32_t phaseID(PassPhase::getPhaseID("shadow-caster"));
class CC_DLL ReflectionProbeBatchedQueue final {
public:
explicit ReflectionProbeBatchedQueue(RenderPipeline *);
~ReflectionProbeBatchedQueue();
void destroy();
void clear();
void gatherRenderObjects(const scene::Camera *, gfx::CommandBuffer *, const scene::ReflectionProbe *probe);
void add(const scene::Model *);
void recordCommandBuffer(gfx::Device *, gfx::RenderPass *, gfx::CommandBuffer *);
void resetMacro();
bool isUseReflectMapPass(const scene::SubModel *subModel) const;
private:
int getDefaultPassIndex(const scene::SubModel *subModel) const;
int getReflectMapPassIndex(const scene::SubModel *subModel) const;
// weak reference
RenderPipeline *_pipeline{nullptr};
// weak reference
ccstd::vector<const scene::SubModel *> _subModels;
// weak reference
ccstd::vector<scene::Pass *> _passes;
// weak reference
ccstd::vector<gfx::Shader *> _shaders;
// manage memory manually
RenderInstancedQueue *_instancedQueue{nullptr};
uint32_t _phaseID{0};
uint32_t _phaseReflectMapID{0};
ccstd::vector<const scene::SubModel *> _rgbeSubModels;
ccstd::vector<scene::IMacroPatch> _patches;
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,530 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "RenderAdditiveLightQueue.h"
#include "Define.h"
#include "GlobalDescriptorSetManager.h"
#include "InstancedBuffer.h"
#include "PipelineSceneData.h"
#include "PipelineStateManager.h"
#include "PipelineUBO.h"
#include "RenderInstancedQueue.h"
#include "base/Utils.h"
#include "forward/ForwardPipeline.h"
#include "gfx-base/GFXDevice.h"
#include "scene/Camera.h"
#include "scene/DirectionalLight.h"
#include "scene/Light.h"
#include "scene/Pass.h"
#include "scene/PointLight.h"
#include "scene/RangedDirectionalLight.h"
#include "scene/RenderScene.h"
#include "scene/Shadow.h"
#include "scene/SphereLight.h"
#include "scene/SpotLight.h"
namespace cc {
namespace pipeline {
RenderAdditiveLightQueue::RenderAdditiveLightQueue(RenderPipeline *pipeline) : _pipeline(pipeline) {
auto *device = gfx::Device::getInstance();
const auto alignment = device->getCapabilities().uboOffsetAlignment;
_lightBufferStride = ((UBOForwardLight::SIZE + alignment - 1) / alignment) * alignment;
_lightBufferElementCount = _lightBufferStride / sizeof(float);
_lightBuffer = device->createBuffer({
gfx::BufferUsageBit::UNIFORM | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::HOST | gfx::MemoryUsageBit::DEVICE,
_lightBufferStride * _lightBufferCount,
_lightBufferStride,
});
_firstLightBufferView = device->createBuffer({_lightBuffer, 0, UBOForwardLight::SIZE});
_lightBufferData.resize(static_cast<size_t>(_lightBufferElementCount) * _lightBufferCount);
_dynamicOffsets.resize(1, 0);
_phaseID = getPhaseID("forward-add");
_shadowUBO.fill(0.F);
}
void RenderAdditiveLightQueue::recordCommandBuffer(gfx::Device *device, scene::Camera *camera, gfx::RenderPass *renderPass, gfx::CommandBuffer *cmdBuffer) {
const uint32_t offset = _pipeline->getPipelineUBO()->getCurrentCameraUBOOffset();
for (uint32_t i = 0; i < _instancedQueues.size(); ++i) {
const auto *light = _instancedLightPass.lights[i];
_dynamicOffsets[0] = _instancedLightPass.dynamicOffsets[i];
auto *globalDescriptorSet = _pipeline->getGlobalDSManager()->getOrCreateDescriptorSet(light);
_instancedQueues[i]->recordCommandBuffer(device, renderPass, cmdBuffer, globalDescriptorSet, offset, &_dynamicOffsets);
}
const bool enableOcclusionQuery = _pipeline->isOcclusionQueryEnabled();
for (const auto &lightPass : _lightPasses) {
const auto *const subModel = lightPass.subModel;
if (!enableOcclusionQuery || !_pipeline->isOccluded(camera, subModel)) {
const auto *pass = lightPass.pass;
const auto &dynamicOffsets = lightPass.dynamicOffsets;
auto *shader = lightPass.shader;
const auto lights = lightPass.lights;
auto *ia = subModel->getInputAssembler();
auto *pso = PipelineStateManager::getOrCreatePipelineState(pass, shader, ia, renderPass);
auto *descriptorSet = subModel->getDescriptorSet();
cmdBuffer->bindPipelineState(pso);
cmdBuffer->bindDescriptorSet(materialSet, pass->getDescriptorSet());
cmdBuffer->bindInputAssembler(ia);
for (size_t i = 0; i < dynamicOffsets.size(); ++i) {
const auto *light = lights[i];
auto *globalDescriptorSet = _pipeline->getGlobalDSManager()->getOrCreateDescriptorSet(light);
_dynamicOffsets[0] = dynamicOffsets[i];
cmdBuffer->bindDescriptorSet(globalSet, globalDescriptorSet, 1, &offset);
cmdBuffer->bindDescriptorSet(localSet, descriptorSet, _dynamicOffsets);
cmdBuffer->draw(ia);
}
}
}
}
void RenderAdditiveLightQueue::gatherLightPasses(const scene::Camera *camera, gfx::CommandBuffer *cmdBuffer) {
static ccstd::vector<uint32_t> lightPassIndices;
clear();
_validPunctualLights = _pipeline->getPipelineSceneData()->getValidPunctualLights();
if (_validPunctualLights.empty()) return;
updateUBOs(camera, cmdBuffer);
updateLightDescriptorSet(camera, cmdBuffer);
const auto &renderObjects = _pipeline->getPipelineSceneData()->getRenderObjects();
for (const auto &renderObject : renderObjects) {
const auto *const model = renderObject.model;
if (!getLightPassIndex(model, &lightPassIndices)) continue;
_lightIndices.clear();
lightCulling(model);
if (_lightIndices.empty()) continue;
int i = 0;
for (const auto &subModel : model->getSubModels()) {
const auto lightPassIdx = lightPassIndices[i];
if (lightPassIdx == UINT_MAX) continue;
auto *pass = subModel->getPass(lightPassIdx);
if (pass == nullptr) continue;
const bool isTransparent = subModel->getPass(0)->getBlendState()->targets[0].blend;
if (isTransparent) {
continue;
}
auto *descriptorSet = subModel->getDescriptorSet();
descriptorSet->bindBuffer(UBOForwardLight::BINDING, _firstLightBufferView);
descriptorSet->update();
addRenderQueue(subModel, model, pass, lightPassIdx);
++i;
}
}
// only for instanced and batched, no light culling applied
for (uint32_t l = 0; l < _validPunctualLights.size(); l++) {
const auto *light = _validPunctualLights[l];
_instancedLightPass.lights.emplace_back(light);
_instancedLightPass.dynamicOffsets.emplace_back(_lightBufferStride * l);
}
for (const auto &instancedQueue : _instancedQueues) {
instancedQueue->uploadBuffers(cmdBuffer);
}
}
void RenderAdditiveLightQueue::clear() {
for (const auto &instancedQueue : _instancedQueues) {
instancedQueue->clear();
}
_instancedQueues.clear();
for (auto lightPass : _lightPasses) {
lightPass.dynamicOffsets.clear();
lightPass.lights.clear();
}
_lightPasses.clear();
_instancedLightPass.dynamicOffsets.clear();
_instancedLightPass.lights.clear();
}
bool RenderAdditiveLightQueue::cullSphereLight(const scene::SphereLight *light, const scene::Model *model) {
return model->getWorldBounds() && !model->getWorldBounds()->aabbAabb(light->getAABB());
}
bool RenderAdditiveLightQueue::cullSpotLight(const scene::SpotLight *light, const scene::Model *model) {
return model->getWorldBounds() && (!model->getWorldBounds()->aabbAabb(light->getAABB()) || !model->getWorldBounds()->aabbFrustum(light->getFrustum()));
}
bool RenderAdditiveLightQueue::cullPointLight(const scene::PointLight *light, const scene::Model *model) {
return model->getWorldBounds() && !model->getWorldBounds()->aabbAabb(light->getAABB());
}
bool RenderAdditiveLightQueue::cullRangedDirLight(const scene::RangedDirectionalLight *light, const scene::Model *model) {
geometry::AABB rangedDirLightBoundingBox(0.0F, 0.0F, 0.0F, 0.5F, 0.5F, 0.5F);
light->getNode()->updateWorldTransform();
rangedDirLightBoundingBox.transform(light->getNode()->getWorldMatrix(), &rangedDirLightBoundingBox);
return model->getWorldBounds() && (!model->getWorldBounds()->aabbAabb(rangedDirLightBoundingBox));
}
void RenderAdditiveLightQueue::addRenderQueue(scene::SubModel *subModel, const scene::Model *model, scene::Pass *pass, uint32_t lightPassIdx) {
const auto lightCount = _lightIndices.size();
const auto batchingScheme = pass->getBatchingScheme();
AdditiveLightPass lightPass;
if (batchingScheme == scene::BatchingSchemes::NONE) {
lightPass.subModel = subModel;
lightPass.pass = pass;
lightPass.shader = subModel->getShader(lightPassIdx);
lightPass.dynamicOffsets.resize(lightCount);
}
for (uint32_t i = 0; i < lightCount; ++i) {
const auto lightIdx = _lightIndices[i];
const auto *light = _validPunctualLights[lightIdx];
const auto visibility = light->getVisibility();
if ((visibility & model->getNode()->getLayer()) == model->getNode()->getLayer()) {
switch (batchingScheme) {
case scene::BatchingSchemes::INSTANCING: {
auto *buffer = pass->getInstancedBuffer(i);
buffer->merge(subModel, lightPassIdx);
buffer->setDynamicOffset(0, _lightBufferStride);
if (i >= _instancedQueues.size()) {
_instancedQueues.emplace_back(ccnew RenderInstancedQueue());
}
_instancedQueues[i]->add(buffer);
} break;
case scene::BatchingSchemes::NONE: {
lightPass.lights.emplace_back(light);
lightPass.dynamicOffsets[i] = _lightBufferStride * lightIdx;
} break;
}
} else {
lightPass.dynamicOffsets.clear();
}
}
if (batchingScheme == scene::BatchingSchemes::NONE) {
_lightPasses.emplace_back(std::move(lightPass));
}
}
void RenderAdditiveLightQueue::updateUBOs(const scene::Camera *camera, gfx::CommandBuffer *cmdBuffer) {
const auto exposure = camera->getExposure();
const auto validLightCount = _validPunctualLights.size();
const auto *sceneData = _pipeline->getPipelineSceneData();
const auto *shadowInfo = sceneData->getShadows();
size_t offset = 0;
if (validLightCount > _lightBufferCount) {
_lightBufferCount = nextPow2(static_cast<uint32_t>(validLightCount));
_lightBuffer->resize(utils::toUint(_lightBufferStride * _lightBufferCount));
_lightBufferData.resize(static_cast<size_t>(_lightBufferElementCount) * _lightBufferCount);
auto *device = gfx::Device::getInstance();
_firstLightBufferView = device->createBuffer({_lightBuffer, 0, UBOForwardLight::SIZE});
}
for (unsigned l = 0; l < validLightCount; l++, offset += _lightBufferElementCount) {
const auto *light = _validPunctualLights[l];
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<const scene::SphereLight *>(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<const scene::SpotLight *>(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<const scene::PointLight *>(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<const scene::RangedDirectionalLight *>(light);
position = rangedDirLight->getPosition();
size = 0.0F;
range = 0.0F;
luminanceHDR = rangedDirLight->getIlluminanceHDR();
luminanceLDR = rangedDirLight->getIlluminanceLDR();
}
auto index = offset + UBOForwardLight::LIGHT_POS_OFFSET;
_lightBufferData[index++] = position.x;
_lightBufferData[index++] = position.y;
_lightBufferData[index] = position.z;
index = offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET;
_lightBufferData[index++] = size;
_lightBufferData[index] = range;
index = offset + UBOForwardLight::LIGHT_COLOR_OFFSET;
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 (sceneData->isHDR()) {
_lightBufferData[index] = luminanceHDR * exposure * _lightMeterScale;
} else {
_lightBufferData[index] = luminanceLDR;
}
switch (light->getType()) {
case scene::LightType::SPHERE:
_lightBufferData[offset + UBOForwardLight::LIGHT_POS_OFFSET + 3] = static_cast<float>(scene::LightType::SPHERE);
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 2] = 0;
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 3] = 0;
break;
case scene::LightType::SPOT: {
const auto *spotLight = static_cast<const scene::SpotLight *>(light);
_lightBufferData[offset + UBOForwardLight::LIGHT_POS_OFFSET + 3] = static_cast<float>(scene::LightType::SPOT);
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 2] = spotLight->getSpotAngle();
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 3] = (shadowInfo->isEnabled() &&
spotLight->isShadowEnabled() &&
shadowInfo->getType() == scene::ShadowType::SHADOW_MAP)
? 1.0F
: 0.0F;
index = offset + 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 + UBOForwardLight::LIGHT_POS_OFFSET + 3] = static_cast<float>(scene::LightType::POINT);
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 2] = 0;
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 3] = 0;
break;
case scene::LightType::RANGED_DIRECTIONAL: {
_lightBufferData[offset + UBOForwardLight::LIGHT_POS_OFFSET + 3] = static_cast<float>(scene::LightType::RANGED_DIRECTIONAL);
const auto *rangedDirLight = static_cast<const scene::RangedDirectionalLight *>(light);
const Vec3 &right = rangedDirLight->getRight();
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 0] = right.x;
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 1] = right.y;
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 2] = right.z;
_lightBufferData[offset + UBOForwardLight::LIGHT_SIZE_RANGE_ANGLE_OFFSET + 3] = 0;
const auto &direction = rangedDirLight->getDirection();
_lightBufferData[offset + UBOForwardLight::LIGHT_DIR_OFFSET + 0] = direction.x;
_lightBufferData[offset + UBOForwardLight::LIGHT_DIR_OFFSET + 1] = direction.y;
_lightBufferData[offset + UBOForwardLight::LIGHT_DIR_OFFSET + 2] = direction.z;
_lightBufferData[offset + UBOForwardLight::LIGHT_DIR_OFFSET + 3] = 0;
const auto &scale = rangedDirLight->getScale();
_lightBufferData[offset + UBOForwardLight::LIGHT_BOUNDING_SIZE_VS_OFFSET + 0] = scale.x * 0.5F;
_lightBufferData[offset + UBOForwardLight::LIGHT_BOUNDING_SIZE_VS_OFFSET + 1] = scale.y * 0.5F;
_lightBufferData[offset + UBOForwardLight::LIGHT_BOUNDING_SIZE_VS_OFFSET + 2] = scale.z * 0.5F;
_lightBufferData[offset + UBOForwardLight::LIGHT_BOUNDING_SIZE_VS_OFFSET + 3] = 0;
} break;
default:
break;
}
}
cmdBuffer->updateBuffer(_lightBuffer, _lightBufferData.data(), static_cast<uint32_t>(_lightBufferData.size() * sizeof(float)));
}
void RenderAdditiveLightQueue::updateLightDescriptorSet(const scene::Camera *camera, gfx::CommandBuffer *cmdBuffer) {
const auto *sceneData = _pipeline->getPipelineSceneData();
auto *shadowInfo = sceneData->getShadows();
const auto *const scene = camera->getScene();
const auto *device = gfx::Device::getInstance();
const bool hFTexture = supportsR32FloatTexture(device);
const float packing = hFTexture ? 0.0F : 1.0F;
const scene::Light *mainLight = scene->getMainLight();
const auto cap = _pipeline->getDevice()->getCapabilities();
for (const auto *light : _validPunctualLights) {
auto *descriptorSet = _pipeline->getGlobalDSManager()->getOrCreateDescriptorSet(light);
if (!descriptorSet) {
continue;
}
_shadowUBO.fill(0.0F);
switch (light->getType()) {
case scene::LightType::SPHERE: {
// update planar PROJ
if (mainLight) {
PipelineUBO::updatePlanarNormalAndDistance(shadowInfo, &_shadowUBO);
}
// Reserve sphere light shadow interface
const auto &shadowSize = shadowInfo->getSize();
float shadowWHPBInfos[4] = {shadowSize.x, shadowSize.y, 1.0F, 0.0F};
memcpy(_shadowUBO.data() + UBOShadow::SHADOW_WIDTH_HEIGHT_PCF_BIAS_INFO_OFFSET, &shadowWHPBInfos, sizeof(float) * 4);
float shadowLPNNInfos[4] = {static_cast<float>(scene::LightType::SPHERE), packing, 0.0F, 0.0F};
memcpy(_shadowUBO.data() + UBOShadow::SHADOW_LIGHT_PACKING_NBIAS_NULL_INFO_OFFSET, &shadowLPNNInfos, sizeof(float) * 4);
} break;
case scene::LightType::SPOT: {
const auto *spotLight = static_cast<const scene::SpotLight *>(light);
// update planar PROJ
if (mainLight) {
PipelineUBO::updatePlanarNormalAndDistance(shadowInfo, &_shadowUBO);
}
const auto &matShadowCamera = light->getNode()->getWorldMatrix();
const auto matShadowView = matShadowCamera.getInversed();
cc::Mat4 matShadowProj;
cc::Mat4::createPerspective(spotLight->getAngle(), 1.0F, 0.001F, spotLight->getRange(), true, cap.clipSpaceMinZ, cap.clipSpaceSignY, 0, &matShadowProj);
cc::Mat4 matShadowViewProj = matShadowProj;
cc::Mat4 matShadowInvProj = matShadowProj;
matShadowInvProj.inverse();
matShadowViewProj.multiply(matShadowView);
memcpy(_shadowUBO.data() + UBOShadow::MAT_LIGHT_VIEW_OFFSET, matShadowView.m, sizeof(matShadowView));
memcpy(_shadowUBO.data() + UBOShadow::MAT_LIGHT_VIEW_PROJ_OFFSET, matShadowViewProj.m, sizeof(matShadowViewProj));
// shadow info
float shadowNFLSInfos[4] = {0.1F, spotLight->getRange(), 0.0F, 0.0F};
memcpy(_shadowUBO.data() + UBOShadow::SHADOW_NEAR_FAR_LINEAR_SATURATION_INFO_OFFSET, &shadowNFLSInfos, sizeof(shadowNFLSInfos));
const auto &shadowSize = shadowInfo->getSize();
float shadowWHPBInfos[4] = {shadowSize.x, shadowSize.y, spotLight->getShadowPcf(), spotLight->getShadowBias()};
memcpy(_shadowUBO.data() + UBOShadow::SHADOW_WIDTH_HEIGHT_PCF_BIAS_INFO_OFFSET, &shadowWHPBInfos, sizeof(shadowWHPBInfos));
float shadowLPNNInfos[4] = {static_cast<float>(scene::LightType::SPOT), packing, spotLight->getShadowNormalBias(), 0.0F};
memcpy(_shadowUBO.data() + UBOShadow::SHADOW_LIGHT_PACKING_NBIAS_NULL_INFO_OFFSET, &shadowLPNNInfos, sizeof(float) * 4);
float shadowInvProjDepthInfos[4] = {matShadowInvProj.m[10], matShadowInvProj.m[14], matShadowInvProj.m[11], matShadowInvProj.m[15]};
memcpy(_shadowUBO.data() + UBOShadow::SHADOW_INV_PROJ_DEPTH_INFO_OFFSET, &shadowInvProjDepthInfos, sizeof(shadowInvProjDepthInfos));
float shadowProjDepthInfos[4] = {matShadowProj.m[10], matShadowProj.m[14], matShadowProj.m[11], matShadowProj.m[15]};
memcpy(_shadowUBO.data() + UBOShadow::SHADOW_PROJ_DEPTH_INFO_OFFSET, &shadowProjDepthInfos, sizeof(shadowProjDepthInfos));
float shadowProjInfos[4] = {matShadowProj.m[00], matShadowProj.m[05], 1.0F / matShadowProj.m[00], 1.0F / matShadowProj.m[05]};
memcpy(_shadowUBO.data() + UBOShadow::SHADOW_PROJ_INFO_OFFSET, &shadowProjInfos, sizeof(shadowProjInfos));
// Spot light sampler binding
const auto &shadowFramebufferMap = sceneData->getShadowFramebufferMap();
if (shadowFramebufferMap.count(light) > 0) {
auto *texture = shadowFramebufferMap.at(light)->getColorTextures()[0];
if (texture) {
descriptorSet->bindTexture(SPOTSHADOWMAP::BINDING, texture);
}
}
} break;
case scene::LightType::POINT: {
// update planar PROJ
if (mainLight) {
PipelineUBO::updatePlanarNormalAndDistance(shadowInfo, &_shadowUBO);
}
// Reserve point light shadow interface
const auto &shadowSize = shadowInfo->getSize();
float shadowWHPBInfos[4] = {shadowSize.x, shadowSize.y, 1.0F, 0.0F};
memcpy(_shadowUBO.data() + UBOShadow::SHADOW_WIDTH_HEIGHT_PCF_BIAS_INFO_OFFSET, &shadowWHPBInfos, sizeof(float) * 4);
float shadowLPNNInfos[4] = {static_cast<float>(scene::LightType::POINT), packing, 0.0F, 0.0F};
memcpy(_shadowUBO.data() + UBOShadow::SHADOW_LIGHT_PACKING_NBIAS_NULL_INFO_OFFSET, &shadowLPNNInfos, sizeof(float) * 4);
} break;
default:
break;
}
memcpy(_shadowUBO.data() + UBOShadow::SHADOW_COLOR_OFFSET, shadowInfo->getShadowColor4f().data(), sizeof(float) * 4);
descriptorSet->update();
cmdBuffer->updateBuffer(descriptorSet->getBuffer(UBOShadow::BINDING), _shadowUBO.data(), UBOShadow::SIZE);
}
}
bool RenderAdditiveLightQueue::getLightPassIndex(const scene::Model *model, ccstd::vector<uint32_t> *lightPassIndices) const {
lightPassIndices->clear();
bool hasValidLightPass = false;
for (const auto &subModel : model->getSubModels()) {
int lightPassIndex = 0;
for (const auto &pass : *(subModel->getPasses())) {
if (pass->getPhase() == _phaseID) {
hasValidLightPass = true;
break;
}
++lightPassIndex;
}
lightPassIndices->push_back(lightPassIndex);
}
return hasValidLightPass;
}
void RenderAdditiveLightQueue::lightCulling(const scene::Model *model) {
bool isCulled = false;
for (size_t i = 0; i < _validPunctualLights.size(); i++) {
const auto *const light = _validPunctualLights[i];
switch (light->getType()) {
case scene::LightType::SPHERE:
isCulled = cullSphereLight(static_cast<const scene::SphereLight *>(light), model);
break;
case scene::LightType::SPOT:
isCulled = cullSpotLight(static_cast<const scene::SpotLight *>(light), model);
break;
case scene::LightType::POINT:
isCulled = cullSphereLight(static_cast<const scene::SphereLight *>(light), model);
break;
case scene::LightType::RANGED_DIRECTIONAL:
isCulled = cullRangedDirLight(static_cast<const scene::RangedDirectionalLight *>(light), model);
break;
default:
isCulled = false;
break;
}
if (!isCulled) {
_lightIndices.emplace_back(utils::toUint(i));
}
}
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,108 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "Define.h"
#include "base/Ptr.h"
#include "base/std/container/array.h"
namespace cc {
namespace scene {
class Camera;
class Pass;
class Light;
class SpotLight;
class SphereLight;
class PointLight;
class RangedDirectionalLight;
} // namespace scene
namespace pipeline {
struct RenderObject;
class RenderPipeline;
class RenderInstancedQueue;
class ForwardPipeline;
struct AdditiveLightPass {
const scene::SubModel *subModel{nullptr}; // weak reference
const scene::Pass *pass{nullptr}; // weak reference
gfx::Shader *shader{nullptr}; //weak reference
ccstd::vector<uint32_t> dynamicOffsets;
ccstd::vector<const scene::Light *> lights; //light is weak reference
};
class RenderAdditiveLightQueue final {
public:
explicit RenderAdditiveLightQueue(RenderPipeline *pipeline);
~RenderAdditiveLightQueue() = default;
void recordCommandBuffer(gfx::Device *device, scene::Camera *camera, gfx::RenderPass *renderPass, gfx::CommandBuffer *cmdBuffer);
void gatherLightPasses(const scene::Camera *camera, gfx::CommandBuffer *cmdBuffer);
private:
static bool cullSphereLight(const scene::SphereLight *light, const scene::Model *model);
static bool cullSpotLight(const scene::SpotLight *light, const scene::Model *model);
static bool cullPointLight(const scene::PointLight *light, const scene::Model *model);
static bool cullRangedDirLight(const scene::RangedDirectionalLight *light, const scene::Model *model);
void clear();
void addRenderQueue(scene::SubModel *subModel, const scene::Model *model, scene::Pass *pass, uint32_t lightPassIdx);
void updateUBOs(const scene::Camera *camera, gfx::CommandBuffer *cmdBuffer);
void updateLightDescriptorSet(const scene::Camera *camera, gfx::CommandBuffer *cmdBuffer);
bool getLightPassIndex(const scene::Model *model, ccstd::vector<uint32_t> *lightPassIndices) const;
void lightCulling(const scene::Model *model);
uint32_t _lightBufferStride{0};
uint32_t _lightBufferElementCount{0};
uint32_t _lightBufferCount{16};
uint32_t _phaseID{0};
// weak reference
RenderPipeline *_pipeline{nullptr};
IntrusivePtr<gfx::Buffer> _lightBuffer;
IntrusivePtr<gfx::Buffer> _firstLightBufferView;
float _lightMeterScale{10000.0F};
AdditiveLightPass _instancedLightPass;
ccstd::vector<uint32_t> _dynamicOffsets;
ccstd::vector<uint32_t> _lightIndices;
ccstd::vector<float> _lightBufferData;
ccstd::array<float, UBOShadow::COUNT> _shadowUBO{};
// weak reference
ccstd::vector<const scene::Light *> _validPunctualLights;
ccstd::vector<IntrusivePtr<RenderInstancedQueue>> _instancedQueues;
ccstd::vector<AdditiveLightPass> _lightPasses;
ccstd::vector<ccstd::vector<uint32_t>> _sortedPSOCIArray;
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,82 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "RenderFlow.h"
#include <algorithm>
#include "RenderStage.h"
#include "base/memory/Memory.h"
namespace cc {
namespace pipeline {
RenderFlow::RenderFlow() = default;
RenderFlow::~RenderFlow() = default;
bool RenderFlow::initialize(const RenderFlowInfo &info) {
_name = info.name;
_priority = info.priority;
_tag = info.tag;
_stages = info.stages;
_isResourceOwner = false;
return true;
}
void RenderFlow::activate(RenderPipeline *pipeline) {
_pipeline = pipeline;
std::sort(_stages.begin(), _stages.end(), [](const RenderStage *s1, const RenderStage *s2) {
return s1->getPriority() < s2->getPriority();
});
for (auto const &stage : _stages) {
stage->activate(pipeline, this);
}
}
void RenderFlow::render(scene::Camera *camera) {
for (auto const &stage : _stages) {
stage->render(camera);
}
}
void RenderFlow::destroy() {
for (auto &stage : _stages) {
CC_SAFE_DESTROY(stage);
}
_stages.clear();
}
RenderStage *RenderFlow::getRenderstageByName(const ccstd::string &name) const {
for (auto const &node : _stages) {
if (node->getName() == name) {
return node;
}
}
return nullptr;
}
} //namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,78 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "Define.h"
#include "RenderStage.h"
#include "base/RefCounted.h"
namespace cc {
namespace scene {
class Camera;
}
namespace pipeline {
class RenderPipeline;
class RenderStage;
struct CC_DLL RenderFlowInfo {
ccstd::string name;
uint32_t priority = 0;
uint32_t tag = 0;
RenderStageList stages;
};
class CC_DLL RenderFlow : public RefCounted {
public:
RenderFlow();
~RenderFlow() override;
virtual bool initialize(const RenderFlowInfo &info);
virtual void activate(RenderPipeline *pipeline);
virtual void render(scene::Camera *camera);
virtual void destroy();
inline const ccstd::string &getName() const { return _name; }
inline void setName(ccstd::string &name) { _name = name; }
inline uint32_t getPriority() const { return _priority; }
inline void setPriority(uint32_t priority) { _priority = priority; }
inline uint32_t getTag() const { return _tag; }
inline void setTag(uint32_t tag) { _tag = tag; }
inline const RenderStageList &getStages() const { return _stages; }
inline void setStages(const RenderStageList &stages) { _stages = stages; }
RenderStage *getRenderstageByName(const ccstd::string &name) const;
protected:
RenderStageList _stages;
ccstd::string _name;
// weak reference
RenderPipeline *_pipeline{nullptr};
uint32_t _priority{0};
uint32_t _tag{0};
bool _isResourceOwner{false};
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,103 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "RenderInstancedQueue.h"
#include "InstancedBuffer.h"
#include "PipelineStateManager.h"
#include "gfx-base/GFXCommandBuffer.h"
#include "gfx-base/GFXDescriptorSet.h"
#include "gfx-base/GFXDevice.h"
#include "gfx-base/GFXRenderPass.h"
namespace cc {
namespace pipeline {
void RenderInstancedQueue::clear() {
for (auto *it : _queues) {
it->clear();
}
_renderQueues.clear();
_queues.clear();
}
void RenderInstancedQueue::sort() {
std::copy(_queues.cbegin(), _queues.cend(), std::back_inserter(_renderQueues));
auto isOpaque = [](const InstancedBuffer *instance) {
return instance->getPass()->getBlendState()->targets[0].blend == 0;
};
std::stable_partition(_renderQueues.begin(), _renderQueues.end(), isOpaque);
}
void RenderInstancedQueue::uploadBuffers(gfx::CommandBuffer *cmdBuffer) {
for (auto *instanceBuffer : _queues) {
if (instanceBuffer->hasPendingModels()) {
instanceBuffer->uploadBuffers(cmdBuffer);
}
}
}
void RenderInstancedQueue::recordCommandBuffer(gfx::Device * /*device*/, gfx::RenderPass *renderPass, gfx::CommandBuffer *cmdBuffer,
gfx::DescriptorSet *ds, uint32_t offset, const ccstd::vector<uint32_t> *dynamicOffsets) {
auto recordCommands = [&](const auto &renderQueue) {
for (const auto *instanceBuffer : renderQueue) {
if (!instanceBuffer->hasPendingModels()) continue;
const auto &instances = instanceBuffer->getInstances();
const auto *pass = instanceBuffer->getPass();
cmdBuffer->bindDescriptorSet(materialSet, pass->getDescriptorSet());
gfx::PipelineState *lastPSO = nullptr;
for (const auto &instance : instances) {
if (!instance.drawInfo.instanceCount) {
continue;
}
auto *pso = PipelineStateManager::getOrCreatePipelineState(pass, instance.shader, instance.ia, renderPass);
if (lastPSO != pso) {
cmdBuffer->bindPipelineState(pso);
lastPSO = pso;
}
if (ds) cmdBuffer->bindDescriptorSet(globalSet, ds, 1, &offset);
if (dynamicOffsets) {
cmdBuffer->bindDescriptorSet(localSet, instance.descriptorSet, *dynamicOffsets);
} else {
cmdBuffer->bindDescriptorSet(localSet, instance.descriptorSet, instanceBuffer->dynamicOffsets());
}
cmdBuffer->bindInputAssembler(instance.ia);
cmdBuffer->draw(instance.ia);
}
}
};
if (_renderQueues.empty()) {
recordCommands(_queues);
} else {
recordCommands(_renderQueues);
}
}
void RenderInstancedQueue::add(InstancedBuffer *instancedBuffer) {
_queues.emplace(instancedBuffer);
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,65 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "Define.h"
#include "base/Macros.h"
#include "base/TypeDef.h"
#include "base/std/container/set.h"
#include "base/std/container/vector.h"
namespace cc {
namespace gfx {
class Device;
class RenderPass;
class CommandBuffer;
class DescriptorSet;
} // namespace gfx
namespace pipeline {
class InstancedBuffer;
class CC_DLL RenderInstancedQueue final : public RefCounted {
public:
RenderInstancedQueue() = default;
~RenderInstancedQueue() override = default;
void recordCommandBuffer(gfx::Device *device, gfx::RenderPass *renderPass, gfx::CommandBuffer *cmdBuffer,
gfx::DescriptorSet *ds = nullptr, uint32_t offset = 0, const ccstd::vector<uint32_t> *dynamicOffsets = nullptr);
void add(InstancedBuffer *instancedBuffer);
void uploadBuffers(gfx::CommandBuffer *cmdBuffer);
void sort();
void clear();
bool empty() { return _queues.empty(); }
private:
// `InstancedBuffer *`: weak reference
ccstd::set<InstancedBuffer *> _queues;
ccstd::vector<InstancedBuffer *> _renderQueues;
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,362 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "RenderPipeline.h"
#if CC_USE_GEOMETRY_RENDERER
#include "GeometryRenderer.h"
#endif
#include "GlobalDescriptorSetManager.h"
#include "InstancedBuffer.h"
#include "PipelineSceneData.h"
#include "PipelineStateManager.h"
#include "PipelineUBO.h"
#include "RenderFlow.h"
#include "base/StringUtil.h"
#include "base/std/hash/hash.h"
#include "frame-graph/FrameGraph.h"
#include "gfx-base/GFXDevice.h"
#include "helper/Utils.h"
#if CC_USE_DEBUG_RENDERER
#include "profiler/DebugRenderer.h"
#endif
#include "custom/NativeBuiltinUtils.h"
#include "scene/Camera.h"
#include "scene/Skybox.h"
namespace cc {
namespace pipeline {
framegraph::StringHandle RenderPipeline::fgStrHandleOutDepthTexture = framegraph::FrameGraph::stringToHandle("depthTexture");
framegraph::StringHandle RenderPipeline::fgStrHandleOutColorTexture = framegraph::FrameGraph::stringToHandle("outputTexture");
framegraph::StringHandle RenderPipeline::fgStrHandlePostprocessPass = framegraph::FrameGraph::stringToHandle("pipelinePostPass");
framegraph::StringHandle RenderPipeline::fgStrHandleBloomOutTexture = framegraph::FrameGraph::stringToHandle("combineTex");
RenderPipeline *RenderPipeline::instance = nullptr;
RenderPipeline *RenderPipeline::getInstance() {
return RenderPipeline::instance;
}
RenderPipeline::RenderPipeline()
: _device(gfx::Device::getInstance()) {
RenderPipeline::instance = this;
_globalDSManager = ccnew GlobalDSManager();
_pipelineUBO = ccnew PipelineUBO();
}
RenderPipeline::~RenderPipeline() {
RenderPipeline::instance = nullptr;
}
bool RenderPipeline::initialize(const RenderPipelineInfo &info) {
_flows = info.flows;
_tag = info.tag;
return true;
}
bool RenderPipeline::isEnvmapEnabled() const {
return _pipelineSceneData->getSkybox()->isUseIBL();
}
bool RenderPipeline::activate(gfx::Swapchain * /*swapchain*/) {
_globalDSManager->activate(_device);
_descriptorSet = _globalDSManager->getGlobalDescriptorSet();
_pipelineUBO->activate(_device, this);
_pipelineSceneData->activate(_device);
#if CC_USE_DEBUG_RENDERER
CC_DEBUG_RENDERER->activate(_device);
#endif
// generate macros here rather than construct func because _clusterEnabled
// switch may be changed in root.ts setRenderPipeline() function which is after
// pipeline construct.
generateConstantMacros();
for (auto const &flow : _flows) {
flow->activate(this);
}
return true;
}
void RenderPipeline::render(const ccstd::vector<scene::Camera *> &cameras) {
for (auto const &flow : _flows) {
for (auto *camera : cameras) {
flow->render(camera);
}
}
RenderPipeline::framegraphGC();
}
void RenderPipeline::onGlobalPipelineStateChanged() {
// do nothing
}
void RenderPipeline::destroyQuadInputAssembler() {
CC_SAFE_DESTROY_AND_DELETE(_quadIB);
for (auto *node : _quadVB) {
CC_SAFE_DESTROY_AND_DELETE(node);
}
for (auto node : _quadIA) {
CC_SAFE_DESTROY_AND_DELETE(node.second);
}
_quadVB.clear();
_quadIA.clear();
}
#if CC_USE_GEOMETRY_RENDERER
void RenderPipeline::updateGeometryRenderer(const ccstd::vector<scene::Camera *> &cameras) {
if (_geometryRenderer) {
return;
}
// Query the first camera rendering to swapchain.
for (const auto *camera : cameras) {
if (camera && camera->getWindow() && camera->getWindow()->getSwapchain()) {
const_cast<scene::Camera *>(camera)->initGeometryRenderer();
_geometryRenderer = camera->getGeometryRenderer();
return;
}
}
}
#endif
bool RenderPipeline::destroy() {
for (auto const &flow : _flows) {
CC_SAFE_DESTROY(flow);
}
_flows.clear();
#if CC_USE_GEOMETRY_RENDERER
_geometryRenderer = nullptr;
#endif
_descriptorSet = nullptr;
CC_SAFE_DESTROY_AND_DELETE(_globalDSManager);
CC_SAFE_DESTROY_AND_DELETE(_pipelineUBO);
CC_SAFE_DESTROY_NULL(_pipelineSceneData);
#if CC_USE_DEBUG_RENDERER
CC_DEBUG_RENDERER->destroy();
#endif
for (auto *const queryPool : _queryPools) {
queryPool->destroy();
}
_queryPools.clear();
for (auto *const cmdBuffer : _commandBuffers) {
cmdBuffer->destroy();
}
_commandBuffers.clear();
PipelineStateManager::destroyAll();
framegraph::FrameGraph::gc(0);
return Super::destroy();
}
gfx::Color RenderPipeline::getClearcolor(scene::Camera *camera) const {
auto *const sceneData = getPipelineSceneData();
gfx::Color clearColor{0.0F, 0.0F, 0.0F, 1.0F};
if (static_cast<uint32_t>(camera->getClearFlag()) & static_cast<uint32_t>(gfx::ClearFlagBit::COLOR)) {
clearColor = camera->getClearColor();
}
clearColor.w = 0.F;
return clearColor;
}
void RenderPipeline::updateQuadVertexData(const Vec4 &viewport, gfx::Buffer *buffer) {
float vbData[16] = {0.F};
genQuadVertexData(viewport, vbData);
buffer->update(vbData, sizeof(vbData));
}
gfx::InputAssembler *RenderPipeline::getIAByRenderArea(const gfx::Rect &renderArea) {
auto bufferWidth{static_cast<float>(_width)};
auto bufferHeight{static_cast<float>(_height)};
Vec4 viewport{
static_cast<float>(renderArea.x) / bufferWidth,
static_cast<float>(renderArea.y) / bufferHeight,
static_cast<float>(renderArea.width) / bufferWidth,
static_cast<float>(renderArea.height) / bufferHeight,
};
const auto iter = _quadIA.find(viewport);
if (iter != _quadIA.end()) {
return iter->second;
}
gfx::Buffer *vb = nullptr;
gfx::InputAssembler *ia = nullptr;
createQuadInputAssembler(_quadIB, &vb, &ia);
_quadVB.push_back(vb);
_quadIA[viewport] = ia;
updateQuadVertexData(viewport, vb);
return ia;
}
bool RenderPipeline::createQuadInputAssembler(gfx::Buffer *quadIB, gfx::Buffer **quadVB, gfx::InputAssembler **quadIA) {
// step 1 create vertex buffer
uint32_t vbStride = sizeof(float) * 4;
uint32_t vbSize = vbStride * 4;
if (*quadVB == nullptr) {
*quadVB = _device->createBuffer({gfx::BufferUsageBit::VERTEX | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::DEVICE, vbSize, vbStride});
}
// step 2 create input assembler
gfx::InputAssemblerInfo info;
info.attributes.push_back({"a_position", gfx::Format::RG32F});
info.attributes.push_back({"a_texCoord", gfx::Format::RG32F});
info.vertexBuffers.push_back(*quadVB);
info.indexBuffer = quadIB;
*quadIA = _device->createInputAssembler(info);
return (*quadIA) != nullptr;
}
void RenderPipeline::ensureEnoughSize(const ccstd::vector<scene::Camera *> &cameras) {
for (auto *camera : cameras) {
_width = std::max(camera->getWindow()->getWidth(), _width);
_height = std::max(camera->getWindow()->getHeight(), _height);
}
}
gfx::Viewport RenderPipeline::getViewport(scene::Camera *camera) {
auto scale{_pipelineSceneData->getShadingScale()};
const gfx::Rect &rect = getRenderArea(camera);
return {
static_cast<int>(static_cast<float>(rect.x) * scale),
static_cast<int>(static_cast<float>(rect.y) * scale),
static_cast<uint32_t>(static_cast<float>(rect.width) * scale),
static_cast<uint32_t>(static_cast<float>(rect.height) * scale)};
}
gfx::Rect RenderPipeline::getScissor(scene::Camera *camera) {
auto scale{_pipelineSceneData->getShadingScale()};
const gfx::Rect &rect = getRenderArea(camera);
return {
static_cast<int>(static_cast<float>(rect.x) * scale),
static_cast<int>(static_cast<float>(rect.y) * scale),
static_cast<uint32_t>(static_cast<float>(rect.width) * scale),
static_cast<uint32_t>(static_cast<float>(rect.height) * scale)};
}
gfx::Rect RenderPipeline::getRenderArea(scene::Camera *camera) {
float w{static_cast<float>(camera->getWindow()->getWidth())};
float h{static_cast<float>(camera->getWindow()->getHeight())};
const auto &vp = camera->getViewport();
return {
static_cast<int32_t>(vp.x * w),
static_cast<int32_t>(vp.y * h),
static_cast<uint32_t>(vp.z * w),
static_cast<uint32_t>(vp.w * h),
};
}
float RenderPipeline::getShadingScale() const {
return _pipelineSceneData->getShadingScale();
}
void RenderPipeline::setShadingScale(float scale) {
_pipelineSceneData->setShadingScale(scale);
}
void RenderPipeline::genQuadVertexData(const Vec4 &viewport, float vbData[16]) {
render::setupQuadVertexBuffer(*_device, viewport, vbData);
}
void RenderPipeline::generateConstantMacros() {
_constantMacros = StringUtil::format(
R"(
#define CC_DEVICE_SUPPORT_FLOAT_TEXTURE %d
#define CC_ENABLE_CLUSTERED_LIGHT_CULLING %d
#define CC_DEVICE_MAX_VERTEX_UNIFORM_VECTORS %d
#define CC_DEVICE_MAX_FRAGMENT_UNIFORM_VECTORS %d
#define CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT %d
#define CC_PLATFORM_ANDROID_AND_WEBGL 0
#define CC_ENABLE_WEBGL_HIGHP_STRUCT_VALUES 0
#define CC_JOINT_UNIFORM_CAPACITY %d
)",
hasAnyFlags(_device->getFormatFeatures(gfx::Format::RGBA32F), gfx::FormatFeature::RENDER_TARGET | gfx::FormatFeature::SAMPLED_TEXTURE),
_clusterEnabled ? 1 : 0,
_device->getCapabilities().maxVertexUniformVectors,
_device->getCapabilities().maxFragmentUniformVectors,
_device->hasFeature(gfx::Feature::INPUT_ATTACHMENT_BENEFIT),
SkinningJointCapacity::jointUniformCapacity);
}
gfx::DescriptorSetLayout *RenderPipeline::getDescriptorSetLayout() const { return _globalDSManager->getDescriptorSetLayout(); }
RenderStage *RenderPipeline::getRenderstageByName(const ccstd::string &name) const {
for (auto const &flow : _flows) {
auto *val = flow->getRenderstageByName(name);
if (val) {
return val;
}
}
return nullptr;
}
bool RenderPipeline::isOccluded(const scene::Camera *camera, const scene::SubModel *subModel) {
auto *model = subModel->getOwner();
auto *worldBound = model->getWorldBounds();
// assume visible if there is no worldBound.
if (!worldBound) {
return false;
}
// assume visible if camera is inside of worldBound.
if (worldBound->contain(camera->getPosition())) {
return false;
}
// assume visible if no query in the last frame.
uint32_t id = subModel->getId();
if (!_queryPools[0]->hasResult(id)) {
return false;
}
// check query results.
return _queryPools[0]->getResult(id) == 0;
}
void RenderPipeline::framegraphGC() {
static uint64_t frameCount{0U};
static constexpr uint32_t INTERVAL_IN_SECONDS = 30;
if (++frameCount % (INTERVAL_IN_SECONDS * 60) == 0) {
framegraph::FrameGraph::gc(INTERVAL_IN_SECONDS * 60);
}
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,210 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "Define.h"
#include "RenderFlow.h"
#include "base/std/container/string.h"
#include "base/std/container/unordered_map.h"
#include "core/assets/Asset.h"
#include "frame-graph/FrameGraph.h"
#include "frame-graph/Handle.h"
#include "renderer/core/PassUtils.h"
#include "scene/Model.h"
namespace cc {
namespace gfx {
class CommandBuffer;
class DescriptorSet;
class DescriptorSetLayout;
} // namespace gfx
namespace scene {
class Camera;
class SubModel;
} // namespace scene
namespace render {
class PipelineRuntime;
} // namespace render
namespace pipeline {
class PipelineUBO;
class PipelineSceneData;
class GlobalDSManager;
class RenderStage;
class GeometryRenderer;
struct CC_DLL RenderPipelineInfo {
uint32_t tag = 0;
RenderFlowList flows;
};
class CC_DLL RenderPipeline : public Asset {
public:
using Super = Asset;
static RenderPipeline *getInstance();
static framegraph::StringHandle fgStrHandleOutDepthTexture;
static framegraph::StringHandle fgStrHandleOutColorTexture;
static framegraph::StringHandle fgStrHandlePostprocessPass;
static framegraph::StringHandle fgStrHandleBloomOutTexture;
static gfx::Rect getRenderArea(scene::Camera *camera);
RenderPipeline();
~RenderPipeline() override;
virtual bool activate(gfx::Swapchain *swapchain);
bool destroy() override;
virtual bool initialize(const RenderPipelineInfo &info);
virtual void render(const ccstd::vector<scene::Camera *> &cameras);
virtual void onGlobalPipelineStateChanged();
inline const RenderFlowList &getFlows() const { return _flows; }
inline void setFlows(const RenderFlowList &flows) { _flows = flows; }
inline uint32_t getTag() const { return _tag; }
inline void setTag(uint32_t tag) { _tag = tag; }
inline const ccstd::unordered_map<ccstd::string, InternalBindingInst> &getGlobalBindings() const { return _globalBindings; }
inline const MacroRecord &getMacros() const { return _macros; }
inline void setValue(const ccstd::string &name, int32_t value) { _macros[name] = value; }
inline void setValue(const ccstd::string &name, bool value) { _macros[name] = value; }
inline void setValue(const ccstd::string &name, const ccstd::string &value) { _macros[name] = value; }
inline GlobalDSManager *getGlobalDSManager() const { return _globalDSManager; }
inline gfx::DescriptorSet *getDescriptorSet() const { return _descriptorSet; }
gfx::DescriptorSetLayout *getDescriptorSetLayout() const;
inline PipelineSceneData *getPipelineSceneData() const { return _pipelineSceneData; }
inline const gfx::CommandBufferList &getCommandBuffers() const { return _commandBuffers; }
inline const gfx::QueryPoolList &getQueryPools() const { return _queryPools; }
inline PipelineUBO *getPipelineUBO() const { return _pipelineUBO; }
inline const ccstd::string &getConstantMacros() const { return _constantMacros; }
inline gfx::Device *getDevice() const { return _device; }
RenderStage *getRenderstageByName(const ccstd::string &name) const;
bool isOccluded(const scene::Camera *camera, const scene::SubModel *subModel);
bool isOcclusionQueryEnabled() const {
#if CC_USE_OCCLUSION_QUERY
return _occlusionQueryEnabled && _device->getCapabilities().supportQuery;
#else
return false;
#endif
}
void setOcclusionQueryEnabled(bool enable) { _occlusionQueryEnabled = enable; }
bool isEnvmapEnabled() const;
gfx::Viewport getViewport(scene::Camera *camera);
gfx::Rect getScissor(scene::Camera *camera);
void genQuadVertexData(const Vec4 &viewport, float data[16]);
uint32_t getWidth() const { return _width; }
uint32_t getHeight() const { return _height; }
framegraph::FrameGraph &getFrameGraph() { return _fg; }
gfx::Color getClearcolor(scene::Camera *camera) const;
gfx::InputAssembler *getIAByRenderArea(const gfx::Rect &renderArea);
void updateQuadVertexData(const Vec4 &viewport, gfx::Buffer *buffer);
void ensureEnoughSize(const ccstd::vector<scene::Camera *> &cameras);
bool createQuadInputAssembler(gfx::Buffer *quadIB, gfx::Buffer **quadVB, gfx::InputAssembler **quadIA);
float getShadingScale() const;
void setShadingScale(float scale);
inline scene::Model *getProfiler() const { return _profiler; }
inline void setProfiler(scene::Model *value) { _profiler = value; }
inline bool isClusterEnabled() const { return _clusterEnabled; }
inline void setClusterEnabled(bool enable) { _clusterEnabled = enable; }
inline bool isBloomEnabled() const { return _bloomEnabled; }
inline void setBloomEnabled(bool enable) { _bloomEnabled = enable; }
inline GeometryRenderer *getGeometryRenderer() const {
#if CC_USE_GEOMETRY_RENDERER
return _geometryRenderer;
#else
return nullptr;
#endif
}
inline void resetRenderQueue(bool reset) { _resetRenderQueue = reset; }
inline bool isRenderQueueReset() const { return _resetRenderQueue; }
render::PipelineRuntime *getPipelineRuntime() const { return _pipelineRuntime; }
void setPipelineRuntime(render::PipelineRuntime *pipelineRuntime) {
_pipelineRuntime = pipelineRuntime;
}
protected:
static RenderPipeline *instance;
void generateConstantMacros();
void destroyQuadInputAssembler();
#if CC_USE_GEOMETRY_RENDERER
void updateGeometryRenderer(const ccstd::vector<scene::Camera *> &cameras);
#endif
static void framegraphGC();
gfx::CommandBufferList _commandBuffers;
gfx::QueryPoolList _queryPools;
RenderFlowList _flows;
ccstd::unordered_map<ccstd::string, InternalBindingInst> _globalBindings;
MacroRecord _macros;
uint32_t _tag{0};
ccstd::string _constantMacros;
// weak reference
gfx::Device *_device{nullptr};
// manage memory manually
GlobalDSManager *_globalDSManager{nullptr};
// weak reference, get from _globalDSManager
gfx::DescriptorSet *_descriptorSet{nullptr};
// manage memory manually
PipelineUBO *_pipelineUBO{nullptr};
IntrusivePtr<scene::Model> _profiler;
IntrusivePtr<PipelineSceneData> _pipelineSceneData;
#if CC_USE_GEOMETRY_RENDERER
IntrusivePtr<GeometryRenderer> _geometryRenderer;
#endif
// has not initBuiltinRes,
// create temporary default Texture to binding sampler2d
uint32_t _width{0};
uint32_t _height{0};
gfx::Buffer *_quadIB{nullptr};
// manage memory manually
ccstd::vector<gfx::Buffer *> _quadVB;
// manage memory manually
ccstd::unordered_map<Vec4, gfx::InputAssembler *, Hasher<Vec4>> _quadIA;
framegraph::FrameGraph _fg;
ccstd::unordered_map<gfx::ClearFlags, gfx::RenderPass *> _renderPasses;
// use cluster culling or not
bool _clusterEnabled{false};
bool _bloomEnabled{false};
bool _occlusionQueryEnabled{false};
bool _resetRenderQueue{true};
render::PipelineRuntime *_pipelineRuntime{nullptr};
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,122 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "RenderQueue.h"
#include <utility>
#include "PipelineSceneData.h"
#include "PipelineStateManager.h"
#include "RenderPipeline.h"
#include "gfx-base/GFXCommandBuffer.h"
#include "gfx-base/GFXDevice.h"
#include "gfx-base/GFXShader.h"
#include "scene/Model.h"
#include "scene/Pass.h"
#include "scene/SubModel.h"
namespace cc {
namespace pipeline {
RenderQueue::RenderQueue(RenderPipeline *pipeline, RenderQueueCreateInfo desc, bool useOcclusionQuery)
: _pipeline(pipeline), _passDesc(std::move(desc)), _useOcclusionQuery(useOcclusionQuery) {
}
void RenderQueue::clear() {
_queue.clear();
}
bool RenderQueue::insertRenderPass(const RenderObject &renderObj, uint32_t subModelIdx, uint32_t passIdx) {
const auto *subModel = renderObj.model->getSubModels()[subModelIdx].get();
const auto *const pass = subModel->getPass(passIdx);
const bool isTransparent = pass->getBlendState()->targets[0].blend;
if (isTransparent != _passDesc.isTransparent || !(pass->getPhase() & _passDesc.phases)) {
return false;
}
auto passPriority = static_cast<uint32_t>(pass->getPriority());
auto modelPriority = static_cast<uint32_t>(subModel->getPriority());
auto shaderId = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(subModel->getShader(passIdx)));
const auto hash = (0 << 30) | (passPriority << 16) | (modelPriority << 8) | passIdx;
const auto priority = renderObj.model->getPriority();
RenderPass renderPass = {priority, hash, renderObj.depth, shaderId, passIdx, subModel};
_queue.emplace_back(renderPass);
return true;
}
void RenderQueue::sort() {
#if CC_PLATFORM != CC_PLATFORM_LINUX && CC_PLATFORM != CC_PLATFORM_QNX
std::sort(_queue.begin(), _queue.end(), _passDesc.sortFunc);
#else
//cannot use std::function as comparator in algorithms https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65942#c11
std::sort(_queue.begin(), _queue.end(), [this](const RenderPass &a, const RenderPass &b) -> bool {
return _passDesc.sortFunc(a, b);
});
#endif
}
void RenderQueue::recordCommandBuffer(gfx::Device * /*device*/, scene::Camera *camera, gfx::RenderPass *renderPass, gfx::CommandBuffer *cmdBuff, uint32_t subpassIndex) {
PipelineSceneData *const sceneData = _pipeline->getPipelineSceneData();
bool enableOcclusionQuery = _pipeline->isOcclusionQueryEnabled() && _useOcclusionQuery;
auto *queryPool = _pipeline->getQueryPools()[0];
for (auto &i : _queue) {
const auto *subModel = i.subModel;
if (enableOcclusionQuery) {
cmdBuff->beginQuery(queryPool, subModel->getId());
}
if (enableOcclusionQuery && _pipeline->isOccluded(camera, subModel)) {
gfx::InputAssembler *inputAssembler = sceneData->getOcclusionQueryInputAssembler();
const scene::Pass *pass = sceneData->getOcclusionQueryPass();
gfx::Shader *shader = sceneData->getOcclusionQueryShader();
auto *pso = PipelineStateManager::getOrCreatePipelineState(pass, shader, inputAssembler, renderPass, subpassIndex);
cmdBuff->bindPipelineState(pso);
cmdBuff->bindDescriptorSet(materialSet, pass->getDescriptorSet());
cmdBuff->bindDescriptorSet(localSet, subModel->getWorldBoundDescriptorSet());
cmdBuff->bindInputAssembler(inputAssembler);
cmdBuff->draw(inputAssembler);
} else {
const auto passIdx = i.passIndex;
auto *inputAssembler = subModel->getInputAssembler();
const auto *pass = subModel->getPass(passIdx);
auto *shader = subModel->getShader(passIdx);
auto *pso = PipelineStateManager::getOrCreatePipelineState(pass, shader, inputAssembler, renderPass, subpassIndex);
cmdBuff->bindPipelineState(pso);
cmdBuff->bindDescriptorSet(materialSet, pass->getDescriptorSet());
cmdBuff->bindDescriptorSet(localSet, subModel->getDescriptorSet());
cmdBuff->bindInputAssembler(inputAssembler);
cmdBuff->draw(inputAssembler);
}
if (enableOcclusionQuery) {
cmdBuff->endQuery(queryPool, subModel->getId());
}
}
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,56 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "Define.h"
namespace cc {
namespace scene {
class Camera;
}
namespace pipeline {
class RenderPipeline;
class CC_DLL RenderQueue final {
public:
explicit RenderQueue(RenderPipeline *pipeline, RenderQueueCreateInfo desc, bool useOcclusionQuery = false);
void clear();
bool insertRenderPass(const RenderObject &renderObj, uint32_t subModelIdx, uint32_t passIdx);
void recordCommandBuffer(gfx::Device *device, scene::Camera *camera, gfx::RenderPass *renderPass, gfx::CommandBuffer *cmdBuff, uint32_t subpassIndex = 0);
void sort();
bool empty() { return _queue.empty(); }
private:
// weak reference
RenderPipeline *_pipeline{nullptr};
RenderPassList _queue;
RenderQueueCreateInfo _passDesc;
bool _useOcclusionQuery{false};
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,57 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "RenderStage.h"
#include "RenderQueue.h"
#include "gfx-base/GFXDevice.h"
namespace cc {
namespace pipeline {
RenderStage::RenderStage()
: _device(gfx::Device::getInstance()) {
}
RenderStage::~RenderStage() = default;
bool RenderStage::initialize(const RenderStageInfo &info) {
_name = info.name;
_priority = info.priority;
_tag = info.tag;
return true;
}
void RenderStage::activate(RenderPipeline *pipeline, RenderFlow *flow) {
_pipeline = pipeline;
_flow = flow;
}
void RenderStage::destroy() {
for (auto *renderQueue : _renderQueues) {
CC_SAFE_DELETE(renderQueue);
}
_renderQueues.clear();
_renderQueueDescriptors.clear();
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,93 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "Define.h"
#include "base/RefCounted.h"
namespace cc {
namespace scene {
class Camera;
}
namespace gfx {
class Framebuffer;
} // namespace gfx
namespace pipeline {
class RenderFlow;
class RenderPipeline;
class RenderQueue;
struct CC_DLL RenderStageInfo {
ccstd::string name;
uint32_t priority = 0;
uint32_t tag = 0;
RenderQueueDescList renderQueues;
};
class CC_DLL RenderStage : public RefCounted {
public:
RenderStage();
~RenderStage() override;
virtual void activate(RenderPipeline *pipeline, RenderFlow *flow);
virtual bool initialize(const RenderStageInfo &info);
virtual void destroy();
// should not be pure virtual, since it will be instantiated in inspector
virtual void render(scene::Camera *camera) {}
inline const ccstd::string &getName() const { return _name; }
inline void setName(ccstd::string &name) { _name = name; }
inline uint32_t getPriority() const { return _priority; }
inline void setPriority(uint32_t priority) { _priority = priority; }
inline uint32_t getTag() const { return _tag; }
inline void setTag(uint32_t tag) { _tag = tag; }
inline RenderFlow *getFlow() const { return _flow; }
protected:
gfx::Rect _renderArea;
// Generate quad ia, cannot be updated inside renderpass.
// weak reference, it is created and recorded in RenderPipeline::_quadIA.
gfx::InputAssembler *_inputAssembler{nullptr};
RenderQueueDescList _renderQueueDescriptors;
// Manage memory manually.
ccstd::vector<RenderQueue *> _renderQueues;
// weak reference
RenderPipeline *_pipeline{nullptr};
// weak reference
RenderFlow *_flow{nullptr};
// weak reference
gfx::Device *_device{nullptr};
ccstd::string _name;
uint32_t _priority{0};
uint32_t _tag{0};
gfx::ColorList _clearColors = {{0.0F, 0.0F, 0.0F, 0.0F}, {0.0F, 0.0F, 0.0F, 0.0F}, {0.0F, 0.0F, 0.0F, 0.0F}, {0.0F, 0.0F, 0.0F, 0.0F}};
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,276 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "base/std/container/array.h"
#include "Define.h"
#include "PipelineSceneData.h"
#include "RenderPipeline.h"
#include "SceneCulling.h"
#include "base/std/container/map.h"
#include "core/geometry/AABB.h"
#include "core/geometry/Frustum.h"
#include "core/geometry/Intersect.h"
#include "core/geometry/Sphere.h"
#include "core/platform/Debug.h"
#include "core/scene-graph/Node.h"
#include "math/Quaternion.h"
#include "profiler/Profiler.h"
#include "scene/Camera.h"
#include "scene/DirectionalLight.h"
#include "scene/LODGroup.h"
#include "scene/Light.h"
#include "scene/Octree.h"
#include "scene/RangedDirectionalLight.h"
#include "scene/RenderScene.h"
#include "scene/Shadow.h"
#include "scene/Skybox.h"
#include "scene/SpotLight.h"
#include "shadow/CSMLayers.h"
namespace cc {
namespace pipeline {
RenderObject genRenderObject(const scene::Model *model, const scene::Camera *camera) {
float depth = 0;
if (model->getNode()) {
const auto *node = model->getTransform();
cc::Vec3 position;
const auto *bounds = model->getWorldBounds();
Vec3::subtract(bounds ? bounds->center : node->getWorldPosition(), camera->getPosition(), &position);
depth = position.dot(camera->getForward());
}
return {depth, model};
}
void validPunctualLightsCulling(const RenderPipeline *pipeline, const scene::Camera *camera) {
const auto *const scene = camera->getScene();
PipelineSceneData *sceneData = pipeline->getPipelineSceneData();
sceneData->clearValidPunctualLights();
geometry::Sphere sphere;
for (const auto &light : scene->getSpotLights()) {
if (light->isBaked()) {
continue;
}
sphere.setCenter(light->getPosition());
sphere.setRadius(light->getRange());
if (sphere.sphereFrustum(camera->getFrustum())) {
sceneData->addValidPunctualLight(static_cast<scene::Light *>(light));
}
}
for (const auto &light : scene->getSphereLights()) {
if (light->isBaked()) {
continue;
}
sphere.setCenter(light->getPosition());
sphere.setRadius(light->getRange());
if (sphere.sphereFrustum(camera->getFrustum())) {
sceneData->addValidPunctualLight(static_cast<scene::Light *>(light));
}
}
for (const auto &light : scene->getPointLights()) {
if (light->isBaked()) {
continue;
}
sphere.setCenter(light->getPosition());
sphere.setRadius(light->getRange());
if (sphere.sphereFrustum(camera->getFrustum())) {
sceneData->addValidPunctualLight(static_cast<scene::Light *>(light));
}
}
for (const auto &light : scene->getRangedDirLights()) {
if (light->isBaked()) {
continue;
}
geometry::AABB rangedDirLightBoundingBox(0.0F, 0.0F, 0.0F, 0.5F, 0.5F, 0.5F);
light->getNode()->updateWorldTransform();
rangedDirLightBoundingBox.transform(light->getNode()->getWorldMatrix(), &rangedDirLightBoundingBox);
if (rangedDirLightBoundingBox.aabbFrustum(camera->getFrustum())) {
sceneData->addValidPunctualLight(static_cast<scene::Light *>(light));
}
}
}
// Todo If you want to optimize the cutting efficiency, you can get it from the octree
void shadowCulling(const RenderPipeline *pipeline, const scene::Camera *camera, ShadowTransformInfo *layer) {
const auto *sceneData = pipeline->getPipelineSceneData();
auto *csmLayers = sceneData->getCSMLayers();
const auto *const scene = camera->getScene();
const auto *mainLight = scene->getMainLight();
const uint32_t visibility = camera->getVisibility();
layer->clearShadowObjects();
if (csmLayers->getLayerObjects().empty()) return;
for (auto it = csmLayers->getLayerObjects().begin(); it != csmLayers->getLayerObjects().end();) {
const auto *model = it->model;
if (!model || !model->isEnabled() || !model->getNode()) {
it = csmLayers->getLayerObjects().erase(it);
continue;
}
const auto *node = model->getNode();
if (((visibility & node->getLayer()) != node->getLayer()) && !(visibility & static_cast<uint32_t>(model->getVisFlags()))) {
it = csmLayers->getLayerObjects().erase(it);
continue;
}
if (!model->getWorldBounds() || !model->isCastShadow()) {
it = csmLayers->getLayerObjects().erase(it);
continue;
}
// frustum culling
const bool accurate = model->getWorldBounds()->aabbFrustum(layer->getValidFrustum());
if (!accurate) {
++it;
continue;
}
layer->addShadowObject(genRenderObject(model, camera));
if (layer->getLevel() < static_cast<uint32_t>(mainLight->getCSMLevel())) {
if (mainLight->getCSMOptimizationMode() == scene::CSMOptimizationMode::REMOVE_DUPLICATES &&
aabbFrustumCompletelyInside(*model->getWorldBounds(), layer->getValidFrustum())) {
it = csmLayers->getLayerObjects().erase(it);
} else {
++it;
}
} else {
++it;
}
}
}
void sceneCulling(const RenderPipeline *pipeline, scene::Camera *camera) {
CC_PROFILE(SceneCulling);
PipelineSceneData *const sceneData = pipeline->getPipelineSceneData();
const scene::Shadows *shadowInfo = sceneData->getShadows();
CSMLayers *csmLayers = sceneData->getCSMLayers();
const scene::Skybox *skyBox = sceneData->getSkybox();
const scene::RenderScene *const scene = camera->getScene();
scene::DirectionalLight *mainLight = scene->getMainLight();
if (shadowInfo != nullptr && shadowInfo->isEnabled() && shadowInfo->getType() == scene::ShadowType::SHADOW_MAP) {
// update dirLightFrustum
if (mainLight && mainLight->getNode()) {
csmLayers->update(sceneData, camera);
}
}
sceneData->clearRenderObjects();
csmLayers->clearCastShadowObjects();
csmLayers->clearLayerObjects();
auto clearFlagValue = static_cast<uint32_t>(camera->getClearFlag());
if (clearFlagValue & skyboxFlag) {
if (skyBox != nullptr && skyBox->isEnabled() && skyBox->getModel()) {
sceneData->addRenderObject(genRenderObject(skyBox->getModel(), camera));
} else if (clearFlagValue == skyboxFlag) {
debug::warnID(15100, camera->getName());
}
}
const scene::Octree *octree = scene->getOctree();
if (octree && octree->isEnabled()) {
for (const auto &model : scene->getModels()) {
// filter model by view visibility
if (model->isEnabled()) {
if (scene->isCulledByLod(camera, model)) {
continue;
}
if (model->isCastShadow()) {
csmLayers->addCastShadowObject(genRenderObject(model, camera));
csmLayers->addLayerObject(genRenderObject(model, camera));
}
const auto visibility = camera->getVisibility();
const auto *const node = model->getNode();
if ((model->getNode() && ((visibility & node->getLayer()) == node->getLayer())) ||
(visibility & static_cast<uint32_t>(model->getVisFlags()))) {
const auto *modelWorldBounds = model->getWorldBounds();
if (!modelWorldBounds && (skyBox == nullptr || skyBox->getModel() != model)) {
sceneData->addRenderObject(genRenderObject(model, camera));
}
}
}
}
ccstd::vector<const scene::Model *> models;
models.reserve(scene->getModels().size() / 4);
octree->queryVisibility(camera, camera->getFrustum(), false, models);
for (const auto &model : models) {
if (scene->isCulledByLod(camera, model)) {
continue;
}
sceneData->addRenderObject(genRenderObject(model, camera));
}
} else {
for (const auto &model : scene->getModels()) {
// filter model by view visibility
if (model->isEnabled()) {
if (scene->isCulledByLod(camera, model)) {
continue;
}
const auto visibility = camera->getVisibility();
const auto *const node = model->getNode();
// cast shadow render Object
if (model->isCastShadow()) {
csmLayers->addCastShadowObject(genRenderObject(model, camera));
csmLayers->addLayerObject(genRenderObject(model, camera));
}
if ((model->getNode() && ((visibility & node->getLayer()) == node->getLayer())) ||
(visibility & static_cast<uint32_t>(model->getVisFlags()))) {
const auto *modelWorldBounds = model->getWorldBounds();
if (!modelWorldBounds) {
sceneData->addRenderObject(genRenderObject(model, camera));
continue;
}
// frustum culling
if (modelWorldBounds->aabbFrustum(camera->getFrustum())) {
sceneData->addRenderObject(genRenderObject(model, camera));
}
}
}
}
}
csmLayers = nullptr;
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,52 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "core/geometry/Frustum.h"
#include "core/geometry/Sphere.h"
#include "pipeline/Define.h"
#include "scene/Define.h"
namespace cc {
class Mat4;
class Vec4;
class Vec3;
namespace scene {
class Camera;
class Shadows;
class Light;
} // namespace scene
namespace pipeline {
struct RenderObject;
class RenderPipeline;
class ShadowTransformInfo;
RenderObject genRenderObject(const scene::Model *, const scene::Camera *);
void validPunctualLightsCulling(const RenderPipeline *pipeline, const scene::Camera *camera);
void shadowCulling(const RenderPipeline *, const scene::Camera *, ShadowTransformInfo *);
void sceneCulling(const RenderPipeline *, scene::Camera *);
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,171 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "ShadowMapBatchedQueue.h"
#include "Define.h"
#include "InstancedBuffer.h"
#include "PipelineSceneData.h"
#include "PipelineStateManager.h"
#include "RenderInstancedQueue.h"
#include "SceneCulling.h"
#include "forward/ForwardPipeline.h"
#include "gfx-base/GFXCommandBuffer.h"
#include "gfx-base/GFXDevice.h"
#include "scene/Camera.h"
#include "scene/DirectionalLight.h"
#include "scene/Shadow.h"
#include "scene/SpotLight.h"
#include "shadow/CSMLayers.h"
namespace cc {
namespace pipeline {
ShadowMapBatchedQueue::ShadowMapBatchedQueue(RenderPipeline *pipeline)
: _phaseID(getPhaseID("shadow-caster")) {
_pipeline = pipeline;
_instancedQueue = ccnew RenderInstancedQueue;
}
ShadowMapBatchedQueue::~ShadowMapBatchedQueue() = default;
void ShadowMapBatchedQueue::gatherLightPasses(const scene::Camera *camera, const scene::Light *light, gfx::CommandBuffer *cmdBuffer, uint32_t level) {
clear();
const PipelineSceneData *sceneData = _pipeline->getPipelineSceneData();
const scene::Shadows *shadowInfo = sceneData->getShadows();
const CSMLayers *csmLayers = sceneData->getCSMLayers();
if (light && shadowInfo->isEnabled() && shadowInfo->getType() == scene::ShadowType::SHADOW_MAP) {
switch (light->getType()) {
case scene::LightType::DIRECTIONAL: {
const auto *dirLight = static_cast<const scene::DirectionalLight *>(light);
if (shadowInfo->isEnabled() && shadowInfo->getType() == scene::ShadowType::SHADOW_MAP) {
if (dirLight->isShadowEnabled()) {
ShadowTransformInfo *layer;
if (dirLight->isShadowFixedArea()) {
layer = csmLayers->getSpecialLayer();
} else {
layer = csmLayers->getLayers()[level];
}
bool isCullingEnable = camera->isCullingEnabled();
if (isCullingEnable) {
shadowCulling(_pipeline, camera, layer);
}
const RenderObjectList &dirShadowObjects = layer->getShadowObjects();
for (const auto &ro : dirShadowObjects) {
add(ro.model);
}
}
}
} break;
case scene::LightType::SPOT: {
const auto *spotLight = static_cast<const scene::SpotLight *>(light);
const RenderObjectList &castShadowObjects = csmLayers->getCastShadowObjects();
if (spotLight->isShadowEnabled()) {
const auto visibility = spotLight->getVisibility();
geometry::AABB ab;
for (const auto &ro : castShadowObjects) {
const auto *model = ro.model;
if ((visibility & model->getNode()->getLayer()) != model->getNode()->getLayer() || !model->isEnabled() || !model->isCastShadow() || !model->getNode()) {
continue;
}
if (model->getWorldBounds()) {
if (model->getWorldBounds()->aabbFrustum(spotLight->getFrustum())) {
add(model);
}
}
}
}
} break;
default:
break;
}
_instancedQueue->uploadBuffers(cmdBuffer);
}
}
void ShadowMapBatchedQueue::clear() {
_subModels.clear();
_shaders.clear();
_passes.clear();
if (_instancedQueue) _instancedQueue->clear();
}
void ShadowMapBatchedQueue::add(const scene::Model *model) {
for (const auto &subModel : model->getSubModels()) {
const auto shadowPassIdx = getShadowPassIndex(subModel);
if (shadowPassIdx == -1) {
continue;
}
const auto *pass = subModel->getPass(shadowPassIdx);
const auto batchingScheme = pass->getBatchingScheme();
if (batchingScheme == scene::BatchingSchemes::INSTANCING) {
auto *instancedBuffer = subModel->getPass(shadowPassIdx)->getInstancedBuffer();
instancedBuffer->merge(subModel, shadowPassIdx);
_instancedQueue->add(instancedBuffer);
} else { // standard draw
_subModels.emplace_back(subModel);
_shaders.emplace_back(subModel->getShader(shadowPassIdx));
_passes.emplace_back(pass);
}
}
}
void ShadowMapBatchedQueue::recordCommandBuffer(gfx::Device *device, gfx::RenderPass *renderPass, gfx::CommandBuffer *cmdBuffer) const {
_instancedQueue->recordCommandBuffer(device, renderPass, cmdBuffer);
for (size_t i = 0; i < _subModels.size(); i++) {
const auto *const subModel = _subModels[i];
auto *const shader = _shaders[i];
const auto *pass = _passes[i];
auto *const ia = subModel->getInputAssembler();
auto *const pso = PipelineStateManager::getOrCreatePipelineState(pass, shader, ia, renderPass);
cmdBuffer->bindPipelineState(pso);
cmdBuffer->bindDescriptorSet(materialSet, pass->getDescriptorSet());
cmdBuffer->bindDescriptorSet(localSet, subModel->getDescriptorSet());
cmdBuffer->bindInputAssembler(ia);
cmdBuffer->draw(ia);
}
}
void ShadowMapBatchedQueue::destroy() {
CC_SAFE_DELETE(_instancedQueue)
}
int ShadowMapBatchedQueue::getShadowPassIndex(const scene::SubModel *subModel) const {
int i = 0;
for (const auto &pass : *(subModel->getPasses())) {
if (pass->getPhase() == _phaseID) {
return i;
}
++i;
}
return -1;
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,69 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "Define.h"
#include "cocos/base/Macros.h"
namespace cc {
namespace scene {
class Camera;
class Pass;
} // namespace scene
namespace pipeline {
struct RenderObject;
class RenderInstancedQueue;
class RenderPipeline;
//const uint32_t phaseID(PassPhase::getPhaseID("shadow-caster"));
class CC_DLL ShadowMapBatchedQueue final {
public:
explicit ShadowMapBatchedQueue(RenderPipeline *);
~ShadowMapBatchedQueue();
void destroy();
void clear();
void gatherLightPasses(const scene::Camera *, const scene::Light *, gfx::CommandBuffer *, uint32_t level = 0);
void add(const scene::Model *);
void recordCommandBuffer(gfx::Device *, gfx::RenderPass *, gfx::CommandBuffer *) const;
private:
int getShadowPassIndex(const scene::SubModel *subModel) const;
// weak reference
RenderPipeline *_pipeline{nullptr};
// weak reference
ccstd::vector<const scene::SubModel *> _subModels;
// weak reference
ccstd::vector<const scene::Pass *> _passes;
// weak reference
ccstd::vector<gfx::Shader *> _shaders;
// manage memory manually
RenderInstancedQueue *_instancedQueue{nullptr};
uint32_t _phaseID = 0;
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,67 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "UIPhase.h"
#include "RenderPipeline.h"
#include "gfx-base/GFXCommandBuffer.h"
#include "pipeline/PipelineStateManager.h"
#include "scene/Camera.h"
#include "scene/DrawBatch2D.h"
#include "scene/Pass.h"
#include "scene/RenderScene.h"
#include "scene/SubModel.h"
namespace cc {
namespace pipeline {
void UIPhase::activate(RenderPipeline *pipeline) {
_pipeline = pipeline;
_phaseID = getPhaseID("default");
};
void UIPhase::render(scene::Camera *camera, gfx::RenderPass *renderPass) {
auto *cmdBuff = _pipeline->getCommandBuffers()[0];
const auto &batches = camera->getScene()->getBatches();
for (auto *batch : batches) {
if (!(camera->getVisibility() & (batch->getVisFlags()))) continue;
const auto &passes = batch->getPasses();
for (size_t i = 0; i < batch->getShaders().size(); ++i) {
const scene::Pass *pass = passes[i];
if (pass->getPhase() != _phaseID) continue;
auto *shader = batch->getShaders()[i];
auto *inputAssembler = batch->getInputAssembler();
auto *ds = batch->getDescriptorSet();
auto *pso = PipelineStateManager::getOrCreatePipelineState(pass, shader, inputAssembler, renderPass);
cmdBuff->bindPipelineState(pso);
cmdBuff->bindDescriptorSet(materialSet, pass->getDescriptorSet());
cmdBuff->bindInputAssembler(inputAssembler);
cmdBuff->bindDescriptorSet(localSet, ds);
cmdBuff->draw(batch->getDrawInfo());
}
}
}
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,52 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "base/Macros.h"
#include "base/TypeDef.h"
namespace cc {
namespace scene {
class Camera;
}
namespace gfx {
class RenderPass;
}
namespace pipeline {
class RenderPipeline;
class CC_DLL UIPhase {
public:
UIPhase() = default;
void activate(RenderPipeline *pipeline);
void render(scene::Camera *camera, gfx::RenderPass *renderPass);
protected:
// weak reference
RenderPipeline *_pipeline{nullptr};
uint32_t _phaseID{0};
};
} // namespace pipeline
} // namespace cc

View File

@@ -0,0 +1,45 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include "cocos/base/std/variant.h"
namespace cc {
namespace render {
class OutputArchive;
class InputArchive;
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,41 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#include "ArchiveTypes.h"
namespace cc {
namespace render {
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,74 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include <boost/container/pmr/memory_resource.hpp>
#include <string_view>
#include "cocos/renderer/pipeline/custom/ArchiveFwd.h"
namespace cc {
namespace render {
class OutputArchive {
public:
OutputArchive() noexcept = default;
OutputArchive(OutputArchive&& rhs) = delete;
OutputArchive(OutputArchive const& rhs) = delete;
OutputArchive& operator=(OutputArchive&& rhs) = delete;
OutputArchive& operator=(OutputArchive const& rhs) = delete;
virtual ~OutputArchive() noexcept = default;
virtual void writeBool(bool value) = 0;
virtual void writeNumber(double value) = 0;
virtual void writeString(std::string_view value) = 0;
virtual boost::container::pmr::memory_resource *scratch() const noexcept = 0;
};
class InputArchive {
public:
InputArchive() noexcept = default;
InputArchive(InputArchive&& rhs) = delete;
InputArchive(InputArchive const& rhs) = delete;
InputArchive& operator=(InputArchive&& rhs) = delete;
InputArchive& operator=(InputArchive const& rhs) = delete;
virtual ~InputArchive() noexcept = default;
virtual bool readBool() = 0;
virtual double readNumber() = 0;
virtual std::string_view readString() = 0;
virtual boost::container::pmr::memory_resource *scratch() const noexcept = 0;
};
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,93 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
***************************************************************************/
#pragma once
#include <cstdint>
#include <istream>
#include <ostream>
#include "cocos/base/std/container/string.h"
#include "cocos/renderer/pipeline/custom/ArchiveTypes.h"
namespace cc {
namespace render {
class BinaryOutputArchive final : public OutputArchive {
public:
BinaryOutputArchive(std::ostream& os, boost::container::pmr::memory_resource* scratch)
: _os(os), _scratch(scratch) {}
void writeBool(bool value) override {
uint8_t v = value ? 1 : 0;
_os.write(reinterpret_cast<const char*>(&v), sizeof(v));
}
void writeNumber(double value) override {
_os.write(reinterpret_cast<const char*>(&value), sizeof(value));
}
void writeString(std::string_view value) override {
writeNumber(static_cast<double>(value.size()));
_os.write(value.data(), static_cast<std::streamsize>(value.size()));
}
boost::container::pmr::memory_resource* scratch() const noexcept override {
return _scratch;
}
private:
std::ostream& _os;
boost::container::pmr::memory_resource* _scratch;
};
class BinaryInputArchive final : public InputArchive {
public:
BinaryInputArchive(std::istream& is, boost::container::pmr::memory_resource* scratch)
: _is(is), _temp(scratch) {}
bool readBool() override {
uint8_t v;
_is.read(reinterpret_cast<char*>(&v), sizeof(v));
return v != 0;
}
double readNumber() override {
double v;
_is.read(reinterpret_cast<char*>(&v), sizeof(v));
return v;
}
std::string_view readString() override {
double size = readNumber();
_temp.resize(static_cast<size_t>(size));
_is.read(_temp.data(), static_cast<std::streamsize>(size));
return _temp;
}
boost::container::pmr::memory_resource* scratch() const noexcept override {
return _temp.get_allocator().resource();
}
private:
std::istream& _is;
ccstd::pmr::string _temp;
};
} // namespace render
} // namespace cc

View File

@@ -0,0 +1,53 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include "cocos/base/std/variant.h"
#include "cocos/renderer/pipeline/custom/RenderGraphFwd.h"
namespace cc {
namespace render {
class Customization;
class CustomPipelineContext;
struct CustomRenderGraphContext;
class CustomRenderPass;
class CustomRenderSubpass;
class CustomComputeSubpass;
class CustomComputePass;
class CustomRenderQueue;
class CustomRenderCommand;
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,41 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#include "CustomTypes.h"
namespace cc {
namespace render {
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,130 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include "cocos/base/std/container/string.h"
#include "cocos/renderer/pipeline/custom/CustomFwd.h"
#include "cocos/renderer/pipeline/custom/RenderGraphTypes.h"
namespace cc {
namespace render {
class Customization {
public:
Customization() noexcept = default;
Customization(Customization&& rhs) = delete;
Customization(Customization const& rhs) = delete;
Customization& operator=(Customization&& rhs) = delete;
Customization& operator=(Customization const& rhs) = delete;
virtual ~Customization() noexcept = default;
virtual std::string_view getName() const noexcept = 0;
};
class CustomPipelineContext : public Customization {
public:
CustomPipelineContext() noexcept = default;
virtual IntrusivePtr<gfx::Buffer> createCustomBuffer(std::string_view type, const gfx::BufferInfo &info) = 0;
virtual IntrusivePtr<gfx::Texture> createCustomTexture(std::string_view type, const gfx::TextureInfo &info) = 0;
virtual void destroy() noexcept = 0;
};
struct CustomRenderGraphContext {
std::shared_ptr<CustomPipelineContext> pipelineContext;
const RenderGraph* renderGraph{nullptr};
const ResourceGraph* resourceGraph{nullptr};
gfx::CommandBuffer* primaryCommandBuffer{nullptr};
};
class CustomRenderPass : public Customization {
public:
CustomRenderPass() noexcept = default;
virtual void beginRenderPass(const CustomRenderGraphContext &rg, RenderGraph::vertex_descriptor passID) = 0;
virtual void endRenderPass(const CustomRenderGraphContext &rg, RenderGraph::vertex_descriptor passID) = 0;
};
class CustomRenderSubpass : public Customization {
public:
CustomRenderSubpass() noexcept = default;
virtual void beginRenderSubpass(const CustomRenderGraphContext &rg, RenderGraph::vertex_descriptor passID) = 0;
virtual void endRenderSubpass(const CustomRenderGraphContext &rg, RenderGraph::vertex_descriptor passID) = 0;
};
class CustomComputeSubpass : public Customization {
public:
CustomComputeSubpass() noexcept = default;
virtual void beginComputeSubpass(const CustomRenderGraphContext &rg, RenderGraph::vertex_descriptor passID) = 0;
virtual void endComputeSubpass(const CustomRenderGraphContext &rg, RenderGraph::vertex_descriptor passID) = 0;
};
class CustomComputePass : public Customization {
public:
CustomComputePass() noexcept = default;
virtual void beginComputePass(const CustomRenderGraphContext &rg, RenderGraph::vertex_descriptor passID) = 0;
virtual void endComputePass(const CustomRenderGraphContext &rg, RenderGraph::vertex_descriptor passID) = 0;
};
class CustomRenderQueue {
public:
CustomRenderQueue() noexcept = default;
CustomRenderQueue(CustomRenderQueue&& rhs) = delete;
CustomRenderQueue(CustomRenderQueue const& rhs) = delete;
CustomRenderQueue& operator=(CustomRenderQueue&& rhs) = delete;
CustomRenderQueue& operator=(CustomRenderQueue const& rhs) = delete;
virtual ~CustomRenderQueue() noexcept = default;
virtual void beginRenderQueue(const CustomRenderGraphContext &rg, RenderGraph::vertex_descriptor passID) = 0;
virtual void endRenderQueue(const CustomRenderGraphContext &rg, RenderGraph::vertex_descriptor passID) = 0;
};
class CustomRenderCommand {
public:
CustomRenderCommand() noexcept = default;
CustomRenderCommand(CustomRenderCommand&& rhs) = delete;
CustomRenderCommand(CustomRenderCommand const& rhs) = delete;
CustomRenderCommand& operator=(CustomRenderCommand&& rhs) = delete;
CustomRenderCommand& operator=(CustomRenderCommand const& rhs) = delete;
virtual ~CustomRenderCommand() noexcept = default;
virtual void beginRenderCommand(const CustomRenderGraphContext &rg, RenderGraph::vertex_descriptor passID) = 0;
virtual void endRenderCommand(const CustomRenderGraphContext &rg, RenderGraph::vertex_descriptor passID) = 0;
};
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,962 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include <string_view>
#include <tuple>
#include "cocos/renderer/pipeline/custom/FGDispatcherTypes.h"
#include "cocos/renderer/pipeline/custom/details/GraphImpl.h"
#include "cocos/renderer/pipeline/custom/details/Overload.h"
#include "cocos/renderer/pipeline/custom/details/PathUtils.h"
namespace cc {
namespace render {
// IncidenceGraph
inline ResourceAccessGraph::vertex_descriptor
source(const ResourceAccessGraph::edge_descriptor& e, const ResourceAccessGraph& /*g*/) noexcept {
return e.source;
}
inline ResourceAccessGraph::vertex_descriptor
target(const ResourceAccessGraph::edge_descriptor& e, const ResourceAccessGraph& /*g*/) noexcept {
return e.target;
}
inline std::pair<ResourceAccessGraph::out_edge_iterator, ResourceAccessGraph::out_edge_iterator>
out_edges(ResourceAccessGraph::vertex_descriptor u, const ResourceAccessGraph& g) noexcept { // NOLINT
return std::make_pair(
ResourceAccessGraph::out_edge_iterator(const_cast<ResourceAccessGraph&>(g).getOutEdgeList(u).begin(), u),
ResourceAccessGraph::out_edge_iterator(const_cast<ResourceAccessGraph&>(g).getOutEdgeList(u).end(), u));
}
inline ResourceAccessGraph::degree_size_type
out_degree(ResourceAccessGraph::vertex_descriptor u, const ResourceAccessGraph& g) noexcept { // NOLINT
return gsl::narrow_cast<ResourceAccessGraph::degree_size_type>(g.getOutEdgeList(u).size());
}
inline std::pair<ResourceAccessGraph::edge_descriptor, bool>
edge(ResourceAccessGraph::vertex_descriptor u, ResourceAccessGraph::vertex_descriptor v, const ResourceAccessGraph& g) noexcept {
const auto& outEdgeList = g.getOutEdgeList(u);
auto iter = std::find(outEdgeList.begin(), outEdgeList.end(), ResourceAccessGraph::OutEdge(v));
bool hasEdge = (iter != outEdgeList.end());
return {ResourceAccessGraph::edge_descriptor(u, v), hasEdge};
}
// BidirectionalGraph(Directed)
inline std::pair<ResourceAccessGraph::in_edge_iterator, ResourceAccessGraph::in_edge_iterator>
in_edges(ResourceAccessGraph::vertex_descriptor u, const ResourceAccessGraph& g) noexcept { // NOLINT
return std::make_pair(
ResourceAccessGraph::in_edge_iterator(const_cast<ResourceAccessGraph&>(g).getInEdgeList(u).begin(), u),
ResourceAccessGraph::in_edge_iterator(const_cast<ResourceAccessGraph&>(g).getInEdgeList(u).end(), u));
}
inline ResourceAccessGraph::degree_size_type
in_degree(ResourceAccessGraph::vertex_descriptor u, const ResourceAccessGraph& g) noexcept { // NOLINT
return gsl::narrow_cast<ResourceAccessGraph::degree_size_type>(g.getInEdgeList(u).size());
}
inline ResourceAccessGraph::degree_size_type
degree(ResourceAccessGraph::vertex_descriptor u, const ResourceAccessGraph& g) noexcept {
return in_degree(u, g) + out_degree(u, g);
}
// AdjacencyGraph
inline std::pair<ResourceAccessGraph::adjacency_iterator, ResourceAccessGraph::adjacency_iterator>
adjacent_vertices(ResourceAccessGraph::vertex_descriptor u, const ResourceAccessGraph& g) noexcept { // NOLINT
auto edges = out_edges(u, g);
return std::make_pair(ResourceAccessGraph::adjacency_iterator(edges.first, &g), ResourceAccessGraph::adjacency_iterator(edges.second, &g));
}
// VertexListGraph
inline std::pair<ResourceAccessGraph::vertex_iterator, ResourceAccessGraph::vertex_iterator>
vertices(const ResourceAccessGraph& g) noexcept {
return std::make_pair(const_cast<ResourceAccessGraph&>(g).getVertexList().begin(), const_cast<ResourceAccessGraph&>(g).getVertexList().end());
}
inline ResourceAccessGraph::vertices_size_type
num_vertices(const ResourceAccessGraph& g) noexcept { // NOLINT
return gsl::narrow_cast<ResourceAccessGraph::vertices_size_type>(g.getVertexList().size());
}
// EdgeListGraph
inline std::pair<ResourceAccessGraph::edge_iterator, ResourceAccessGraph::edge_iterator>
edges(const ResourceAccessGraph& g0) noexcept {
auto& g = const_cast<ResourceAccessGraph&>(g0);
return std::make_pair(
ResourceAccessGraph::edge_iterator(g.getVertexList().begin(), g.getVertexList().begin(), g.getVertexList().end(), g),
ResourceAccessGraph::edge_iterator(g.getVertexList().begin(), g.getVertexList().end(), g.getVertexList().end(), g));
}
inline ResourceAccessGraph::edges_size_type
num_edges(const ResourceAccessGraph& g) noexcept { // NOLINT
ResourceAccessGraph::edges_size_type numEdges = 0;
auto range = vertices(g);
for (auto iter = range.first; iter != range.second; ++iter) {
numEdges += out_degree(*iter, g);
}
return numEdges;
}
// MutableGraph(Edge)
inline std::pair<ResourceAccessGraph::edge_descriptor, bool>
add_edge( // NOLINT
ResourceAccessGraph::vertex_descriptor u,
ResourceAccessGraph::vertex_descriptor v, ResourceAccessGraph& g) {
auto& outEdgeList = g.getOutEdgeList(u);
outEdgeList.emplace_back(v);
auto& inEdgeList = g.getInEdgeList(v);
inEdgeList.emplace_back(u);
return std::make_pair(ResourceAccessGraph::edge_descriptor(u, v), true);
}
inline void remove_edge(ResourceAccessGraph::vertex_descriptor u, ResourceAccessGraph::vertex_descriptor v, ResourceAccessGraph& g) noexcept { // NOLINT
auto& s = g._vertices[u];
auto& t = g._vertices[v];
s.outEdges.erase(std::remove(s.outEdges.begin(), s.outEdges.end(), ResourceAccessGraph::OutEdge(v)), s.outEdges.end());
t.inEdges.erase(std::remove(t.inEdges.begin(), t.inEdges.end(), ResourceAccessGraph::InEdge(u)), t.inEdges.end());
}
inline void remove_edge(ResourceAccessGraph::out_edge_iterator outIter, ResourceAccessGraph& g) noexcept { // NOLINT
auto e = *outIter;
const auto u = source(e, g);
const auto v = target(e, g);
auto& s = g._vertices[u];
auto& t = g._vertices[v];
auto inIter = std::find(t.inEdges.begin(), t.inEdges.end(), ResourceAccessGraph::InEdge(u));
CC_EXPECTS(inIter != t.inEdges.end());
t.inEdges.erase(inIter);
s.outEdges.erase(outIter.base());
}
inline void remove_edge(ResourceAccessGraph::edge_descriptor e, ResourceAccessGraph& g) noexcept { // NOLINT
const auto u = source(e, g);
const auto v = target(e, g);
auto& s = g._vertices[u];
auto outIter = std::find(s.outEdges.begin(), s.outEdges.end(), ResourceAccessGraph::OutEdge(v));
CC_EXPECTS(outIter != s.outEdges.end());
remove_edge(ResourceAccessGraph::out_edge_iterator(outIter, u), g);
}
// MutableGraph(Vertex)
inline void clear_out_edges(ResourceAccessGraph::vertex_descriptor u, ResourceAccessGraph& g) noexcept { // NOLINT
// Bidirectional (OutEdges)
auto& outEdgeList = g.getOutEdgeList(u);
auto outEnd = outEdgeList.end();
for (auto iter = outEdgeList.begin(); iter != outEnd; ++iter) {
auto& inEdgeList = g.getInEdgeList((*iter).get_target());
// eraseFromIncidenceList
impl::sequenceEraseIf(inEdgeList, [u](const auto& e) {
return e.get_target() == u;
});
}
outEdgeList.clear();
}
inline void clear_in_edges(ResourceAccessGraph::vertex_descriptor u, ResourceAccessGraph& g) noexcept { // NOLINT
// Bidirectional (InEdges)
auto& inEdgeList = g.getInEdgeList(u);
auto inEnd = inEdgeList.end();
for (auto iter = inEdgeList.begin(); iter != inEnd; ++iter) {
auto& outEdgeList = g.getOutEdgeList((*iter).get_target());
// eraseFromIncidenceList
impl::sequenceEraseIf(outEdgeList, [u](const auto& e) {
return e.get_target() == u;
});
}
inEdgeList.clear();
}
inline void clear_vertex(ResourceAccessGraph::vertex_descriptor u, ResourceAccessGraph& g) noexcept { // NOLINT
clear_out_edges(u, g);
clear_in_edges(u, g);
}
inline void remove_vertex(ResourceAccessGraph::vertex_descriptor u, ResourceAccessGraph& g) noexcept { // NOLINT
{ // UuidGraph
const auto& key = g.passID[u];
auto num = g.passIndex.erase(key);
CC_ENSURES(num == 1);
for (auto&& pair : g.passIndex) {
auto& v = pair.second;
if (v > u) {
--v;
}
}
}
impl::removeVectorVertex(const_cast<ResourceAccessGraph&>(g), u, ResourceAccessGraph::directed_category{});
// remove components
g.passID.erase(g.passID.begin() + static_cast<std::ptrdiff_t>(u));
g.passResource.erase(g.passResource.begin() + static_cast<std::ptrdiff_t>(u));
g.rpInfo.erase(g.rpInfo.begin() + static_cast<std::ptrdiff_t>(u));
g.barrier.erase(g.barrier.begin() + static_cast<std::ptrdiff_t>(u));
}
// MutablePropertyGraph(Vertex)
template <class Component0, class Component1, class Component2, class Component3>
inline ResourceAccessGraph::vertex_descriptor
addVertex(Component0&& c0, Component1&& c1, Component2&& c2, Component3&& c3, ResourceAccessGraph& g) {
auto v = gsl::narrow_cast<ResourceAccessGraph::vertex_descriptor>(g._vertices.size());
g._vertices.emplace_back();
{ // UuidGraph
const auto& uuid = c0;
auto res = g.passIndex.emplace(uuid, v);
CC_ENSURES(res.second);
}
g.passID.emplace_back(std::forward<Component0>(c0));
g.passResource.emplace_back(std::forward<Component1>(c1));
g.rpInfo.emplace_back(std::forward<Component2>(c2));
g.barrier.emplace_back(std::forward<Component3>(c3));
return v;
}
template <class Component0, class Component1, class Component2, class Component3>
inline ResourceAccessGraph::vertex_descriptor
addVertex(std::piecewise_construct_t /*tag*/, Component0&& c0, Component1&& c1, Component2&& c2, Component3&& c3, ResourceAccessGraph& g) {
auto v = gsl::narrow_cast<ResourceAccessGraph::vertex_descriptor>(g._vertices.size());
g._vertices.emplace_back();
{ // UuidGraph
std::apply(
[&](const auto&... args) {
auto res = g.passIndex.emplace(std::piecewise_construct, std::forward_as_tuple(args...), std::forward_as_tuple(v));
CC_ENSURES(res.second);
},
c0);
}
std::apply(
[&](auto&&... args) {
g.passID.emplace_back(std::forward<decltype(args)>(args)...);
},
std::forward<Component0>(c0));
std::apply(
[&](auto&&... args) {
g.passResource.emplace_back(std::forward<decltype(args)>(args)...);
},
std::forward<Component1>(c1));
std::apply(
[&](auto&&... args) {
g.rpInfo.emplace_back(std::forward<decltype(args)>(args)...);
},
std::forward<Component2>(c2));
std::apply(
[&](auto&&... args) {
g.barrier.emplace_back(std::forward<decltype(args)>(args)...);
},
std::forward<Component3>(c3));
return v;
}
// IncidenceGraph
inline RelationGraph::vertex_descriptor
source(const RelationGraph::edge_descriptor& e, const RelationGraph& /*g*/) noexcept {
return e.source;
}
inline RelationGraph::vertex_descriptor
target(const RelationGraph::edge_descriptor& e, const RelationGraph& /*g*/) noexcept {
return e.target;
}
inline std::pair<RelationGraph::out_edge_iterator, RelationGraph::out_edge_iterator>
out_edges(RelationGraph::vertex_descriptor u, const RelationGraph& g) noexcept { // NOLINT
return std::make_pair(
RelationGraph::out_edge_iterator(const_cast<RelationGraph&>(g).getOutEdgeList(u).begin(), u),
RelationGraph::out_edge_iterator(const_cast<RelationGraph&>(g).getOutEdgeList(u).end(), u));
}
inline RelationGraph::degree_size_type
out_degree(RelationGraph::vertex_descriptor u, const RelationGraph& g) noexcept { // NOLINT
return gsl::narrow_cast<RelationGraph::degree_size_type>(g.getOutEdgeList(u).size());
}
inline std::pair<RelationGraph::edge_descriptor, bool>
edge(RelationGraph::vertex_descriptor u, RelationGraph::vertex_descriptor v, const RelationGraph& g) noexcept {
const auto& outEdgeList = g.getOutEdgeList(u);
auto iter = std::find(outEdgeList.begin(), outEdgeList.end(), RelationGraph::OutEdge(v));
bool hasEdge = (iter != outEdgeList.end());
return {RelationGraph::edge_descriptor(u, v), hasEdge};
}
// BidirectionalGraph(Directed)
inline std::pair<RelationGraph::in_edge_iterator, RelationGraph::in_edge_iterator>
in_edges(RelationGraph::vertex_descriptor u, const RelationGraph& g) noexcept { // NOLINT
return std::make_pair(
RelationGraph::in_edge_iterator(const_cast<RelationGraph&>(g).getInEdgeList(u).begin(), u),
RelationGraph::in_edge_iterator(const_cast<RelationGraph&>(g).getInEdgeList(u).end(), u));
}
inline RelationGraph::degree_size_type
in_degree(RelationGraph::vertex_descriptor u, const RelationGraph& g) noexcept { // NOLINT
return gsl::narrow_cast<RelationGraph::degree_size_type>(g.getInEdgeList(u).size());
}
inline RelationGraph::degree_size_type
degree(RelationGraph::vertex_descriptor u, const RelationGraph& g) noexcept {
return in_degree(u, g) + out_degree(u, g);
}
// AdjacencyGraph
inline std::pair<RelationGraph::adjacency_iterator, RelationGraph::adjacency_iterator>
adjacent_vertices(RelationGraph::vertex_descriptor u, const RelationGraph& g) noexcept { // NOLINT
auto edges = out_edges(u, g);
return std::make_pair(RelationGraph::adjacency_iterator(edges.first, &g), RelationGraph::adjacency_iterator(edges.second, &g));
}
// VertexListGraph
inline std::pair<RelationGraph::vertex_iterator, RelationGraph::vertex_iterator>
vertices(const RelationGraph& g) noexcept {
return std::make_pair(const_cast<RelationGraph&>(g).getVertexList().begin(), const_cast<RelationGraph&>(g).getVertexList().end());
}
inline RelationGraph::vertices_size_type
num_vertices(const RelationGraph& g) noexcept { // NOLINT
return gsl::narrow_cast<RelationGraph::vertices_size_type>(g.getVertexList().size());
}
// EdgeListGraph
inline std::pair<RelationGraph::edge_iterator, RelationGraph::edge_iterator>
edges(const RelationGraph& g0) noexcept {
auto& g = const_cast<RelationGraph&>(g0);
return std::make_pair(
RelationGraph::edge_iterator(g.getVertexList().begin(), g.getVertexList().begin(), g.getVertexList().end(), g),
RelationGraph::edge_iterator(g.getVertexList().begin(), g.getVertexList().end(), g.getVertexList().end(), g));
}
inline RelationGraph::edges_size_type
num_edges(const RelationGraph& g) noexcept { // NOLINT
RelationGraph::edges_size_type numEdges = 0;
auto range = vertices(g);
for (auto iter = range.first; iter != range.second; ++iter) {
numEdges += out_degree(*iter, g);
}
return numEdges;
}
// MutableGraph(Edge)
inline std::pair<RelationGraph::edge_descriptor, bool>
add_edge( // NOLINT
RelationGraph::vertex_descriptor u,
RelationGraph::vertex_descriptor v, RelationGraph& g) {
auto& outEdgeList = g.getOutEdgeList(u);
outEdgeList.emplace_back(v);
auto& inEdgeList = g.getInEdgeList(v);
inEdgeList.emplace_back(u);
return std::make_pair(RelationGraph::edge_descriptor(u, v), true);
}
inline void remove_edge(RelationGraph::vertex_descriptor u, RelationGraph::vertex_descriptor v, RelationGraph& g) noexcept { // NOLINT
auto& s = g._vertices[u];
auto& t = g._vertices[v];
s.outEdges.erase(std::remove(s.outEdges.begin(), s.outEdges.end(), RelationGraph::OutEdge(v)), s.outEdges.end());
t.inEdges.erase(std::remove(t.inEdges.begin(), t.inEdges.end(), RelationGraph::InEdge(u)), t.inEdges.end());
}
inline void remove_edge(RelationGraph::out_edge_iterator outIter, RelationGraph& g) noexcept { // NOLINT
auto e = *outIter;
const auto u = source(e, g);
const auto v = target(e, g);
auto& s = g._vertices[u];
auto& t = g._vertices[v];
auto inIter = std::find(t.inEdges.begin(), t.inEdges.end(), RelationGraph::InEdge(u));
CC_EXPECTS(inIter != t.inEdges.end());
t.inEdges.erase(inIter);
s.outEdges.erase(outIter.base());
}
inline void remove_edge(RelationGraph::edge_descriptor e, RelationGraph& g) noexcept { // NOLINT
const auto u = source(e, g);
const auto v = target(e, g);
auto& s = g._vertices[u];
auto outIter = std::find(s.outEdges.begin(), s.outEdges.end(), RelationGraph::OutEdge(v));
CC_EXPECTS(outIter != s.outEdges.end());
remove_edge(RelationGraph::out_edge_iterator(outIter, u), g);
}
// MutableGraph(Vertex)
inline void clear_out_edges(RelationGraph::vertex_descriptor u, RelationGraph& g) noexcept { // NOLINT
// Bidirectional (OutEdges)
auto& outEdgeList = g.getOutEdgeList(u);
auto outEnd = outEdgeList.end();
for (auto iter = outEdgeList.begin(); iter != outEnd; ++iter) {
auto& inEdgeList = g.getInEdgeList((*iter).get_target());
// eraseFromIncidenceList
impl::sequenceEraseIf(inEdgeList, [u](const auto& e) {
return e.get_target() == u;
});
}
outEdgeList.clear();
}
inline void clear_in_edges(RelationGraph::vertex_descriptor u, RelationGraph& g) noexcept { // NOLINT
// Bidirectional (InEdges)
auto& inEdgeList = g.getInEdgeList(u);
auto inEnd = inEdgeList.end();
for (auto iter = inEdgeList.begin(); iter != inEnd; ++iter) {
auto& outEdgeList = g.getOutEdgeList((*iter).get_target());
// eraseFromIncidenceList
impl::sequenceEraseIf(outEdgeList, [u](const auto& e) {
return e.get_target() == u;
});
}
inEdgeList.clear();
}
inline void clear_vertex(RelationGraph::vertex_descriptor u, RelationGraph& g) noexcept { // NOLINT
clear_out_edges(u, g);
clear_in_edges(u, g);
}
inline void remove_vertex(RelationGraph::vertex_descriptor u, RelationGraph& g) noexcept { // NOLINT
{ // UuidGraph
const auto& key = g.descID[u];
auto num = g.vertexMap.erase(key);
CC_ENSURES(num == 1);
for (auto&& pair : g.vertexMap) {
auto& v = pair.second;
if (v > u) {
--v;
}
}
}
impl::removeVectorVertex(const_cast<RelationGraph&>(g), u, RelationGraph::directed_category{});
// remove components
g.descID.erase(g.descID.begin() + static_cast<std::ptrdiff_t>(u));
}
// MutablePropertyGraph(Vertex)
template <class Component0>
inline RelationGraph::vertex_descriptor
addVertex(Component0&& c0, RelationGraph& g) {
auto v = gsl::narrow_cast<RelationGraph::vertex_descriptor>(g._vertices.size());
g._vertices.emplace_back();
{ // UuidGraph
const auto& uuid = c0;
auto res = g.vertexMap.emplace(uuid, v);
CC_ENSURES(res.second);
}
g.descID.emplace_back(std::forward<Component0>(c0));
return v;
}
template <class Component0>
inline RelationGraph::vertex_descriptor
addVertex(std::piecewise_construct_t /*tag*/, Component0&& c0, RelationGraph& g) {
auto v = gsl::narrow_cast<RelationGraph::vertex_descriptor>(g._vertices.size());
g._vertices.emplace_back();
{ // UuidGraph
std::apply(
[&](const auto&... args) {
auto res = g.vertexMap.emplace(std::piecewise_construct, std::forward_as_tuple(args...), std::forward_as_tuple(v));
CC_ENSURES(res.second);
},
c0);
}
std::apply(
[&](auto&&... args) {
g.descID.emplace_back(std::forward<decltype(args)>(args)...);
},
std::forward<Component0>(c0));
return v;
}
} // namespace render
} // namespace cc
namespace boost {
// Vertex Index
template <>
struct property_map<cc::render::ResourceAccessGraph, vertex_index_t> {
using const_type = identity_property_map;
using type = identity_property_map;
};
// Vertex Component
template <>
struct property_map<cc::render::ResourceAccessGraph, cc::render::ResourceAccessGraph::PassIDTag> {
using const_type = cc::render::impl::VectorVertexComponentPropertyMap<
lvalue_property_map_tag,
const cc::render::ResourceAccessGraph,
const ccstd::pmr::vector<cc::render::RenderGraph::vertex_descriptor>,
cc::render::RenderGraph::vertex_descriptor,
const cc::render::RenderGraph::vertex_descriptor&>;
using type = cc::render::impl::VectorVertexComponentPropertyMap<
lvalue_property_map_tag,
cc::render::ResourceAccessGraph,
ccstd::pmr::vector<cc::render::RenderGraph::vertex_descriptor>,
cc::render::RenderGraph::vertex_descriptor,
cc::render::RenderGraph::vertex_descriptor&>;
};
// Vertex Component
template <>
struct property_map<cc::render::ResourceAccessGraph, cc::render::ResourceAccessGraph::PassNodeTag> {
using const_type = cc::render::impl::VectorVertexComponentPropertyMap<
lvalue_property_map_tag,
const cc::render::ResourceAccessGraph,
const ccstd::pmr::vector<cc::render::ResourceAccessNode>,
cc::render::ResourceAccessNode,
const cc::render::ResourceAccessNode&>;
using type = cc::render::impl::VectorVertexComponentPropertyMap<
lvalue_property_map_tag,
cc::render::ResourceAccessGraph,
ccstd::pmr::vector<cc::render::ResourceAccessNode>,
cc::render::ResourceAccessNode,
cc::render::ResourceAccessNode&>;
};
// Vertex ComponentMember
template <class T>
struct property_map<cc::render::ResourceAccessGraph, T cc::render::ResourceAccessNode::*> {
using const_type = cc::render::impl::VectorVertexComponentMemberPropertyMap<
lvalue_property_map_tag,
const cc::render::ResourceAccessGraph,
const ccstd::pmr::vector<cc::render::ResourceAccessNode>,
T,
const T&,
T cc::render::ResourceAccessNode::*>;
using type = cc::render::impl::VectorVertexComponentMemberPropertyMap<
lvalue_property_map_tag,
cc::render::ResourceAccessGraph,
ccstd::pmr::vector<cc::render::ResourceAccessNode>,
T,
T&,
T cc::render::ResourceAccessNode::*>;
};
// Vertex Component
template <>
struct property_map<cc::render::ResourceAccessGraph, cc::render::ResourceAccessGraph::RenderPassInfoTag> {
using const_type = cc::render::impl::VectorVertexComponentPropertyMap<
lvalue_property_map_tag,
const cc::render::ResourceAccessGraph,
const ccstd::pmr::vector<cc::render::FGRenderPassInfo>,
cc::render::FGRenderPassInfo,
const cc::render::FGRenderPassInfo&>;
using type = cc::render::impl::VectorVertexComponentPropertyMap<
lvalue_property_map_tag,
cc::render::ResourceAccessGraph,
ccstd::pmr::vector<cc::render::FGRenderPassInfo>,
cc::render::FGRenderPassInfo,
cc::render::FGRenderPassInfo&>;
};
// Vertex ComponentMember
template <class T>
struct property_map<cc::render::ResourceAccessGraph, T cc::render::FGRenderPassInfo::*> {
using const_type = cc::render::impl::VectorVertexComponentMemberPropertyMap<
lvalue_property_map_tag,
const cc::render::ResourceAccessGraph,
const ccstd::pmr::vector<cc::render::FGRenderPassInfo>,
T,
const T&,
T cc::render::FGRenderPassInfo::*>;
using type = cc::render::impl::VectorVertexComponentMemberPropertyMap<
lvalue_property_map_tag,
cc::render::ResourceAccessGraph,
ccstd::pmr::vector<cc::render::FGRenderPassInfo>,
T,
T&,
T cc::render::FGRenderPassInfo::*>;
};
// Vertex Component
template <>
struct property_map<cc::render::ResourceAccessGraph, cc::render::ResourceAccessGraph::BarrierTag> {
using const_type = cc::render::impl::VectorVertexComponentPropertyMap<
lvalue_property_map_tag,
const cc::render::ResourceAccessGraph,
const ccstd::pmr::vector<cc::render::BarrierNode>,
cc::render::BarrierNode,
const cc::render::BarrierNode&>;
using type = cc::render::impl::VectorVertexComponentPropertyMap<
lvalue_property_map_tag,
cc::render::ResourceAccessGraph,
ccstd::pmr::vector<cc::render::BarrierNode>,
cc::render::BarrierNode,
cc::render::BarrierNode&>;
};
// Vertex ComponentMember
template <class T>
struct property_map<cc::render::ResourceAccessGraph, T cc::render::BarrierNode::*> {
using const_type = cc::render::impl::VectorVertexComponentMemberPropertyMap<
lvalue_property_map_tag,
const cc::render::ResourceAccessGraph,
const ccstd::pmr::vector<cc::render::BarrierNode>,
T,
const T&,
T cc::render::BarrierNode::*>;
using type = cc::render::impl::VectorVertexComponentMemberPropertyMap<
lvalue_property_map_tag,
cc::render::ResourceAccessGraph,
ccstd::pmr::vector<cc::render::BarrierNode>,
T,
T&,
T cc::render::BarrierNode::*>;
};
// Vertex Index
template <>
struct property_map<cc::render::RelationGraph, vertex_index_t> {
using const_type = identity_property_map;
using type = identity_property_map;
};
// Vertex Component
template <>
struct property_map<cc::render::RelationGraph, cc::render::RelationGraph::DescIDTag> {
using const_type = cc::render::impl::VectorVertexComponentPropertyMap<
lvalue_property_map_tag,
const cc::render::RelationGraph,
const ccstd::pmr::vector<cc::render::ResourceAccessGraph::vertex_descriptor>,
cc::render::ResourceAccessGraph::vertex_descriptor,
const cc::render::ResourceAccessGraph::vertex_descriptor&>;
using type = cc::render::impl::VectorVertexComponentPropertyMap<
lvalue_property_map_tag,
cc::render::RelationGraph,
ccstd::pmr::vector<cc::render::ResourceAccessGraph::vertex_descriptor>,
cc::render::ResourceAccessGraph::vertex_descriptor,
cc::render::ResourceAccessGraph::vertex_descriptor&>;
};
} // namespace boost
namespace cc {
namespace render {
// Vertex Index
inline boost::property_map<ResourceAccessGraph, boost::vertex_index_t>::const_type
get(boost::vertex_index_t /*tag*/, const ResourceAccessGraph& /*g*/) noexcept {
return {};
}
inline boost::property_map<ResourceAccessGraph, boost::vertex_index_t>::type
get(boost::vertex_index_t /*tag*/, ResourceAccessGraph& /*g*/) noexcept {
return {};
}
inline impl::ColorMap<ResourceAccessGraph::vertex_descriptor>
get(ccstd::pmr::vector<boost::default_color_type>& colors, const ResourceAccessGraph& /*g*/) noexcept {
return {colors};
}
// Vertex Component
inline typename boost::property_map<ResourceAccessGraph, ResourceAccessGraph::PassIDTag>::const_type
get(ResourceAccessGraph::PassIDTag /*tag*/, const ResourceAccessGraph& g) noexcept {
return {g.passID};
}
inline typename boost::property_map<ResourceAccessGraph, ResourceAccessGraph::PassIDTag>::type
get(ResourceAccessGraph::PassIDTag /*tag*/, ResourceAccessGraph& g) noexcept {
return {g.passID};
}
// Vertex Component
inline typename boost::property_map<ResourceAccessGraph, ResourceAccessGraph::PassNodeTag>::const_type
get(ResourceAccessGraph::PassNodeTag /*tag*/, const ResourceAccessGraph& g) noexcept {
return {g.passResource};
}
inline typename boost::property_map<ResourceAccessGraph, ResourceAccessGraph::PassNodeTag>::type
get(ResourceAccessGraph::PassNodeTag /*tag*/, ResourceAccessGraph& g) noexcept {
return {g.passResource};
}
// Vertex ComponentMember
template <class T>
inline typename boost::property_map<ResourceAccessGraph, T ResourceAccessNode::*>::const_type
get(T ResourceAccessNode::*memberPointer, const ResourceAccessGraph& g) noexcept {
return {g.passResource, memberPointer};
}
template <class T>
inline typename boost::property_map<ResourceAccessGraph, T ResourceAccessNode::*>::type
get(T ResourceAccessNode::*memberPointer, ResourceAccessGraph& g) noexcept {
return {g.passResource, memberPointer};
}
// Vertex Component
inline typename boost::property_map<ResourceAccessGraph, ResourceAccessGraph::RenderPassInfoTag>::const_type
get(ResourceAccessGraph::RenderPassInfoTag /*tag*/, const ResourceAccessGraph& g) noexcept {
return {g.rpInfo};
}
inline typename boost::property_map<ResourceAccessGraph, ResourceAccessGraph::RenderPassInfoTag>::type
get(ResourceAccessGraph::RenderPassInfoTag /*tag*/, ResourceAccessGraph& g) noexcept {
return {g.rpInfo};
}
// Vertex ComponentMember
template <class T>
inline typename boost::property_map<ResourceAccessGraph, T FGRenderPassInfo::*>::const_type
get(T FGRenderPassInfo::*memberPointer, const ResourceAccessGraph& g) noexcept {
return {g.rpInfo, memberPointer};
}
template <class T>
inline typename boost::property_map<ResourceAccessGraph, T FGRenderPassInfo::*>::type
get(T FGRenderPassInfo::*memberPointer, ResourceAccessGraph& g) noexcept {
return {g.rpInfo, memberPointer};
}
// Vertex Component
inline typename boost::property_map<ResourceAccessGraph, ResourceAccessGraph::BarrierTag>::const_type
get(ResourceAccessGraph::BarrierTag /*tag*/, const ResourceAccessGraph& g) noexcept {
return {g.barrier};
}
inline typename boost::property_map<ResourceAccessGraph, ResourceAccessGraph::BarrierTag>::type
get(ResourceAccessGraph::BarrierTag /*tag*/, ResourceAccessGraph& g) noexcept {
return {g.barrier};
}
// Vertex ComponentMember
template <class T>
inline typename boost::property_map<ResourceAccessGraph, T BarrierNode::*>::const_type
get(T BarrierNode::*memberPointer, const ResourceAccessGraph& g) noexcept {
return {g.barrier, memberPointer};
}
template <class T>
inline typename boost::property_map<ResourceAccessGraph, T BarrierNode::*>::type
get(T BarrierNode::*memberPointer, ResourceAccessGraph& g) noexcept {
return {g.barrier, memberPointer};
}
// Vertex Constant Getter
template <class Tag>
inline decltype(auto)
get(Tag tag, const ResourceAccessGraph& g, ResourceAccessGraph::vertex_descriptor v) noexcept {
return get(get(tag, g), v);
}
// Vertex Mutable Getter
template <class Tag>
inline decltype(auto)
get(Tag tag, ResourceAccessGraph& g, ResourceAccessGraph::vertex_descriptor v) noexcept {
return get(get(tag, g), v);
}
// Vertex Setter
template <class Tag, class... Args>
inline void put(
Tag tag, ResourceAccessGraph& g,
ResourceAccessGraph::vertex_descriptor v,
Args&&... args) {
put(get(tag, g), v, std::forward<Args>(args)...);
}
// UuidGraph
inline ResourceAccessGraph::vertex_descriptor
vertex(const RenderGraph::vertex_descriptor& key, const ResourceAccessGraph& g) {
return g.passIndex.at(key);
}
template <class KeyLike>
inline ResourceAccessGraph::vertex_descriptor
vertex(const KeyLike& key, const ResourceAccessGraph& g) {
const auto& index = g.passIndex;
auto iter = index.find(key);
if (iter == index.end()) {
throw std::out_of_range("at(key, ResourceAccessGraph) out of range");
}
return iter->second;
}
template <class KeyLike>
inline ResourceAccessGraph::vertex_descriptor
findVertex(const KeyLike& key, const ResourceAccessGraph& g) noexcept {
const auto& index = g.passIndex;
auto iter = index.find(key);
if (iter == index.end()) {
return ResourceAccessGraph::null_vertex();
}
return iter->second;
}
inline bool
contains(const RenderGraph::vertex_descriptor& key, const ResourceAccessGraph& g) noexcept {
auto iter = g.passIndex.find(key);
return iter != g.passIndex.end();
}
template <class KeyLike>
inline bool
contains(const KeyLike& key, const ResourceAccessGraph& g) noexcept {
auto iter = g.passIndex.find(key);
return iter != g.passIndex.end();
}
// MutableGraph(Vertex)
inline ResourceAccessGraph::vertex_descriptor
add_vertex(ResourceAccessGraph& g, const RenderGraph::vertex_descriptor& key) { // NOLINT
return addVertex(
std::piecewise_construct,
std::forward_as_tuple(key), // passID
std::forward_as_tuple(), // passResource
std::forward_as_tuple(), // rpInfo
std::forward_as_tuple(), // barrier
g);
}
// Vertex Index
inline boost::property_map<RelationGraph, boost::vertex_index_t>::const_type
get(boost::vertex_index_t /*tag*/, const RelationGraph& /*g*/) noexcept {
return {};
}
inline boost::property_map<RelationGraph, boost::vertex_index_t>::type
get(boost::vertex_index_t /*tag*/, RelationGraph& /*g*/) noexcept {
return {};
}
inline impl::ColorMap<RelationGraph::vertex_descriptor>
get(ccstd::pmr::vector<boost::default_color_type>& colors, const RelationGraph& /*g*/) noexcept {
return {colors};
}
// Vertex Component
inline typename boost::property_map<RelationGraph, RelationGraph::DescIDTag>::const_type
get(RelationGraph::DescIDTag /*tag*/, const RelationGraph& g) noexcept {
return {g.descID};
}
inline typename boost::property_map<RelationGraph, RelationGraph::DescIDTag>::type
get(RelationGraph::DescIDTag /*tag*/, RelationGraph& g) noexcept {
return {g.descID};
}
// Vertex Constant Getter
template <class Tag>
inline decltype(auto)
get(Tag tag, const RelationGraph& g, RelationGraph::vertex_descriptor v) noexcept {
return get(get(tag, g), v);
}
// Vertex Mutable Getter
template <class Tag>
inline decltype(auto)
get(Tag tag, RelationGraph& g, RelationGraph::vertex_descriptor v) noexcept {
return get(get(tag, g), v);
}
// Vertex Setter
template <class Tag, class... Args>
inline void put(
Tag tag, RelationGraph& g,
RelationGraph::vertex_descriptor v,
Args&&... args) {
put(get(tag, g), v, std::forward<Args>(args)...);
}
// UuidGraph
inline RelationGraph::vertex_descriptor
vertex(const ResourceAccessGraph::vertex_descriptor& key, const RelationGraph& g) {
return g.vertexMap.at(key);
}
template <class KeyLike>
inline RelationGraph::vertex_descriptor
vertex(const KeyLike& key, const RelationGraph& g) {
const auto& index = g.vertexMap;
auto iter = index.find(key);
if (iter == index.end()) {
throw std::out_of_range("at(key, RelationGraph) out of range");
}
return iter->second;
}
template <class KeyLike>
inline RelationGraph::vertex_descriptor
findVertex(const KeyLike& key, const RelationGraph& g) noexcept {
const auto& index = g.vertexMap;
auto iter = index.find(key);
if (iter == index.end()) {
return RelationGraph::null_vertex();
}
return iter->second;
}
inline bool
contains(const ResourceAccessGraph::vertex_descriptor& key, const RelationGraph& g) noexcept {
auto iter = g.vertexMap.find(key);
return iter != g.vertexMap.end();
}
template <class KeyLike>
inline bool
contains(const KeyLike& key, const RelationGraph& g) noexcept {
auto iter = g.vertexMap.find(key);
return iter != g.vertexMap.end();
}
// MutableGraph(Vertex)
inline RelationGraph::vertex_descriptor
add_vertex(RelationGraph& g, const ResourceAccessGraph::vertex_descriptor& key) { // NOLINT
return addVertex(
std::piecewise_construct,
std::forward_as_tuple(key), // descID
g);
}
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,174 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#include "FGDispatcherTypes.h"
namespace cc {
namespace render {
ResourceAccessNode::ResourceAccessNode(const allocator_type& alloc) noexcept
: resourceStatus(alloc) {}
ResourceAccessNode::ResourceAccessNode(ResourceAccessNode&& rhs, const allocator_type& alloc)
: resourceStatus(std::move(rhs.resourceStatus), alloc) {}
ResourceAccessNode::ResourceAccessNode(ResourceAccessNode const& rhs, const allocator_type& alloc)
: resourceStatus(rhs.resourceStatus, alloc) {}
AttachmentInfo::AttachmentInfo(const allocator_type& alloc) noexcept
: parentName(alloc) {}
AttachmentInfo::AttachmentInfo(AttachmentInfo&& rhs, const allocator_type& alloc)
: parentName(std::move(rhs.parentName), alloc),
attachmentIndex(rhs.attachmentIndex),
isResolveView(rhs.isResolveView) {}
AttachmentInfo::AttachmentInfo(AttachmentInfo const& rhs, const allocator_type& alloc)
: parentName(rhs.parentName, alloc),
attachmentIndex(rhs.attachmentIndex),
isResolveView(rhs.isResolveView) {}
FGRenderPassInfo::FGRenderPassInfo(const allocator_type& alloc) noexcept
: orderedViews(alloc),
viewIndex(alloc) {}
FGRenderPassInfo::FGRenderPassInfo(FGRenderPassInfo&& rhs, const allocator_type& alloc)
: colorAccesses(std::move(rhs.colorAccesses)),
dsAccess(rhs.dsAccess),
dsResolveAccess(rhs.dsResolveAccess),
rpInfo(std::move(rhs.rpInfo)),
orderedViews(std::move(rhs.orderedViews), alloc),
viewIndex(std::move(rhs.viewIndex), alloc),
resolveCount(rhs.resolveCount),
uniqueRasterViewCount(rhs.uniqueRasterViewCount) {}
FGRenderPassInfo::FGRenderPassInfo(FGRenderPassInfo const& rhs, const allocator_type& alloc)
: colorAccesses(rhs.colorAccesses),
dsAccess(rhs.dsAccess),
dsResolveAccess(rhs.dsResolveAccess),
rpInfo(rhs.rpInfo),
orderedViews(rhs.orderedViews, alloc),
viewIndex(rhs.viewIndex, alloc),
resolveCount(rhs.resolveCount),
uniqueRasterViewCount(rhs.uniqueRasterViewCount) {}
ResourceAccessGraph::ResourceAccessGraph(const allocator_type& alloc) noexcept
: _vertices(alloc),
passID(alloc),
passResource(alloc),
rpInfo(alloc),
barrier(alloc),
passIndex(alloc),
resourceNames(alloc),
resourceIndex(alloc),
leafPasses(alloc),
culledPasses(alloc),
resourceLifeRecord(alloc),
topologicalOrder(alloc),
resourceAccess(alloc),
movedTarget(alloc),
movedSourceStatus(alloc),
movedTargetStatus(alloc) {}
// ContinuousContainer
void ResourceAccessGraph::reserve(vertices_size_type sz) {
_vertices.reserve(sz);
passID.reserve(sz);
passResource.reserve(sz);
rpInfo.reserve(sz);
barrier.reserve(sz);
}
ResourceAccessGraph::Vertex::Vertex(const allocator_type& alloc) noexcept
: outEdges(alloc),
inEdges(alloc) {}
ResourceAccessGraph::Vertex::Vertex(Vertex&& rhs, const allocator_type& alloc)
: outEdges(std::move(rhs.outEdges), alloc),
inEdges(std::move(rhs.inEdges), alloc) {}
ResourceAccessGraph::Vertex::Vertex(Vertex const& rhs, const allocator_type& alloc)
: outEdges(rhs.outEdges, alloc),
inEdges(rhs.inEdges, alloc) {}
RelationGraph::RelationGraph(const allocator_type& alloc) noexcept
: _vertices(alloc),
descID(alloc),
vertexMap(alloc) {}
// ContinuousContainer
void RelationGraph::reserve(vertices_size_type sz) {
_vertices.reserve(sz);
descID.reserve(sz);
}
RelationGraph::Vertex::Vertex(const allocator_type& alloc) noexcept
: outEdges(alloc),
inEdges(alloc) {}
RelationGraph::Vertex::Vertex(Vertex&& rhs, const allocator_type& alloc)
: outEdges(std::move(rhs.outEdges), alloc),
inEdges(std::move(rhs.inEdges), alloc) {}
RelationGraph::Vertex::Vertex(Vertex const& rhs, const allocator_type& alloc)
: outEdges(rhs.outEdges, alloc),
inEdges(rhs.inEdges, alloc) {}
RenderingInfo::RenderingInfo(const allocator_type& alloc) noexcept
: clearColors(alloc) {}
RenderingInfo::RenderingInfo(RenderingInfo&& rhs, const allocator_type& alloc)
: renderpassInfo(std::move(rhs.renderpassInfo)),
framebufferInfo(std::move(rhs.framebufferInfo)),
clearColors(std::move(rhs.clearColors), alloc),
clearDepth(rhs.clearDepth),
clearStencil(rhs.clearStencil) {}
RenderingInfo::RenderingInfo(RenderingInfo const& rhs, const allocator_type& alloc)
: renderpassInfo(rhs.renderpassInfo),
framebufferInfo(rhs.framebufferInfo),
clearColors(rhs.clearColors, alloc),
clearDepth(rhs.clearDepth),
clearStencil(rhs.clearStencil) {}
FrameGraphDispatcher::FrameGraphDispatcher(ResourceGraph& resourceGraphIn, const RenderGraph& renderGraphIn, const LayoutGraphData& layoutGraphIn, boost::container::pmr::memory_resource* scratchIn, const allocator_type& alloc) noexcept
: resourceAccessGraph(alloc),
resourceGraph(resourceGraphIn),
renderGraph(renderGraphIn),
layoutGraph(layoutGraphIn),
scratch(scratchIn),
relationGraph(alloc) {}
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,506 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include <boost/graph/adjacency_iterator.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/properties.hpp>
#include <boost/range/irange.hpp>
#include <variant>
#include "cocos/base/std/container/string.h"
#include "cocos/base/std/container/vector.h"
#include "cocos/renderer/pipeline/custom/LayoutGraphTypes.h"
#include "cocos/renderer/pipeline/custom/RenderGraphTypes.h"
#include "cocos/renderer/pipeline/custom/details/GraphTypes.h"
#include "cocos/renderer/pipeline/custom/details/Map.h"
#include "cocos/renderer/pipeline/custom/details/Set.h"
#include "gfx-base/GFXDef-common.h"
namespace cc {
namespace render {
struct NullTag {
};
struct ResourceLifeRecord {
uint32_t start{0};
uint32_t end{0};
};
struct LeafStatus {
bool isExternal{false};
bool needCulling{false};
};
struct AccessStatus {
gfx::AccessFlagBit accessFlag{gfx::AccessFlagBit::NONE};
gfx::ResourceRange range;
};
struct ResourceAccessNode {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {resourceStatus.get_allocator().resource()};
}
ResourceAccessNode(const allocator_type& alloc) noexcept; // NOLINT
ResourceAccessNode(ResourceAccessNode&& rhs, const allocator_type& alloc);
ResourceAccessNode(ResourceAccessNode const& rhs, const allocator_type& alloc);
ResourceAccessNode(ResourceAccessNode&& rhs) noexcept = default;
ResourceAccessNode(ResourceAccessNode const& rhs) = delete;
ResourceAccessNode& operator=(ResourceAccessNode&& rhs) = default;
ResourceAccessNode& operator=(ResourceAccessNode const& rhs) = default;
PmrFlatMap<ccstd::pmr::string, AccessStatus> resourceStatus;
};
struct LayoutAccess {
gfx::AccessFlagBit prevAccess{gfx::AccessFlagBit::NONE};
gfx::AccessFlagBit nextAccess{gfx::AccessFlagBit::NONE};
};
struct AttachmentInfo {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {parentName.get_allocator().resource()};
}
AttachmentInfo(const allocator_type& alloc) noexcept; // NOLINT
AttachmentInfo(AttachmentInfo&& rhs, const allocator_type& alloc);
AttachmentInfo(AttachmentInfo const& rhs, const allocator_type& alloc);
AttachmentInfo(AttachmentInfo&& rhs) noexcept = default;
AttachmentInfo(AttachmentInfo const& rhs) = delete;
AttachmentInfo& operator=(AttachmentInfo&& rhs) = default;
AttachmentInfo& operator=(AttachmentInfo const& rhs) = default;
ccstd::pmr::string parentName;
uint32_t attachmentIndex{0};
uint32_t isResolveView{0};
};
struct FGRenderPassInfo {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {orderedViews.get_allocator().resource()};
}
FGRenderPassInfo(const allocator_type& alloc) noexcept; // NOLINT
FGRenderPassInfo(FGRenderPassInfo&& rhs, const allocator_type& alloc);
FGRenderPassInfo(FGRenderPassInfo const& rhs, const allocator_type& alloc);
FGRenderPassInfo(FGRenderPassInfo&& rhs) noexcept = default;
FGRenderPassInfo(FGRenderPassInfo const& rhs) = delete;
FGRenderPassInfo& operator=(FGRenderPassInfo&& rhs) = default;
FGRenderPassInfo& operator=(FGRenderPassInfo const& rhs) = default;
ccstd::vector<LayoutAccess> colorAccesses;
LayoutAccess dsAccess;
LayoutAccess dsResolveAccess;
gfx::RenderPassInfo rpInfo;
ccstd::pmr::vector<ccstd::pmr::string> orderedViews;
PmrTransparentMap<ccstd::pmr::string, AttachmentInfo> viewIndex;
uint32_t resolveCount{0};
uint32_t uniqueRasterViewCount{0};
};
struct Barrier {
ResourceGraph::vertex_descriptor resourceID{0xFFFFFFFF};
gfx::BarrierType type{gfx::BarrierType::FULL};
gfx::GFXObject* barrier{nullptr};
RenderGraph::vertex_descriptor beginVert{0xFFFFFFFF};
RenderGraph::vertex_descriptor endVert{0xFFFFFFFF};
AccessStatus beginStatus;
AccessStatus endStatus;
};
struct BarrierNode {
ccstd::vector<Barrier> frontBarriers;
ccstd::vector<Barrier> rearBarriers;
};
struct SliceNode {
bool full{false};
ccstd::vector<uint32_t> mips;
};
struct TextureNode {
bool full{false};
ccstd::vector<SliceNode> slices;
};
struct ResourceNode {
bool full{false};
ccstd::vector<TextureNode> planes;
};
struct ResourceAccessGraph {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {_vertices.get_allocator().resource()};
}
inline boost::container::pmr::memory_resource* resource() const noexcept {
return get_allocator().resource();
}
ResourceAccessGraph(const allocator_type& alloc) noexcept; // NOLINT
ResourceAccessGraph(ResourceAccessGraph&& rhs) = delete;
ResourceAccessGraph(ResourceAccessGraph const& rhs) = delete;
ResourceAccessGraph& operator=(ResourceAccessGraph&& rhs) = delete;
ResourceAccessGraph& operator=(ResourceAccessGraph const& rhs) = delete;
// Graph
using directed_category = boost::bidirectional_tag;
using vertex_descriptor = uint32_t;
using edge_descriptor = impl::EdgeDescriptor<directed_category, vertex_descriptor>;
using edge_parallel_category = boost::allow_parallel_edge_tag;
struct traversal_category // NOLINT
: virtual boost::incidence_graph_tag,
virtual boost::bidirectional_graph_tag,
virtual boost::adjacency_graph_tag,
virtual boost::vertex_list_graph_tag,
virtual boost::edge_list_graph_tag {};
constexpr static vertex_descriptor null_vertex() noexcept { // NOLINT
return std::numeric_limits<vertex_descriptor>::max();
}
// IncidenceGraph
using OutEdge = impl::StoredEdge<vertex_descriptor>;
using out_edge_iterator = impl::OutEdgeIter<
ccstd::pmr::vector<OutEdge>::iterator,
vertex_descriptor, edge_descriptor, int32_t>;
using degree_size_type = uint32_t;
// BidirectionalGraph
using InEdge = impl::StoredEdge<vertex_descriptor>;
using in_edge_iterator = impl::InEdgeIter<
ccstd::pmr::vector<InEdge>::iterator,
vertex_descriptor, edge_descriptor, int32_t>;
// AdjacencyGraph
using adjacency_iterator = boost::adjacency_iterator_generator<
ResourceAccessGraph, vertex_descriptor, out_edge_iterator>::type;
// VertexListGraph
using vertex_iterator = boost::integer_range<vertex_descriptor>::iterator;
using vertices_size_type = uint32_t;
// VertexList help functions
inline ccstd::pmr::vector<OutEdge>& getOutEdgeList(vertex_descriptor v) noexcept {
return _vertices[v].outEdges;
}
inline const ccstd::pmr::vector<OutEdge>& getOutEdgeList(vertex_descriptor v) const noexcept {
return _vertices[v].outEdges;
}
inline ccstd::pmr::vector<InEdge>& getInEdgeList(vertex_descriptor v) noexcept {
return _vertices[v].inEdges;
}
inline const ccstd::pmr::vector<InEdge>& getInEdgeList(vertex_descriptor v) const noexcept {
return _vertices[v].inEdges;
}
inline boost::integer_range<vertex_descriptor> getVertexList() const noexcept {
return {0, static_cast<vertices_size_type>(_vertices.size())};
}
inline vertex_descriptor getCurrentID() const noexcept {
return static_cast<vertex_descriptor>(_vertices.size());
}
inline ccstd::pmr::vector<boost::default_color_type> colors(boost::container::pmr::memory_resource* mr) const {
return ccstd::pmr::vector<boost::default_color_type>(_vertices.size(), mr);
}
// EdgeListGraph
using edge_iterator = impl::DirectedEdgeIterator<vertex_iterator, out_edge_iterator, ResourceAccessGraph>;
using edges_size_type = uint32_t;
LayoutAccess getAccess(ccstd::pmr::string, RenderGraph::vertex_descriptor vertID);
// ContinuousContainer
void reserve(vertices_size_type sz);
// Members
struct Vertex {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {outEdges.get_allocator().resource()};
}
Vertex(const allocator_type& alloc) noexcept; // NOLINT
Vertex(Vertex&& rhs, const allocator_type& alloc);
Vertex(Vertex const& rhs, const allocator_type& alloc);
Vertex(Vertex&& rhs) noexcept = default;
Vertex(Vertex const& rhs) = delete;
Vertex& operator=(Vertex&& rhs) = default;
Vertex& operator=(Vertex const& rhs) = default;
ccstd::pmr::vector<OutEdge> outEdges;
ccstd::pmr::vector<InEdge> inEdges;
};
struct PassIDTag {};
struct PassNodeTag {};
struct RenderPassInfoTag {};
struct BarrierTag {};
// Vertices
ccstd::pmr::vector<Vertex> _vertices;
// Components
ccstd::pmr::vector<RenderGraph::vertex_descriptor> passID;
ccstd::pmr::vector<ResourceAccessNode> passResource;
ccstd::pmr::vector<FGRenderPassInfo> rpInfo;
ccstd::pmr::vector<BarrierNode> barrier;
// UuidGraph
PmrUnorderedMap<RenderGraph::vertex_descriptor, vertex_descriptor> passIndex;
// Members
ccstd::pmr::vector<ccstd::pmr::string> resourceNames;
PmrUnorderedStringMap<ccstd::pmr::string, uint32_t> resourceIndex;
vertex_descriptor presentPassID{0xFFFFFFFF};
PmrFlatMap<vertex_descriptor, LeafStatus> leafPasses;
PmrFlatSet<vertex_descriptor> culledPasses;
PmrFlatMap<ccstd::pmr::string, ResourceLifeRecord> resourceLifeRecord;
ccstd::pmr::vector<vertex_descriptor> topologicalOrder;
PmrTransparentMap<ccstd::pmr::string, PmrFlatMap<uint32_t, AccessStatus>> resourceAccess;
PmrFlatMap<ccstd::pmr::string, PmrFlatMap<ccstd::pmr::string, ccstd::pmr::string>> movedTarget;
PmrFlatMap<ccstd::pmr::string, AccessStatus> movedSourceStatus;
PmrFlatMap<ccstd::pmr::string, ResourceNode> movedTargetStatus;
};
struct RelationGraph {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {_vertices.get_allocator().resource()};
}
inline boost::container::pmr::memory_resource* resource() const noexcept {
return get_allocator().resource();
}
RelationGraph(const allocator_type& alloc) noexcept; // NOLINT
RelationGraph(RelationGraph&& rhs) = delete;
RelationGraph(RelationGraph const& rhs) = delete;
RelationGraph& operator=(RelationGraph&& rhs) = delete;
RelationGraph& operator=(RelationGraph const& rhs) = delete;
// Graph
using directed_category = boost::bidirectional_tag;
using vertex_descriptor = uint32_t;
using edge_descriptor = impl::EdgeDescriptor<directed_category, vertex_descriptor>;
using edge_parallel_category = boost::allow_parallel_edge_tag;
struct traversal_category // NOLINT
: virtual boost::incidence_graph_tag,
virtual boost::bidirectional_graph_tag,
virtual boost::adjacency_graph_tag,
virtual boost::vertex_list_graph_tag,
virtual boost::edge_list_graph_tag {};
constexpr static vertex_descriptor null_vertex() noexcept { // NOLINT
return std::numeric_limits<vertex_descriptor>::max();
}
// IncidenceGraph
using OutEdge = impl::StoredEdge<vertex_descriptor>;
using out_edge_iterator = impl::OutEdgeIter<
ccstd::pmr::vector<OutEdge>::iterator,
vertex_descriptor, edge_descriptor, int32_t>;
using degree_size_type = uint32_t;
// BidirectionalGraph
using InEdge = impl::StoredEdge<vertex_descriptor>;
using in_edge_iterator = impl::InEdgeIter<
ccstd::pmr::vector<InEdge>::iterator,
vertex_descriptor, edge_descriptor, int32_t>;
// AdjacencyGraph
using adjacency_iterator = boost::adjacency_iterator_generator<
RelationGraph, vertex_descriptor, out_edge_iterator>::type;
// VertexListGraph
using vertex_iterator = boost::integer_range<vertex_descriptor>::iterator;
using vertices_size_type = uint32_t;
// VertexList help functions
inline ccstd::pmr::vector<OutEdge>& getOutEdgeList(vertex_descriptor v) noexcept {
return _vertices[v].outEdges;
}
inline const ccstd::pmr::vector<OutEdge>& getOutEdgeList(vertex_descriptor v) const noexcept {
return _vertices[v].outEdges;
}
inline ccstd::pmr::vector<InEdge>& getInEdgeList(vertex_descriptor v) noexcept {
return _vertices[v].inEdges;
}
inline const ccstd::pmr::vector<InEdge>& getInEdgeList(vertex_descriptor v) const noexcept {
return _vertices[v].inEdges;
}
inline boost::integer_range<vertex_descriptor> getVertexList() const noexcept {
return {0, static_cast<vertices_size_type>(_vertices.size())};
}
inline vertex_descriptor getCurrentID() const noexcept {
return static_cast<vertex_descriptor>(_vertices.size());
}
inline ccstd::pmr::vector<boost::default_color_type> colors(boost::container::pmr::memory_resource* mr) const {
return ccstd::pmr::vector<boost::default_color_type>(_vertices.size(), mr);
}
// EdgeListGraph
using edge_iterator = impl::DirectedEdgeIterator<vertex_iterator, out_edge_iterator, RelationGraph>;
using edges_size_type = uint32_t;
// ContinuousContainer
void reserve(vertices_size_type sz);
// Members
struct Vertex {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {outEdges.get_allocator().resource()};
}
Vertex(const allocator_type& alloc) noexcept; // NOLINT
Vertex(Vertex&& rhs, const allocator_type& alloc);
Vertex(Vertex const& rhs, const allocator_type& alloc);
Vertex(Vertex&& rhs) noexcept = default;
Vertex(Vertex const& rhs) = delete;
Vertex& operator=(Vertex&& rhs) = default;
Vertex& operator=(Vertex const& rhs) = default;
ccstd::pmr::vector<OutEdge> outEdges;
ccstd::pmr::vector<InEdge> inEdges;
};
struct DescIDTag {};
// Vertices
ccstd::pmr::vector<Vertex> _vertices;
// Components
ccstd::pmr::vector<ResourceAccessGraph::vertex_descriptor> descID;
// UuidGraph
PmrUnorderedMap<ResourceAccessGraph::vertex_descriptor, vertex_descriptor> vertexMap;
};
struct RenderingInfo {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {clearColors.get_allocator().resource()};
}
RenderingInfo(const allocator_type& alloc) noexcept; // NOLINT
RenderingInfo(RenderingInfo&& rhs, const allocator_type& alloc);
RenderingInfo(RenderingInfo const& rhs, const allocator_type& alloc);
RenderingInfo(RenderingInfo&& rhs) noexcept = default;
RenderingInfo(RenderingInfo const& rhs) = delete;
RenderingInfo& operator=(RenderingInfo&& rhs) = default;
RenderingInfo& operator=(RenderingInfo const& rhs) = default;
gfx::RenderPassInfo renderpassInfo;
gfx::FramebufferInfo framebufferInfo;
ccstd::pmr::vector<gfx::Color> clearColors;
float clearDepth{0};
uint8_t clearStencil{0};
};
struct FrameGraphDispatcher {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {resourceAccessGraph.get_allocator().resource()};
}
FrameGraphDispatcher(ResourceGraph& resourceGraphIn, const RenderGraph& renderGraphIn, const LayoutGraphData& layoutGraphIn, boost::container::pmr::memory_resource* scratchIn, const allocator_type& alloc) noexcept;
FrameGraphDispatcher(FrameGraphDispatcher&& rhs) = delete;
FrameGraphDispatcher(FrameGraphDispatcher const& rhs) = delete;
FrameGraphDispatcher& operator=(FrameGraphDispatcher&& rhs) = delete;
FrameGraphDispatcher& operator=(FrameGraphDispatcher const& rhs) = delete;
void enablePassReorder(bool enable);
// how much paralell-execution weights during pass reorder,
// eg:0.3 means 30% of effort aim to paralellize execution, other 70% aim to decrease memory using.
// 0 by default
void setParalellWeight(float paralellExecWeight);
void enableMemoryAliasing(bool enable);
void run();
const BarrierNode& getBarrier(RenderGraph::vertex_descriptor u) const;
const ResourceAccessNode& getAccessNode(RenderGraph::vertex_descriptor u) const;
const gfx::RenderPassInfo& getRenderPassInfo(RenderGraph::vertex_descriptor u) const;
RenderingInfo getRenderPassAndFrameBuffer(RenderGraph::vertex_descriptor u, const ResourceGraph& resg) const;
LayoutAccess getResourceAccess(ResourceGraph::vertex_descriptor r, RenderGraph::vertex_descriptor p) const;
// those resource been moved point to another resID
ResourceGraph::vertex_descriptor realResourceID(const ccstd::pmr::string& name) const;
PmrFlatMap<NameLocalID, ResourceGraph::vertex_descriptor> buildDescriptorIndex(
const PmrTransparentMap<ccstd::pmr::string, ccstd::pmr::vector<ComputeView>>&computeViews,
const PmrTransparentMap<ccstd::pmr::string, RasterView>& rasterViews,
boost::container::pmr::memory_resource* scratch) const;
PmrFlatMap<NameLocalID, ResourceGraph::vertex_descriptor> buildDescriptorIndex(
const PmrTransparentMap<ccstd::pmr::string, ccstd::pmr::vector<ComputeView>>&computeViews,
boost::container::pmr::memory_resource* scratch) const;
ResourceAccessGraph resourceAccessGraph;
ResourceGraph& resourceGraph;
const RenderGraph& renderGraph;
const LayoutGraphData& layoutGraph;
boost::container::pmr::memory_resource* scratch{nullptr};
RelationGraph relationGraph;
bool _enablePassReorder{false};
bool _enableAutoBarrier{true};
bool _enableMemoryAliasing{false};
bool _accessGraphBuilt{false};
float _paralellExecWeight{0.0F};
};
} // namespace render
} // namespace cc
// clang-format on

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,81 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include "cocos/base/std/hash/hash.h"
#include "cocos/base/std/variant.h"
#include "cocos/renderer/pipeline/custom/RenderCommonFwd.h"
namespace cc {
namespace render {
struct DescriptorDB;
struct RenderStageTag;
struct RenderPhaseTag;
struct RenderPhase;
enum class RenderPassType : uint32_t;
struct LayoutGraph;
using UniformID = uint32_t;
struct UniformData;
struct UniformBlockData;
struct NameLocalID;
struct DescriptorData;
struct DescriptorBlockData;
struct DescriptorSetLayoutData;
struct DescriptorSetData;
struct PipelineLayoutData;
struct ShaderBindingData;
struct ShaderLayoutData;
struct TechniqueData;
struct EffectData;
struct ShaderProgramData;
struct RenderStageData;
struct RenderPhaseData;
struct LayoutGraphData;
} // namespace render
} // namespace cc
namespace ccstd {
template <>
struct hash<cc::render::NameLocalID> {
hash_t operator()(const cc::render::NameLocalID& val) const noexcept;
};
} // namespace ccstd
// clang-format on

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,73 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include "cocos/renderer/pipeline/custom/LayoutGraphTypes.h"
#include "cocos/renderer/pipeline/custom/RenderCommonNames.h"
namespace cc {
namespace render {
inline const char* getName(const DescriptorDB& /*v*/) noexcept { return "DescriptorDB"; }
inline const char* getName(const RenderStageTag& /*v*/) noexcept { return "RenderStage"; }
inline const char* getName(const RenderPhaseTag& /*v*/) noexcept { return "RenderPhase"; }
inline const char* getName(const RenderPhase& /*v*/) noexcept { return "RenderPhase"; }
inline const char* getName(RenderPassType e) noexcept {
switch (e) {
case RenderPassType::SINGLE_RENDER_PASS: return "SINGLE_RENDER_PASS";
case RenderPassType::RENDER_PASS: return "RENDER_PASS";
case RenderPassType::RENDER_SUBPASS: return "RENDER_SUBPASS";
}
return "";
}
inline const char* getName(const LayoutGraph& /*v*/) noexcept { return "LayoutGraph"; }
inline const char* getName(const UniformData& /*v*/) noexcept { return "UniformData"; }
inline const char* getName(const UniformBlockData& /*v*/) noexcept { return "UniformBlockData"; }
inline const char* getName(const NameLocalID& /*v*/) noexcept { return "NameLocalID"; }
inline const char* getName(const DescriptorData& /*v*/) noexcept { return "DescriptorData"; }
inline const char* getName(const DescriptorBlockData& /*v*/) noexcept { return "DescriptorBlockData"; }
inline const char* getName(const DescriptorSetLayoutData& /*v*/) noexcept { return "DescriptorSetLayoutData"; }
inline const char* getName(const DescriptorSetData& /*v*/) noexcept { return "DescriptorSetData"; }
inline const char* getName(const PipelineLayoutData& /*v*/) noexcept { return "PipelineLayoutData"; }
inline const char* getName(const ShaderBindingData& /*v*/) noexcept { return "ShaderBindingData"; }
inline const char* getName(const ShaderLayoutData& /*v*/) noexcept { return "ShaderLayoutData"; }
inline const char* getName(const TechniqueData& /*v*/) noexcept { return "TechniqueData"; }
inline const char* getName(const EffectData& /*v*/) noexcept { return "EffectData"; }
inline const char* getName(const ShaderProgramData& /*v*/) noexcept { return "ShaderProgramData"; }
inline const char* getName(const RenderStageData& /*v*/) noexcept { return "RenderStageData"; }
inline const char* getName(const RenderPhaseData& /*v*/) noexcept { return "RenderPhaseData"; }
inline const char* getName(const LayoutGraphData& /*v*/) noexcept { return "LayoutGraphData"; }
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,405 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
#pragma once
#include "cocos/renderer/pipeline/custom/ArchiveTypes.h"
#include "cocos/renderer/pipeline/custom/LayoutGraphGraphs.h"
#include "cocos/renderer/pipeline/custom/LayoutGraphTypes.h"
#include "cocos/renderer/pipeline/custom/RenderCommonSerialization.h"
#include "cocos/renderer/pipeline/custom/details/Range.h"
#include "cocos/renderer/pipeline/custom/details/SerializationUtils.h"
namespace cc {
namespace render {
inline void save(OutputArchive& ar, const DescriptorDB& v) {
save(ar, v.blocks);
}
inline void load(InputArchive& ar, DescriptorDB& v) {
load(ar, v.blocks);
}
inline void save(OutputArchive& ar, const RenderPhase& v) {
save(ar, v.shaders);
}
inline void load(InputArchive& ar, RenderPhase& v) {
load(ar, v.shaders);
}
inline void save(OutputArchive& ar, const LayoutGraph& g) {
using Graph = LayoutGraph;
using VertexT = Graph::vertex_descriptor;
using SizeT = Graph::vertices_size_type;
static_assert(std::is_same_v<SizeT, VertexT>);
const auto numVertices = num_vertices(g);
const auto numEdges = num_edges(g);
save(ar, numVertices);
save(ar, numEdges);
save(ar, static_cast<SizeT>(g.stages.size()));
save(ar, static_cast<SizeT>(g.phases.size()));
const auto nameMap = get(Graph::NameTag{}, g);
const auto descriptorsMap = get(Graph::DescriptorsTag{}, g);
for (const auto& v : makeRange(vertices(g))) {
const auto typeID = static_cast<SizeT>(tag(v, g).index());
static_assert(std::is_same_v<decltype(typeID), const SizeT>);
save(ar, typeID);
save(ar, parent(v, g));
save(ar, get(nameMap, v));
save(ar, get(descriptorsMap, v));
visitObject(
v, g,
overload(
[&](const auto& object) {
save(ar, object);
}));
}
}
inline void load(InputArchive& ar, LayoutGraph& g) {
using Graph = LayoutGraph;
using VertexT = Graph::vertex_descriptor;
using SizeT = Graph::vertices_size_type;
static_assert(std::is_same_v<SizeT, VertexT>);
SizeT numVertices = 0;
SizeT numEdges = 0;
load(ar, numVertices);
load(ar, numEdges);
g.reserve(numVertices);
SizeT stages = 0;
SizeT phases = 0;
load(ar, stages);
load(ar, phases);
g.stages.reserve(stages);
g.phases.reserve(phases);
const auto nameMap = get(Graph::NameTag{}, g);
const auto descriptorsMap = get(Graph::DescriptorsTag{}, g);
for (SizeT v = 0; v != numVertices; ++v) {
SizeT id = std::numeric_limits<SizeT>::max();
VertexT u = Graph::null_vertex();
ccstd::pmr::string name(g.get_allocator());
DescriptorDB descriptors(g.get_allocator());
load(ar, id);
load(ar, u);
load(ar, name);
load(ar, descriptors);
switch (id) {
case 0: {
RenderPassType val;
load(ar, val);
addVertex(std::move(name), std::move(descriptors), val, g, u);
break;
}
case 1: {
RenderPhase val(g.get_allocator());
load(ar, val);
addVertex(std::move(name), std::move(descriptors), std::move(val), g, u);
break;
}
default:
throw std::runtime_error("load graph failed");
}
}
}
inline void save(OutputArchive& ar, const UniformData& v) {
save(ar, v.uniformID);
save(ar, v.uniformType);
save(ar, v.offset);
save(ar, v.size);
}
inline void load(InputArchive& ar, UniformData& v) {
load(ar, v.uniformID);
load(ar, v.uniformType);
load(ar, v.offset);
load(ar, v.size);
}
inline void save(OutputArchive& ar, const UniformBlockData& v) {
save(ar, v.bufferSize);
save(ar, v.uniforms);
}
inline void load(InputArchive& ar, UniformBlockData& v) {
load(ar, v.bufferSize);
load(ar, v.uniforms);
}
inline void save(OutputArchive& ar, const NameLocalID& v) {
save(ar, v.value);
}
inline void load(InputArchive& ar, NameLocalID& v) {
load(ar, v.value);
}
inline void save(OutputArchive& ar, const DescriptorData& v) {
save(ar, v.descriptorID);
save(ar, v.type);
save(ar, v.count);
}
inline void load(InputArchive& ar, DescriptorData& v) {
load(ar, v.descriptorID);
load(ar, v.type);
load(ar, v.count);
}
inline void save(OutputArchive& ar, const DescriptorBlockData& v) {
save(ar, v.type);
save(ar, v.visibility);
save(ar, v.offset);
save(ar, v.capacity);
save(ar, v.descriptors);
}
inline void load(InputArchive& ar, DescriptorBlockData& v) {
load(ar, v.type);
load(ar, v.visibility);
load(ar, v.offset);
load(ar, v.capacity);
load(ar, v.descriptors);
}
inline void save(OutputArchive& ar, const DescriptorSetLayoutData& v) {
save(ar, v.slot);
save(ar, v.capacity);
save(ar, v.uniformBlockCapacity);
save(ar, v.samplerTextureCapacity);
save(ar, v.descriptorBlocks);
save(ar, v.uniformBlocks);
save(ar, v.bindingMap);
}
inline void load(InputArchive& ar, DescriptorSetLayoutData& v) {
load(ar, v.slot);
load(ar, v.capacity);
load(ar, v.uniformBlockCapacity);
load(ar, v.samplerTextureCapacity);
load(ar, v.descriptorBlocks);
load(ar, v.uniformBlocks);
load(ar, v.bindingMap);
}
inline void save(OutputArchive& ar, const DescriptorSetData& v) {
save(ar, v.descriptorSetLayoutData);
save(ar, v.descriptorSetLayoutInfo);
// skip, descriptorSetLayout: IntrusivePtr<gfx::DescriptorSetLayout>
// skip, descriptorSet: IntrusivePtr<gfx::DescriptorSet>
}
inline void load(InputArchive& ar, DescriptorSetData& v) {
load(ar, v.descriptorSetLayoutData);
load(ar, v.descriptorSetLayoutInfo);
// skip, descriptorSetLayout: IntrusivePtr<gfx::DescriptorSetLayout>
// skip, descriptorSet: IntrusivePtr<gfx::DescriptorSet>
}
inline void save(OutputArchive& ar, const PipelineLayoutData& v) {
save(ar, v.descriptorSets);
}
inline void load(InputArchive& ar, PipelineLayoutData& v) {
load(ar, v.descriptorSets);
}
inline void save(OutputArchive& ar, const ShaderBindingData& v) {
save(ar, v.descriptorBindings);
}
inline void load(InputArchive& ar, ShaderBindingData& v) {
load(ar, v.descriptorBindings);
}
inline void save(OutputArchive& ar, const ShaderLayoutData& v) {
save(ar, v.layoutData);
save(ar, v.bindingData);
}
inline void load(InputArchive& ar, ShaderLayoutData& v) {
load(ar, v.layoutData);
load(ar, v.bindingData);
}
inline void save(OutputArchive& ar, const TechniqueData& v) {
save(ar, v.passes);
}
inline void load(InputArchive& ar, TechniqueData& v) {
load(ar, v.passes);
}
inline void save(OutputArchive& ar, const EffectData& v) {
save(ar, v.techniques);
}
inline void load(InputArchive& ar, EffectData& v) {
load(ar, v.techniques);
}
inline void save(OutputArchive& ar, const ShaderProgramData& v) {
save(ar, v.layout);
// skip, pipelineLayout: IntrusivePtr<gfx::PipelineLayout>
}
inline void load(InputArchive& ar, ShaderProgramData& v) {
load(ar, v.layout);
// skip, pipelineLayout: IntrusivePtr<gfx::PipelineLayout>
}
inline void save(OutputArchive& ar, const RenderStageData& v) {
save(ar, v.descriptorVisibility);
}
inline void load(InputArchive& ar, RenderStageData& v) {
load(ar, v.descriptorVisibility);
}
inline void save(OutputArchive& ar, const RenderPhaseData& v) {
save(ar, v.rootSignature);
save(ar, v.shaderPrograms);
save(ar, v.shaderIndex);
// skip, pipelineLayout: IntrusivePtr<gfx::PipelineLayout>
}
inline void load(InputArchive& ar, RenderPhaseData& v) {
load(ar, v.rootSignature);
load(ar, v.shaderPrograms);
load(ar, v.shaderIndex);
// skip, pipelineLayout: IntrusivePtr<gfx::PipelineLayout>
}
inline void save(OutputArchive& ar, const LayoutGraphData& g) {
using Graph = LayoutGraphData;
using VertexT = Graph::vertex_descriptor;
using SizeT = Graph::vertices_size_type;
static_assert(std::is_same_v<SizeT, VertexT>);
const auto numVertices = num_vertices(g);
const auto numEdges = num_edges(g);
save(ar, numVertices);
save(ar, numEdges);
save(ar, static_cast<SizeT>(g.stages.size()));
save(ar, static_cast<SizeT>(g.phases.size()));
const auto nameMap = get(Graph::NameTag{}, g);
const auto updateMap = get(Graph::UpdateTag{}, g);
const auto layoutMap = get(Graph::LayoutTag{}, g);
for (const auto& v : makeRange(vertices(g))) {
const auto typeID = static_cast<SizeT>(tag(v, g).index());
static_assert(std::is_same_v<decltype(typeID), const SizeT>);
save(ar, typeID);
save(ar, parent(v, g));
save(ar, get(nameMap, v));
save(ar, get(updateMap, v));
save(ar, get(layoutMap, v));
visitObject(
v, g,
overload(
[&](const auto& object) {
save(ar, object);
}));
}
save(ar, g.valueNames);
save(ar, g.attributeIndex);
save(ar, g.constantIndex);
save(ar, g.shaderLayoutIndex);
save(ar, g.effects);
}
inline void load(InputArchive& ar, LayoutGraphData& g) {
using Graph = LayoutGraphData;
using VertexT = Graph::vertex_descriptor;
using SizeT = Graph::vertices_size_type;
static_assert(std::is_same_v<SizeT, VertexT>);
SizeT numVertices = 0;
SizeT numEdges = 0;
load(ar, numVertices);
load(ar, numEdges);
g.reserve(numVertices);
SizeT stages = 0;
SizeT phases = 0;
load(ar, stages);
load(ar, phases);
g.stages.reserve(stages);
g.phases.reserve(phases);
const auto nameMap = get(Graph::NameTag{}, g);
const auto updateMap = get(Graph::UpdateTag{}, g);
const auto layoutMap = get(Graph::LayoutTag{}, g);
for (SizeT v = 0; v != numVertices; ++v) {
SizeT id = std::numeric_limits<SizeT>::max();
VertexT u = Graph::null_vertex();
ccstd::pmr::string name(g.get_allocator());
UpdateFrequency update{};
PipelineLayoutData layout(g.get_allocator());
load(ar, id);
load(ar, u);
load(ar, name);
load(ar, update);
load(ar, layout);
switch (id) {
case 0: {
RenderStageData val(g.get_allocator());
load(ar, val);
addVertex(std::move(name), update, std::move(layout), std::move(val), g, u);
break;
}
case 1: {
RenderPhaseData val(g.get_allocator());
load(ar, val);
addVertex(std::move(name), update, std::move(layout), std::move(val), g, u);
break;
}
default:
throw std::runtime_error("load graph failed");
}
}
load(ar, g.valueNames);
load(ar, g.attributeIndex);
load(ar, g.constantIndex);
load(ar, g.shaderLayoutIndex);
load(ar, g.effects);
}
} // namespace render
} // namespace cc

View File

@@ -0,0 +1,280 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#include "LayoutGraphTypes.h"
namespace cc {
namespace render {
DescriptorDB::DescriptorDB(const allocator_type& alloc) noexcept
: blocks(alloc) {}
DescriptorDB::DescriptorDB(DescriptorDB&& rhs, const allocator_type& alloc)
: blocks(std::move(rhs.blocks), alloc) {}
DescriptorDB::DescriptorDB(DescriptorDB const& rhs, const allocator_type& alloc)
: blocks(rhs.blocks, alloc) {}
RenderPhase::RenderPhase(const allocator_type& alloc) noexcept
: shaders(alloc) {}
RenderPhase::RenderPhase(RenderPhase&& rhs, const allocator_type& alloc)
: shaders(std::move(rhs.shaders), alloc) {}
RenderPhase::RenderPhase(RenderPhase const& rhs, const allocator_type& alloc)
: shaders(rhs.shaders, alloc) {}
LayoutGraph::LayoutGraph(const allocator_type& alloc) noexcept
: _vertices(alloc),
names(alloc),
descriptors(alloc),
stages(alloc),
phases(alloc),
pathIndex(alloc) {}
LayoutGraph::LayoutGraph(LayoutGraph&& rhs, const allocator_type& alloc)
: _vertices(std::move(rhs._vertices), alloc),
names(std::move(rhs.names), alloc),
descriptors(std::move(rhs.descriptors), alloc),
stages(std::move(rhs.stages), alloc),
phases(std::move(rhs.phases), alloc),
pathIndex(std::move(rhs.pathIndex), alloc) {}
LayoutGraph::LayoutGraph(LayoutGraph const& rhs, const allocator_type& alloc)
: _vertices(rhs._vertices, alloc),
names(rhs.names, alloc),
descriptors(rhs.descriptors, alloc),
stages(rhs.stages, alloc),
phases(rhs.phases, alloc),
pathIndex(rhs.pathIndex, alloc) {}
// ContinuousContainer
void LayoutGraph::reserve(vertices_size_type sz) {
_vertices.reserve(sz);
names.reserve(sz);
descriptors.reserve(sz);
}
LayoutGraph::Vertex::Vertex(const allocator_type& alloc) noexcept
: outEdges(alloc),
inEdges(alloc) {}
LayoutGraph::Vertex::Vertex(Vertex&& rhs, const allocator_type& alloc)
: outEdges(std::move(rhs.outEdges), alloc),
inEdges(std::move(rhs.inEdges), alloc),
handle(std::move(rhs.handle)) {}
LayoutGraph::Vertex::Vertex(Vertex const& rhs, const allocator_type& alloc)
: outEdges(rhs.outEdges, alloc),
inEdges(rhs.inEdges, alloc),
handle(rhs.handle) {}
UniformBlockData::UniformBlockData(const allocator_type& alloc) noexcept
: uniforms(alloc) {}
UniformBlockData::UniformBlockData(UniformBlockData&& rhs, const allocator_type& alloc)
: bufferSize(rhs.bufferSize),
uniforms(std::move(rhs.uniforms), alloc) {}
UniformBlockData::UniformBlockData(UniformBlockData const& rhs, const allocator_type& alloc)
: bufferSize(rhs.bufferSize),
uniforms(rhs.uniforms, alloc) {}
DescriptorBlockData::DescriptorBlockData(const allocator_type& alloc) noexcept
: descriptors(alloc) {}
DescriptorBlockData::DescriptorBlockData(DescriptorTypeOrder typeIn, gfx::ShaderStageFlagBit visibilityIn, uint32_t capacityIn, const allocator_type& alloc) noexcept // NOLINT
: type(typeIn),
visibility(visibilityIn),
capacity(capacityIn),
descriptors(alloc) {}
DescriptorBlockData::DescriptorBlockData(DescriptorBlockData&& rhs, const allocator_type& alloc)
: type(rhs.type),
visibility(rhs.visibility),
offset(rhs.offset),
capacity(rhs.capacity),
descriptors(std::move(rhs.descriptors), alloc) {}
DescriptorBlockData::DescriptorBlockData(DescriptorBlockData const& rhs, const allocator_type& alloc)
: type(rhs.type),
visibility(rhs.visibility),
offset(rhs.offset),
capacity(rhs.capacity),
descriptors(rhs.descriptors, alloc) {}
DescriptorSetLayoutData::DescriptorSetLayoutData(const allocator_type& alloc) noexcept
: descriptorBlocks(alloc),
uniformBlocks(alloc),
bindingMap(alloc) {}
DescriptorSetLayoutData::DescriptorSetLayoutData(uint32_t slotIn, uint32_t capacityIn, ccstd::pmr::vector<DescriptorBlockData> descriptorBlocksIn, PmrUnorderedMap<NameLocalID, gfx::UniformBlock> uniformBlocksIn, PmrFlatMap<NameLocalID, uint32_t> bindingMapIn, const allocator_type& alloc) noexcept // NOLINT
: slot(slotIn),
capacity(capacityIn),
descriptorBlocks(std::move(descriptorBlocksIn), alloc),
uniformBlocks(std::move(uniformBlocksIn), alloc),
bindingMap(std::move(bindingMapIn), alloc) {}
DescriptorSetLayoutData::DescriptorSetLayoutData(DescriptorSetLayoutData&& rhs, const allocator_type& alloc)
: slot(rhs.slot),
capacity(rhs.capacity),
uniformBlockCapacity(rhs.uniformBlockCapacity),
samplerTextureCapacity(rhs.samplerTextureCapacity),
descriptorBlocks(std::move(rhs.descriptorBlocks), alloc),
uniformBlocks(std::move(rhs.uniformBlocks), alloc),
bindingMap(std::move(rhs.bindingMap), alloc) {}
DescriptorSetData::DescriptorSetData(const allocator_type& alloc) noexcept
: descriptorSetLayoutData(alloc) {}
DescriptorSetData::DescriptorSetData(DescriptorSetLayoutData descriptorSetLayoutDataIn, IntrusivePtr<gfx::DescriptorSetLayout> descriptorSetLayoutIn, IntrusivePtr<gfx::DescriptorSet> descriptorSetIn, const allocator_type& alloc) noexcept
: descriptorSetLayoutData(std::move(descriptorSetLayoutDataIn), alloc),
descriptorSetLayout(std::move(descriptorSetLayoutIn)),
descriptorSet(std::move(descriptorSetIn)) {}
DescriptorSetData::DescriptorSetData(DescriptorSetData&& rhs, const allocator_type& alloc)
: descriptorSetLayoutData(std::move(rhs.descriptorSetLayoutData), alloc),
descriptorSetLayoutInfo(std::move(rhs.descriptorSetLayoutInfo)),
descriptorSetLayout(std::move(rhs.descriptorSetLayout)),
descriptorSet(std::move(rhs.descriptorSet)) {}
PipelineLayoutData::PipelineLayoutData(const allocator_type& alloc) noexcept
: descriptorSets(alloc) {}
PipelineLayoutData::PipelineLayoutData(PipelineLayoutData&& rhs, const allocator_type& alloc)
: descriptorSets(std::move(rhs.descriptorSets), alloc) {}
ShaderBindingData::ShaderBindingData(const allocator_type& alloc) noexcept
: descriptorBindings(alloc) {}
ShaderBindingData::ShaderBindingData(ShaderBindingData&& rhs, const allocator_type& alloc)
: descriptorBindings(std::move(rhs.descriptorBindings), alloc) {}
ShaderLayoutData::ShaderLayoutData(const allocator_type& alloc) noexcept
: layoutData(alloc),
bindingData(alloc) {}
ShaderLayoutData::ShaderLayoutData(ShaderLayoutData&& rhs, const allocator_type& alloc)
: layoutData(std::move(rhs.layoutData), alloc),
bindingData(std::move(rhs.bindingData), alloc) {}
TechniqueData::TechniqueData(const allocator_type& alloc) noexcept
: passes(alloc) {}
TechniqueData::TechniqueData(TechniqueData&& rhs, const allocator_type& alloc)
: passes(std::move(rhs.passes), alloc) {}
EffectData::EffectData(const allocator_type& alloc) noexcept
: techniques(alloc) {}
EffectData::EffectData(EffectData&& rhs, const allocator_type& alloc)
: techniques(std::move(rhs.techniques), alloc) {}
ShaderProgramData::ShaderProgramData(const allocator_type& alloc) noexcept
: layout(alloc) {}
ShaderProgramData::ShaderProgramData(ShaderProgramData&& rhs, const allocator_type& alloc)
: layout(std::move(rhs.layout), alloc),
pipelineLayout(std::move(rhs.pipelineLayout)) {}
RenderStageData::RenderStageData(const allocator_type& alloc) noexcept
: descriptorVisibility(alloc) {}
RenderStageData::RenderStageData(RenderStageData&& rhs, const allocator_type& alloc)
: descriptorVisibility(std::move(rhs.descriptorVisibility), alloc) {}
RenderPhaseData::RenderPhaseData(const allocator_type& alloc) noexcept
: rootSignature(alloc),
shaderPrograms(alloc),
shaderIndex(alloc) {}
RenderPhaseData::RenderPhaseData(RenderPhaseData&& rhs, const allocator_type& alloc)
: rootSignature(std::move(rhs.rootSignature), alloc),
shaderPrograms(std::move(rhs.shaderPrograms), alloc),
shaderIndex(std::move(rhs.shaderIndex), alloc),
pipelineLayout(std::move(rhs.pipelineLayout)) {}
LayoutGraphData::LayoutGraphData(const allocator_type& alloc) noexcept
: _vertices(alloc),
names(alloc),
updateFrequencies(alloc),
layouts(alloc),
stages(alloc),
phases(alloc),
valueNames(alloc),
attributeIndex(alloc),
constantIndex(alloc),
shaderLayoutIndex(alloc),
effects(alloc),
pathIndex(alloc) {}
LayoutGraphData::LayoutGraphData(LayoutGraphData&& rhs, const allocator_type& alloc)
: _vertices(std::move(rhs._vertices), alloc),
names(std::move(rhs.names), alloc),
updateFrequencies(std::move(rhs.updateFrequencies), alloc),
layouts(std::move(rhs.layouts), alloc),
stages(std::move(rhs.stages), alloc),
phases(std::move(rhs.phases), alloc),
valueNames(std::move(rhs.valueNames), alloc),
attributeIndex(std::move(rhs.attributeIndex), alloc),
constantIndex(std::move(rhs.constantIndex), alloc),
shaderLayoutIndex(std::move(rhs.shaderLayoutIndex), alloc),
effects(std::move(rhs.effects), alloc),
constantMacros(std::move(rhs.constantMacros)),
pathIndex(std::move(rhs.pathIndex), alloc) {}
// ContinuousContainer
void LayoutGraphData::reserve(vertices_size_type sz) {
_vertices.reserve(sz);
names.reserve(sz);
updateFrequencies.reserve(sz);
layouts.reserve(sz);
}
LayoutGraphData::Vertex::Vertex(const allocator_type& alloc) noexcept
: outEdges(alloc),
inEdges(alloc) {}
LayoutGraphData::Vertex::Vertex(Vertex&& rhs, const allocator_type& alloc)
: outEdges(std::move(rhs.outEdges), alloc),
inEdges(std::move(rhs.inEdges), alloc),
handle(std::move(rhs.handle)) {}
LayoutGraphData::Vertex::Vertex(Vertex const& rhs, const allocator_type& alloc)
: outEdges(rhs.outEdges, alloc),
inEdges(rhs.inEdges, alloc),
handle(rhs.handle) {}
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,729 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include <boost/graph/adjacency_iterator.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/properties.hpp>
#include <boost/range/irange.hpp>
#include "base/std/container/map.h"
#include "cocos/base/Ptr.h"
#include "cocos/base/std/container/string.h"
#include "cocos/base/std/container/vector.h"
#include "cocos/base/std/hash/hash.h"
#include "cocos/renderer/gfx-base/GFXDescriptorSet.h"
#include "cocos/renderer/gfx-base/GFXDescriptorSetLayout.h"
#include "cocos/renderer/gfx-base/GFXPipelineLayout.h"
#include "cocos/renderer/pipeline/custom/LayoutGraphFwd.h"
#include "cocos/renderer/pipeline/custom/RenderCommonTypes.h"
#include "cocos/renderer/pipeline/custom/details/GraphTypes.h"
#include "cocos/renderer/pipeline/custom/details/Map.h"
#include "cocos/renderer/pipeline/custom/details/Set.h"
namespace cc {
namespace render {
struct DescriptorDB {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {blocks.get_allocator().resource()};
}
DescriptorDB(const allocator_type& alloc) noexcept; // NOLINT
DescriptorDB(DescriptorDB&& rhs, const allocator_type& alloc);
DescriptorDB(DescriptorDB const& rhs, const allocator_type& alloc);
DescriptorDB(DescriptorDB&& rhs) noexcept = default;
DescriptorDB(DescriptorDB const& rhs) = delete;
DescriptorDB& operator=(DescriptorDB&& rhs) = default;
DescriptorDB& operator=(DescriptorDB const& rhs) = default;
ccstd::pmr::map<DescriptorBlockIndex, DescriptorBlock> blocks;
};
struct RenderStageTag {};
struct RenderPhaseTag {};
struct RenderPhase {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {shaders.get_allocator().resource()};
}
RenderPhase(const allocator_type& alloc) noexcept; // NOLINT
RenderPhase(RenderPhase&& rhs, const allocator_type& alloc);
RenderPhase(RenderPhase const& rhs, const allocator_type& alloc);
RenderPhase(RenderPhase&& rhs) noexcept = default;
RenderPhase(RenderPhase const& rhs) = delete;
RenderPhase& operator=(RenderPhase&& rhs) = default;
RenderPhase& operator=(RenderPhase const& rhs) = default;
PmrTransparentSet<ccstd::pmr::string> shaders;
};
enum class RenderPassType : uint32_t {
SINGLE_RENDER_PASS,
RENDER_PASS,
RENDER_SUBPASS,
};
struct LayoutGraph {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {_vertices.get_allocator().resource()};
}
inline boost::container::pmr::memory_resource* resource() const noexcept {
return get_allocator().resource();
}
LayoutGraph(const allocator_type& alloc) noexcept; // NOLINT
LayoutGraph(LayoutGraph&& rhs, const allocator_type& alloc);
LayoutGraph(LayoutGraph const& rhs, const allocator_type& alloc);
LayoutGraph(LayoutGraph&& rhs) noexcept = default;
LayoutGraph(LayoutGraph const& rhs) = delete;
LayoutGraph& operator=(LayoutGraph&& rhs) = default;
LayoutGraph& operator=(LayoutGraph const& rhs) = default;
// Graph
using directed_category = boost::bidirectional_tag;
using vertex_descriptor = uint32_t;
using edge_descriptor = impl::EdgeDescriptor<directed_category, vertex_descriptor>;
using edge_parallel_category = boost::allow_parallel_edge_tag;
struct traversal_category // NOLINT
: virtual boost::incidence_graph_tag,
virtual boost::bidirectional_graph_tag,
virtual boost::adjacency_graph_tag,
virtual boost::vertex_list_graph_tag,
virtual boost::edge_list_graph_tag {};
constexpr static vertex_descriptor null_vertex() noexcept { // NOLINT
return std::numeric_limits<vertex_descriptor>::max();
}
// IncidenceGraph
using OutEdge = impl::StoredEdge<vertex_descriptor>;
using out_edge_iterator = impl::OutEdgeIter<
ccstd::pmr::vector<OutEdge>::iterator,
vertex_descriptor, edge_descriptor, int32_t>;
using degree_size_type = uint32_t;
// BidirectionalGraph
using InEdge = impl::StoredEdge<vertex_descriptor>;
using in_edge_iterator = impl::InEdgeIter<
ccstd::pmr::vector<InEdge>::iterator,
vertex_descriptor, edge_descriptor, int32_t>;
// AdjacencyGraph
using adjacency_iterator = boost::adjacency_iterator_generator<
LayoutGraph, vertex_descriptor, out_edge_iterator>::type;
// VertexListGraph
using vertex_iterator = boost::integer_range<vertex_descriptor>::iterator;
using vertices_size_type = uint32_t;
// VertexList help functions
inline ccstd::pmr::vector<OutEdge>& getOutEdgeList(vertex_descriptor v) noexcept {
return _vertices[v].outEdges;
}
inline const ccstd::pmr::vector<OutEdge>& getOutEdgeList(vertex_descriptor v) const noexcept {
return _vertices[v].outEdges;
}
inline ccstd::pmr::vector<InEdge>& getInEdgeList(vertex_descriptor v) noexcept {
return _vertices[v].inEdges;
}
inline const ccstd::pmr::vector<InEdge>& getInEdgeList(vertex_descriptor v) const noexcept {
return _vertices[v].inEdges;
}
inline boost::integer_range<vertex_descriptor> getVertexList() const noexcept {
return {0, static_cast<vertices_size_type>(_vertices.size())};
}
inline vertex_descriptor getCurrentID() const noexcept {
return static_cast<vertex_descriptor>(_vertices.size());
}
inline ccstd::pmr::vector<boost::default_color_type> colors(boost::container::pmr::memory_resource* mr) const {
return ccstd::pmr::vector<boost::default_color_type>(_vertices.size(), mr);
}
// EdgeListGraph
using edge_iterator = impl::DirectedEdgeIterator<vertex_iterator, out_edge_iterator, LayoutGraph>;
using edges_size_type = uint32_t;
// AddressableGraph (Alias)
using ownership_descriptor = impl::EdgeDescriptor<boost::bidirectional_tag, vertex_descriptor>;
using ChildEdge = OutEdge;
using children_iterator = impl::OutEdgeIter<
ccstd::pmr::vector<OutEdge>::iterator,
vertex_descriptor, ownership_descriptor, int32_t>;
using children_size_type = uint32_t;
using ParentEdge = InEdge;
using parent_iterator = impl::InEdgeIter<
ccstd::pmr::vector<InEdge>::iterator,
vertex_descriptor, ownership_descriptor, int32_t>;
using ownership_iterator = impl::DirectedEdgeIterator<vertex_iterator, children_iterator, LayoutGraph>;
using ownerships_size_type = edges_size_type;
// AddressableGraph help functions
inline ccstd::pmr::vector<OutEdge>& getChildrenList(vertex_descriptor v) noexcept {
return _vertices[v].outEdges;
}
inline const ccstd::pmr::vector<OutEdge>& getChildrenList(vertex_descriptor v) const noexcept {
return _vertices[v].outEdges;
}
inline ccstd::pmr::vector<InEdge>& getParentsList(vertex_descriptor v) noexcept {
return _vertices[v].inEdges;
}
inline const ccstd::pmr::vector<InEdge>& getParentsList(vertex_descriptor v) const noexcept {
return _vertices[v].inEdges;
}
// PolymorphicGraph
using VertexTag = ccstd::variant<RenderStageTag, RenderPhaseTag>;
using VertexValue = ccstd::variant<RenderPassType*, RenderPhase*>;
using VertexConstValue = ccstd::variant<const RenderPassType*, const RenderPhase*>;
using VertexHandle = ccstd::variant<
impl::ValueHandle<RenderStageTag, vertex_descriptor>,
impl::ValueHandle<RenderPhaseTag, vertex_descriptor>>;
// ContinuousContainer
void reserve(vertices_size_type sz);
// Members
struct Vertex {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {outEdges.get_allocator().resource()};
}
Vertex(const allocator_type& alloc) noexcept; // NOLINT
Vertex(Vertex&& rhs, const allocator_type& alloc);
Vertex(Vertex const& rhs, const allocator_type& alloc);
Vertex(Vertex&& rhs) noexcept = default;
Vertex(Vertex const& rhs) = delete;
Vertex& operator=(Vertex&& rhs) = default;
Vertex& operator=(Vertex const& rhs) = default;
ccstd::pmr::vector<OutEdge> outEdges;
ccstd::pmr::vector<InEdge> inEdges;
VertexHandle handle;
};
struct NameTag {};
struct DescriptorsTag {};
// Vertices
ccstd::pmr::vector<Vertex> _vertices;
// Components
ccstd::pmr::vector<ccstd::pmr::string> names;
ccstd::pmr::vector<DescriptorDB> descriptors;
// PolymorphicGraph
ccstd::pmr::vector<RenderPassType> stages;
ccstd::pmr::vector<RenderPhase> phases;
// Path
PmrTransparentMap<ccstd::pmr::string, vertex_descriptor> pathIndex;
};
struct UniformData {
UniformData() = default;
UniformData(UniformID uniformIDIn, gfx::Type uniformTypeIn, uint32_t offsetIn) noexcept // NOLINT
: uniformID(uniformIDIn),
uniformType(uniformTypeIn),
offset(offsetIn) {}
UniformID uniformID{0xFFFFFFFF};
gfx::Type uniformType{gfx::Type::UNKNOWN};
uint32_t offset{0};
uint32_t size{0};
};
struct UniformBlockData {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {uniforms.get_allocator().resource()};
}
UniformBlockData(const allocator_type& alloc) noexcept; // NOLINT
UniformBlockData(UniformBlockData&& rhs, const allocator_type& alloc);
UniformBlockData(UniformBlockData const& rhs, const allocator_type& alloc);
UniformBlockData(UniformBlockData&& rhs) noexcept = default;
UniformBlockData(UniformBlockData const& rhs) = delete;
UniformBlockData& operator=(UniformBlockData&& rhs) = default;
UniformBlockData& operator=(UniformBlockData const& rhs) = default;
uint32_t bufferSize{0};
ccstd::pmr::vector<UniformData> uniforms;
};
struct NameLocalID {
uint32_t value{0xFFFFFFFF};
};
inline bool operator==(const NameLocalID& lhs, const NameLocalID& rhs) noexcept {
return std::forward_as_tuple(lhs.value) ==
std::forward_as_tuple(rhs.value);
}
inline bool operator!=(const NameLocalID& lhs, const NameLocalID& rhs) noexcept {
return !(lhs == rhs);
}
inline bool operator<(const NameLocalID& lhs, const NameLocalID& rhs) noexcept {
return std::forward_as_tuple(lhs.value) <
std::forward_as_tuple(rhs.value);
}
struct DescriptorData {
DescriptorData() = default;
DescriptorData(NameLocalID descriptorIDIn, gfx::Type typeIn, uint32_t countIn) noexcept
: descriptorID(descriptorIDIn),
type(typeIn),
count(countIn) {}
DescriptorData(NameLocalID descriptorIDIn, gfx::Type typeIn) noexcept
: descriptorID(descriptorIDIn),
type(typeIn) {}
DescriptorData(NameLocalID descriptorIDIn) noexcept // NOLINT
: descriptorID(descriptorIDIn) {}
NameLocalID descriptorID;
gfx::Type type{gfx::Type::UNKNOWN};
uint32_t count{1};
};
struct DescriptorBlockData {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {descriptors.get_allocator().resource()};
}
DescriptorBlockData(const allocator_type& alloc) noexcept; // NOLINT
DescriptorBlockData(DescriptorTypeOrder typeIn, gfx::ShaderStageFlagBit visibilityIn, uint32_t capacityIn, const allocator_type& alloc) noexcept;
DescriptorBlockData(DescriptorBlockData&& rhs, const allocator_type& alloc);
DescriptorBlockData(DescriptorBlockData const& rhs, const allocator_type& alloc);
DescriptorBlockData(DescriptorBlockData&& rhs) noexcept = default;
DescriptorBlockData(DescriptorBlockData const& rhs) = delete;
DescriptorBlockData& operator=(DescriptorBlockData&& rhs) = default;
DescriptorBlockData& operator=(DescriptorBlockData const& rhs) = default;
DescriptorTypeOrder type{DescriptorTypeOrder::UNIFORM_BUFFER};
gfx::ShaderStageFlagBit visibility{gfx::ShaderStageFlagBit::NONE};
uint32_t offset{0};
uint32_t capacity{0};
ccstd::pmr::vector<DescriptorData> descriptors;
};
struct DescriptorSetLayoutData {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {descriptorBlocks.get_allocator().resource()};
}
DescriptorSetLayoutData(const allocator_type& alloc) noexcept; // NOLINT
DescriptorSetLayoutData(uint32_t slotIn, uint32_t capacityIn, ccstd::pmr::vector<DescriptorBlockData> descriptorBlocksIn, PmrUnorderedMap<NameLocalID, gfx::UniformBlock> uniformBlocksIn, PmrFlatMap<NameLocalID, uint32_t> bindingMapIn, const allocator_type& alloc) noexcept;
DescriptorSetLayoutData(DescriptorSetLayoutData&& rhs, const allocator_type& alloc);
DescriptorSetLayoutData(DescriptorSetLayoutData&& rhs) noexcept = default;
DescriptorSetLayoutData(DescriptorSetLayoutData const& rhs) = delete;
DescriptorSetLayoutData& operator=(DescriptorSetLayoutData&& rhs) = default;
DescriptorSetLayoutData& operator=(DescriptorSetLayoutData const& rhs) = delete;
uint32_t slot{0xFFFFFFFF};
uint32_t capacity{0};
uint32_t uniformBlockCapacity{0};
uint32_t samplerTextureCapacity{0};
ccstd::pmr::vector<DescriptorBlockData> descriptorBlocks;
PmrUnorderedMap<NameLocalID, gfx::UniformBlock> uniformBlocks;
PmrFlatMap<NameLocalID, uint32_t> bindingMap;
};
struct DescriptorSetData {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {descriptorSetLayoutData.get_allocator().resource()};
}
DescriptorSetData(const allocator_type& alloc) noexcept; // NOLINT
DescriptorSetData(DescriptorSetLayoutData descriptorSetLayoutDataIn, IntrusivePtr<gfx::DescriptorSetLayout> descriptorSetLayoutIn, IntrusivePtr<gfx::DescriptorSet> descriptorSetIn, const allocator_type& alloc) noexcept;
DescriptorSetData(DescriptorSetData&& rhs, const allocator_type& alloc);
DescriptorSetData(DescriptorSetData&& rhs) noexcept = default;
DescriptorSetData(DescriptorSetData const& rhs) = delete;
DescriptorSetData& operator=(DescriptorSetData&& rhs) = default;
DescriptorSetData& operator=(DescriptorSetData const& rhs) = delete;
DescriptorSetLayoutData descriptorSetLayoutData;
gfx::DescriptorSetLayoutInfo descriptorSetLayoutInfo;
IntrusivePtr<gfx::DescriptorSetLayout> descriptorSetLayout;
IntrusivePtr<gfx::DescriptorSet> descriptorSet;
};
struct PipelineLayoutData {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {descriptorSets.get_allocator().resource()};
}
PipelineLayoutData(const allocator_type& alloc) noexcept; // NOLINT
PipelineLayoutData(PipelineLayoutData&& rhs, const allocator_type& alloc);
PipelineLayoutData(PipelineLayoutData&& rhs) noexcept = default;
PipelineLayoutData(PipelineLayoutData const& rhs) = delete;
PipelineLayoutData& operator=(PipelineLayoutData&& rhs) = default;
PipelineLayoutData& operator=(PipelineLayoutData const& rhs) = delete;
ccstd::pmr::map<UpdateFrequency, DescriptorSetData> descriptorSets;
};
struct ShaderBindingData {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {descriptorBindings.get_allocator().resource()};
}
ShaderBindingData(const allocator_type& alloc) noexcept; // NOLINT
ShaderBindingData(ShaderBindingData&& rhs, const allocator_type& alloc);
ShaderBindingData(ShaderBindingData&& rhs) noexcept = default;
ShaderBindingData(ShaderBindingData const& rhs) = delete;
ShaderBindingData& operator=(ShaderBindingData&& rhs) = default;
ShaderBindingData& operator=(ShaderBindingData const& rhs) = delete;
PmrFlatMap<NameLocalID, uint32_t> descriptorBindings;
};
struct ShaderLayoutData {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {layoutData.get_allocator().resource()};
}
ShaderLayoutData(const allocator_type& alloc) noexcept; // NOLINT
ShaderLayoutData(ShaderLayoutData&& rhs, const allocator_type& alloc);
ShaderLayoutData(ShaderLayoutData&& rhs) noexcept = default;
ShaderLayoutData(ShaderLayoutData const& rhs) = delete;
ShaderLayoutData& operator=(ShaderLayoutData&& rhs) = default;
ShaderLayoutData& operator=(ShaderLayoutData const& rhs) = delete;
ccstd::pmr::map<UpdateFrequency, DescriptorSetLayoutData> layoutData;
ccstd::pmr::map<UpdateFrequency, ShaderBindingData> bindingData;
};
struct TechniqueData {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {passes.get_allocator().resource()};
}
TechniqueData(const allocator_type& alloc) noexcept; // NOLINT
TechniqueData(TechniqueData&& rhs, const allocator_type& alloc);
TechniqueData(TechniqueData&& rhs) noexcept = default;
TechniqueData(TechniqueData const& rhs) = delete;
TechniqueData& operator=(TechniqueData&& rhs) = default;
TechniqueData& operator=(TechniqueData const& rhs) = delete;
ccstd::pmr::vector<ShaderLayoutData> passes;
};
struct EffectData {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {techniques.get_allocator().resource()};
}
EffectData(const allocator_type& alloc) noexcept; // NOLINT
EffectData(EffectData&& rhs, const allocator_type& alloc);
EffectData(EffectData&& rhs) noexcept = default;
EffectData(EffectData const& rhs) = delete;
EffectData& operator=(EffectData&& rhs) = default;
EffectData& operator=(EffectData const& rhs) = delete;
ccstd::pmr::map<ccstd::pmr::string, TechniqueData> techniques;
};
struct ShaderProgramData {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {layout.get_allocator().resource()};
}
ShaderProgramData(const allocator_type& alloc) noexcept; // NOLINT
ShaderProgramData(ShaderProgramData&& rhs, const allocator_type& alloc);
ShaderProgramData(ShaderProgramData&& rhs) noexcept = default;
ShaderProgramData(ShaderProgramData const& rhs) = delete;
ShaderProgramData& operator=(ShaderProgramData&& rhs) = default;
ShaderProgramData& operator=(ShaderProgramData const& rhs) = delete;
PipelineLayoutData layout;
IntrusivePtr<gfx::PipelineLayout> pipelineLayout;
};
struct RenderStageData {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {descriptorVisibility.get_allocator().resource()};
}
RenderStageData(const allocator_type& alloc) noexcept; // NOLINT
RenderStageData(RenderStageData&& rhs, const allocator_type& alloc);
RenderStageData(RenderStageData&& rhs) noexcept = default;
RenderStageData(RenderStageData const& rhs) = delete;
RenderStageData& operator=(RenderStageData&& rhs) = default;
RenderStageData& operator=(RenderStageData const& rhs) = delete;
PmrUnorderedMap<NameLocalID, gfx::ShaderStageFlagBit> descriptorVisibility;
};
struct RenderPhaseData {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {rootSignature.get_allocator().resource()};
}
RenderPhaseData(const allocator_type& alloc) noexcept; // NOLINT
RenderPhaseData(RenderPhaseData&& rhs, const allocator_type& alloc);
RenderPhaseData(RenderPhaseData&& rhs) noexcept = default;
RenderPhaseData(RenderPhaseData const& rhs) = delete;
RenderPhaseData& operator=(RenderPhaseData&& rhs) = default;
RenderPhaseData& operator=(RenderPhaseData const& rhs) = delete;
ccstd::pmr::string rootSignature;
ccstd::pmr::vector<ShaderProgramData> shaderPrograms;
PmrTransparentMap<ccstd::pmr::string, uint32_t> shaderIndex;
IntrusivePtr<gfx::PipelineLayout> pipelineLayout;
};
struct LayoutGraphData {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {_vertices.get_allocator().resource()};
}
inline boost::container::pmr::memory_resource* resource() const noexcept {
return get_allocator().resource();
}
LayoutGraphData(const allocator_type& alloc) noexcept; // NOLINT
LayoutGraphData(LayoutGraphData&& rhs, const allocator_type& alloc);
LayoutGraphData(LayoutGraphData&& rhs) noexcept = default;
LayoutGraphData(LayoutGraphData const& rhs) = delete;
LayoutGraphData& operator=(LayoutGraphData&& rhs) = default;
LayoutGraphData& operator=(LayoutGraphData const& rhs) = delete;
// Graph
using directed_category = boost::bidirectional_tag;
using vertex_descriptor = uint32_t;
using edge_descriptor = impl::EdgeDescriptor<directed_category, vertex_descriptor>;
using edge_parallel_category = boost::allow_parallel_edge_tag;
struct traversal_category // NOLINT
: virtual boost::incidence_graph_tag,
virtual boost::bidirectional_graph_tag,
virtual boost::adjacency_graph_tag,
virtual boost::vertex_list_graph_tag,
virtual boost::edge_list_graph_tag {};
constexpr static vertex_descriptor null_vertex() noexcept { // NOLINT
return std::numeric_limits<vertex_descriptor>::max();
}
// IncidenceGraph
using OutEdge = impl::StoredEdge<vertex_descriptor>;
using out_edge_iterator = impl::OutEdgeIter<
ccstd::pmr::vector<OutEdge>::iterator,
vertex_descriptor, edge_descriptor, int32_t>;
using degree_size_type = uint32_t;
// BidirectionalGraph
using InEdge = impl::StoredEdge<vertex_descriptor>;
using in_edge_iterator = impl::InEdgeIter<
ccstd::pmr::vector<InEdge>::iterator,
vertex_descriptor, edge_descriptor, int32_t>;
// AdjacencyGraph
using adjacency_iterator = boost::adjacency_iterator_generator<
LayoutGraphData, vertex_descriptor, out_edge_iterator>::type;
// VertexListGraph
using vertex_iterator = boost::integer_range<vertex_descriptor>::iterator;
using vertices_size_type = uint32_t;
// VertexList help functions
inline ccstd::pmr::vector<OutEdge>& getOutEdgeList(vertex_descriptor v) noexcept {
return _vertices[v].outEdges;
}
inline const ccstd::pmr::vector<OutEdge>& getOutEdgeList(vertex_descriptor v) const noexcept {
return _vertices[v].outEdges;
}
inline ccstd::pmr::vector<InEdge>& getInEdgeList(vertex_descriptor v) noexcept {
return _vertices[v].inEdges;
}
inline const ccstd::pmr::vector<InEdge>& getInEdgeList(vertex_descriptor v) const noexcept {
return _vertices[v].inEdges;
}
inline boost::integer_range<vertex_descriptor> getVertexList() const noexcept {
return {0, static_cast<vertices_size_type>(_vertices.size())};
}
inline vertex_descriptor getCurrentID() const noexcept {
return static_cast<vertex_descriptor>(_vertices.size());
}
inline ccstd::pmr::vector<boost::default_color_type> colors(boost::container::pmr::memory_resource* mr) const {
return ccstd::pmr::vector<boost::default_color_type>(_vertices.size(), mr);
}
// EdgeListGraph
using edge_iterator = impl::DirectedEdgeIterator<vertex_iterator, out_edge_iterator, LayoutGraphData>;
using edges_size_type = uint32_t;
// AddressableGraph (Alias)
using ownership_descriptor = impl::EdgeDescriptor<boost::bidirectional_tag, vertex_descriptor>;
using ChildEdge = OutEdge;
using children_iterator = impl::OutEdgeIter<
ccstd::pmr::vector<OutEdge>::iterator,
vertex_descriptor, ownership_descriptor, int32_t>;
using children_size_type = uint32_t;
using ParentEdge = InEdge;
using parent_iterator = impl::InEdgeIter<
ccstd::pmr::vector<InEdge>::iterator,
vertex_descriptor, ownership_descriptor, int32_t>;
using ownership_iterator = impl::DirectedEdgeIterator<vertex_iterator, children_iterator, LayoutGraphData>;
using ownerships_size_type = edges_size_type;
// AddressableGraph help functions
inline ccstd::pmr::vector<OutEdge>& getChildrenList(vertex_descriptor v) noexcept {
return _vertices[v].outEdges;
}
inline const ccstd::pmr::vector<OutEdge>& getChildrenList(vertex_descriptor v) const noexcept {
return _vertices[v].outEdges;
}
inline ccstd::pmr::vector<InEdge>& getParentsList(vertex_descriptor v) noexcept {
return _vertices[v].inEdges;
}
inline const ccstd::pmr::vector<InEdge>& getParentsList(vertex_descriptor v) const noexcept {
return _vertices[v].inEdges;
}
// PolymorphicGraph
using VertexTag = ccstd::variant<RenderStageTag, RenderPhaseTag>;
using VertexValue = ccstd::variant<RenderStageData*, RenderPhaseData*>;
using VertexConstValue = ccstd::variant<const RenderStageData*, const RenderPhaseData*>;
using VertexHandle = ccstd::variant<
impl::ValueHandle<RenderStageTag, vertex_descriptor>,
impl::ValueHandle<RenderPhaseTag, vertex_descriptor>>;
// ContinuousContainer
void reserve(vertices_size_type sz);
// Members
struct Vertex {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {outEdges.get_allocator().resource()};
}
Vertex(const allocator_type& alloc) noexcept; // NOLINT
Vertex(Vertex&& rhs, const allocator_type& alloc);
Vertex(Vertex const& rhs, const allocator_type& alloc);
Vertex(Vertex&& rhs) noexcept = default;
Vertex(Vertex const& rhs) = delete;
Vertex& operator=(Vertex&& rhs) = default;
Vertex& operator=(Vertex const& rhs) = default;
ccstd::pmr::vector<OutEdge> outEdges;
ccstd::pmr::vector<InEdge> inEdges;
VertexHandle handle;
};
struct NameTag {};
struct UpdateTag {};
struct LayoutTag {};
// Vertices
ccstd::pmr::vector<Vertex> _vertices;
// Components
ccstd::pmr::vector<ccstd::pmr::string> names;
ccstd::pmr::vector<UpdateFrequency> updateFrequencies;
ccstd::pmr::vector<PipelineLayoutData> layouts;
// PolymorphicGraph
ccstd::pmr::vector<RenderStageData> stages;
ccstd::pmr::vector<RenderPhaseData> phases;
// Members
ccstd::pmr::vector<ccstd::pmr::string> valueNames;
PmrFlatMap<ccstd::pmr::string, NameLocalID> attributeIndex;
PmrFlatMap<ccstd::pmr::string, NameLocalID> constantIndex;
PmrFlatMap<ccstd::pmr::string, uint32_t> shaderLayoutIndex;
PmrFlatMap<ccstd::pmr::string, EffectData> effects;
ccstd::string constantMacros;
// Path
PmrTransparentMap<ccstd::pmr::string, vertex_descriptor> pathIndex;
};
} // namespace render
} // namespace cc
namespace ccstd {
inline hash_t hash<cc::render::NameLocalID>::operator()(const cc::render::NameLocalID& val) const noexcept {
hash_t seed = 0;
hash_combine(seed, val.value);
return seed;
}
} // namespace ccstd
// clang-format on

View File

@@ -0,0 +1,511 @@
/****************************************************************************
Copyright (c) 2021-2022 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "LayoutGraphUtils.h"
#include <tuple>
#include <utility>
#include "LayoutGraphGraphs.h"
#include "LayoutGraphNames.h"
#include "LayoutGraphTypes.h"
#include "RenderCommonNames.h"
#include "RenderCommonTypes.h"
#include "cocos/base/Log.h"
#include "cocos/base/StringUtil.h"
#include "cocos/base/std/container/string.h"
#include "cocos/renderer/gfx-base/GFXDef-common.h"
#include "details/DebugUtils.h"
#include "details/GslUtils.h"
#include "details/Map.h"
#include "details/Range.h"
namespace cc {
namespace render {
namespace {
DescriptorBlockData& getDescriptorBlockData(
PmrFlatMap<DescriptorBlockIndex, DescriptorBlockData>& map,
const DescriptorBlockIndex& index) {
auto iter = map.find(index);
if (iter != map.end()) {
return iter->second;
}
iter = map.emplace(
std::piecewise_construct,
std::forward_as_tuple(index),
std::forward_as_tuple(index.descriptorType, index.visibility, 0))
.first;
return iter->second;
}
} // namespace
gfx::DescriptorType getGfxDescriptorType(DescriptorTypeOrder type) {
switch (type) {
case DescriptorTypeOrder::UNIFORM_BUFFER:
return gfx::DescriptorType::UNIFORM_BUFFER;
case DescriptorTypeOrder::DYNAMIC_UNIFORM_BUFFER:
return gfx::DescriptorType::DYNAMIC_UNIFORM_BUFFER;
case DescriptorTypeOrder::SAMPLER_TEXTURE:
return gfx::DescriptorType::SAMPLER_TEXTURE;
case DescriptorTypeOrder::SAMPLER:
return gfx::DescriptorType::SAMPLER;
case DescriptorTypeOrder::TEXTURE:
return gfx::DescriptorType::TEXTURE;
case DescriptorTypeOrder::STORAGE_BUFFER:
return gfx::DescriptorType::STORAGE_BUFFER;
case DescriptorTypeOrder::DYNAMIC_STORAGE_BUFFER:
return gfx::DescriptorType::DYNAMIC_STORAGE_BUFFER;
case DescriptorTypeOrder::STORAGE_IMAGE:
return gfx::DescriptorType::STORAGE_IMAGE;
case DescriptorTypeOrder::INPUT_ATTACHMENT:
return gfx::DescriptorType::INPUT_ATTACHMENT;
default:
CC_LOG_ERROR("DescriptorType not found");
return gfx::DescriptorType::INPUT_ATTACHMENT;
}
}
DescriptorTypeOrder getDescriptorTypeOrder(gfx::DescriptorType type) {
switch (type) {
case gfx::DescriptorType::UNIFORM_BUFFER:
return DescriptorTypeOrder::UNIFORM_BUFFER;
case gfx::DescriptorType::DYNAMIC_UNIFORM_BUFFER:
return DescriptorTypeOrder::DYNAMIC_UNIFORM_BUFFER;
case gfx::DescriptorType::SAMPLER_TEXTURE:
return DescriptorTypeOrder::SAMPLER_TEXTURE;
case gfx::DescriptorType::SAMPLER:
return DescriptorTypeOrder::SAMPLER;
case gfx::DescriptorType::TEXTURE:
return DescriptorTypeOrder::TEXTURE;
case gfx::DescriptorType::STORAGE_BUFFER:
return DescriptorTypeOrder::STORAGE_BUFFER;
case gfx::DescriptorType::DYNAMIC_STORAGE_BUFFER:
return DescriptorTypeOrder::DYNAMIC_STORAGE_BUFFER;
case gfx::DescriptorType::STORAGE_IMAGE:
return DescriptorTypeOrder::STORAGE_IMAGE;
case gfx::DescriptorType::INPUT_ATTACHMENT:
return DescriptorTypeOrder::INPUT_ATTACHMENT;
case gfx::DescriptorType::UNKNOWN:
default:
CC_LOG_ERROR("DescriptorTypeOrder not found");
return DescriptorTypeOrder::INPUT_ATTACHMENT;
}
}
NameLocalID getOrCreateDescriptorID(LayoutGraphData& lg, std::string_view name) {
auto iter = lg.attributeIndex.find(name);
if (iter != lg.attributeIndex.end()) {
return iter->second;
}
const auto id = static_cast<uint32_t>(lg.valueNames.size());
lg.attributeIndex.emplace(name, NameLocalID{id});
lg.valueNames.emplace_back(name);
return NameLocalID{id};
}
void makeDescriptorSetLayoutData(
LayoutGraphData& lg,
UpdateFrequency rate, uint32_t set, const IDescriptorInfo& descriptors,
DescriptorSetLayoutData& data,
boost::container::pmr::memory_resource* scratch) {
PmrFlatMap<DescriptorBlockIndex, DescriptorBlockData> map(scratch);
PmrFlatMap<NameLocalID, gfx::UniformBlock> uniformBlocks(scratch);
for (const auto& cb : descriptors.blocks) {
auto& block = getDescriptorBlockData(
map, DescriptorBlockIndex{
rate,
ParameterType::TABLE,
DescriptorTypeOrder::UNIFORM_BUFFER,
cb.stageFlags,
});
const auto nameID = getOrCreateDescriptorID(lg, cb.name);
block.descriptors.emplace_back(nameID, gfx::Type::UNKNOWN, 1);
// add uniform buffer
uniformBlocks.emplace(
std::piecewise_construct,
std::forward_as_tuple(nameID),
std::forward_as_tuple(gfx::UniformBlock{set, 0xFFFFFFFF, cb.name, cb.members, 1}));
}
for (const auto& samplerTexture : descriptors.samplerTextures) {
auto& block = getDescriptorBlockData(
map, DescriptorBlockIndex{
rate,
ParameterType::TABLE,
DescriptorTypeOrder::SAMPLER_TEXTURE,
samplerTexture.stageFlags,
});
const auto nameID = getOrCreateDescriptorID(lg, samplerTexture.name);
block.descriptors.emplace_back(nameID, samplerTexture.type, samplerTexture.count);
}
for (const auto& sampler : descriptors.samplers) {
auto& block = getDescriptorBlockData(
map, DescriptorBlockIndex{
rate,
ParameterType::TABLE,
DescriptorTypeOrder::SAMPLER,
sampler.stageFlags,
});
const auto nameID = getOrCreateDescriptorID(lg, sampler.name);
block.descriptors.emplace_back(nameID, gfx::Type::SAMPLER, sampler.count);
}
for (const auto& texture : descriptors.textures) {
auto& block = getDescriptorBlockData(
map, DescriptorBlockIndex{
rate,
ParameterType::TABLE,
DescriptorTypeOrder::TEXTURE,
texture.stageFlags,
});
const auto nameID = getOrCreateDescriptorID(lg, texture.name);
block.descriptors.emplace_back(nameID, texture.type, texture.count);
}
for (const auto& buffer : descriptors.buffers) {
auto& block = getDescriptorBlockData(
map, DescriptorBlockIndex{
rate,
ParameterType::TABLE,
DescriptorTypeOrder::STORAGE_BUFFER,
buffer.stageFlags,
});
const auto nameID = getOrCreateDescriptorID(lg, buffer.name);
block.descriptors.emplace_back(nameID, gfx::Type::UNKNOWN, 1);
}
for (const auto& image : descriptors.images) {
auto& block = getDescriptorBlockData(
map, DescriptorBlockIndex{
rate,
ParameterType::TABLE,
DescriptorTypeOrder::STORAGE_IMAGE,
image.stageFlags,
});
const auto nameID = getOrCreateDescriptorID(lg, image.name);
block.descriptors.emplace_back(nameID, image.type, image.count);
}
for (const auto& subpassInput : descriptors.subpassInputs) {
auto& block = getDescriptorBlockData(
map, DescriptorBlockIndex{
rate,
ParameterType::TABLE,
DescriptorTypeOrder::INPUT_ATTACHMENT,
subpassInput.stageFlags,
});
const auto nameID = getOrCreateDescriptorID(lg, subpassInput.name);
block.descriptors.emplace_back(nameID, gfx::Type::UNKNOWN, subpassInput.count);
}
// calculate bindings
uint32_t capacity = 0;
for (auto&& [index, block] : map) {
block.offset = capacity;
for (const auto& d : block.descriptors) {
if (index.descriptorType == DescriptorTypeOrder::UNIFORM_BUFFER) {
// update uniform buffer binding
auto iter = uniformBlocks.find(d.descriptorID);
if (iter == uniformBlocks.end()) {
CC_LOG_ERROR("Uniform block not found");
continue;
}
auto& ub = iter->second;
assert(ub.binding == 0xFFFFFFFF);
ub.binding = block.capacity;
// add uniform buffer to output
data.uniformBlocks.emplace(d.descriptorID, std::move(ub));
}
// update block capacity
auto iter = data.bindingMap.find(d.descriptorID);
if (iter != data.bindingMap.end()) {
CC_LOG_ERROR("Duplicated descriptor name: %s", lg.valueNames[d.descriptorID.value].c_str());
continue;
}
data.bindingMap.emplace(d.descriptorID, block.offset + block.capacity);
block.capacity += d.count;
}
// increate total capacity
capacity += block.capacity;
data.capacity += block.capacity;
if (index.descriptorType == DescriptorTypeOrder::UNIFORM_BUFFER ||
index.descriptorType == DescriptorTypeOrder::DYNAMIC_UNIFORM_BUFFER) {
data.uniformBlockCapacity += block.capacity;
} else if (index.descriptorType == DescriptorTypeOrder::SAMPLER_TEXTURE) {
data.samplerTextureCapacity += block.capacity;
}
data.descriptorBlocks.emplace_back(std::move(block));
}
}
void initializeDescriptorSetLayoutInfo(
const DescriptorSetLayoutData& layoutData,
gfx::DescriptorSetLayoutInfo& info) {
for (const auto& block : layoutData.descriptorBlocks) {
auto slot = block.offset;
for (const auto& d : block.descriptors) {
auto& binding = info.bindings.emplace_back();
binding.binding = slot;
binding.descriptorType = getGfxDescriptorType(block.type);
binding.count = d.count;
binding.stageFlags = block.visibility;
binding.immutableSamplers = {};
// update slot
slot += d.count;
}
}
}
namespace {
const ccstd::unordered_map<ccstd::string, uint32_t> DEFAULT_UNIFORM_COUNTS{
{"cc_lightPos", pipeline::UBOForwardLight::LIGHTS_PER_PASS},
{"cc_lightColor", pipeline::UBOForwardLight::LIGHTS_PER_PASS},
{"cc_lightSizeRangeAngle", pipeline::UBOForwardLight::LIGHTS_PER_PASS},
{"cc_lightDir", pipeline::UBOForwardLight::LIGHTS_PER_PASS},
{"cc_lightBoundingSizeVS", pipeline::UBOForwardLight::LIGHTS_PER_PASS},
};
const TransparentSet<ccstd::string> DYNAMIC_UNIFORM_BLOCK{
{"CCCamera"},
{"CCForwardLight"},
{"CCUILocal"},
};
} // namespace
uint32_t getUniformBlockSize(const ccstd::vector<gfx::Uniform>& blockMembers) {
uint32_t prevSize = 0;
for (const auto& m : blockMembers) {
if (m.count) {
prevSize += getTypeSize(m.type) * m.count;
continue;
}
auto iter = DEFAULT_UNIFORM_COUNTS.find(m.name);
if (iter != DEFAULT_UNIFORM_COUNTS.end()) {
prevSize += getTypeSize(m.type) * iter->second;
continue;
}
if (m.name == "cc_joints") {
const auto sz = getTypeSize(m.type) * pipeline::UBOSkinning::layout.members[0].count;
CC_EXPECTS(sz == pipeline::UBOSkinning::size);
prevSize += sz;
continue;
}
CC_LOG_ERROR("Invalid uniform count: %s", m.name.c_str());
}
CC_ENSURES(prevSize);
return prevSize;
}
bool isDynamicUniformBlock(std::string_view name) {
return DYNAMIC_UNIFORM_BLOCK.find(name) != DYNAMIC_UNIFORM_BLOCK.end();
}
gfx::DescriptorSet* getOrCreatePerPassDescriptorSet(
gfx::Device* device,
LayoutGraphData& lg, LayoutGraphData::vertex_descriptor vertID) {
auto& ppl = get(LayoutGraphData::LayoutTag{}, lg, vertID);
auto iter = ppl.descriptorSets.find(UpdateFrequency::PER_PASS);
if (iter == ppl.descriptorSets.end()) {
return nullptr;
}
auto& data = iter->second;
if (!data.descriptorSet) {
if (!data.descriptorSetLayout) {
data.descriptorSetLayout = device->createDescriptorSetLayout(data.descriptorSetLayoutInfo);
}
CC_ENSURES(data.descriptorSetLayout);
data.descriptorSet = device->createDescriptorSet(gfx::DescriptorSetInfo{data.descriptorSetLayout.get()});
}
CC_ENSURES(data.descriptorSet);
return data.descriptorSet;
}
void generateConstantMacros(
gfx::Device* device,
ccstd::string& constantMacros) {
constantMacros = StringUtil::format(
R"(
#define CC_DEVICE_SUPPORT_FLOAT_TEXTURE %d
#define CC_DEVICE_MAX_VERTEX_UNIFORM_VECTORS %d
#define CC_DEVICE_MAX_FRAGMENT_UNIFORM_VECTORS %d
#define CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT %d
#define CC_PLATFORM_ANDROID_AND_WEBGL 0
#define CC_ENABLE_WEBGL_HIGHP_STRUCT_VALUES 0
#define CC_JOINT_UNIFORM_CAPACITY %d
)",
hasAnyFlags(device->getFormatFeatures(gfx::Format::RGBA32F),
gfx::FormatFeature::RENDER_TARGET | gfx::FormatFeature::SAMPLED_TEXTURE),
device->getCapabilities().maxVertexUniformVectors,
device->getCapabilities().maxFragmentUniformVectors,
device->hasFeature(gfx::Feature::INPUT_ATTACHMENT_BENEFIT),
pipeline::SkinningJointCapacity::jointUniformCapacity);
}
namespace {
ccstd::string getName(gfx::ShaderStageFlagBit stage) {
std::ostringstream oss;
int count = 0;
if (hasFlag(stage, gfx::ShaderStageFlagBit::VERTEX)) {
if (count++) {
oss << " | ";
}
oss << "Vertex";
}
if (hasFlag(stage, gfx::ShaderStageFlagBit::CONTROL)) {
if (count++) {
oss << " | ";
}
oss << "Control";
}
if (hasFlag(stage, gfx::ShaderStageFlagBit::EVALUATION)) {
if (count++) {
oss << " | ";
}
oss << "Evaluation";
}
if (hasFlag(stage, gfx::ShaderStageFlagBit::GEOMETRY)) {
if (count++) {
oss << " | ";
}
oss << "Geometry";
}
if (hasFlag(stage, gfx::ShaderStageFlagBit::FRAGMENT)) {
if (count++) {
oss << " | ";
}
oss << "Fragment";
}
if (hasFlag(stage, gfx::ShaderStageFlagBit::COMPUTE)) {
if (count++) {
oss << " | ";
}
oss << "Compute";
}
if (hasAllFlags(stage, gfx::ShaderStageFlagBit::ALL)) {
if (count++) {
oss << " | ";
}
oss << "All";
}
return oss.str();
}
} // namespace
void printLayoutGraphData(
const LayoutGraphData& lg, std::ostream& oss,
boost::container::pmr::memory_resource* scratch) {
ccstd::pmr::string space(scratch);
oss << "\n";
for (const auto v : makeRange(vertices(lg))) {
if (parent(v, lg) != LayoutGraphData::null_vertex()) {
continue;
}
const auto& name = get(LayoutGraphData::NameTag{}, lg, v);
OSS << "\"" << name << "\": ";
visit(
[&](auto tag) {
oss << getName(tag);
},
tag(v, lg));
oss << " {\n";
INDENT_BEG();
const auto& info = get(LayoutGraphData::LayoutTag{}, lg, v);
for (const auto& set : info.descriptorSets) {
OSS << "Set<" << getName(set.first) << "> {\n";
{
INDENT();
for (const auto& block : set.second.descriptorSetLayoutData.descriptorBlocks) {
OSS << "Block<" << getName(block.type) << ", " << getName(block.visibility) << "> {\n";
{
INDENT();
OSS << "capacity: " << block.capacity << ",\n";
OSS << "count: " << block.descriptors.size() << ",\n";
if (!block.descriptors.empty()) {
OSS << "Descriptors{ ";
int count = 0;
for (const auto& d : block.descriptors) {
if (count++) {
oss << ", ";
}
const auto& name = lg.valueNames.at(d.descriptorID.value);
oss << "\"" << name;
if (d.count != 1) {
oss << "[" << d.count << "]";
}
oss << "\"";
}
oss << " }\n";
}
}
OSS << "}\n";
}
}
OSS << "}\n";
}
INDENT_END();
OSS << "}\n";
}
}
gfx::TextureType getTextureType(ResourceDimension dimension, uint32_t arraySize) {
switch (dimension) {
case ResourceDimension::TEXTURE1D:
return arraySize > 1 ? gfx::TextureType::TEX1D_ARRAY : gfx::TextureType::TEX1D;
case ResourceDimension::TEXTURE2D:
return arraySize > 1 ? gfx::TextureType::TEX2D_ARRAY : gfx::TextureType::TEX2D;
case ResourceDimension::TEXTURE3D:
return gfx::TextureType::TEX3D;
case ResourceDimension::BUFFER:
default:
return gfx::TextureType::TEX2D;
}
}
ResourceDimension getResourceDimension(gfx::TextureType type) {
switch (type) {
case gfx::TextureType::TEX1D:
case gfx::TextureType::TEX1D_ARRAY:
return ResourceDimension::TEXTURE1D;
case gfx::TextureType::TEX3D:
return ResourceDimension::TEXTURE3D;
case gfx::TextureType::TEX2D:
case gfx::TextureType::TEX2D_ARRAY:
case gfx::TextureType::CUBE:
default:
return ResourceDimension::TEXTURE2D;
}
}
} // namespace render
} // namespace cc

View File

@@ -0,0 +1,74 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include <boost/container/pmr/memory_resource.hpp>
#include <iosfwd>
#include "cocos/core/assets/EffectAsset.h"
#include "cocos/renderer/pipeline/custom/LayoutGraphTypes.h"
#include "cocos/renderer/pipeline/custom/RenderCommonTypes.h"
#include "gfx-base/GFXDevice.h"
namespace cc {
namespace render {
gfx::DescriptorType getGfxDescriptorType(DescriptorTypeOrder type);
DescriptorTypeOrder getDescriptorTypeOrder(gfx::DescriptorType type);
NameLocalID getOrCreateDescriptorID(LayoutGraphData& lg, std::string_view name);
void makeDescriptorSetLayoutData(
LayoutGraphData& lg,
UpdateFrequency rate, uint32_t set, const IDescriptorInfo& descriptors,
DescriptorSetLayoutData& data,
boost::container::pmr::memory_resource* scratch);
void initializeDescriptorSetLayoutInfo(
const DescriptorSetLayoutData& layoutData,
gfx::DescriptorSetLayoutInfo& info);
uint32_t getUniformBlockSize(const ccstd::vector<gfx::Uniform>& blockMembers);
bool isDynamicUniformBlock(std::string_view name);
gfx::DescriptorSet* getOrCreatePerPassDescriptorSet(
gfx::Device* device,
LayoutGraphData& lg, LayoutGraphData::vertex_descriptor vertID);
void generateConstantMacros(
gfx::Device* device,
ccstd::string& constantMacros);
void printLayoutGraphData(
const LayoutGraphData& lg, std::ostream& oss,
boost::container::pmr::memory_resource* scratch);
gfx::TextureType getTextureType(ResourceDimension dimension, uint32_t arraySize);
ResourceDimension getResourceDimension(gfx::TextureType type);
} // namespace render
} // namespace cc

View File

@@ -0,0 +1,900 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "NativeBuiltinUtils.h"
#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"
namespace cc {
namespace render {
void setupQuadVertexBuffer(gfx::Device &device, const Vec4 &viewport, float vbData[16]) {
const float minX = viewport.x;
const float maxX = viewport.x + viewport.z;
float minY = viewport.y;
float maxY = viewport.y + viewport.w;
if (device.getCapabilities().screenSpaceSignY > 0) {
std::swap(minY, maxY);
}
int n = 0;
vbData[n++] = -1.0F;
vbData[n++] = -1.0F;
vbData[n++] = minX; // uv
vbData[n++] = maxY;
vbData[n++] = 1.0F;
vbData[n++] = -1.0F;
vbData[n++] = maxX;
vbData[n++] = maxY;
vbData[n++] = -1.0F;
vbData[n++] = 1.0F;
vbData[n++] = minX;
vbData[n++] = minY;
vbData[n++] = 1.0F;
vbData[n++] = 1.0F;
vbData[n++] = maxX;
vbData[n++] = minY;
}
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
void updateRasterPassConstants(uint32_t width, uint32_t height, Setter &setter) {
const auto &root = *Root::getInstance();
const auto shadingWidth = static_cast<float>(width);
const auto shadingHeight = static_cast<float>(height);
setter.setVec4(
"cc_time",
Vec4(
root.getCumulativeTime(),
root.getFrameTime(),
static_cast<float>(CC_CURRENT_ENGINE()->getTotalFrames()),
0.0F));
setter.setVec4(
"cc_screenSize",
Vec4(shadingWidth, shadingHeight, 1.0F / shadingWidth, 1.0F / shadingHeight));
setter.setVec4(
"cc_nativeSize",
Vec4(shadingWidth, shadingHeight, 1.0F / shadingWidth, 1.0F / shadingHeight));
const auto *debugView = root.getDebugView();
float debugViewData[4] = {0.0F, 0.0F, 0.0F, 0.0F};
if (debugView && debugView->isEnabled()) {
debugViewData[0] = static_cast<float>(debugView->getSingleMode());
for (auto i = static_cast<uint32_t>(pipeline::DebugViewCompositeType::DIRECT_DIFFUSE);
i < static_cast<uint32_t>(pipeline::DebugViewCompositeType::MAX_BIT_COUNT); ++i) {
const uint32_t offset = i >> 3;
const uint32_t bit = i % 8;
debugViewData[1 + offset] += (debugView->isCompositeModeEnabled(i) ? 1.0F : 0.0F) * powf(10.0F, static_cast<float>(bit));
}
debugViewData[3] += (debugView->isLightingWithAlbedo() ? 1.0F : 0.0F) * powf(10.0F, static_cast<float>(6));
debugViewData[3] += (debugView->isCsmLayerColoration() ? 1.0F : 0.0F) * powf(10.0F, static_cast<float>(7));
}
setter.setVec4(
"cc_debug_view_mode",
Vec4(debugViewData[0], debugViewData[1], debugViewData[2], debugViewData[3]));
}
namespace {
uint8_t getCombineSignY(gfx::Device *device) {
// 0: vk, 1: metal, 2: none, 3: gl-like
static int8_t combineSignY{-1};
if (combineSignY < 0) {
const float screenSpaceSignY = device->getCapabilities().screenSpaceSignY * 0.5F + 0.5F;
const float clipSpaceSignY = device->getCapabilities().clipSpaceSignY * 0.5F + 0.5F;
combineSignY = static_cast<int8_t>(static_cast<int>(screenSpaceSignY) << 1 | static_cast<int>(clipSpaceSignY));
}
return static_cast<uint8_t>(combineSignY);
}
} // namespace
void setCameraUBOValues(
const scene::Camera &camera,
const LayoutGraphData &layoutGraph,
const pipeline::PipelineSceneData &cfg,
const scene::DirectionalLight *mainLight,
RenderData &data) {
CC_EXPECTS(camera.getNode());
CC_EXPECTS(cfg.getSkybox());
const auto &skybox = *cfg.getSkybox();
const auto &shadingScale = cfg.getShadingScale();
// Camera
setMat4Impl(data, layoutGraph, "cc_matView", camera.getMatView());
setMat4Impl(data, layoutGraph, "cc_matViewInv", camera.getNode()->getWorldMatrix());
setMat4Impl(data, layoutGraph, "cc_matProj", camera.getMatProj());
setMat4Impl(data, layoutGraph, "cc_matProjInv", camera.getMatProjInv());
setMat4Impl(data, layoutGraph, "cc_matViewProj", camera.getMatViewProj());
setMat4Impl(data, layoutGraph, "cc_matViewProjInv", camera.getMatViewProjInv());
setVec4Impl(data, layoutGraph, "cc_cameraPos",
Vec4(
camera.getPosition().x,
camera.getPosition().y,
camera.getPosition().z,
getCombineSignY(cc::gfx::Device::getInstance())));
setVec4Impl(data, layoutGraph, "cc_surfaceTransform",
Vec4(
static_cast<float>(camera.getSurfaceTransform()),
static_cast<float>(camera.getCameraUsage()),
cosf(static_cast<float>(mathutils::toRadian(skybox.getRotationAngle()))),
sinf(static_cast<float>(mathutils::toRadian(skybox.getRotationAngle())))));
setVec4Impl(data, layoutGraph, "cc_screenScale",
Vec4(
cfg.getShadingScale(),
cfg.getShadingScale(),
1.0F / cfg.getShadingScale(),
1.0F / cfg.getShadingScale()));
setVec4Impl(data, layoutGraph, "cc_exposure",
Vec4(
camera.getExposure(),
1.0F / camera.getExposure(),
cfg.isHDR() ? 1.0F : 0.0F,
1.0F / scene::Camera::getStandardExposureValue()));
if (mainLight) {
const auto &shadowInfo = *cfg.getShadows();
const bool shadowEnable = (mainLight->isShadowEnabled() &&
shadowInfo.getType() == scene::ShadowType::SHADOW_MAP);
setVec4Impl(data, layoutGraph, "cc_mainLitDir",
Vec4(
mainLight->getDirection().x,
mainLight->getDirection().y,
mainLight->getDirection().z,
shadowEnable));
auto r = mainLight->getColor().x;
auto g = mainLight->getColor().y;
auto b = mainLight->getColor().z;
if (mainLight->isUseColorTemperature()) {
r *= mainLight->getColorTemperatureRGB().x;
g *= mainLight->getColorTemperatureRGB().y;
b *= mainLight->getColorTemperatureRGB().z;
}
auto w = mainLight->getIlluminance();
if (cfg.isHDR()) {
w *= camera.getExposure();
}
setVec4Impl(data, layoutGraph, "cc_mainLitColor", Vec4(r, g, b, w));
} else {
setVec4Impl(data, layoutGraph, "cc_mainLitDir", Vec4(0, 0, 1, 0));
setVec4Impl(data, layoutGraph, "cc_mainLitColor", Vec4(0, 0, 0, 0));
}
CC_EXPECTS(cfg.getAmbient());
auto &ambient = *cfg.getAmbient();
auto &skyColor = ambient.getSkyColor();
if (cfg.isHDR()) {
skyColor.w = ambient.getSkyIllum() * camera.getExposure();
} else {
skyColor.w = ambient.getSkyIllum();
}
setVec4Impl(data, layoutGraph, "cc_ambientSky",
Vec4(skyColor.x, skyColor.y, skyColor.z, skyColor.w));
setVec4Impl(data, layoutGraph, "cc_ambientGround",
Vec4(
ambient.getGroundAlbedo().x,
ambient.getGroundAlbedo().y,
ambient.getGroundAlbedo().z,
skybox.getEnvmap() ? static_cast<float>(skybox.getEnvmap()->mipmapLevel()) : 1.0F));
CC_EXPECTS(cfg.getFog());
const auto &fog = *cfg.getFog();
const auto &colorTempRGB = fog.getColorArray();
setVec4Impl(data, layoutGraph, "cc_fogColor",
Vec4(colorTempRGB.x, colorTempRGB.y, colorTempRGB.z, colorTempRGB.z));
setVec4Impl(data, layoutGraph, "cc_fogBase",
Vec4(fog.getFogStart(), fog.getFogEnd(), fog.getFogDensity(), 0.0F));
setVec4Impl(data, layoutGraph, "cc_fogAdd",
Vec4(fog.getFogTop(), fog.getFogRange(), fog.getFogAtten(), 0.0F));
setVec4Impl(data, layoutGraph, "cc_nearFar",
Vec4(camera.getNearClip(), camera.getFarClip(), camera.getClipSpaceMinz(), 0.0F));
setVec4Impl(data, layoutGraph, "cc_viewPort",
Vec4(
camera.getViewport().x,
camera.getViewport().y,
shadingScale * static_cast<float>(camera.getWindow()->getWidth()) * camera.getViewport().z,
shadingScale * static_cast<float>(camera.getWindow()->getHeight()) * camera.getViewport().w));
}
namespace {
float getPCFRadius(
const scene::Shadows &shadowInfo,
const scene::DirectionalLight &mainLight) {
const auto &shadowMapSize = shadowInfo.getSize().x;
switch (mainLight.getShadowPcf()) {
case scene::PCFType::HARD:
return 0.0F;
case scene::PCFType::SOFT:
return 1.0F / (shadowMapSize * 0.5F);
case scene::PCFType::SOFT_2X:
return 2.0F / (shadowMapSize * 0.5F);
case scene::PCFType::SOFT_4X:
return 3.0F / (shadowMapSize * 0.5F);
default:
break;
}
return 0.0F;
}
} // namespace
void setShadowUBOView(
gfx::Device &device,
const LayoutGraphData &layoutGraph,
const pipeline::PipelineSceneData &pplSceneData,
const scene::DirectionalLight &mainLight,
RenderData &data) {
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()) {
if (shadowInfo.getType() == scene::ShadowType::SHADOW_MAP) {
if (mainLight.isShadowEnabled()) {
if (mainLight.isShadowFixedArea() ||
mainLight.getCSMLevel() == scene::CSMLevel::LEVEL_1 || !csmSupported) {
// Shadow
const auto &matShadowView = csmLayers.getSpecialLayer()->getMatShadowView();
const auto &matShadowProj = csmLayers.getSpecialLayer()->getMatShadowProj();
const auto &matShadowViewProj = csmLayers.getSpecialLayer()->getMatShadowViewProj();
const auto &near = mainLight.getShadowNear();
const auto &far = mainLight.getShadowFar();
setMat4Impl(data, layoutGraph, "cc_matLightView", matShadowView);
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]));
setMat4Impl(data, layoutGraph, "cc_matLightViewProj", matShadowViewProj);
vec4ShadowInfo.set(near, far, 0, 1.0F - mainLight.getShadowSaturation());
setVec4Impl(data, layoutGraph, "cc_shadowNFLSInfo", vec4ShadowInfo);
vec4ShadowInfo.set(static_cast<float>(scene::LightType::DIRECTIONAL), packing, mainLight.getShadowNormalBias(), 0);
setVec4Impl(data, layoutGraph, "cc_shadowLPNNInfo", vec4ShadowInfo);
} else {
{ // CSM
const auto layerThreshold = getPCFRadius(shadowInfo, mainLight);
const auto numCascades = static_cast<uint32_t>(mainLight.getCSMLevel());
setVec4ArraySizeImpl(data, layoutGraph, "cc_csmViewDir0", numCascades);
setVec4ArraySizeImpl(data, layoutGraph, "cc_csmViewDir1", numCascades);
setVec4ArraySizeImpl(data, layoutGraph, "cc_csmViewDir2", numCascades);
setVec4ArraySizeImpl(data, layoutGraph, "cc_csmAtlas", numCascades);
setMat4ArraySizeImpl(data, layoutGraph, "cc_matCSMViewProj", numCascades);
setVec4ArraySizeImpl(data, layoutGraph, "cc_csmProjDepthInfo", numCascades);
setVec4ArraySizeImpl(data, layoutGraph, "cc_csmProjInfo", numCascades);
Vec4 csmSplitsInfo{};
for (uint32_t i = 0; i < numCascades; ++i) {
const auto &layer = *csmLayers.getLayers()[i];
const auto &matShadowView = layer.getMatShadowView();
vec4ShadowInfo.set(matShadowView.m[0], matShadowView.m[4], matShadowView.m[8], layerThreshold);
setVec4ArrayElemImpl(data, layoutGraph, "cc_csmViewDir0", vec4ShadowInfo, i);
vec4ShadowInfo.set(matShadowView.m[1], matShadowView.m[5], matShadowView.m[9], layer.getSplitCameraNear());
setVec4ArrayElemImpl(data, layoutGraph, "cc_csmViewDir1", vec4ShadowInfo, i);
vec4ShadowInfo.set(matShadowView.m[2], matShadowView.m[6], matShadowView.m[10], layer.getSplitCameraFar());
setVec4ArrayElemImpl(data, layoutGraph, "cc_csmViewDir2", vec4ShadowInfo, i);
const auto &csmAtlas = layer.getCSMAtlas();
setVec4ArrayElemImpl(data, layoutGraph, "cc_csmAtlas", csmAtlas, i);
const auto &matShadowViewProj = layer.getMatShadowViewProj();
setMat4ArrayElemImpl(data, layoutGraph, "cc_matCSMViewProj", matShadowViewProj, i);
const auto &matShadowProj = layer.getMatShadowProj();
setVec4ArrayElemImpl(data, layoutGraph,
"cc_csmProjDepthInfo",
Vec4(matShadowProj.m[10], matShadowProj.m[14],
matShadowProj.m[11], matShadowProj.m[15]),
i);
setVec4ArrayElemImpl(data, layoutGraph,
"cc_csmProjInfo",
Vec4(matShadowProj.m[00], matShadowProj.m[05],
1.0F / matShadowProj.m[00], 1.0F / matShadowProj.m[05]),
i);
(&csmSplitsInfo.x)[i] = layer.getSplitCameraFar() / mainLight.getShadowDistance();
}
setVec4Impl(data, layoutGraph, "cc_csmSplitsInfo", csmSplitsInfo);
}
{ // Shadow
vec4ShadowInfo.set(0, 0, 0, 1.0F - mainLight.getShadowSaturation());
setVec4Impl(data, layoutGraph, "cc_shadowNFLSInfo", vec4ShadowInfo);
vec4ShadowInfo.set(
static_cast<float>(scene::LightType::DIRECTIONAL),
packing,
mainLight.getShadowNormalBias(),
static_cast<float>(mainLight.getCSMLevel()));
setVec4Impl(data, layoutGraph, "cc_shadowLPNNInfo", vec4ShadowInfo);
}
}
{ // Shadow
vec4ShadowInfo.set(
shadowInfo.getSize().x, shadowInfo.getSize().y,
static_cast<float>(mainLight.getShadowPcf()), mainLight.getShadowBias());
setVec4Impl(data, layoutGraph, "cc_shadowWHPBInfo", vec4ShadowInfo);
}
}
} else {
const Vec3 tempVec3 = shadowInfo.getNormal().getNormalized();
setVec4Impl(data, layoutGraph,
"cc_planarNDInfo",
Vec4(tempVec3.x, tempVec3.y, tempVec3.z, -shadowInfo.getDistance()));
vec4ShadowInfo.set(
0, 0,
0, shadowInfo.getPlaneBias());
setVec4Impl(data, layoutGraph, "cc_shadowWHPBInfo", vec4ShadowInfo);
}
{
const auto &color = shadowInfo.getShadowColor4f();
setColorImpl(data, layoutGraph, "cc_shadowColor",
gfx::Color{color[0], color[1], color[2], color[3]});
}
}
}
void setShadowUBOLightView(
gfx::Device *device,
const LayoutGraphData &layoutGraph,
const pipeline::PipelineSceneData &pplSceneData,
const BuiltinCascadedShadowMap *csm,
const scene::Light &light,
uint32_t level,
RenderData &data) {
const auto &shadowInfo = *pplSceneData.getShadows();
const auto &packing = pipeline::supportsR32FloatTexture(device) ? 0.0F : 1.0F;
const auto &cap = device->getCapabilities();
Vec4 vec4ShadowInfo{};
// ShadowMap
switch (light.getType()) {
case scene::LightType::DIRECTIONAL: {
const auto &mainLight = dynamic_cast<const scene::DirectionalLight &>(light);
if (shadowInfo.isEnabled() && mainLight.isShadowEnabled()) {
if (shadowInfo.getType() == scene::ShadowType::SHADOW_MAP) {
float near = 0.1F;
float far = 0.0F;
Mat4 matShadowView;
Mat4 matShadowProj;
Mat4 matShadowViewProj;
scene::CSMLevel levelCount{};
CC_EXPECTS(csm);
if (mainLight.isShadowFixedArea() || mainLight.getCSMLevel() == scene::CSMLevel::LEVEL_1) {
matShadowView = csm->specialLayer.shadowView;
matShadowProj = csm->specialLayer.shadowProj;
matShadowViewProj = csm->specialLayer.shadowViewProj;
if (mainLight.isShadowFixedArea()) {
near = mainLight.getShadowNear();
far = mainLight.getShadowFar();
levelCount = static_cast<scene::CSMLevel>(0);
} else {
near = 0.1F;
far = csm->specialLayer.shadowCameraFar;
levelCount = scene::CSMLevel::LEVEL_1;
}
vec4ShadowInfo.set(static_cast<float>(scene::LightType::DIRECTIONAL), packing, mainLight.getShadowNormalBias(), 0);
setVec4Impl(data, layoutGraph, "cc_shadowLPNNInfo", vec4ShadowInfo);
} else {
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);
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]));
setMat4Impl(data, layoutGraph, "cc_matLightViewProj", matShadowViewProj);
vec4ShadowInfo.set(near, far, 0, 1.0F - mainLight.getShadowSaturation());
setVec4Impl(data, layoutGraph, "cc_shadowNFLSInfo", vec4ShadowInfo);
vec4ShadowInfo.set(
static_cast<float>(scene::LightType::DIRECTIONAL),
packing,
mainLight.getShadowNormalBias(),
static_cast<float>(levelCount));
setVec4Impl(data, layoutGraph, "cc_shadowLPNNInfo", vec4ShadowInfo);
vec4ShadowInfo.set(
shadowInfo.getSize().x,
shadowInfo.getSize().y,
static_cast<float>(mainLight.getShadowPcf()),
mainLight.getShadowBias());
setVec4Impl(data, layoutGraph, "cc_shadowWHPBInfo", vec4ShadowInfo);
}
}
break;
}
case scene::LightType::SPOT: {
const auto &spotLight = dynamic_cast<const scene::SpotLight &>(light);
if (shadowInfo.isEnabled() && spotLight.isShadowEnabled()) {
const auto &matShadowCamera = spotLight.getNode()->getWorldMatrix();
const auto matShadowView = matShadowCamera.getInversed();
setMat4Impl(data, layoutGraph, "cc_matLightView", matShadowView);
Mat4 matShadowViewProj{};
Mat4::createPerspective(spotLight.getAngle(), 1.0F, 0.001F,
spotLight.getRange(), true,
cap.clipSpaceMinZ, cap.clipSpaceSignY, 0, &matShadowViewProj);
matShadowViewProj.multiply(matShadowView);
setMat4Impl(data, layoutGraph, "cc_matLightViewProj", matShadowViewProj);
const Vec4 shadowNFLSInfos(0.01F, spotLight.getRange(), 0.0F, 0.0F);
setVec4Impl(data, layoutGraph, "cc_shadowNFLSInfo", shadowNFLSInfos);
const Vec4 shadowWHPBInfos(
shadowInfo.getSize().x,
shadowInfo.getSize().y,
spotLight.getShadowPcf(),
spotLight.getShadowBias());
setVec4Impl(data, layoutGraph, "cc_shadowWHPBInfo", shadowWHPBInfos);
const Vec4 shadowLPNNInfos(static_cast<float>(scene::LightType::SPOT), packing, spotLight.getShadowNormalBias(), 0.0F);
setVec4Impl(data, layoutGraph, "cc_shadowLPNNInfo", shadowLPNNInfos);
}
break;
}
default:
break;
}
const auto &color = shadowInfo.getShadowColor4f();
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<Mat4, Mat4, Mat4, Mat4>
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<float>(scene::LightType::SPHERE), packing, 0.0F, 0.0F});
} break;
case scene::LightType::SPOT: {
const auto &shadowSize = shadowInfo.getSize();
const auto &spotLight = dynamic_cast<const scene::SpotLight &>(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<float>(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<float>(scene::LightType::POINT), packing, 0.0F, 0.0F});
} break;
default:
break;
}
}
void setLegacyTextureUBOView(
gfx::Device &device,
const LayoutGraphData &layoutGraph,
const pipeline::PipelineSceneData &pplSceneData,
RenderData &data) {
const auto &skybox = *pplSceneData.getSkybox();
if (skybox.getReflectionMap()) {
auto &texture = *skybox.getReflectionMap()->getGFXTexture();
auto *sampler = device.getSampler(skybox.getReflectionMap()->getSamplerInfo());
setTextureImpl(data, layoutGraph, "cc_environment", &texture);
setSamplerImpl(data, layoutGraph, "cc_environment", sampler);
} else {
const auto *envmap =
skybox.getEnvmap()
? skybox.getEnvmap()
: BuiltinResMgr::getInstance()->get<TextureCube>("default-cube-texture");
if (envmap) {
auto *texture = envmap->getGFXTexture();
auto *sampler = device.getSampler(envmap->getSamplerInfo());
setTextureImpl(data, layoutGraph, "cc_environment", texture);
setSamplerImpl(data, layoutGraph, "cc_environment", sampler);
}
}
const auto *diffuseMap =
skybox.getDiffuseMap()
? skybox.getDiffuseMap()
: BuiltinResMgr::getInstance()->get<TextureCube>("default-cube-texture");
if (diffuseMap) {
auto *texture = diffuseMap->getGFXTexture();
auto *sampler = device.getSampler(diffuseMap->getSamplerInfo());
setTextureImpl(data, layoutGraph, "cc_diffuseMap", texture);
setSamplerImpl(data, layoutGraph, "cc_diffuseMap", sampler);
}
gfx::SamplerInfo samplerPointInfo{
gfx::Filter::POINT,
gfx::Filter::POINT,
gfx::Filter::NONE,
gfx::Address::CLAMP,
gfx::Address::CLAMP,
gfx::Address::CLAMP};
auto *pointSampler = device.getSampler(samplerPointInfo);
setSamplerImpl(data, layoutGraph, "cc_shadowMap", pointSampler);
// setTextureImpl(data, layoutGraph, "cc_shadowMap", BuiltinResMgr::getInstance()->get<Texture2D>("default-texture")->getGFXTexture());
setSamplerImpl(data, layoutGraph, "cc_spotShadowMap", pointSampler);
// setTextureImpl(data, layoutGraph, "cc_spotShadowMap", BuiltinResMgr::getInstance()->get<Texture2D>("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<float *>(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<const scene::SphereLight *>(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<const scene::SpotLight *>(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<const scene::PointLight *>(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<const scene::RangedDirectionalLight *>(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<float>(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<const scene::SpotLight *>(light);
lightBufferData[offset + pipeline::UBOForwardLight::LIGHT_POS_OFFSET + 3] = static_cast<float>(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<float>(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<float>(scene::LightType::RANGED_DIRECTIONAL);
const auto *rangedDirLight = static_cast<const scene::RangedDirectionalLight *>(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<const NativePipeline &>(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<const NativePipeline &>(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

View File

@@ -0,0 +1,122 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include <cstdint>
#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
namespace pipeline {
class PipelineSceneData;
} // namespace pipeline
namespace render {
void setCameraUBOValues(
const scene::Camera &camera,
const LayoutGraphData &layoutGraph,
const pipeline::PipelineSceneData &cfg,
const scene::DirectionalLight *mainLight,
RenderData &data);
void setLegacyTextureUBOView(
gfx::Device &device,
const LayoutGraphData &layoutGraph,
const pipeline::PipelineSceneData &sceneData,
RenderData &data);
// For use shadow map
void setShadowUBOView(
gfx::Device &device,
const LayoutGraphData &layoutGraph,
const pipeline::PipelineSceneData &sceneData,
const scene::DirectionalLight &mainLight,
RenderData &data);
// For build shadow map
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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,96 @@
/****************************************************************************
Copyright (c) 2021-2022 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include <sstream>
#include "BinaryArchive.h"
#include "LayoutGraphSerialization.h"
#include "NativePipelineTypes.h"
#include "RenderInterfaceTypes.h"
#include "RenderingModule.h"
#include "details/GslUtils.h"
#include "pipeline/custom/LayoutGraphTypes.h"
#include "pipeline/custom/details/Pmr.h"
namespace cc {
namespace render {
namespace {
NativeRenderingModule* sRenderingModule = nullptr;
NativePipeline* sPipeline = nullptr;
} // namespace
RenderingModule* Factory::init(gfx::Device* deviceIn, const ccstd::vector<unsigned char>& bufferIn) {
std::shared_ptr<NativeProgramLibrary> ptr(
allocatePmrUniquePtr<NativeProgramLibrary>(
boost::container::pmr::get_default_resource()));
{
std::string buffer(bufferIn.begin(), bufferIn.end());
std::istringstream iss(buffer, std::ios::binary);
BinaryInputArchive ar(iss, boost::container::pmr::get_default_resource());
load(ar, ptr->layoutGraph);
}
ptr->init(deviceIn);
sRenderingModule = ccnew NativeRenderingModule(std::move(ptr));
return sRenderingModule;
}
void Factory::destroy(RenderingModule* renderingModule) noexcept {
auto* ptr = dynamic_cast<NativeRenderingModule*>(renderingModule);
if (ptr) {
ptr->programLibrary.reset();
CC_EXPECTS(sRenderingModule == renderingModule);
sRenderingModule = nullptr;
sPipeline = nullptr;
}
}
Pipeline* Factory::createPipeline() {
if (sPipeline) {
return sPipeline;
}
sPipeline = ccnew NativePipeline(boost::container::pmr::get_default_resource());
CC_EXPECTS(sRenderingModule);
sRenderingModule->programLibrary->pipeline = sPipeline;
return sPipeline;
}
ProgramLibrary* getProgramLibrary() {
if (!sRenderingModule) {
return nullptr;
}
return sRenderingModule->programLibrary.get();
}
RenderingModule* getRenderingModule() {
return sRenderingModule;
}
} // namespace render
} // namespace cc

View File

@@ -0,0 +1,47 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include "cocos/base/std/variant.h"
#include "cocos/renderer/pipeline/custom/LayoutGraphFwd.h"
#include "cocos/renderer/pipeline/custom/PrivateFwd.h"
namespace cc {
namespace render {
struct ProgramInfo;
struct ProgramGroup;
} // namespace render
} // namespace cc
// clang-format on

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,130 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include "cocos/base/std/variant.h"
#include "cocos/renderer/pipeline/custom/NativeFwd.h"
namespace cc {
namespace scene {
class ReflectionProbe;
} // namespace scene
namespace render {
template <class T>
using Array4 = std::array<T, 4>;
} // 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;
class NativeMultisampleRenderSubpassBuilder;
class NativeComputeSubpassBuilder;
class NativeRenderPassBuilder;
class NativeMultisampleRenderPassBuilder;
class NativeComputeQueueBuilder;
class NativeComputePassBuilder;
struct RenderInstancingQueue;
struct DrawInstance;
struct ProbeHelperQueue;
struct RenderDrawQueue;
struct NativeRenderQueue;
struct ResourceGroup;
struct BufferPool;
struct DescriptorSetPool;
struct UniformBlockResource;
struct ProgramResource;
struct LayoutGraphNodeResource;
struct QuadResource;
enum class ResourceType;
struct SceneResource;
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;
} // namespace render
} // namespace cc
namespace ccstd {
template <>
struct hash<cc::render::FrustumCullingKey> {
hash_t operator()(const cc::render::FrustumCullingKey& val) const noexcept;
};
template <>
struct hash<cc::render::FrustumCullingID> {
hash_t operator()(const cc::render::FrustumCullingID& val) const noexcept;
};
template <>
struct hash<cc::render::LightBoundsCullingKey> {
hash_t operator()(const cc::render::LightBoundsCullingKey& val) const noexcept;
};
} // namespace ccstd
// clang-format on

View File

@@ -0,0 +1,39 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include <string_view>
#include <tuple>
#include "cocos/renderer/pipeline/custom/NativePipelineTypes.h"
#include "cocos/renderer/pipeline/custom/details/GraphImpl.h"
#include "cocos/renderer/pipeline/custom/details/Overload.h"
#include "cocos/renderer/pipeline/custom/details/PathUtils.h"
// clang-format on

View File

@@ -0,0 +1,265 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#include "NativePipelineTypes.h"
namespace cc {
namespace render {
RenderInstancingQueue::RenderInstancingQueue(const allocator_type& alloc) noexcept
: sortedBatches(alloc),
passInstances(alloc),
instanceBuffers(alloc) {}
RenderInstancingQueue::RenderInstancingQueue(RenderInstancingQueue&& rhs, const allocator_type& alloc)
: sortedBatches(std::move(rhs.sortedBatches), alloc),
passInstances(std::move(rhs.passInstances), alloc),
instanceBuffers(std::move(rhs.instanceBuffers), alloc) {}
RenderInstancingQueue::RenderInstancingQueue(RenderInstancingQueue const& rhs, const allocator_type& alloc)
: sortedBatches(rhs.sortedBatches, alloc),
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) {}
RenderDrawQueue::RenderDrawQueue(RenderDrawQueue&& rhs, const allocator_type& alloc)
: instances(std::move(rhs.instances), alloc) {}
RenderDrawQueue::RenderDrawQueue(RenderDrawQueue const& rhs, const allocator_type& alloc)
: instances(rhs.instances, alloc) {}
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),
subpassOrPassLayoutID(subpassOrPassLayoutIDIn) {}
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),
lightByteOffset(rhs.lightByteOffset) {}
ResourceGroup::ResourceGroup(const allocator_type& alloc) noexcept
: instancingBuffers(alloc) {}
BufferPool::BufferPool(const allocator_type& alloc) noexcept
: currentBuffers(alloc),
currentBufferViews(alloc),
freeBuffers(alloc),
freeBufferViews(alloc) {}
BufferPool::BufferPool(gfx::Device* deviceIn, uint32_t bufferSizeIn, bool dynamicIn, const allocator_type& alloc) noexcept // NOLINT
: device(deviceIn),
bufferSize(bufferSizeIn),
dynamic(dynamicIn),
currentBuffers(alloc),
currentBufferViews(alloc),
freeBuffers(alloc),
freeBufferViews(alloc) {}
BufferPool::BufferPool(BufferPool&& rhs, const allocator_type& alloc)
: device(rhs.device),
bufferSize(rhs.bufferSize),
dynamic(rhs.dynamic),
currentBuffers(std::move(rhs.currentBuffers), alloc),
currentBufferViews(std::move(rhs.currentBufferViews), alloc),
freeBuffers(std::move(rhs.freeBuffers), alloc),
freeBufferViews(std::move(rhs.freeBufferViews), alloc) {}
DescriptorSetPool::DescriptorSetPool(const allocator_type& alloc) noexcept
: currentDescriptorSets(alloc),
freeDescriptorSets(alloc) {}
DescriptorSetPool::DescriptorSetPool(gfx::Device* deviceIn, IntrusivePtr<gfx::DescriptorSetLayout> setLayoutIn, const allocator_type& alloc) noexcept // NOLINT
: device(deviceIn),
setLayout(std::move(setLayoutIn)),
currentDescriptorSets(alloc),
freeDescriptorSets(alloc) {}
DescriptorSetPool::DescriptorSetPool(DescriptorSetPool&& rhs, const allocator_type& alloc)
: device(rhs.device),
setLayout(std::move(rhs.setLayout)),
currentDescriptorSets(std::move(rhs.currentDescriptorSets), alloc),
freeDescriptorSets(std::move(rhs.freeDescriptorSets), alloc) {}
UniformBlockResource::UniformBlockResource(const allocator_type& alloc) noexcept
: cpuBuffer(alloc),
bufferPool(alloc) {}
UniformBlockResource::UniformBlockResource(UniformBlockResource&& rhs, const allocator_type& alloc)
: cpuBuffer(std::move(rhs.cpuBuffer), alloc),
bufferPool(std::move(rhs.bufferPool), alloc) {}
ProgramResource::ProgramResource(const allocator_type& alloc) noexcept
: uniformBuffers(alloc),
descriptorSetPool(alloc) {}
ProgramResource::ProgramResource(ProgramResource&& rhs, const allocator_type& alloc)
: uniformBuffers(std::move(rhs.uniformBuffers), alloc),
descriptorSetPool(std::move(rhs.descriptorSetPool), alloc) {}
LayoutGraphNodeResource::LayoutGraphNodeResource(const allocator_type& alloc) noexcept
: uniformBuffers(alloc),
descriptorSetPool(alloc),
programResources(alloc) {}
LayoutGraphNodeResource::LayoutGraphNodeResource(LayoutGraphNodeResource&& rhs, const allocator_type& alloc)
: uniformBuffers(std::move(rhs.uniformBuffers), alloc),
descriptorSetPool(std::move(rhs.descriptorSetPool), alloc),
programResources(std::move(rhs.programResources), alloc) {}
SceneResource::SceneResource(const allocator_type& alloc) noexcept
: resourceIndex(alloc),
storageBuffers(alloc),
storageImages(alloc) {}
SceneResource::SceneResource(SceneResource&& rhs, const allocator_type& alloc)
: resourceIndex(std::move(rhs.resourceIndex), alloc),
storageBuffers(std::move(rhs.storageBuffers), alloc),
storageImages(std::move(rhs.storageImages), alloc) {}
FrustumCulling::FrustumCulling(const allocator_type& alloc) noexcept
: resultIndex(alloc) {}
FrustumCulling::FrustumCulling(FrustumCulling&& rhs, const allocator_type& alloc)
: resultIndex(std::move(rhs.resultIndex), alloc) {}
FrustumCulling::FrustumCulling(FrustumCulling const& rhs, const allocator_type& alloc)
: resultIndex(rhs.resultIndex, 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
: frustumCullings(alloc),
frustumCullingResults(alloc),
lightBoundsCullings(alloc),
lightBoundsCullingResults(alloc),
renderQueues(alloc),
renderQueueIndex(alloc) {}
SceneCulling::SceneCulling(SceneCulling&& rhs, const allocator_type& 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),
renderQueueIndex(std::move(rhs.renderQueueIndex), alloc),
numFrustumCulling(rhs.numFrustumCulling),
numLightBoundsCulling(rhs.numLightBoundsCulling),
numRenderQueues(rhs.numRenderQueues),
gpuCullingPassID(rhs.gpuCullingPassID),
enableLightCulling(rhs.enableLightCulling) {}
LightResource::LightResource(const allocator_type& alloc) noexcept
: cpuBuffer(alloc),
lights(alloc),
lightIndex(alloc) {}
NativeRenderContext::NativeRenderContext(std::unique_ptr<gfx::DefaultResource> defaultResourceIn, const allocator_type& alloc) noexcept
: defaultResource(std::move(defaultResourceIn)),
resourceGroups(alloc),
layoutGraphResources(alloc),
renderSceneResources(alloc),
sceneCulling(alloc),
lightResources(alloc) {}
NativeProgramLibrary::NativeProgramLibrary(const allocator_type& alloc) noexcept
: layoutGraph(alloc),
phases(alloc),
localLayoutData(alloc) {}
PipelineCustomization::PipelineCustomization(const allocator_type& alloc) noexcept
: contexts(alloc),
renderPasses(alloc),
renderSubpasses(alloc),
computeSubpasses(alloc),
computePasses(alloc),
renderQueues(alloc),
renderCommands(alloc) {}
PipelineCustomization::PipelineCustomization(PipelineCustomization&& rhs, const allocator_type& alloc)
: currentContext(std::move(rhs.currentContext)),
contexts(std::move(rhs.contexts), alloc),
renderPasses(std::move(rhs.renderPasses), alloc),
renderSubpasses(std::move(rhs.renderSubpasses), alloc),
computeSubpasses(std::move(rhs.computeSubpasses), alloc),
computePasses(std::move(rhs.computePasses), alloc),
renderQueues(std::move(rhs.renderQueues), alloc),
renderCommands(std::move(rhs.renderCommands), alloc) {}
PipelineCustomization::PipelineCustomization(PipelineCustomization const& rhs, const allocator_type& alloc)
: currentContext(rhs.currentContext),
contexts(rhs.contexts, alloc),
renderPasses(rhs.renderPasses, alloc),
renderSubpasses(rhs.renderSubpasses, alloc),
computeSubpasses(rhs.computeSubpasses, alloc),
computePasses(rhs.computePasses, alloc),
renderQueues(rhs.renderQueues, alloc),
renderCommands(rhs.renderCommands, alloc) {}
} // namespace render
} // namespace cc
// clang-format on

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,149 @@
#include "NativePipelineTypes.h"
#include "details/GslUtils.h"
namespace cc {
namespace render {
void BufferPool::init(gfx::Device* deviceIn, uint32_t sz, bool bDynamic) {
CC_EXPECTS(deviceIn);
CC_EXPECTS(sz);
CC_EXPECTS(!device);
CC_EXPECTS(bufferSize == 0);
device = deviceIn;
bufferSize = sz;
dynamic = bDynamic;
}
void BufferPool::syncResources() {
for (auto& buffer : currentBuffers) {
freeBuffers.emplace_back(std::move(buffer));
}
currentBuffers.clear();
for (auto& bufferView : currentBufferViews) {
freeBufferViews.emplace_back(std::move(bufferView));
}
currentBufferViews.clear();
}
gfx::Buffer* BufferPool::allocateBuffer() {
CC_EXPECTS(device);
CC_EXPECTS(bufferSize);
gfx::Buffer* ptr = nullptr;
if (freeBuffers.empty()) {
{
gfx::BufferInfo info{
gfx::BufferUsageBit::UNIFORM | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::HOST | gfx::MemoryUsageBit::DEVICE,
bufferSize,
bufferSize};
freeBuffers.emplace_back(device->createBuffer(info));
}
if (dynamic) {
gfx::BufferViewInfo info{
freeBuffers.back().get(),
0, bufferSize};
freeBufferViews.emplace_back(device->createBuffer(info));
}
}
{
CC_ENSURES(!freeBuffers.empty());
auto& buffer = freeBuffers.back();
ptr = buffer.get();
CC_EXPECTS(buffer->getSize() == bufferSize);
currentBuffers.emplace_back(std::move(buffer));
freeBuffers.pop_back();
}
if (dynamic) {
CC_ENSURES(!freeBufferViews.empty());
auto& bufferView = freeBufferViews.back();
ptr = bufferView.get();
CC_EXPECTS(bufferView->getSize() == bufferSize);
currentBufferViews.emplace_back(std::move(bufferView));
freeBufferViews.pop_back();
}
CC_ENSURES(ptr);
if (dynamic) {
CC_ENSURES(ptr->isBufferView());
} else {
CC_ENSURES(!ptr->isBufferView());
}
return ptr;
}
void UniformBlockResource::init(gfx::Device* deviceIn, uint32_t sz, bool bDynamic) {
CC_EXPECTS(cpuBuffer.empty());
cpuBuffer.resize(sz);
bufferPool.init(deviceIn, sz, bDynamic);
}
gfx::Buffer* UniformBlockResource::createFromCpuBuffer() {
CC_EXPECTS(cpuBuffer.size() == bufferPool.bufferSize);
auto* bufferOrView = bufferPool.allocateBuffer();
if (bufferPool.dynamic) {
auto* buffer = bufferPool.currentBuffers.back().get();
buffer->update(cpuBuffer.data(), static_cast<uint32_t>(cpuBuffer.size()));
} else {
bufferOrView->update(cpuBuffer.data(), static_cast<uint32_t>(cpuBuffer.size()));
}
return bufferOrView;
}
void DescriptorSetPool::init(gfx::Device* deviceIn,
IntrusivePtr<gfx::DescriptorSetLayout> layout) {
CC_EXPECTS(deviceIn);
CC_EXPECTS(layout);
CC_EXPECTS(!device);
CC_EXPECTS(!setLayout);
device = deviceIn;
setLayout = std::move(layout);
}
void DescriptorSetPool::syncDescriptorSets() {
for (auto& set : currentDescriptorSets) {
freeDescriptorSets.emplace_back(std::move(set));
}
currentDescriptorSets.clear();
}
gfx::DescriptorSet& DescriptorSetPool::getCurrentDescriptorSet() {
CC_EXPECTS(!currentDescriptorSets.empty());
return *currentDescriptorSets.back();
}
const gfx::DescriptorSet& DescriptorSetPool::getCurrentDescriptorSet() const {
CC_EXPECTS(!currentDescriptorSets.empty());
return *currentDescriptorSets.back();
}
gfx::DescriptorSet* DescriptorSetPool::allocateDescriptorSet() {
CC_EXPECTS(device);
CC_EXPECTS(setLayout);
gfx::DescriptorSet* ptr = nullptr;
if (freeDescriptorSets.empty()) {
freeDescriptorSets.emplace_back(
device->createDescriptorSet(gfx::DescriptorSetInfo{setLayout.get()}));
}
{
CC_ENSURES(!freeDescriptorSets.empty());
auto& set = freeDescriptorSets.back();
ptr = set.get();
CC_EXPECTS(set->getLayout() == setLayout);
currentDescriptorSets.emplace_back(std::move(set));
freeDescriptorSets.pop_back();
}
CC_ENSURES(ptr);
return ptr;
}
} // namespace render
} // namespace cc

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,327 @@
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/filtered_graph.hpp>
#include "cocos/renderer/pipeline/custom/RenderCommonNames.h"
#include "cocos/renderer/pipeline/custom/RenderGraphGraphs.h"
#include "cocos/renderer/pipeline/custom/details/DebugUtils.h"
#include "cocos/renderer/pipeline/custom/details/GraphTypes.h"
#include "cocos/renderer/pipeline/custom/details/GraphView.h"
namespace cc {
namespace render {
namespace {
const char *getName(const gfx::LoadOp &op) {
switch (op) {
case gfx::LoadOp::LOAD:
return "LOAD";
case gfx::LoadOp::CLEAR:
return "CLEAR";
case gfx::LoadOp::DISCARD:
return "DISCARD";
default:
return "UNKNOWN";
}
return "UNKNOWN";
}
const char *getName(const gfx::StoreOp &op) {
switch (op) {
case gfx::StoreOp::STORE:
return "STORE";
case gfx::StoreOp::DISCARD:
return "DISCARD";
default:
return "UNKNOWN";
}
return "UNKNOWN";
}
std::string getName(const gfx::ClearFlagBit &flags) {
std::ostringstream oss;
int count = 0;
if (hasAnyFlags(flags, gfx::ClearFlagBit::COLOR)) {
if (count++) {
oss << "|";
}
oss << "COLOR";
}
if (hasAnyFlags(flags, gfx::ClearFlagBit::DEPTH)) {
if (count++) {
oss << "|";
}
oss << "DEPTH";
}
if (hasAnyFlags(flags, gfx::ClearFlagBit::STENCIL)) {
if (count++) {
oss << "|";
}
oss << "STENCIL";
}
if (flags == gfx::ClearFlagBit::NONE) {
oss << "NONE";
}
return oss.str();
}
struct RenderGraphPrintVisitor : boost::dfs_visitor<> {
void discover_vertex(
RenderGraph::vertex_descriptor vertID,
const AddressableView<RenderGraph> &gv) const {
const auto &g = gv.mGraph;
const auto &name = get(RenderGraph::NameTag{}, g, vertID);
visitObject(
vertID, gv.mGraph,
[&](const RasterPass &pass) {
OSS << "RasterPass \"" << name << "\" {\n";
indent(space);
for (const auto &[name, rasterView] : pass.rasterViews) {
OSS << "RasterView \"" << name << "\" {\n";
{
INDENT();
OSS << "slotName: \"" << rasterView.slotName << "\";\n";
OSS << "accessType: " << getName(rasterView.accessType) << ";\n";
OSS << "attachmentType: " << getName(rasterView.attachmentType) << ";\n";
OSS << "loadOp: " << getName(rasterView.loadOp) << ";\n";
OSS << "storeOp: " << getName(rasterView.storeOp) << ";\n";
OSS << "clearFlags: " << getName(rasterView.clearFlags) << ";\n";
const auto &c = rasterView.clearColor;
if (hasAnyFlags(rasterView.clearFlags, gfx::ClearFlagBit::COLOR)) {
OSS << "clearColor: [" << c.x << ", " << c.y << ", " << c.z << ", " << c.z << "];\n";
} else if (hasAnyFlags(rasterView.clearFlags, gfx::ClearFlagBit::DEPTH_STENCIL)) {
OSS << "clearColor: [" << c.x << ", " << c.y << "];\n";
}
}
OSS << "}\n";
}
for (const auto &[name, computeViews] : pass.computeViews) {
OSS << "ComputeViews \"" << name << "\" {\n";
{
INDENT();
for (const auto &computeView : computeViews) {
OSS << "ComputeView \"" << computeView.name << "\" {\n";
{
INDENT();
OSS << "accessType: " << getName(computeView.accessType) << ";\n";
OSS << "clearFlags: " << getName(computeView.clearFlags) << ";\n";
const auto &c = computeView.clearValue;
if (hasAnyFlags(computeView.clearFlags, gfx::ClearFlagBit::COLOR)) {
OSS << "clearColor: [" << c.x << ", " << c.y << ", " << c.z << ", " << c.z << "];\n";
} else if (hasAnyFlags(computeView.clearFlags, gfx::ClearFlagBit::DEPTH_STENCIL)) {
OSS << "clearColor: [" << c.x << ", " << c.y << "];\n";
}
}
OSS << "}\n";
}
}
OSS << "}\n";
}
},
[&](const RasterSubpass &subpass) {
std::ignore = subpass;
},
[&](const ComputeSubpass &subpass) {
std::ignore = subpass;
},
[&](const ComputePass &pass) {
OSS << "ComputePass \"" << name << "\" {\n";
indent(space);
for (const auto &[name, computeViews] : pass.computeViews) {
OSS << "ComputeViews \"" << name << "\" {\n";
{
INDENT();
for (const auto &computeView : computeViews) {
OSS << "ComputeView \"" << computeView.name << "\" {\n";
{
INDENT();
OSS << "accessType: " << getName(computeView.accessType) << ";\n";
OSS << "clearFlags: " << getName(computeView.clearFlags) << ";\n";
const auto &c = computeView.clearValue;
if (hasAnyFlags(computeView.clearFlags, gfx::ClearFlagBit::COLOR)) {
OSS << "clearColor: [" << c.x << ", " << c.y << ", " << c.z << ", " << c.z << "];\n";
} else if (hasAnyFlags(computeView.clearFlags, gfx::ClearFlagBit::DEPTH_STENCIL)) {
OSS << "clearColor: [" << c.x << ", " << c.y << "];\n";
}
}
OSS << "}\n";
}
}
OSS << "}\n";
}
},
[&](const ResolvePass &pass) {
OSS << "ResolvePass \"" << name << "\" {\n";
for (const auto &pair : pass.resolvePairs) {
INDENT();
OSS << "source: \"" << pair.source << "\", target: \"" << pair.target << "\"\n";
}
indent(space);
},
[&](const CopyPass &pass) {
OSS << "CopyPass \"" << name << "\" {\n";
for (const auto &pair : pass.copyPairs) {
INDENT();
OSS << "source: \"" << pair.source << "\", target: \"" << pair.target << "\"\n";
}
indent(space);
},
[&](const MovePass &pass) {
OSS << "MovePass \"" << name << "\" {\n";
for (const auto &pair : pass.movePairs) {
INDENT();
OSS << "source: \"" << pair.source << "\", target: \"" << pair.target << "\"\n";
}
indent(space);
},
[&](const RaytracePass &pass) {
std::ignore = pass;
OSS << "RaytracePass \"" << name << "\" {\n";
indent(space);
},
[&](const RenderQueue &queue) {
OSS << "Queue \"" << name << "\" {\n";
{
INDENT();
OSS << "hint: " << getName(queue.hint) << ";\n";
}
indent(space);
},
[&](const SceneData &scene) {
std::ignore = scene;
OSS << "Scene \"" << name << "\" {\n";
indent(space);
},
[&](const Blit &blit) {
std::ignore = blit;
OSS << "Blit \"" << name << "\";\n";
},
[&](const Dispatch &dispatch) {
OSS << "Dispatch \"" << name << "\", ["
<< dispatch.threadGroupCountX << ", "
<< dispatch.threadGroupCountY << ", "
<< dispatch.threadGroupCountZ << "];\n";
},
[&](const ccstd::pmr::vector<ClearView> &clearViews) {
OSS << "Clear \"" << name << "\" {\n";
indent(space);
for (const auto &view : clearViews) {
INDENT();
OSS << "\"" << view.slotName << "\" {\n";
{
INDENT();
OSS << "clearFlags: " << getName(view.clearFlags) << ";\n";
const auto &c = view.clearColor;
if (hasAnyFlags(view.clearFlags, gfx::ClearFlagBit::COLOR)) {
OSS << "clearColor: [" << c.x << ", " << c.y << ", " << c.z << ", " << c.z << "];\n";
} else if (hasAnyFlags(view.clearFlags, gfx::ClearFlagBit::DEPTH_STENCIL)) {
OSS << "clearColor: [" << c.x << ", " << c.y << "];\n";
}
}
OSS << "}\n";
}
},
[&](const gfx::Viewport &vp) {
OSS << "Viewport \"" << name << "\" ["
<< "left: " << vp.left << ", "
<< "top: " << vp.top << ", "
<< "width: " << vp.width << ", "
<< "height: " << vp.height << ", "
<< "minDepth: " << vp.minDepth << ", "
<< "maxDepth: " << vp.maxDepth << "]\n";
});
}
void finish_vertex(
RenderGraph::vertex_descriptor vertID,
const AddressableView<RenderGraph> &gv) const {
std::ignore = gv;
visitObject(
vertID, gv.mGraph,
[&](const RasterPass &pass) {
std::ignore = pass;
unindent(space);
OSS << "}\n";
},
[&](const RasterSubpass &subpass) {
std::ignore = subpass;
},
[&](const ComputeSubpass &subpass) {
std::ignore = subpass;
},
[&](const ComputePass &pass) {
std::ignore = pass;
unindent(space);
OSS << "}\n";
},
[&](const ResolvePass &pass) {
std::ignore = pass;
unindent(space);
OSS << "}\n";
},
[&](const CopyPass &pass) {
std::ignore = pass;
unindent(space);
OSS << "}\n";
},
[&](const MovePass &pass) {
std::ignore = pass;
unindent(space);
OSS << "}\n";
},
[&](const RaytracePass &pass) {
std::ignore = pass;
unindent(space);
OSS << "}\n";
},
[&](const RenderQueue &queue) {
std::ignore = queue;
unindent(space);
OSS << "}\n";
},
[&](const SceneData &scene) {
std::ignore = scene;
unindent(space);
OSS << "}\n";
},
[&](const Blit &blit) {
},
[&](const Dispatch &dispatch) {
},
[&](const ccstd::pmr::vector<ClearView> &clear) {
std::ignore = clear;
unindent(space);
OSS << "}\n";
},
[&](const gfx::Viewport &clear) {
});
}
std::ostringstream &oss;
ccstd::pmr::string &space;
};
} // namespace
ccstd::string RenderGraph::print(
boost::container::pmr::memory_resource *scratch) const {
const auto &rg = *this;
std::ostringstream oss;
ccstd::pmr::string space(scratch);
oss << "\n";
OSS << "RenderGraph {\n";
{
INDENT();
RenderGraphPrintVisitor visitor{
{}, oss, space};
AddressableView<RenderGraph> graphView(rg);
auto colors = rg.colors(scratch);
boost::depth_first_search(graphView, visitor, get(colors, rg));
}
OSS << "}\n";
return oss.str();
}
} // namespace render
} // namespace cc

View File

@@ -0,0 +1,229 @@
#pragma once
#include "cocos/renderer/pipeline/custom/LayoutGraphGraphs.h"
#include "cocos/renderer/pipeline/custom/NativeTypes.h"
#include "cocos/renderer/pipeline/custom/RenderGraphGraphs.h"
#include "cocos/renderer/pipeline/custom/details/GslUtils.h"
#include "pipeline/custom/RenderGraphTypes.h"
namespace cc {
namespace render {
template <class Component0, class Component1, class Component2, class Component3, class Tag, class ValueT>
RenderGraph::vertex_descriptor
addVertex2(Tag tag, Component0 &&c0, Component1 &&c1, Component2 &&c2, Component3 &&c3, ValueT &&val,
RenderGraph &g, RenderGraph::vertex_descriptor u = RenderGraph::null_vertex()) {
auto v = addVertex(
tag,
std::forward<Component0>(c0),
std::forward<Component1>(c1),
std::forward<Component2>(c2),
std::forward<Component3>(c3),
std::forward<ValueT>(val),
g,
u);
g.sortedVertices.emplace_back(v);
CC_EXPECTS(g.sortedVertices.size() == num_vertices(g));
return v;
}
inline LayoutGraphData::vertex_descriptor getSubpassOrPassID(
RenderGraph::vertex_descriptor vertID,
const RenderGraph &rg, const LayoutGraphData &lg) {
const auto queueID = parent(vertID, rg);
CC_ENSURES(queueID != RenderGraph::null_vertex());
const auto subpassOrPassID = parent(queueID, rg);
CC_ENSURES(subpassOrPassID != RenderGraph::null_vertex());
const auto passID = parent(subpassOrPassID, rg);
auto layoutID = LayoutGraphData::null_vertex();
if (passID == RenderGraph::null_vertex()) { // single render pass
const auto &layoutName = get(RenderGraph::LayoutTag{}, rg, subpassOrPassID);
CC_ENSURES(!layoutName.empty());
layoutID = locate(LayoutGraphData::null_vertex(), layoutName, lg);
} else { // render pass
const auto &passLayoutName = get(RenderGraph::LayoutTag{}, rg, passID);
CC_ENSURES(!passLayoutName.empty());
const auto passLayoutID = locate(LayoutGraphData::null_vertex(), passLayoutName, lg);
CC_ENSURES(passLayoutID != LayoutGraphData::null_vertex());
const auto &subpassLayoutName = get(RenderGraph::LayoutTag{}, rg, subpassOrPassID);
if (subpassLayoutName.empty()) {
layoutID = passLayoutID; // expect to be multisample pass
} else {
const auto subpassLayoutID = locate(passLayoutID, subpassLayoutName, lg);
CC_ENSURES(subpassLayoutID != LayoutGraphData::null_vertex());
layoutID = subpassLayoutID;
}
}
CC_ENSURES(layoutID != LayoutGraphData::null_vertex());
return layoutID;
}
inline std::tuple<RenderGraph::vertex_descriptor, LayoutGraphData::vertex_descriptor>
addRenderPassVertex(
RenderGraph &renderGraph, const LayoutGraphData &layoutGraph,
uint32_t width, uint32_t height, // NOLINT(bugprone-easily-swappable-parameters)
uint32_t count, uint32_t quality, // NOLINT(bugprone-easily-swappable-parameters)
const ccstd::string &passName) {
RasterPass pass(renderGraph.get_allocator());
pass.width = width;
pass.height = height;
pass.viewport.width = width;
pass.viewport.height = height;
pass.count = count;
pass.quality = quality;
auto passID = addVertex2(
RasterPassTag{},
std::forward_as_tuple(passName),
std::forward_as_tuple(passName),
std::forward_as_tuple(),
std::forward_as_tuple(),
std::forward_as_tuple(std::move(pass)),
renderGraph);
auto passLayoutID = locate(LayoutGraphData::null_vertex(), passName, layoutGraph);
CC_EXPECTS(passLayoutID != LayoutGraphData::null_vertex());
return {passID, passLayoutID};
}
inline std::tuple<RenderGraph::vertex_descriptor, LayoutGraphData::vertex_descriptor>
addRenderSubpassVertex(
RasterPass &pass,
RenderGraph &renderGraph, RenderGraph::vertex_descriptor passID,
const LayoutGraphData &layoutGraph, LayoutGraphData::vertex_descriptor passLayoutID,
const ccstd::string &subpassName,
uint32_t count, uint32_t quality) { // NOLINT(bugprone-easily-swappable-parameters)
// if subpassName is empty, it must be basic multisample render pass
CC_EXPECTS(!subpassName.empty() || count > 1);
auto &subpassGraph = pass.subpassGraph;
const auto subpassIndex = num_vertices(pass.subpassGraph);
{
auto id = addVertex(
std::piecewise_construct,
std::forward_as_tuple(subpassName),
std::forward_as_tuple(),
subpassGraph);
CC_ENSURES(id == subpassIndex);
}
RasterSubpass subpass(subpassIndex, count, quality, renderGraph.get_allocator());
subpass.viewport.width = pass.width;
subpass.viewport.height = pass.height;
auto subpassID = addVertex2(
RasterSubpassTag{},
std::forward_as_tuple(subpassName),
std::forward_as_tuple(subpassName),
std::forward_as_tuple(),
std::forward_as_tuple(),
std::forward_as_tuple(std::move(subpass)),
renderGraph, passID);
auto subpassLayoutID = LayoutGraphData::null_vertex();
if (subpassName.empty()) { // Basic multisample render pass (single subpass)
CC_EXPECTS(count > 1);
subpassLayoutID = passLayoutID;
} else {
if constexpr (ENABLE_SUBPASS) {
subpassLayoutID = locate(passLayoutID, subpassName, layoutGraph);
} else {
subpassLayoutID = locate(LayoutGraphData::null_vertex(), subpassName, layoutGraph);
}
}
CC_ENSURES(subpassLayoutID != LayoutGraphData::null_vertex());
return {subpassID, subpassLayoutID};
}
template <class Tag>
void addPassComputeViewImpl(
Tag tag,
RenderGraph &renderGraph,
RenderGraph::vertex_descriptor passID,
const ccstd::string &name, const ComputeView &view) {
std::ignore = tag;
CC_EXPECTS(!name.empty());
CC_EXPECTS(!view.name.empty());
auto &pass = get(Tag{}, passID, renderGraph);
auto iter = pass.computeViews.find(name.c_str());
if (iter == pass.computeViews.end()) {
bool added = false;
std::tie(iter, added) = pass.computeViews.emplace(
std::piecewise_construct,
std::forward_as_tuple(name.c_str()),
std::forward_as_tuple());
CC_ENSURES(added);
}
iter->second.emplace_back(view);
}
template <class Tag>
void addSubpassComputeViewImpl(
Tag tag,
RenderGraph &renderGraph,
RenderGraph::vertex_descriptor subpassID,
const ccstd::string &name, const ComputeView &view) {
std::ignore = tag;
CC_EXPECTS(!name.empty());
CC_EXPECTS(!view.name.empty());
auto &subpass = get(Tag{}, subpassID, renderGraph);
const auto passID = parent(subpassID, renderGraph);
CC_EXPECTS(passID != RenderGraph::null_vertex());
CC_EXPECTS(holds<RasterPassTag>(passID, renderGraph));
auto &pass = get(RasterPassTag{}, passID, renderGraph);
CC_EXPECTS(subpass.subpassID < num_vertices(pass.subpassGraph));
auto &subpassData = get(SubpassGraph::SubpassTag{}, pass.subpassGraph, subpass.subpassID);
CC_EXPECTS(subpass.computeViews.size() == subpassData.computeViews.size());
{
auto iter = subpassData.computeViews.find(name.c_str());
if (iter == subpassData.computeViews.end()) {
bool added = false;
std::tie(iter, added) = subpassData.computeViews.emplace(
std::piecewise_construct,
std::forward_as_tuple(name.c_str()),
std::forward_as_tuple());
CC_ENSURES(added);
}
iter->second.emplace_back(view);
}
{
auto iter = subpass.computeViews.find(name.c_str());
if (iter == subpass.computeViews.end()) {
bool added = false;
std::tie(iter, added) = subpass.computeViews.emplace(
std::piecewise_construct,
std::forward_as_tuple(name.c_str()),
std::forward_as_tuple());
CC_ENSURES(added);
}
iter->second.emplace_back(view);
}
CC_ENSURES(subpass.computeViews.size() == subpassData.computeViews.size());
CC_ENSURES(subpass.computeViews.find(std::string_view{name}) != subpass.computeViews.end());
CC_ENSURES(subpassData.computeViews.find(std::string_view{name}) != subpassData.computeViews.end());
CC_ENSURES(subpass.computeViews.find(std::string_view{name})->second.size() ==
subpassData.computeViews.find(std::string_view{name})->second.size());
}
inline bool defaultAttachment(std::string_view slotName) {
return slotName.empty() || slotName == "_";
}
static constexpr std::string_view DEPTH_PLANE_NAME = "depth";
static constexpr std::string_view STENCIL_PLANE_NAME = "stencil";
static constexpr std::string_view CUBE_TOP_NAME = "top";
static constexpr std::string_view CUBE_BOTTOM_NAME = "bottom";
static constexpr std::string_view CUBE_FRONT_NAME = "front";
static constexpr std::string_view CUBE_REAR_NAME = "rear";
static constexpr std::string_view CUBE_LEFT_NAME = "left";
static constexpr std::string_view CUBE_RIGHT_NAME = "right";
} // namespace render
} // namespace cc

View File

@@ -0,0 +1,271 @@
/****************************************************************************
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
https://www.cocos.com/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include <algorithm>
#include <iterator>
#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<cc::scene::IMacroPatch> 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<cc::scene::SubModel> &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<int>(k);
}
}
return 0xFFFFFFFF;
}
void ProbeHelperQueue::applyMacro(
const LayoutGraphData &lg, const cc::scene::Model &model,
LayoutGraphData::vertex_descriptor probeLayoutId) {
const std::vector<cc::IntrusivePtr<cc::scene::SubModel>> &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<cc::scene::IMacroPatch> 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();
const auto *const pass = subModel->getPass(passIdx);
auto passPriority = static_cast<uint32_t>(pass->getPriority());
auto modelPriority = static_cast<uint32_t>(subModel->getPriority());
auto shaderId = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(subModel->getShader(passIdx)));
const auto hash = (0 << 30) | (passPriority << 16) | (modelPriority << 8) | passIdx;
const auto priority = model.getPriority();
instances.emplace_back(DrawInstance{subModel, priority, hash, depth, shaderId, passIdx});
}
void RenderDrawQueue::sortOpaqueOrCutout() {
std::sort(instances.begin(), instances.end(), [](const DrawInstance &lhs, const DrawInstance &rhs) {
return std::forward_as_tuple(lhs.hash, lhs.depth, lhs.shaderID) <
std::forward_as_tuple(rhs.hash, rhs.depth, rhs.shaderID);
});
}
void RenderDrawQueue::sortTransparent() {
std::sort(instances.begin(), instances.end(), [](const DrawInstance &lhs, const DrawInstance &rhs) {
return std::forward_as_tuple(lhs.priority, lhs.hash, -lhs.depth, lhs.shaderID) <
std::forward_as_tuple(rhs.priority, rhs.hash, -rhs.depth, rhs.shaderID);
});
}
void RenderDrawQueue::recordCommandBuffer(
gfx::RenderPass *renderPass, uint32_t subpassIndex,
gfx::CommandBuffer *cmdBuff,
uint32_t lightByteOffset) const {
for (const auto &instance : instances) {
const auto *subModel = instance.subModel;
const auto passIdx = instance.passIndex;
auto *inputAssembler = subModel->getInputAssembler();
const auto *pass = subModel->getPass(passIdx);
auto *shader = subModel->getShader(passIdx);
auto *pso = pipeline::PipelineStateManager::getOrCreatePipelineState(pass, shader, inputAssembler, renderPass, subpassIndex);
cmdBuff->bindPipelineState(pso);
cmdBuff->bindDescriptorSet(pipeline::materialSet, pass->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);
}
}
bool RenderInstancingQueue::empty() const noexcept {
CC_EXPECTS(!passInstances.empty() || sortedBatches.empty());
return passInstances.empty();
}
void RenderInstancingQueue::clear() {
sortedBatches.clear();
passInstances.clear();
for (auto &buffer : instanceBuffers) {
buffer->clear();
}
}
void RenderInstancingQueue::add(
const scene::Pass &pass,
scene::SubModel &submodel, uint32_t passID) {
auto iter = passInstances.find(&pass);
if (iter == passInstances.end()) {
const auto instanceBufferID = static_cast<uint32_t>(passInstances.size());
if (instanceBufferID >= instanceBuffers.size()) {
CC_EXPECTS(instanceBufferID == instanceBuffers.size());
instanceBuffers.emplace_back(ccnew pipeline::InstancedBuffer(nullptr));
}
bool added = false;
std::tie(iter, added) = passInstances.emplace(&pass, instanceBufferID);
CC_ENSURES(added);
CC_ENSURES(iter->second < instanceBuffers.size());
const auto &instanceBuffer = instanceBuffers[iter->second];
instanceBuffer->setPass(&pass);
const auto &instances = instanceBuffer->getInstances();
for (const auto &item : instances) {
CC_EXPECTS(item.drawInfo.instanceCount == 0);
}
}
auto &instancedBuffer = *instanceBuffers[iter->second];
instancedBuffer.merge(&submodel, passID);
}
void RenderInstancingQueue::sort() {
sortedBatches.reserve(passInstances.size());
for (const auto &[pass, bufferID] : passInstances) {
sortedBatches.emplace_back(instanceBuffers[bufferID]);
}
}
void RenderInstancingQueue::uploadBuffers(gfx::CommandBuffer *cmdBuffer) const {
for (const auto &[pass, bufferID] : passInstances) {
const auto &ib = instanceBuffers[bufferID];
if (ib->hasPendingModels()) {
ib->uploadBuffers(cmdBuffer);
}
}
}
void RenderInstancingQueue::recordCommandBuffer(
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()) {
continue;
}
const auto &instances = instanceBuffer->getInstances();
const auto *drawPass = instanceBuffer->getPass();
cmdBuffer->bindDescriptorSet(pipeline::materialSet, drawPass->getDescriptorSet());
gfx::PipelineState *lastPSO = nullptr;
for (const auto &instance : instances) {
if (!instance.drawInfo.instanceCount) {
continue;
}
auto *pso = pipeline::PipelineStateManager::getOrCreatePipelineState(
drawPass, instance.shader, instance.ia, renderPass, subpassIndex);
if (lastPSO != pso) {
cmdBuffer->bindPipelineState(pso);
lastPSO = pso;
}
if (lightByteOffset != 0xFFFFFFFF) {
cmdBuffer->bindDescriptorSet(pipeline::localSet, instance.descriptorSet, 1, &lightByteOffset);
} else {
cmdBuffer->bindDescriptorSet(pipeline::localSet, instance.descriptorSet, instanceBuffer->dynamicOffsets());
}
cmdBuffer->bindInputAssembler(instance.ia);
cmdBuffer->draw(instance.ia);
}
}
}
void NativeRenderQueue::sort() {
opaqueQueue.sortOpaqueOrCutout();
transparentQueue.sortTransparent();
opaqueInstancingQueue.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

View File

@@ -0,0 +1,55 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "LayoutGraphGraphs.h"
#include "NativePipelineTypes.h"
#include "details/GslUtils.h"
namespace cc {
namespace render {
uint32_t NativeRenderingModule::getPassID(const ccstd::string &name) const {
CC_EXPECTS(programLibrary);
CC_EXPECTS(!name.empty());
return locate(LayoutGraphData::null_vertex(), name, programLibrary->layoutGraph);
}
uint32_t NativeRenderingModule::getSubpassID(uint32_t passID, const ccstd::string &name) const {
CC_EXPECTS(programLibrary);
CC_EXPECTS(!name.empty());
CC_EXPECTS(passID != LayoutGraphData::null_vertex());
return locate(passID, name, programLibrary->layoutGraph);
}
uint32_t NativeRenderingModule::getPhaseID(uint32_t subpassOrPassID, const ccstd::string &name) const {
CC_EXPECTS(programLibrary);
CC_EXPECTS(!name.empty());
CC_EXPECTS(subpassOrPassID != LayoutGraphData::null_vertex());
return locate(subpassOrPassID, name, programLibrary->layoutGraph);
}
} // namespace render
} // namespace cc

View File

@@ -0,0 +1,455 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include <boost/graph/depth_first_search.hpp>
#include "NativePipelineTypes.h"
#include "RenderGraphGraphs.h"
#include "RenderGraphTypes.h"
#include "cocos/renderer/gfx-base/GFXDevice.h"
#include "details/Range.h"
#include "gfx-base/GFXDef-common.h"
#include "pipeline/custom/RenderCommonFwd.h"
#include "cocos/scene/RenderWindow.h"
namespace cc {
namespace render {
ResourceGroup::~ResourceGroup() noexcept {
for (const auto& buffer : instancingBuffers) {
buffer->clear();
}
}
void ProgramResource::syncResources() noexcept {
for (auto&& [nameID, buffer] : uniformBuffers) {
buffer.bufferPool.syncResources();
}
descriptorSetPool.syncDescriptorSets();
}
void LayoutGraphNodeResource::syncResources() noexcept {
for (auto&& [nameID, buffer] : uniformBuffers) {
buffer.bufferPool.syncResources();
}
descriptorSetPool.syncDescriptorSets();
for (auto&& [programName, programResource] : programResources) {
programResource.syncResources();
}
}
void NativeRenderContext::clearPreviousResources(uint64_t finishedFenceValue) noexcept {
for (auto iter = resourceGroups.begin(); iter != resourceGroups.end();) {
if (iter->first <= finishedFenceValue) {
iter = resourceGroups.erase(iter);
} else {
break;
}
}
for (auto& node : layoutGraphResources) {
node.syncResources();
}
}
namespace {
gfx::BufferInfo getBufferInfo(const ResourceDesc& desc) {
using namespace gfx; // NOLINT(google-build-using-namespace)
BufferUsage usage = BufferUsage::TRANSFER_SRC | BufferUsage::TRANSFER_DST;
if (any(desc.flags & ResourceFlags::UNIFORM)) {
usage |= BufferUsage::UNIFORM;
}
if (any(desc.flags & ResourceFlags::STORAGE)) {
usage |= BufferUsage::STORAGE;
}
if (any(desc.flags & ResourceFlags::INDIRECT)) {
usage |= BufferUsage::INDIRECT;
}
return {
usage,
MemoryUsage::DEVICE,
desc.width,
1U, // stride should not be used
BufferFlagBit::NONE,
};
}
gfx::TextureInfo getTextureInfo(const ResourceDesc& desc) {
using namespace gfx; // NOLINT(google-build-using-namespace)
// usage
TextureUsage usage = TextureUsage::NONE;
if (any(desc.flags & ResourceFlags::COLOR_ATTACHMENT)) {
usage |= TextureUsage::COLOR_ATTACHMENT;
}
if (any(desc.flags & ResourceFlags::DEPTH_STENCIL_ATTACHMENT)) {
CC_EXPECTS(!any(desc.flags & ResourceFlags::COLOR_ATTACHMENT));
usage |= TextureUsage::DEPTH_STENCIL_ATTACHMENT;
}
if (any(desc.flags & ResourceFlags::INPUT_ATTACHMENT)) {
usage |= TextureUsage::INPUT_ATTACHMENT;
}
if (any(desc.flags & ResourceFlags::STORAGE)) {
usage |= TextureUsage::STORAGE;
}
if (any(desc.flags & ResourceFlags::SHADING_RATE)) {
usage |= TextureUsage::SHADING_RATE;
}
if (any(desc.flags & ResourceFlags::SAMPLED)) {
usage |= TextureUsage::SAMPLED;
}
if (any(desc.flags & ResourceFlags::TRANSFER_SRC)) {
usage |= TextureUsage::TRANSFER_SRC;
}
if (any(desc.flags & ResourceFlags::TRANSFER_DST)) {
usage |= TextureUsage::TRANSFER_DST;
}
return {
desc.viewType,
usage,
desc.format,
desc.width,
desc.height,
desc.textureFlags,
desc.viewType == TextureType::TEX3D ? 1U : desc.depthOrArraySize,
desc.mipLevels,
desc.sampleCount,
desc.viewType == TextureType::TEX3D ? desc.depthOrArraySize : 1U,
nullptr,
};
}
gfx::TextureViewInfo getTextureViewInfo(const SubresourceView& subresView, gfx::TextureType viewType) {
using namespace gfx; // NOLINT(google-build-using-namespace)
return {
nullptr,
viewType,
subresView.format,
subresView.indexOrFirstMipLevel,
subresView.numMipLevels,
subresView.firstArraySlice,
subresView.numArraySlices,
subresView.firstPlane,
subresView.numPlanes,
};
}
bool isTextureEqual(const gfx::Texture *texture, const ResourceDesc& desc) {
if (!texture) {
return false;
}
const auto& info = texture->getInfo();
return desc.width == info.width && desc.height == info.height && desc.format == info.format;
}
} // namespace
bool ManagedTexture::checkResource(const ResourceDesc& desc) const {
return isTextureEqual(texture.get(), desc);
}
void ResourceGraph::validateSwapchains() {
bool swapchainInvalidated = false;
for (auto& sc : swapchains) {
if (!sc.swapchain) {
continue;
}
if (sc.generation != sc.swapchain->getGeneration()) {
swapchainInvalidated = true;
sc.generation = sc.swapchain->getGeneration();
}
}
if (swapchainInvalidated) {
renderPasses.clear();
}
}
namespace {
std::pair<SubresourceView, ResourceGraph::vertex_descriptor>
getOriginView(const ResourceGraph& resg, ResourceGraph::vertex_descriptor vertID) {
// copy origin view
SubresourceView originView = get<SubresourceView>(vertID, resg);
auto parentID = parent(vertID, resg);
CC_EXPECTS(parentID != resg.null_vertex());
while (resg.isTextureView(parentID)) {
const auto& prtView = get(SubresourceViewTag{}, parentID, resg);
originView.firstPlane += prtView.firstPlane;
originView.firstArraySlice += prtView.firstArraySlice;
originView.indexOrFirstMipLevel += prtView.indexOrFirstMipLevel;
parentID = parent(parentID, resg);
}
CC_EXPECTS(parentID != resg.null_vertex());
CC_EXPECTS(resg.isTexture(parentID));
CC_ENSURES(!resg.isTextureView(parentID));
return {originView, parentID};
}
void recreateTextureView(
gfx::Device* device,
ResourceGraph& resg,
const SubresourceView& originView,
ResourceGraph::vertex_descriptor parentID,
SubresourceView& view) {
const auto& desc = get(ResourceGraph::DescTag{}, resg, parentID);
auto textureViewInfo = getTextureViewInfo(originView, desc.viewType);
const auto& parentTexture = resg.getTexture(parentID);
CC_EXPECTS(parentTexture);
textureViewInfo.texture = parentTexture;
view.textureView = device->createTexture(textureViewInfo);
}
} // namespace
// NOLINTNEXTLINE(misc-no-recursion)
void ResourceGraph::mount(gfx::Device* device, vertex_descriptor vertID) {
std::ignore = device;
auto& resg = *this;
const auto& desc = get(ResourceGraph::DescTag{}, *this, vertID);
visitObject(
vertID, resg,
[&](const ManagedResource& resource) {
// to be removed
},
[&](ManagedBuffer& buffer) {
if (!buffer.buffer) {
auto info = getBufferInfo(desc);
buffer.buffer = device->createBuffer(info);
}
CC_ENSURES(buffer.buffer);
buffer.fenceValue = nextFenceValue;
},
[&](ManagedTexture& texture) {
if (!texture.checkResource(desc)) {
auto info = getTextureInfo(desc);
texture.texture = device->createTexture(info);
// recreate depth stencil views, currently is not recursive
for (const auto& e : makeRange(children(vertID, *this))) {
const auto childID = child(e, *this);
auto* view = get_if<SubresourceView>(childID, this);
if (view) {
const auto [originView, parentID] = getOriginView(resg, childID);
CC_ENSURES(parentID == vertID);
recreateTextureView(device, *this, originView, parentID, *view);
}
}
}
CC_ENSURES(texture.texture);
texture.fenceValue = nextFenceValue;
},
[&](const PersistentBuffer& buffer) {
CC_EXPECTS(buffer.buffer);
std::ignore = buffer;
},
[&](const PersistentTexture& texture) {
CC_EXPECTS(texture.texture);
std::ignore = texture;
},
[&](const IntrusivePtr<gfx::Framebuffer>& fb) {
// deprecated
CC_EXPECTS(false);
CC_EXPECTS(fb);
std::ignore = fb;
},
[&](const RenderSwapchain& window) {
CC_EXPECTS(window.swapchain || window.renderWindow);
std::ignore = window;
},
[&](const FormatView& view) { // NOLINT(misc-no-recursion)
std::ignore = view;
auto parentID = parent(vertID, resg);
CC_EXPECTS(parentID != resg.null_vertex());
while (resg.isTextureView(parentID)) {
parentID = parent(parentID, resg);
}
CC_EXPECTS(parentID != resg.null_vertex());
CC_EXPECTS(resg.isTexture(parentID));
CC_ENSURES(!resg.isTextureView(parentID));
mount(device, parentID);
},
[&](SubresourceView& view) { // NOLINT(misc-no-recursion)
const auto [originView, parentID] = getOriginView(resg, vertID);
mount(device, parentID); // NOLINT(misc-no-recursion)
if (!isTextureEqual(view.textureView, desc)) {
recreateTextureView(device, *this, originView, parentID, view);
}
});
}
void ResourceGraph::unmount(uint64_t completedFenceValue) {
auto& resg = *this;
for (const auto& vertID : makeRange(vertices(resg))) {
// here msvc has strange behaviour when using visitObject
// we use if-else instead.
if (holds<ManagedBufferTag>(vertID, resg)) {
auto& buffer = get(ManagedBufferTag{}, vertID, resg);
if (buffer.buffer && buffer.fenceValue <= completedFenceValue) {
buffer.buffer.reset();
}
} else if (holds<ManagedTextureTag>(vertID, resg)) {
auto& texture = get(ManagedTextureTag{}, vertID, resg);
if (texture.texture && texture.fenceValue <= completedFenceValue) {
invalidatePersistentRenderPassAndFramebuffer(texture.texture.get());
texture.texture.reset();
const auto& traits = get(ResourceGraph::TraitsTag{}, resg, vertID);
if (traits.hasSideEffects()) {
auto& states = get(ResourceGraph::StatesTag{}, resg, vertID);
states.states = cc::gfx::AccessFlagBit::NONE;
}
}
}
}
}
bool ResourceGraph::isTexture(vertex_descriptor resID) const noexcept {
return visitObject(
resID, *this,
[&](const ManagedBuffer& res) {
std::ignore = res;
return false;
},
[&](const IntrusivePtr<gfx::Buffer>& res) {
std::ignore = res;
return false;
},
[&](const auto& res) {
std::ignore = res;
return true;
});
}
bool ResourceGraph::isTextureView(vertex_descriptor resID) const noexcept {
return visitObject(
resID, *this,
[&](const FormatView& view) {
std::ignore = view;
return true;
},
[&](const SubresourceView& view) {
std::ignore = view;
return true;
},
[&](const auto& res) {
std::ignore = res;
return false;
});
}
gfx::Buffer* ResourceGraph::getBuffer(vertex_descriptor resID) {
gfx::Buffer* buffer = nullptr;
visitObject(
resID, *this,
[&](const ManagedBuffer& res) {
buffer = res.buffer.get();
},
[&](const IntrusivePtr<gfx::Buffer>& buf) {
buffer = buf.get();
},
[&](const auto& buffer) {
std::ignore = buffer;
CC_EXPECTS(false);
});
CC_ENSURES(buffer);
return buffer;
}
gfx::Texture* ResourceGraph::getTexture(vertex_descriptor resID) {
gfx::Texture* texture = nullptr;
visitObject(
resID, *this,
[&](const ManagedTexture& res) {
texture = res.texture.get();
},
[&](const IntrusivePtr<gfx::Texture>& tex) {
texture = tex.get();
},
[&](const IntrusivePtr<gfx::Framebuffer>& fb) {
// deprecated
CC_EXPECTS(false);
CC_EXPECTS(fb->getColorTextures().size() == 1);
CC_EXPECTS(fb->getColorTextures().at(0));
texture = fb->getColorTextures()[0];
},
[&](const RenderSwapchain& sc) {
if (sc.swapchain) {
texture = sc.swapchain->getColorTexture();
} else {
CC_EXPECTS(sc.renderWindow);
const auto& fb = sc.renderWindow->getFramebuffer();
CC_EXPECTS(fb);
CC_EXPECTS(fb->getColorTextures().size() == 1);
CC_EXPECTS(fb->getColorTextures().at(0));
texture = fb->getColorTextures()[0];
}
},
[&](const FormatView& view) {
// TODO(zhouzhenglong): add ImageView support
std::ignore = view;
CC_EXPECTS(false);
},
[&](const SubresourceView& view) {
// TODO(zhouzhenglong): add ImageView support
texture = view.textureView;
},
[&](const auto& buffer) {
std::ignore = buffer;
CC_EXPECTS(false);
});
CC_ENSURES(texture);
return texture;
}
void ResourceGraph::invalidatePersistentRenderPassAndFramebuffer(gfx::Texture* pTexture) {
if (!pTexture) {
return;
}
for (auto iter = renderPasses.begin(); iter != renderPasses.end();) {
const auto& pass = iter->second;
bool bErase = false;
for (const auto& color : pass.framebuffer->getColorTextures()) {
if (color == pTexture) {
bErase = true;
break;
}
}
if (pass.framebuffer->getDepthStencilTexture() == pTexture) {
bErase = true;
}
if (bErase) {
iter = renderPasses.erase(iter);
} else {
++iter;
}
}
}
} // namespace render
} // namespace cc

View File

@@ -0,0 +1,816 @@
#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 <boost/align/align_up.hpp>
namespace cc {
namespace render {
const static uint32_t REFLECTION_PROBE_DEFAULT_MASK = ~static_cast<uint32_t>(pipeline::LayerList::UI_2D) & ~static_cast<uint32_t>(pipeline::LayerList::PROFILER) & ~static_cast<uint32_t>(pipeline::LayerList::UI_3D) & ~static_cast<uint32_t>(pipeline::LayerList::GIZMOS) & ~static_cast<uint32_t>(pipeline::LayerList::SCENE_GIZMO) & ~static_cast<uint32_t>(pipeline::LayerList::EDITOR);
void NativeRenderQueue::clear() noexcept {
probeQueue.clear();
opaqueQueue.instances.clear();
transparentQueue.instances.clear();
opaqueInstancingQueue.clear();
transparentInstancingQueue.clear();
sceneFlags = SceneFlags::NONE;
subpassOrPassLayoutID = 0xFFFFFFFF;
}
bool NativeRenderQueue::empty() const noexcept {
return opaqueQueue.instances.empty() &&
transparentQueue.instances.empty() &&
opaqueInstancingQueue.empty() &&
transparentInstancingQueue.empty();
}
FrustumCullingID SceneCulling::getOrCreateFrustumCulling(const SceneData& sceneData) {
const auto* const scene = sceneData.scene;
// get or add scene to queries
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 = FrustumCullingKey{
sceneData.camera,
sceneData.light.probe,
sceneData.light.light,
sceneData.light.level,
bCastShadow,
};
// find query source
auto iter = queries.resultIndex.find(key);
if (iter == queries.resultIndex.end()) {
// create query source
// make query source id
const FrustumCullingID frustomCulledResultID{numFrustumCulling++};
if (numFrustumCulling > frustumCullingResults.size()) {
// space is not enough, create query source
CC_EXPECTS(numFrustumCulling == frustumCullingResults.size() + 1);
frustumCullingResults.emplace_back();
}
// add query source to query index
bool added = false;
std::tie(iter, added) = queries.resultIndex.emplace(key, frustomCulledResultID);
CC_ENSURES(added);
}
return iter->second;
}
LightBoundsCullingID SceneCulling::getOrCreateLightBoundsCulling(
const SceneData& sceneData, FrustumCullingID frustumCullingID) {
if (!any(sceneData.cullingFlags & CullingFlags::LIGHT_BOUNDS)) {
return {};
}
if (sceneData.shadingLight->getType() == scene::LightType::DIRECTIONAL) {
return {};
}
if (!enableLightCulling) {
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()) {
CC_EXPECTS(numRenderQueues == renderQueues.size() + 1);
renderQueues.emplace_back();
}
CC_ENSURES(targetID < renderQueues.size());
auto& rq = renderQueues[targetID];
CC_EXPECTS(rq.empty());
CC_EXPECTS(rq.sceneFlags == SceneFlags::NONE);
CC_EXPECTS(rq.subpassOrPassLayoutID == 0xFFFFFFFF);
rq.sceneFlags = sceneFlags;
rq.subpassOrPassLayoutID = subpassOrPassLayoutID;
return NativeRenderQueueID{targetID};
}
void SceneCulling::collectCullingQueries(
const RenderGraph& rg, const LayoutGraphData& lg) {
for (const auto vertID : makeRange(vertices(rg))) {
if (!holds<SceneTag>(vertID, rg)) {
continue;
}
const auto& sceneData = get(SceneTag{}, vertID, rg);
if (!sceneData.scene) {
CC_EXPECTS(false);
continue;
}
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
? sceneData.light.light->getType()
: scene::LightType::UNKNOWN;
// add render queue to query source
renderQueueIndex.emplace(
vertID,
NativeRenderQueueDesc{
frustomCulledResultID,
lightBoundsCullingID,
targetID,
lightType,
});
}
}
namespace {
const pipeline::PipelineSceneData* kPipelineSceneData = nullptr;
const LayoutGraphData* kLayoutGraph = nullptr;
bool isNodeVisible(const Node* node, uint32_t visibility) {
return node && ((visibility & node->getLayer()) == node->getLayer());
}
uint32_t isModelVisible(const scene::Model& model, uint32_t visibility) {
return visibility & static_cast<uint32_t>(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<uint32_t>(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 false;
}
geometry::AABB transWorldBounds{};
transWorldBounds.set(modelWorldBounds->getCenter(), modelWorldBounds->getHalfExtents());
const scene::Shadows& shadows = *kPipelineSceneData->getShadows();
if (shadows.getType() == scene::ShadowType::PLANAR && castShadow) {
modelWorldBounds->transform(shadows.getMatLight(), &transWorldBounds);
}
return !transWorldBounds.aabbFrustum(frustum);
}
void octreeCulling(
const scene::Octree& octree,
const scene::Model* skyboxModel,
const scene::RenderScene& scene,
const scene::Camera& camera,
const geometry::Frustum& cameraOrLightFrustum,
bool bCastShadow,
ccstd::vector<const scene::Model*>& models) {
const auto visibility = camera.getVisibility();
const auto camSkyboxFlag = (static_cast<int32_t>(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() || !model.getNode() || model.getWorldBounds() || (bCastShadow && !model.isCastShadow())) {
continue;
}
// filter model by view visibility
if (isNodeVisible(model.getNode(), visibility) || isModelVisible(model, visibility)) {
models.emplace_back(&model);
}
}
// add instances with world bounds
octree.queryVisibility(&camera, cameraOrLightFrustum, bCastShadow, models);
// TODO(zhouzhenglong): move lod culling into octree query
auto iter = std::remove_if(
models.begin(), models.end(),
[&](const scene::Model* model) {
return scene.isCulledByLod(&camera, model);
});
models.erase(iter, models.end());
}
void bruteForceCulling(
const scene::Model* skyboxModel,
const scene::RenderScene& scene,
const scene::Camera& camera,
const geometry::Frustum& cameraOrLightFrustum,
bool bCastShadow,
const scene::ReflectionProbe* probe,
ccstd::vector<const scene::Model*>& models) {
const auto visibility = camera.getVisibility();
const auto camSkyboxFlag = (static_cast<int32_t>(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() || !model.getNode() || (bCastShadow && !model.isCastShadow())) {
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* skyboxModel,
const scene::RenderScene& scene,
const scene::Camera& camera,
const geometry::Frustum& cameraOrLightFrustum,
bool bCastShadow,
const scene::ReflectionProbe* probe,
ccstd::vector<const scene::Model*>& models) {
const auto* const octree = scene.getOctree();
if (octree && octree->isEnabled() && !probe) {
octreeCulling(
*octree, skyboxModel,
scene, camera, cameraOrLightFrustum, bCastShadow, models);
} else {
bruteForceCulling(
skyboxModel,
scene, camera, cameraOrLightFrustum, bCastShadow, probe, models);
}
}
} // namespace
void SceneCulling::batchFrustumCulling(const NativePipeline& ppl) {
const auto& pplSceneData = *ppl.getPipelineSceneData();
const auto* const skybox = pplSceneData.getSkybox();
const auto* const skyboxModel = skybox && skybox->isEnabled() ? skybox->getModel() : nullptr;
for (const auto& [scene, queries] : frustumCullings) {
CC_ENSURES(scene);
for (const auto& [key, frustomCulledResultID] : queries.resultIndex) {
CC_EXPECTS(key.camera);
CC_EXPECTS(key.camera->getScene() == scene);
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];
if (probe) {
sceneCulling(
skyboxModel,
*scene, camera,
camera.getFrustum(),
bCastShadow,
probe,
models);
continue;
}
if (light) {
switch (light->getType()) {
case scene::LightType::SPOT:
sceneCulling(
skyboxModel,
*scene, camera,
dynamic_cast<const scene::SpotLight*>(light)->getFrustum(),
bCastShadow,
nullptr,
models);
break;
case scene::LightType::DIRECTIONAL: {
const auto* mainLight = dynamic_cast<const scene::DirectionalLight*>(light);
const auto& frustum = getBuiltinShadowFrustum(ppl, camera, mainLight, level);
sceneCulling(
skyboxModel,
*scene, camera,
frustum,
bCastShadow,
nullptr,
models);
} break;
default:
// noop
break;
}
} else {
sceneCulling(
skyboxModel,
*scene, camera,
camera.getFrustum(),
bCastShadow,
nullptr,
models);
}
}
}
}
namespace {
void executeSphereLightCulling(
const scene::SphereLight& light,
const ccstd::vector<const scene::Model*>& frustumCullingResult,
ccstd::vector<const scene::Model*>& 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<const scene::Model*>& frustumCullingResult,
ccstd::vector<const scene::Model*>& 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<const scene::Model*>& frustumCullingResult,
ccstd::vector<const scene::Model*>& 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<const scene::Model*>& frustumCullingResult,
ccstd::vector<const scene::Model*>& 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<const scene::SphereLight*>(key.cullingLight);
CC_ENSURES(light);
executeSphereLightCulling(*light, frustumCullingResult, lightBoundsCullingResult.instances);
} break;
case scene::LightType::SPOT: {
const auto* light = dynamic_cast<const scene::SpotLight*>(key.cullingLight);
CC_ENSURES(light);
executeSpotLightCulling(*light, frustumCullingResult, lightBoundsCullingResult.instances);
} break;
case scene::LightType::POINT: {
const auto* light = dynamic_cast<const scene::PointLight*>(key.cullingLight);
CC_ENSURES(light);
executePointLightCulling(*light, frustumCullingResult, lightBoundsCullingResult.instances);
} break;
case scene::LightType::RANGED_DIRECTIONAL: {
const auto* light = dynamic_cast<const scene::RangedDirectionalLight*>(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) {
if (target.blend) {
bBlend = true;
}
}
return bBlend;
}
float computeSortingDepth(const scene::Camera& camera, const scene::Model& model) {
float depth = 0;
if (model.getNode()) {
const auto* node = model.getTransform();
Vec3 position;
const auto* bounds = model.getWorldBounds();
Vec3::subtract(bounds ? bounds->center : node->getWorldPosition(), camera.getPosition(), &position);
depth = position.dot(camera.getForward());
}
return depth;
}
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
const bool bRenderPhaseAllowed = phaseLayoutID == pass.getPhaseID();
if (!bRenderPhaseAllowed) {
continue;
}
// check scene flags
const bool bBlend = isBlend(pass);
const bool bOpaqueOrMask = !bBlend;
if (!bDrawBlend && bBlend) {
// skip transparent object
continue;
}
if (!bDrawOpaqueOrMask && bOpaqueOrMask) {
// skip opaque object
continue;
}
// add object to queue
if (pass.getBatchingScheme() == scene::BatchingSchemes::INSTANCING) {
if (bBlend) {
queue.transparentInstancingQueue.add(pass, *subModel, passIdx);
} else {
queue.opaqueInstancingQueue.add(pass, *subModel, passIdx);
}
} else {
// TODO(zhouzhenglong): change camera to frustum
const float depth = computeSortingDepth(camera, model);
if (bBlend) {
queue.transparentQueue.add(model, depth, subModelIdx, passIdx);
} else {
queue.opaqueQueue.add(model, depth, subModelIdx, passIdx);
}
}
}
}
}
} // namespace
void SceneCulling::fillRenderQueues(
const RenderGraph& rg, const pipeline::PipelineSceneData& pplSceneData) {
const auto* const skybox = pplSceneData.getSkybox();
for (auto&& [sceneID, desc] : renderQueueIndex) {
CC_EXPECTS(holds<SceneTag>(sceneID, rg));
const auto frustomCulledResultID = desc.frustumCulledResultID;
const auto lightBoundsCullingID = desc.lightBoundsCulledResultID;
const auto targetID = desc.renderQueueTarget;
const auto& sceneData = get(SceneTag{}, sceneID, rg);
// check scene flags
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);
const bool bDrawProbe = any(sceneData.flags & SceneFlags::REFLECTION_PROBE);
if (!bDrawShadowCaster && !bDrawBlend && !bDrawOpaqueOrMask && !bDrawProbe) {
// nothing to draw
continue;
}
// render queue info
const auto renderQueueID = parent(sceneID, rg);
CC_EXPECTS(holds<QueueTag>(renderQueueID, rg));
const auto& renderQueue = get(QueueTag{}, renderQueueID, rg);
const auto phaseLayoutID = renderQueue.phaseID;
CC_EXPECTS(phaseLayoutID != LayoutGraphData::null_vertex());
// culling source
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.value < renderQueues.size());
auto& nativeQueue = renderQueues[targetID.value];
CC_EXPECTS(nativeQueue.empty());
// skybox
const auto* camera = sceneData.camera;
CC_EXPECTS(camera);
// fill native queue
for (const auto* const model : sourceModels) {
addRenderObject(
phaseLayoutID, bDrawOpaqueOrMask, bDrawBlend,
bDrawProbe, *sceneData.camera, *model, nativeQueue);
}
// post-processing
nativeQueue.sort();
}
}
void SceneCulling::buildRenderQueues(
const RenderGraph& rg, const LayoutGraphData& lg,
const NativePipeline& ppl) {
kPipelineSceneData = ppl.pipelineSceneData;
kLayoutGraph = &lg;
collectCullingQueries(rg, lg);
batchFrustumCulling(ppl);
batchLightBoundsCulling(); // cull frustum-culling's results by light bounds
fillRenderQueues(rg, *ppl.pipelineSceneData);
}
void SceneCulling::clear() noexcept {
// 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();
}
// 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<uint32_t>(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<uint32_t>(lights.size()) * elementSize);
}
void LightResource::tryUpdateRenderSceneLocalDescriptorSet(const SceneCulling& sceneCulling) {
if (sceneCulling.lightBoundsCullingResults.empty()) {
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();
const auto& prev = set->getBuffer(binding);
if (resized || prev != firstLightBufferView) {
set->bindBuffer(binding, firstLightBufferView);
set->update();
}
}
}
}
resized = false;
}
} // namespace render
} // namespace cc

View File

@@ -0,0 +1,335 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "cocos/renderer/pipeline/custom/NativeBuiltinUtils.h"
#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"
namespace cc {
namespace render {
void NativeSetter::setMat4(const ccstd::string &name, const Mat4 &mat) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setMat4Impl(data, *layoutGraph, name, mat);
}
void NativeSetter::setQuaternion(const ccstd::string &name, const Quaternion &quat) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setQuaternionImpl(data, *layoutGraph, name, quat);
}
void NativeSetter::setColor(const ccstd::string &name, const gfx::Color &color) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setColorImpl(data, *layoutGraph, name, color);
}
void NativeSetter::setVec4(const ccstd::string &name, const Vec4 &vec) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setVec4Impl(data, *layoutGraph, name, vec);
}
void NativeSetter::setVec2(const ccstd::string &name, const Vec2 &vec) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setVec2Impl(data, *layoutGraph, name, vec);
}
void NativeSetter::setFloat(const ccstd::string &name, float v) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setFloatImpl(data, *layoutGraph, name, v);
}
void NativeSetter::setArrayBuffer(const ccstd::string &name, const ArrayBuffer *buffer) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setArrayBufferImpl(data, *layoutGraph, name, *buffer);
}
void NativeSetter::setBuffer(const ccstd::string &name, gfx::Buffer *buffer) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setBufferImpl(data, *layoutGraph, name, buffer);
}
void NativeSetter::setTexture(const ccstd::string &name, gfx::Texture *texture) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setTextureImpl(data, *layoutGraph, name, texture);
}
void NativeSetter::setReadWriteBuffer(const ccstd::string &name, gfx::Buffer *buffer) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setReadWriteBufferImpl(data, *layoutGraph, name, buffer);
}
void NativeSetter::setReadWriteTexture(const ccstd::string &name, gfx::Texture *texture) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setReadWriteTextureImpl(data, *layoutGraph, name, texture);
}
void NativeSetter::setSampler(const ccstd::string &name, gfx::Sampler *sampler) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setSamplerImpl(data, *layoutGraph, name, sampler);
}
void NativeSetter::setVec4ArraySize(const ccstd::string &name, uint32_t sz) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setVec4ArraySizeImpl(data, *layoutGraph, name, sz);
}
void NativeSetter::setVec4ArrayElem(const ccstd::string &name, const cc::Vec4 &vec, uint32_t id) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setVec4ArrayElemImpl(data, *layoutGraph, name, vec, id);
}
void NativeSetter::setMat4ArraySize(const ccstd::string &name, uint32_t sz) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setMat4ArraySizeImpl(data, *layoutGraph, name, sz);
}
void NativeSetter::setMat4ArrayElem(const ccstd::string &name, const cc::Mat4 &mat, uint32_t id) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setMat4ArrayElemImpl(data, *layoutGraph, name, mat, id);
}
void NativeSetter::setBuiltinCameraConstants(const scene::Camera *camera) {
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
setCameraUBOValues(
*camera,
*layoutGraph,
*pipelineRuntime->getPipelineSceneData(),
camera->getScene()->getMainLight(), data);
}
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, csm, *light, level, data);
}
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, nullptr, *light, 0, data);
}
void NativeSetter::setBuiltinShadowMapConstants(
const scene::DirectionalLight *light) {
CC_EXPECTS(light);
auto *device = pipelineRuntime->getDevice();
const auto &sceneData = *pipelineRuntime->getPipelineSceneData();
auto &data = get(RenderGraph::DataTag{}, *renderGraph, nodeID);
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) {
std::ignore = camera;
setBuiltinShadowMapConstants(light);
}
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<float>(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<float>(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<float>(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<float>(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
} // namespace cc

View File

@@ -0,0 +1,77 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#include "NativeTypes.h"
namespace cc {
namespace render {
ProgramInfo::ProgramInfo(const allocator_type& alloc) noexcept
: attributes(alloc) {}
ProgramInfo::ProgramInfo(IProgramInfo programInfoIn, gfx::ShaderInfo shaderInfoIn, ccstd::pmr::vector<gfx::Attribute> attributesIn, ccstd::vector<signed> blockSizesIn, ccstd::unordered_map<ccstd::string, uint32_t> handleMapIn, const allocator_type& alloc) noexcept
: programInfo(std::move(programInfoIn)),
shaderInfo(std::move(shaderInfoIn)),
attributes(std::move(attributesIn), alloc),
blockSizes(std::move(blockSizesIn)),
handleMap(std::move(handleMapIn)) {}
ProgramInfo::ProgramInfo(ProgramInfo&& rhs, const allocator_type& alloc)
: programInfo(std::move(rhs.programInfo)),
shaderInfo(std::move(rhs.shaderInfo)),
attributes(std::move(rhs.attributes), alloc),
blockSizes(std::move(rhs.blockSizes)),
handleMap(std::move(rhs.handleMap)) {}
ProgramInfo::ProgramInfo(ProgramInfo const& rhs, const allocator_type& alloc)
: programInfo(rhs.programInfo),
shaderInfo(rhs.shaderInfo),
attributes(rhs.attributes, alloc),
blockSizes(rhs.blockSizes),
handleMap(rhs.handleMap) {}
ProgramGroup::ProgramGroup(const allocator_type& alloc) noexcept
: programInfos(alloc),
programProxies(alloc) {}
ProgramGroup::ProgramGroup(ProgramGroup&& rhs, const allocator_type& alloc)
: programInfos(std::move(rhs.programInfos), alloc),
programProxies(std::move(rhs.programProxies), alloc) {}
ProgramGroup::ProgramGroup(ProgramGroup const& rhs, const allocator_type& alloc)
: programInfos(rhs.programInfos, alloc),
programProxies(rhs.programProxies, alloc) {}
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,91 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include "cocos/base/std/container/string.h"
#include "cocos/base/std/hash/hash.h"
#include "cocos/renderer/gfx-base/GFXRenderPass.h"
#include "cocos/renderer/pipeline/GlobalDescriptorSetManager.h"
#include "cocos/renderer/pipeline/custom/LayoutGraphTypes.h"
#include "cocos/renderer/pipeline/custom/NativeFwd.h"
#include "cocos/renderer/pipeline/custom/PrivateTypes.h"
#include "cocos/renderer/pipeline/custom/details/Map.h"
namespace cc {
namespace render {
struct ProgramInfo {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {attributes.get_allocator().resource()};
}
ProgramInfo(const allocator_type& alloc) noexcept; // NOLINT
ProgramInfo(IProgramInfo programInfoIn, gfx::ShaderInfo shaderInfoIn, ccstd::pmr::vector<gfx::Attribute> attributesIn, ccstd::vector<signed> blockSizesIn, ccstd::unordered_map<ccstd::string, uint32_t> handleMapIn, const allocator_type& alloc) noexcept;
ProgramInfo(ProgramInfo&& rhs, const allocator_type& alloc);
ProgramInfo(ProgramInfo const& rhs, const allocator_type& alloc);
ProgramInfo(ProgramInfo&& rhs) noexcept = default;
ProgramInfo(ProgramInfo const& rhs) = delete;
ProgramInfo& operator=(ProgramInfo&& rhs) = default;
ProgramInfo& operator=(ProgramInfo const& rhs) = default;
IProgramInfo programInfo;
gfx::ShaderInfo shaderInfo;
ccstd::pmr::vector<gfx::Attribute> attributes;
ccstd::vector<signed> blockSizes;
ccstd::unordered_map<ccstd::string, uint32_t> handleMap;
};
struct ProgramGroup {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {programInfos.get_allocator().resource()};
}
ProgramGroup(const allocator_type& alloc) noexcept; // NOLINT
ProgramGroup(ProgramGroup&& rhs, const allocator_type& alloc);
ProgramGroup(ProgramGroup const& rhs, const allocator_type& alloc);
ProgramGroup(ProgramGroup&& rhs) noexcept = default;
ProgramGroup(ProgramGroup const& rhs) = delete;
ProgramGroup& operator=(ProgramGroup&& rhs) = default;
ProgramGroup& operator=(ProgramGroup const& rhs) = default;
PmrTransparentMap<ccstd::pmr::string, ProgramInfo> programInfos;
PmrFlatMap<ccstd::pmr::string, IntrusivePtr<ProgramProxy>> programProxies;
};
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,168 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "cocos/renderer/pipeline/custom/NativeUtils.h"
#include "cocos/renderer/pipeline/custom/LayoutGraphGraphs.h"
#include "cocos/renderer/pipeline/custom/NativePipelineTypes.h"
#include "cocos/renderer/pipeline/custom/RenderGraphGraphs.h"
#include "cocos/renderer/pipeline/custom/details/GslUtils.h"
namespace cc {
namespace render {
namespace {
render::NameLocalID getNameID(
const PmrFlatMap<ccstd::pmr::string, render::NameLocalID> &index,
std::string_view name) {
auto iter = index.find(name);
CC_EXPECTS(iter != index.end());
return iter->second;
}
} // namespace
void setMat4Impl(
RenderData &data, const LayoutGraphData &lg, std::string_view name,
const cc::Mat4 &v) {
auto nameID = getNameID(lg.constantIndex, name);
static_assert(sizeof(Mat4) == 16 * 4, "sizeof(Mat4) is not 64 bytes");
data.constants[nameID.value].resize(sizeof(Mat4));
memcpy(data.constants[nameID.value].data(), v.m, sizeof(v));
}
void setMat4ArrayElemImpl(
RenderData &data, const LayoutGraphData &lg, std::string_view name,
const cc::Mat4 &v, uint32_t i) {
auto nameID = getNameID(lg.constantIndex, name);
static_assert(sizeof(Mat4) == 16 * 4, "sizeof(Mat4) is not 64 bytes");
auto &dst = data.constants[nameID.value];
CC_EXPECTS(sizeof(Mat4) * (i + 1) <= dst.size());
memcpy(dst.data() + sizeof(Mat4) * i, v.m, sizeof(v));
}
void setMat4ArraySizeImpl(
RenderData &data, const LayoutGraphData &lg, std::string_view name,
uint32_t sz) {
CC_EXPECTS(sz);
auto nameID = getNameID(lg.constantIndex, name);
static_assert(sizeof(Mat4) == 16 * 4, "sizeof(Mat4) is not 64 bytes");
data.constants[nameID.value].resize(sizeof(Mat4) * sz);
}
void setQuaternionImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, const Quaternion &quat) {
auto nameID = getNameID(lg.constantIndex, name);
static_assert(sizeof(Quaternion) == 4 * 4, "sizeof(Quaternion) is not 16 bytes");
static_assert(std::is_trivially_copyable<Quaternion>::value, "Quaternion is not trivially copyable");
data.constants[nameID.value].resize(sizeof(Quaternion));
memcpy(data.constants[nameID.value].data(), &quat, sizeof(quat));
}
void setColorImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, const gfx::Color &color) {
auto nameID = getNameID(lg.constantIndex, name);
static_assert(sizeof(gfx::Color) == 4 * 4, "sizeof(Color) is not 16 bytes");
static_assert(std::is_trivially_copyable<gfx::Color>::value, "Color is not trivially copyable");
data.constants[nameID.value].resize(sizeof(gfx::Color));
memcpy(data.constants[nameID.value].data(), &color, sizeof(color));
}
void setVec4Impl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, const Vec4 &vec) {
auto nameID = getNameID(lg.constantIndex, name);
static_assert(sizeof(Vec4) == 4 * 4, "sizeof(Vec4) is not 16 bytes");
// static_assert(std::is_trivially_copyable<Vec4>::value, "Vec4 is not trivially copyable");
data.constants[nameID.value].resize(sizeof(Vec4));
memcpy(data.constants[nameID.value].data(), &vec.x, sizeof(vec));
}
void setVec4ArrayElemImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name,
const Vec4 &vec, uint32_t i) {
auto nameID = getNameID(lg.constantIndex, name);
static_assert(sizeof(Vec4) == 4 * 4, "sizeof(Vec4) is not 16 bytes");
// static_assert(std::is_trivially_copyable<Vec4>::value, "Vec4 is not trivially copyable");
auto &dst = data.constants[nameID.value];
CC_EXPECTS(sizeof(Vec4) * (i + 1) <= dst.size());
memcpy(dst.data() + sizeof(Vec4) * i, &vec.x, sizeof(vec));
}
void setVec4ArraySizeImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name,
uint32_t sz) {
CC_EXPECTS(sz);
auto nameID = getNameID(lg.constantIndex, name);
static_assert(sizeof(Vec4) == 4 * 4, "sizeof(Vec4) is not 16 bytes");
// static_assert(std::is_trivially_copyable<Vec4>::value, "Vec4 is not trivially copyable");
data.constants[nameID.value].resize(sizeof(Vec4) * sz);
}
void setVec2Impl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, const Vec2 &vec) {
auto nameID = getNameID(lg.constantIndex, name);
static_assert(sizeof(Vec2) == 2 * 4, "sizeof(Vec2) is not 8 bytes");
// static_assert(std::is_trivially_copyable<Vec4>::value, "Vec2 is not trivially copyable");
data.constants[nameID.value].resize(sizeof(Vec2));
memcpy(data.constants[nameID.value].data(), &vec.x, sizeof(vec));
}
void setFloatImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, float v) {
auto nameID = getNameID(lg.constantIndex, name);
static_assert(sizeof(float) == 4, "sizeof(float) is not 4 bytes");
data.constants[nameID.value].resize(sizeof(float));
memcpy(data.constants[nameID.value].data(), &v, sizeof(v));
}
void setArrayBufferImpl(
RenderData &data, const LayoutGraphData &lg, std::string_view name,
const ArrayBuffer &buffer) {
auto nameID = getNameID(lg.constantIndex, name);
data.constants[nameID.value].resize(buffer.byteLength());
memcpy(data.constants[nameID.value].data(), buffer.getData(), buffer.byteLength());
}
void setBufferImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, gfx::Buffer *buffer) {
auto nameID = getNameID(lg.attributeIndex, name);
data.buffers[nameID.value] = IntrusivePtr<gfx::Buffer>(buffer);
}
void setTextureImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, gfx::Texture *texture) {
auto nameID = getNameID(lg.attributeIndex, name);
data.textures[nameID.value] = IntrusivePtr<gfx::Texture>(texture);
}
void setReadWriteBufferImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, gfx::Buffer *buffer) {
auto nameID = getNameID(lg.attributeIndex, name);
data.buffers[nameID.value] = IntrusivePtr<gfx::Buffer>(buffer);
}
void setReadWriteTextureImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, gfx::Texture *texture) {
auto nameID = getNameID(lg.attributeIndex, name);
data.textures[nameID.value] = IntrusivePtr<gfx::Texture>(texture);
}
void setSamplerImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, gfx::Sampler *sampler) {
auto nameID = getNameID(lg.attributeIndex, name);
data.samplers[nameID.value] = sampler;
}
} // namespace render
} // namespace cc

View File

@@ -0,0 +1,87 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#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"
namespace cc {
namespace render {
void setMat4Impl(
RenderData &data, const LayoutGraphData &lg, std::string_view name,
const cc::Mat4 &v);
void setMat4ArrayElemImpl(
RenderData &data, const LayoutGraphData &lg, std::string_view name,
const cc::Mat4 &v, uint32_t i);
void setMat4ArraySizeImpl(
RenderData &data, const LayoutGraphData &lg, std::string_view name,
uint32_t sz);
void setQuaternionImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, const Quaternion &quat);
void setColorImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, const gfx::Color &color);
void setVec4Impl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, const Vec4 &vec);
void setVec4ArrayElemImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name,
const Vec4 &vec, uint32_t i);
void setVec4ArraySizeImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name,
uint32_t sz);
void setVec2Impl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, const Vec2 &vec);
void setFloatImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, float v);
void setArrayBufferImpl(
RenderData &data, const LayoutGraphData &lg, std::string_view name,
const ArrayBuffer &buffer);
void setBufferImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, gfx::Buffer *buffer);
void setTextureImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, gfx::Texture *texture);
void setReadWriteBufferImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, gfx::Buffer *buffer);
void setReadWriteTextureImpl(RenderData &data, const LayoutGraphData &lg, const ccstd::string &name, gfx::Texture *texture);
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

View File

@@ -0,0 +1,46 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include "cocos/base/std/variant.h"
#include "cocos/renderer/pipeline/custom/RenderInterfaceFwd.h"
namespace cc {
namespace render {
class ProgramProxy;
class ProgramLibrary;
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,41 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#include "PrivateTypes.h"
namespace cc {
namespace render {
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,90 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include "cocos/renderer/core/ProgramLib.h"
#include "cocos/renderer/pipeline/custom/PrivateFwd.h"
#include "cocos/renderer/pipeline/custom/RenderInterfaceTypes.h"
namespace cc {
namespace render {
class ProgramProxy : public RefCounted {
public:
ProgramProxy() = default;
ProgramProxy(ProgramProxy&& rhs) = delete;
ProgramProxy(ProgramProxy const& rhs) = delete;
ProgramProxy& operator=(ProgramProxy&& rhs) = delete;
ProgramProxy& operator=(ProgramProxy const& rhs) = delete;
~ProgramProxy() noexcept override = default;
virtual const ccstd::string &getName() const noexcept = 0;
virtual gfx::Shader *getShader() const noexcept = 0;
};
class ProgramLibrary {
public:
ProgramLibrary() noexcept = default;
ProgramLibrary(ProgramLibrary&& rhs) = delete;
ProgramLibrary(ProgramLibrary const& rhs) = delete;
ProgramLibrary& operator=(ProgramLibrary&& rhs) = delete;
ProgramLibrary& operator=(ProgramLibrary const& rhs) = delete;
virtual ~ProgramLibrary() noexcept = default;
virtual void addEffect(const EffectAsset *effectAsset) = 0;
virtual void precompileEffect(gfx::Device *device, EffectAsset *effectAsset) = 0;
virtual ccstd::string getKey(uint32_t phaseID, const ccstd::string &programName, const MacroRecord &defines) const = 0;
virtual IntrusivePtr<gfx::PipelineLayout> getPipelineLayout(gfx::Device *device, uint32_t phaseID, const ccstd::string &programName) = 0;
virtual const gfx::DescriptorSetLayout &getMaterialDescriptorSetLayout(gfx::Device *device, uint32_t phaseID, const ccstd::string &programName) = 0;
virtual const gfx::DescriptorSetLayout &getLocalDescriptorSetLayout(gfx::Device *device, uint32_t phaseID, const ccstd::string &programName) = 0;
virtual const IProgramInfo &getProgramInfo(uint32_t phaseID, const ccstd::string &programName) const = 0;
virtual const gfx::ShaderInfo &getShaderInfo(uint32_t phaseID, const ccstd::string &programName) const = 0;
virtual ProgramProxy *getProgramVariant(gfx::Device *device, uint32_t phaseID, const ccstd::string &name, MacroRecord &defines, const ccstd::pmr::string *key) = 0;
virtual gfx::PipelineState *getComputePipelineState(gfx::Device *device, uint32_t phaseID, const ccstd::string &name, MacroRecord &defines, const ccstd::pmr::string *key) = 0;
virtual const ccstd::vector<int> &getBlockSizes(uint32_t phaseID, const ccstd::string &programName) const = 0;
virtual const ccstd::unordered_map<ccstd::string, uint32_t> &getHandleMap(uint32_t phaseID, const ccstd::string &programName) const = 0;
virtual uint32_t getProgramID(uint32_t phaseID, const ccstd::pmr::string &programName) = 0;
virtual uint32_t getDescriptorNameID(const ccstd::pmr::string &name) = 0;
virtual const ccstd::pmr::string &getDescriptorName(uint32_t nameID) = 0;
ProgramProxy *getProgramVariant(gfx::Device *device, uint32_t phaseID, const ccstd::string &name, MacroRecord &defines) {
return getProgramVariant(device, phaseID, name, defines, nullptr);
}
gfx::PipelineState *getComputePipelineState(gfx::Device *device, uint32_t phaseID, const ccstd::string &name, MacroRecord &defines) {
return getComputePipelineState(device, phaseID, name, defines, nullptr);
}
};
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,96 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include "cocos/base/std/hash/hash.h"
#include "cocos/base/std/variant.h"
namespace cc {
namespace render {
enum class UpdateFrequency;
enum class ParameterType;
struct RasterPassTag;
struct RasterSubpassTag;
struct ComputeSubpassTag;
struct ComputeTag;
struct ResolveTag;
struct CopyTag;
struct MoveTag;
struct RaytraceTag;
enum class ResourceResidency;
enum class QueueHint;
enum class ResourceDimension;
enum class ResourceFlags : uint32_t;
struct BufferTag;
struct TextureTag;
enum class TaskType;
enum class SceneFlags : uint32_t;
enum class LightingMode : uint32_t;
enum class AttachmentType;
enum class AccessType;
enum class ClearValueType;
struct LightInfo;
enum class DescriptorTypeOrder;
struct Descriptor;
struct DescriptorBlock;
struct DescriptorBlockFlattened;
struct DescriptorBlockIndex;
enum class ResolveFlags : uint32_t;
struct ResolvePair;
struct CopyPair;
struct UploadPair;
struct MovePair;
struct PipelineStatistics;
} // namespace render
} // namespace cc
namespace ccstd {
template <>
struct hash<cc::render::ResolvePair> {
hash_t operator()(const cc::render::ResolvePair& val) const noexcept;
};
} // namespace ccstd
// clang-format on

View File

@@ -0,0 +1,496 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#include "cocos/bindings/auto/jsb_gfx_auto.h"
#include "cocos/bindings/auto/jsb_scene_auto.h"
#include "cocos/renderer/pipeline/custom/RenderCommonJsb.h"
#include "cocos/renderer/pipeline/custom/RenderCommonTypes.h"
#include "cocos/renderer/pipeline/custom/details/JsbConversion.h"
bool nativevalue_to_se(const cc::render::LightInfo &from, se::Value &to, se::Object *ctx) { // NOLINT
se::HandleObject obj(se::Object::createPlainObject());
se::Value tmp;
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);
nativevalue_to_se(from.culledByLight, tmp, ctx);
obj->setProperty("culledByLight", tmp);
to.setObject(obj);
return true;
}
bool nativevalue_to_se(const cc::render::Descriptor &from, se::Value &to, se::Object *ctx) { // NOLINT
se::HandleObject obj(se::Object::createPlainObject());
se::Value tmp;
nativevalue_to_se(from.type, tmp, ctx);
obj->setProperty("type", tmp);
nativevalue_to_se(from.count, tmp, ctx);
obj->setProperty("count", tmp);
to.setObject(obj);
return true;
}
bool nativevalue_to_se(const cc::render::DescriptorBlockFlattened &from, se::Value &to, se::Object *ctx) { // NOLINT
se::HandleObject obj(se::Object::createPlainObject());
se::Value tmp;
nativevalue_to_se(from.descriptorNames, tmp, ctx);
obj->setProperty("descriptorNames", tmp);
nativevalue_to_se(from.uniformBlockNames, tmp, ctx);
obj->setProperty("uniformBlockNames", tmp);
nativevalue_to_se(from.descriptors, tmp, ctx);
obj->setProperty("descriptors", tmp);
nativevalue_to_se(from.uniformBlocks, tmp, ctx);
obj->setProperty("uniformBlocks", tmp);
nativevalue_to_se(from.capacity, tmp, ctx);
obj->setProperty("capacity", tmp);
nativevalue_to_se(from.count, tmp, ctx);
obj->setProperty("count", tmp);
to.setObject(obj);
return true;
}
bool nativevalue_to_se(const cc::render::DescriptorBlockIndex &from, se::Value &to, se::Object *ctx) { // NOLINT
se::HandleObject obj(se::Object::createPlainObject());
se::Value tmp;
nativevalue_to_se(from.updateFrequency, tmp, ctx);
obj->setProperty("updateFrequency", tmp);
nativevalue_to_se(from.parameterType, tmp, ctx);
obj->setProperty("parameterType", tmp);
nativevalue_to_se(from.descriptorType, tmp, ctx);
obj->setProperty("descriptorType", tmp);
nativevalue_to_se(from.visibility, tmp, ctx);
obj->setProperty("visibility", tmp);
to.setObject(obj);
return true;
}
bool nativevalue_to_se(const cc::render::ResolvePair &from, se::Value &to, se::Object *ctx) { // NOLINT
se::HandleObject obj(se::Object::createPlainObject());
se::Value tmp;
nativevalue_to_se(from.source, tmp, ctx);
obj->setProperty("source", tmp);
nativevalue_to_se(from.target, tmp, ctx);
obj->setProperty("target", tmp);
nativevalue_to_se(from.resolveFlags, tmp, ctx);
obj->setProperty("resolveFlags", tmp);
nativevalue_to_se(from.mode, tmp, ctx);
obj->setProperty("mode", tmp);
nativevalue_to_se(from.mode1, tmp, ctx);
obj->setProperty("mode1", tmp);
to.setObject(obj);
return true;
}
bool nativevalue_to_se(const cc::render::CopyPair &from, se::Value &to, se::Object *ctx) { // NOLINT
se::HandleObject obj(se::Object::createPlainObject());
se::Value tmp;
nativevalue_to_se(from.source, tmp, ctx);
obj->setProperty("source", tmp);
nativevalue_to_se(from.target, tmp, ctx);
obj->setProperty("target", tmp);
nativevalue_to_se(from.mipLevels, tmp, ctx);
obj->setProperty("mipLevels", tmp);
nativevalue_to_se(from.numSlices, tmp, ctx);
obj->setProperty("numSlices", tmp);
nativevalue_to_se(from.sourceMostDetailedMip, tmp, ctx);
obj->setProperty("sourceMostDetailedMip", tmp);
nativevalue_to_se(from.sourceFirstSlice, tmp, ctx);
obj->setProperty("sourceFirstSlice", tmp);
nativevalue_to_se(from.sourcePlaneSlice, tmp, ctx);
obj->setProperty("sourcePlaneSlice", tmp);
nativevalue_to_se(from.targetMostDetailedMip, tmp, ctx);
obj->setProperty("targetMostDetailedMip", tmp);
nativevalue_to_se(from.targetFirstSlice, tmp, ctx);
obj->setProperty("targetFirstSlice", tmp);
nativevalue_to_se(from.targetPlaneSlice, tmp, ctx);
obj->setProperty("targetPlaneSlice", tmp);
to.setObject(obj);
return true;
}
bool nativevalue_to_se(const cc::render::UploadPair &from, se::Value &to, se::Object *ctx) { // NOLINT
se::HandleObject obj(se::Object::createPlainObject());
se::Value tmp;
nativevalue_to_se(from.source, tmp, ctx);
obj->setProperty("source", tmp);
nativevalue_to_se(from.target, tmp, ctx);
obj->setProperty("target", tmp);
nativevalue_to_se(from.mipLevels, tmp, ctx);
obj->setProperty("mipLevels", tmp);
nativevalue_to_se(from.numSlices, tmp, ctx);
obj->setProperty("numSlices", tmp);
nativevalue_to_se(from.targetMostDetailedMip, tmp, ctx);
obj->setProperty("targetMostDetailedMip", tmp);
nativevalue_to_se(from.targetFirstSlice, tmp, ctx);
obj->setProperty("targetFirstSlice", tmp);
nativevalue_to_se(from.targetPlaneSlice, tmp, ctx);
obj->setProperty("targetPlaneSlice", tmp);
to.setObject(obj);
return true;
}
bool nativevalue_to_se(const cc::render::MovePair &from, se::Value &to, se::Object *ctx) { // NOLINT
se::HandleObject obj(se::Object::createPlainObject());
se::Value tmp;
nativevalue_to_se(from.source, tmp, ctx);
obj->setProperty("source", tmp);
nativevalue_to_se(from.target, tmp, ctx);
obj->setProperty("target", tmp);
nativevalue_to_se(from.mipLevels, tmp, ctx);
obj->setProperty("mipLevels", tmp);
nativevalue_to_se(from.numSlices, tmp, ctx);
obj->setProperty("numSlices", tmp);
nativevalue_to_se(from.targetMostDetailedMip, tmp, ctx);
obj->setProperty("targetMostDetailedMip", tmp);
nativevalue_to_se(from.targetFirstSlice, tmp, ctx);
obj->setProperty("targetFirstSlice", tmp);
nativevalue_to_se(from.targetPlaneSlice, tmp, ctx);
obj->setProperty("targetPlaneSlice", tmp);
to.setObject(obj);
return true;
}
template <>
bool sevalue_to_native<cc::render::LightInfo>(const se::Value &from, cc::render::LightInfo *to, se::Object *ctx) { // NOLINT
SE_PRECONDITION2(from.isObject(), false, " Convert parameter to LightInfo failed !");
auto *obj = const_cast<se::Object *>(from.toObject());
bool ok = true;
se::Value field;
obj->getProperty("light", &field, true);
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);
}
obj->getProperty("culledByLight", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->culledByLight), ctx);
}
return ok;
}
template <>
bool sevalue_to_native<cc::render::Descriptor>(const se::Value &from, cc::render::Descriptor *to, se::Object *ctx) { // NOLINT
SE_PRECONDITION2(from.isObject(), false, " Convert parameter to Descriptor failed !");
auto *obj = const_cast<se::Object *>(from.toObject());
bool ok = true;
se::Value field;
obj->getProperty("type", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->type), ctx);
}
obj->getProperty("count", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->count), ctx);
}
return ok;
}
template <>
bool sevalue_to_native<cc::render::DescriptorBlockFlattened>(const se::Value &from, cc::render::DescriptorBlockFlattened *to, se::Object *ctx) { // NOLINT
SE_PRECONDITION2(from.isObject(), false, " Convert parameter to DescriptorBlockFlattened failed !");
auto *obj = const_cast<se::Object *>(from.toObject());
bool ok = true;
se::Value field;
obj->getProperty("descriptorNames", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->descriptorNames), ctx);
}
obj->getProperty("uniformBlockNames", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->uniformBlockNames), ctx);
}
obj->getProperty("descriptors", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->descriptors), ctx);
}
obj->getProperty("uniformBlocks", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->uniformBlocks), ctx);
}
obj->getProperty("capacity", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->capacity), ctx);
}
obj->getProperty("count", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->count), ctx);
}
return ok;
}
template <>
bool sevalue_to_native<cc::render::DescriptorBlockIndex>(const se::Value &from, cc::render::DescriptorBlockIndex *to, se::Object *ctx) { // NOLINT
SE_PRECONDITION2(from.isObject(), false, " Convert parameter to DescriptorBlockIndex failed !");
auto *obj = const_cast<se::Object *>(from.toObject());
bool ok = true;
se::Value field;
obj->getProperty("updateFrequency", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->updateFrequency), ctx);
}
obj->getProperty("parameterType", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->parameterType), ctx);
}
obj->getProperty("descriptorType", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->descriptorType), ctx);
}
obj->getProperty("visibility", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->visibility), ctx);
}
return ok;
}
template <>
bool sevalue_to_native<cc::render::ResolvePair>(const se::Value &from, cc::render::ResolvePair *to, se::Object *ctx) { // NOLINT
SE_PRECONDITION2(from.isObject(), false, " Convert parameter to ResolvePair failed !");
auto *obj = const_cast<se::Object *>(from.toObject());
bool ok = true;
se::Value field;
obj->getProperty("source", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->source), ctx);
}
obj->getProperty("target", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->target), ctx);
}
obj->getProperty("resolveFlags", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->resolveFlags), ctx);
}
obj->getProperty("mode", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->mode), ctx);
}
obj->getProperty("mode1", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->mode1), ctx);
}
return ok;
}
template <>
bool sevalue_to_native<cc::render::CopyPair>(const se::Value &from, cc::render::CopyPair *to, se::Object *ctx) { // NOLINT
SE_PRECONDITION2(from.isObject(), false, " Convert parameter to CopyPair failed !");
auto *obj = const_cast<se::Object *>(from.toObject());
bool ok = true;
se::Value field;
obj->getProperty("source", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->source), ctx);
}
obj->getProperty("target", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->target), ctx);
}
obj->getProperty("mipLevels", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->mipLevels), ctx);
}
obj->getProperty("numSlices", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->numSlices), ctx);
}
obj->getProperty("sourceMostDetailedMip", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->sourceMostDetailedMip), ctx);
}
obj->getProperty("sourceFirstSlice", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->sourceFirstSlice), ctx);
}
obj->getProperty("sourcePlaneSlice", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->sourcePlaneSlice), ctx);
}
obj->getProperty("targetMostDetailedMip", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->targetMostDetailedMip), ctx);
}
obj->getProperty("targetFirstSlice", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->targetFirstSlice), ctx);
}
obj->getProperty("targetPlaneSlice", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->targetPlaneSlice), ctx);
}
return ok;
}
template <>
bool sevalue_to_native<cc::render::UploadPair>(const se::Value &from, cc::render::UploadPair *to, se::Object *ctx) { // NOLINT
SE_PRECONDITION2(from.isObject(), false, " Convert parameter to UploadPair failed !");
auto *obj = const_cast<se::Object *>(from.toObject());
bool ok = true;
se::Value field;
obj->getProperty("source", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->source), ctx);
}
obj->getProperty("target", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->target), ctx);
}
obj->getProperty("mipLevels", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->mipLevels), ctx);
}
obj->getProperty("numSlices", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->numSlices), ctx);
}
obj->getProperty("targetMostDetailedMip", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->targetMostDetailedMip), ctx);
}
obj->getProperty("targetFirstSlice", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->targetFirstSlice), ctx);
}
obj->getProperty("targetPlaneSlice", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->targetPlaneSlice), ctx);
}
return ok;
}
template <>
bool sevalue_to_native<cc::render::MovePair>(const se::Value &from, cc::render::MovePair *to, se::Object *ctx) { // NOLINT
SE_PRECONDITION2(from.isObject(), false, " Convert parameter to MovePair failed !");
auto *obj = const_cast<se::Object *>(from.toObject());
bool ok = true;
se::Value field;
obj->getProperty("source", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->source), ctx);
}
obj->getProperty("target", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->target), ctx);
}
obj->getProperty("mipLevels", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->mipLevels), ctx);
}
obj->getProperty("numSlices", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->numSlices), ctx);
}
obj->getProperty("targetMostDetailedMip", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->targetMostDetailedMip), ctx);
}
obj->getProperty("targetFirstSlice", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->targetFirstSlice), ctx);
}
obj->getProperty("targetPlaneSlice", &field, true);
if(!field.isNullOrUndefined()) {
ok &= sevalue_to_native(field, &(to->targetPlaneSlice), ctx);
}
return ok;
}
// clang-format on

View File

@@ -0,0 +1,76 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include "cocos/bindings/manual/jsb_conversions.h"
#include "cocos/renderer/pipeline/custom/RenderCommonFwd.h"
bool nativevalue_to_se(const cc::render::LightInfo &from, se::Value &to, se::Object *ctx); // NOLINT
bool nativevalue_to_se(const cc::render::Descriptor &from, se::Value &to, se::Object *ctx); // NOLINT
bool nativevalue_to_se(const cc::render::DescriptorBlockFlattened &from, se::Value &to, se::Object *ctx); // NOLINT
bool nativevalue_to_se(const cc::render::DescriptorBlockIndex &from, se::Value &to, se::Object *ctx); // NOLINT
bool nativevalue_to_se(const cc::render::ResolvePair &from, se::Value &to, se::Object *ctx); // NOLINT
bool nativevalue_to_se(const cc::render::CopyPair &from, se::Value &to, se::Object *ctx); // NOLINT
bool nativevalue_to_se(const cc::render::UploadPair &from, se::Value &to, se::Object *ctx); // NOLINT
bool nativevalue_to_se(const cc::render::MovePair &from, se::Value &to, se::Object *ctx); // NOLINT
// if function overload is used, android build fails
template <>
bool sevalue_to_native(const se::Value &from, cc::render::LightInfo *to, se::Object *ctx); // NOLINT
template <>
bool sevalue_to_native(const se::Value &from, cc::render::Descriptor *to, se::Object *ctx); // NOLINT
template <>
bool sevalue_to_native(const se::Value &from, cc::render::DescriptorBlockFlattened *to, se::Object *ctx); // NOLINT
template <>
bool sevalue_to_native(const se::Value &from, cc::render::DescriptorBlockIndex *to, se::Object *ctx); // NOLINT
template <>
bool sevalue_to_native(const se::Value &from, cc::render::ResolvePair *to, se::Object *ctx); // NOLINT
template <>
bool sevalue_to_native(const se::Value &from, cc::render::CopyPair *to, se::Object *ctx); // NOLINT
template <>
bool sevalue_to_native(const se::Value &from, cc::render::UploadPair *to, se::Object *ctx); // NOLINT
template <>
bool sevalue_to_native(const se::Value &from, cc::render::MovePair *to, se::Object *ctx); // NOLINT
// clang-format on

View File

@@ -0,0 +1,165 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include "cocos/renderer/pipeline/custom/RenderCommonTypes.h"
namespace cc {
namespace render {
inline const char* getName(UpdateFrequency e) noexcept {
switch (e) {
case UpdateFrequency::PER_INSTANCE: return "PER_INSTANCE";
case UpdateFrequency::PER_BATCH: return "PER_BATCH";
case UpdateFrequency::PER_PHASE: return "PER_PHASE";
case UpdateFrequency::PER_PASS: return "PER_PASS";
case UpdateFrequency::COUNT: return "COUNT";
}
return "";
}
inline const char* getName(ParameterType e) noexcept {
switch (e) {
case ParameterType::CONSTANTS: return "CONSTANTS";
case ParameterType::CBV: return "CBV";
case ParameterType::UAV: return "UAV";
case ParameterType::SRV: return "SRV";
case ParameterType::TABLE: return "TABLE";
case ParameterType::SSV: return "SSV";
}
return "";
}
inline const char* getName(const RasterPassTag& /*v*/) noexcept { return "RasterPass"; }
inline const char* getName(const RasterSubpassTag& /*v*/) noexcept { return "RasterSubpass"; }
inline const char* getName(const ComputeSubpassTag& /*v*/) noexcept { return "ComputeSubpass"; }
inline const char* getName(const ComputeTag& /*v*/) noexcept { return "Compute"; }
inline const char* getName(const ResolveTag& /*v*/) noexcept { return "Resolve"; }
inline const char* getName(const CopyTag& /*v*/) noexcept { return "Copy"; }
inline const char* getName(const MoveTag& /*v*/) noexcept { return "Move"; }
inline const char* getName(const RaytraceTag& /*v*/) noexcept { return "Raytrace"; }
inline const char* getName(ResourceResidency e) noexcept {
switch (e) {
case ResourceResidency::MANAGED: return "MANAGED";
case ResourceResidency::MEMORYLESS: return "MEMORYLESS";
case ResourceResidency::PERSISTENT: return "PERSISTENT";
case ResourceResidency::EXTERNAL: return "EXTERNAL";
case ResourceResidency::BACKBUFFER: return "BACKBUFFER";
}
return "";
}
inline const char* getName(QueueHint e) noexcept {
switch (e) {
case QueueHint::NONE: return "NONE";
case QueueHint::OPAQUE: return "OPAQUE";
case QueueHint::MASK: return "MASK";
case QueueHint::BLEND: return "BLEND";
}
return "";
}
inline const char* getName(ResourceDimension e) noexcept {
switch (e) {
case ResourceDimension::BUFFER: return "BUFFER";
case ResourceDimension::TEXTURE1D: return "TEXTURE1D";
case ResourceDimension::TEXTURE2D: return "TEXTURE2D";
case ResourceDimension::TEXTURE3D: return "TEXTURE3D";
}
return "";
}
inline const char* getName(const BufferTag& /*v*/) noexcept { return "Buffer"; }
inline const char* getName(const TextureTag& /*v*/) noexcept { return "Texture"; }
inline const char* getName(TaskType e) noexcept {
switch (e) {
case TaskType::SYNC: return "SYNC";
case TaskType::ASYNC: return "ASYNC";
}
return "";
}
inline const char* getName(LightingMode e) noexcept {
switch (e) {
case LightingMode::NONE: return "NONE";
case LightingMode::DEFAULT: return "DEFAULT";
case LightingMode::CLUSTERED: return "CLUSTERED";
}
return "";
}
inline const char* getName(AttachmentType e) noexcept {
switch (e) {
case AttachmentType::RENDER_TARGET: return "RENDER_TARGET";
case AttachmentType::DEPTH_STENCIL: return "DEPTH_STENCIL";
case AttachmentType::SHADING_RATE: return "SHADING_RATE";
}
return "";
}
inline const char* getName(AccessType e) noexcept {
switch (e) {
case AccessType::READ: return "READ";
case AccessType::READ_WRITE: return "READ_WRITE";
case AccessType::WRITE: return "WRITE";
}
return "";
}
inline const char* getName(ClearValueType e) noexcept {
switch (e) {
case ClearValueType::NONE: return "NONE";
case ClearValueType::FLOAT_TYPE: return "FLOAT_TYPE";
case ClearValueType::INT_TYPE: return "INT_TYPE";
}
return "";
}
inline const char* getName(const LightInfo& /*v*/) noexcept { return "LightInfo"; }
inline const char* getName(DescriptorTypeOrder e) noexcept {
switch (e) {
case DescriptorTypeOrder::UNIFORM_BUFFER: return "UNIFORM_BUFFER";
case DescriptorTypeOrder::DYNAMIC_UNIFORM_BUFFER: return "DYNAMIC_UNIFORM_BUFFER";
case DescriptorTypeOrder::SAMPLER_TEXTURE: return "SAMPLER_TEXTURE";
case DescriptorTypeOrder::SAMPLER: return "SAMPLER";
case DescriptorTypeOrder::TEXTURE: return "TEXTURE";
case DescriptorTypeOrder::STORAGE_BUFFER: return "STORAGE_BUFFER";
case DescriptorTypeOrder::DYNAMIC_STORAGE_BUFFER: return "DYNAMIC_STORAGE_BUFFER";
case DescriptorTypeOrder::STORAGE_IMAGE: return "STORAGE_IMAGE";
case DescriptorTypeOrder::INPUT_ATTACHMENT: return "INPUT_ATTACHMENT";
}
return "";
}
inline const char* getName(const Descriptor& /*v*/) noexcept { return "Descriptor"; }
inline const char* getName(const DescriptorBlock& /*v*/) noexcept { return "DescriptorBlock"; }
inline const char* getName(const DescriptorBlockFlattened& /*v*/) noexcept { return "DescriptorBlockFlattened"; }
inline const char* getName(const DescriptorBlockIndex& /*v*/) noexcept { return "DescriptorBlockIndex"; }
inline const char* getName(const ResolvePair& /*v*/) noexcept { return "ResolvePair"; }
inline const char* getName(const CopyPair& /*v*/) noexcept { return "CopyPair"; }
inline const char* getName(const UploadPair& /*v*/) noexcept { return "UploadPair"; }
inline const char* getName(const MovePair& /*v*/) noexcept { return "MovePair"; }
inline const char* getName(const PipelineStatistics& /*v*/) noexcept { return "PipelineStatistics"; }
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,202 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
#pragma once
#include "cocos/renderer/pipeline/custom/ArchiveTypes.h"
#include "cocos/renderer/pipeline/custom/RenderCommonTypes.h"
#include "cocos/renderer/pipeline/custom/details/Range.h"
#include "cocos/renderer/pipeline/custom/details/SerializationUtils.h"
namespace cc {
namespace render {
inline void save(OutputArchive& ar, const LightInfo& v) {
// skip, light: IntrusivePtr<scene::Light>
// skip, probe: scene::ReflectionProbe
save(ar, v.level);
save(ar, v.culledByLight);
}
inline void load(InputArchive& ar, LightInfo& v) {
// skip, light: IntrusivePtr<scene::Light>
// skip, probe: scene::ReflectionProbe
load(ar, v.level);
load(ar, v.culledByLight);
}
inline void save(OutputArchive& ar, const Descriptor& v) {
save(ar, v.type);
save(ar, v.count);
}
inline void load(InputArchive& ar, Descriptor& v) {
load(ar, v.type);
load(ar, v.count);
}
inline void save(OutputArchive& ar, const DescriptorBlock& v) {
save(ar, v.descriptors);
save(ar, v.uniformBlocks);
save(ar, v.capacity);
save(ar, v.count);
}
inline void load(InputArchive& ar, DescriptorBlock& v) {
load(ar, v.descriptors);
load(ar, v.uniformBlocks);
load(ar, v.capacity);
load(ar, v.count);
}
inline void save(OutputArchive& ar, const DescriptorBlockFlattened& v) {
save(ar, v.descriptorNames);
save(ar, v.uniformBlockNames);
save(ar, v.descriptors);
save(ar, v.uniformBlocks);
save(ar, v.capacity);
save(ar, v.count);
}
inline void load(InputArchive& ar, DescriptorBlockFlattened& v) {
load(ar, v.descriptorNames);
load(ar, v.uniformBlockNames);
load(ar, v.descriptors);
load(ar, v.uniformBlocks);
load(ar, v.capacity);
load(ar, v.count);
}
inline void save(OutputArchive& ar, const DescriptorBlockIndex& v) {
save(ar, v.updateFrequency);
save(ar, v.parameterType);
save(ar, v.descriptorType);
save(ar, v.visibility);
}
inline void load(InputArchive& ar, DescriptorBlockIndex& v) {
load(ar, v.updateFrequency);
load(ar, v.parameterType);
load(ar, v.descriptorType);
load(ar, v.visibility);
}
inline void save(OutputArchive& ar, const ResolvePair& v) {
save(ar, v.source);
save(ar, v.target);
save(ar, v.resolveFlags);
save(ar, v.mode);
save(ar, v.mode1);
}
inline void load(InputArchive& ar, ResolvePair& v) {
load(ar, v.source);
load(ar, v.target);
load(ar, v.resolveFlags);
load(ar, v.mode);
load(ar, v.mode1);
}
inline void save(OutputArchive& ar, const CopyPair& v) {
save(ar, v.source);
save(ar, v.target);
save(ar, v.mipLevels);
save(ar, v.numSlices);
save(ar, v.sourceMostDetailedMip);
save(ar, v.sourceFirstSlice);
save(ar, v.sourcePlaneSlice);
save(ar, v.targetMostDetailedMip);
save(ar, v.targetFirstSlice);
save(ar, v.targetPlaneSlice);
}
inline void load(InputArchive& ar, CopyPair& v) {
load(ar, v.source);
load(ar, v.target);
load(ar, v.mipLevels);
load(ar, v.numSlices);
load(ar, v.sourceMostDetailedMip);
load(ar, v.sourceFirstSlice);
load(ar, v.sourcePlaneSlice);
load(ar, v.targetMostDetailedMip);
load(ar, v.targetFirstSlice);
load(ar, v.targetPlaneSlice);
}
inline void save(OutputArchive& ar, const MovePair& v) {
save(ar, v.source);
save(ar, v.target);
save(ar, v.mipLevels);
save(ar, v.numSlices);
save(ar, v.targetMostDetailedMip);
save(ar, v.targetFirstSlice);
save(ar, v.targetPlaneSlice);
}
inline void load(InputArchive& ar, MovePair& v) {
load(ar, v.source);
load(ar, v.target);
load(ar, v.mipLevels);
load(ar, v.numSlices);
load(ar, v.targetMostDetailedMip);
load(ar, v.targetFirstSlice);
load(ar, v.targetPlaneSlice);
}
inline void save(OutputArchive& ar, const PipelineStatistics& v) {
save(ar, v.numRenderPasses);
save(ar, v.numManagedTextures);
save(ar, v.totalManagedTextures);
save(ar, v.numUploadBuffers);
save(ar, v.numUploadBufferViews);
save(ar, v.numFreeUploadBuffers);
save(ar, v.numFreeUploadBufferViews);
save(ar, v.numDescriptorSets);
save(ar, v.numFreeDescriptorSets);
save(ar, v.numInstancingBuffers);
save(ar, v.numInstancingUniformBlocks);
}
inline void load(InputArchive& ar, PipelineStatistics& v) {
load(ar, v.numRenderPasses);
load(ar, v.numManagedTextures);
load(ar, v.totalManagedTextures);
load(ar, v.numUploadBuffers);
load(ar, v.numUploadBufferViews);
load(ar, v.numFreeUploadBuffers);
load(ar, v.numFreeUploadBufferViews);
load(ar, v.numDescriptorSets);
load(ar, v.numFreeDescriptorSets);
load(ar, v.numInstancingBuffers);
load(ar, v.numInstancingUniformBlocks);
}
} // namespace render
} // namespace cc

View File

@@ -0,0 +1,158 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#include "RenderCommonTypes.h"
namespace cc {
namespace render {
ResolvePair::ResolvePair(const allocator_type& alloc) noexcept
: source(alloc),
target(alloc) {}
ResolvePair::ResolvePair(ccstd::pmr::string sourceIn, ccstd::pmr::string targetIn, ResolveFlags resolveFlagsIn, gfx::ResolveMode modeIn, gfx::ResolveMode mode1In, const allocator_type& alloc) noexcept // NOLINT
: source(std::move(sourceIn), alloc),
target(std::move(targetIn), alloc),
resolveFlags(resolveFlagsIn),
mode(modeIn),
mode1(mode1In) {}
ResolvePair::ResolvePair(ResolvePair&& rhs, const allocator_type& alloc)
: source(std::move(rhs.source), alloc),
target(std::move(rhs.target), alloc),
resolveFlags(rhs.resolveFlags),
mode(rhs.mode),
mode1(rhs.mode1) {}
ResolvePair::ResolvePair(ResolvePair const& rhs, const allocator_type& alloc)
: source(rhs.source, alloc),
target(rhs.target, alloc),
resolveFlags(rhs.resolveFlags),
mode(rhs.mode),
mode1(rhs.mode1) {}
CopyPair::CopyPair(const allocator_type& alloc) noexcept
: source(alloc),
target(alloc) {}
CopyPair::CopyPair(ccstd::pmr::string sourceIn, ccstd::pmr::string targetIn, uint32_t mipLevelsIn, uint32_t numSlicesIn, uint32_t sourceMostDetailedMipIn, uint32_t sourceFirstSliceIn, uint32_t sourcePlaneSliceIn, uint32_t targetMostDetailedMipIn, uint32_t targetFirstSliceIn, uint32_t targetPlaneSliceIn, const allocator_type& alloc) noexcept // NOLINT
: source(std::move(sourceIn), alloc),
target(std::move(targetIn), alloc),
mipLevels(mipLevelsIn),
numSlices(numSlicesIn),
sourceMostDetailedMip(sourceMostDetailedMipIn),
sourceFirstSlice(sourceFirstSliceIn),
sourcePlaneSlice(sourcePlaneSliceIn),
targetMostDetailedMip(targetMostDetailedMipIn),
targetFirstSlice(targetFirstSliceIn),
targetPlaneSlice(targetPlaneSliceIn) {}
CopyPair::CopyPair(CopyPair&& rhs, const allocator_type& alloc)
: source(std::move(rhs.source), alloc),
target(std::move(rhs.target), alloc),
mipLevels(rhs.mipLevels),
numSlices(rhs.numSlices),
sourceMostDetailedMip(rhs.sourceMostDetailedMip),
sourceFirstSlice(rhs.sourceFirstSlice),
sourcePlaneSlice(rhs.sourcePlaneSlice),
targetMostDetailedMip(rhs.targetMostDetailedMip),
targetFirstSlice(rhs.targetFirstSlice),
targetPlaneSlice(rhs.targetPlaneSlice) {}
CopyPair::CopyPair(CopyPair const& rhs, const allocator_type& alloc)
: source(rhs.source, alloc),
target(rhs.target, alloc),
mipLevels(rhs.mipLevels),
numSlices(rhs.numSlices),
sourceMostDetailedMip(rhs.sourceMostDetailedMip),
sourceFirstSlice(rhs.sourceFirstSlice),
sourcePlaneSlice(rhs.sourcePlaneSlice),
targetMostDetailedMip(rhs.targetMostDetailedMip),
targetFirstSlice(rhs.targetFirstSlice),
targetPlaneSlice(rhs.targetPlaneSlice) {}
UploadPair::UploadPair(const allocator_type& alloc) noexcept
: target(alloc) {}
UploadPair::UploadPair(ccstd::vector<uint8_t> sourceIn, ccstd::pmr::string targetIn, uint32_t mipLevelsIn, uint32_t numSlicesIn, uint32_t targetMostDetailedMipIn, uint32_t targetFirstSliceIn, uint32_t targetPlaneSliceIn, const allocator_type& alloc) noexcept // NOLINT
: source(std::move(sourceIn)),
target(std::move(targetIn), alloc),
mipLevels(mipLevelsIn),
numSlices(numSlicesIn),
targetMostDetailedMip(targetMostDetailedMipIn),
targetFirstSlice(targetFirstSliceIn),
targetPlaneSlice(targetPlaneSliceIn) {}
UploadPair::UploadPair(UploadPair&& rhs, const allocator_type& alloc)
: source(std::move(rhs.source)),
target(std::move(rhs.target), alloc),
mipLevels(rhs.mipLevels),
numSlices(rhs.numSlices),
targetMostDetailedMip(rhs.targetMostDetailedMip),
targetFirstSlice(rhs.targetFirstSlice),
targetPlaneSlice(rhs.targetPlaneSlice) {}
MovePair::MovePair(const allocator_type& alloc) noexcept
: source(alloc),
target(alloc) {}
MovePair::MovePair(ccstd::pmr::string sourceIn, ccstd::pmr::string targetIn, uint32_t mipLevelsIn, uint32_t numSlicesIn, uint32_t targetMostDetailedMipIn, uint32_t targetFirstSliceIn, uint32_t targetPlaneSliceIn, const allocator_type& alloc) noexcept // NOLINT
: source(std::move(sourceIn), alloc),
target(std::move(targetIn), alloc),
mipLevels(mipLevelsIn),
numSlices(numSlicesIn),
targetMostDetailedMip(targetMostDetailedMipIn),
targetFirstSlice(targetFirstSliceIn),
targetPlaneSlice(targetPlaneSliceIn) {}
MovePair::MovePair(MovePair&& rhs, const allocator_type& alloc)
: source(std::move(rhs.source), alloc),
target(std::move(rhs.target), alloc),
mipLevels(rhs.mipLevels),
numSlices(rhs.numSlices),
targetMostDetailedMip(rhs.targetMostDetailedMip),
targetFirstSlice(rhs.targetFirstSlice),
targetPlaneSlice(rhs.targetPlaneSlice) {}
MovePair::MovePair(MovePair const& rhs, const allocator_type& alloc)
: source(rhs.source, alloc),
target(rhs.target, alloc),
mipLevels(rhs.mipLevels),
numSlices(rhs.numSlices),
targetMostDetailedMip(rhs.targetMostDetailedMip),
targetFirstSlice(rhs.targetFirstSlice),
targetPlaneSlice(rhs.targetPlaneSlice) {}
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,480 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include "cocos/base/Ptr.h"
#include "cocos/base/std/container/map.h"
#include "cocos/base/std/container/string.h"
#include "cocos/base/std/hash/hash.h"
#include "cocos/renderer/gfx-base/GFXDef-common.h"
#include "cocos/renderer/pipeline/custom/RenderCommonFwd.h"
#include "cocos/scene/Light.h"
namespace cc {
namespace scene {
class ReflectionProbe;
} // namespace scene
} // namespace cc
namespace cc {
namespace render {
enum class UpdateFrequency {
PER_INSTANCE,
PER_BATCH,
PER_PHASE,
PER_PASS,
COUNT,
};
enum class ParameterType {
CONSTANTS,
CBV,
UAV,
SRV,
TABLE,
SSV,
};
struct RasterPassTag {};
struct RasterSubpassTag {};
struct ComputeSubpassTag {};
struct ComputeTag {};
struct ResolveTag {};
struct CopyTag {};
struct MoveTag {};
struct RaytraceTag {};
enum class ResourceResidency {
MANAGED,
MEMORYLESS,
PERSISTENT,
EXTERNAL,
BACKBUFFER,
};
enum class QueueHint {
NONE,
OPAQUE,
MASK,
BLEND,
RENDER_OPAQUE = OPAQUE,
RENDER_CUTOUT = MASK,
RENDER_TRANSPARENT = BLEND,
};
enum class ResourceDimension {
BUFFER,
TEXTURE1D,
TEXTURE2D,
TEXTURE3D,
};
enum class ResourceFlags : uint32_t {
NONE = 0,
UNIFORM = 0x1,
INDIRECT = 0x2,
STORAGE = 0x4,
SAMPLED = 0x8,
COLOR_ATTACHMENT = 0x10,
DEPTH_STENCIL_ATTACHMENT = 0x20,
INPUT_ATTACHMENT = 0x40,
SHADING_RATE = 0x80,
TRANSFER_SRC = 0x100,
TRANSFER_DST = 0x200,
};
constexpr ResourceFlags operator|(const ResourceFlags lhs, const ResourceFlags rhs) noexcept {
return static_cast<ResourceFlags>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs));
}
constexpr ResourceFlags operator&(const ResourceFlags lhs, const ResourceFlags rhs) noexcept {
return static_cast<ResourceFlags>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs));
}
constexpr ResourceFlags& operator|=(ResourceFlags& lhs, const ResourceFlags rhs) noexcept {
return lhs = lhs | rhs;
}
constexpr ResourceFlags& operator&=(ResourceFlags& lhs, const ResourceFlags rhs) noexcept {
return lhs = lhs & rhs;
}
constexpr bool operator!(ResourceFlags e) noexcept {
return e == static_cast<ResourceFlags>(0);
}
constexpr ResourceFlags operator~(ResourceFlags e) noexcept {
return static_cast<ResourceFlags>(~static_cast<std::underlying_type_t<ResourceFlags>>(e));
}
constexpr bool any(ResourceFlags e) noexcept {
return !!e;
}
struct BufferTag {};
struct TextureTag {};
enum class TaskType {
SYNC,
ASYNC,
};
enum class SceneFlags : uint32_t {
NONE = 0,
OPAQUE = 0x1,
MASK = 0x2,
BLEND = 0x4,
OPAQUE_OBJECT = OPAQUE,
CUTOUT_OBJECT = MASK,
TRANSPARENT_OBJECT = BLEND,
SHADOW_CASTER = 0x8,
UI = 0x10,
DEFAULT_LIGHTING = 0x20,
VOLUMETRIC_LIGHTING = 0x40,
CLUSTERED_LIGHTING = 0x80,
PLANAR_SHADOW = 0x100,
GEOMETRY = 0x200,
PROFILER = 0x400,
DRAW_INSTANCING = 0x800,
DRAW_NON_INSTANCING = 0x1000,
REFLECTION_PROBE = 0x2000,
GPU_DRIVEN = 0x4000,
NON_BUILTIN = 0x8000,
ALL = 0xFFFFFFFF,
};
constexpr SceneFlags operator|(const SceneFlags lhs, const SceneFlags rhs) noexcept {
return static_cast<SceneFlags>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs));
}
constexpr SceneFlags operator&(const SceneFlags lhs, const SceneFlags rhs) noexcept {
return static_cast<SceneFlags>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs));
}
constexpr SceneFlags& operator|=(SceneFlags& lhs, const SceneFlags rhs) noexcept {
return lhs = lhs | rhs;
}
constexpr SceneFlags& operator&=(SceneFlags& lhs, const SceneFlags rhs) noexcept {
return lhs = lhs & rhs;
}
constexpr bool operator!(SceneFlags e) noexcept {
return e == static_cast<SceneFlags>(0);
}
constexpr SceneFlags operator~(SceneFlags e) noexcept {
return static_cast<SceneFlags>(~static_cast<std::underlying_type_t<SceneFlags>>(e));
}
constexpr bool any(SceneFlags e) noexcept {
return !!e;
}
enum class LightingMode : uint32_t {
NONE,
DEFAULT,
CLUSTERED,
};
enum class AttachmentType {
RENDER_TARGET,
DEPTH_STENCIL,
SHADING_RATE,
};
enum class AccessType {
READ,
READ_WRITE,
WRITE,
};
enum class ClearValueType {
NONE,
FLOAT_TYPE,
INT_TYPE,
};
struct LightInfo {
LightInfo() = default;
LightInfo(IntrusivePtr<scene::Light> lightIn, uint32_t levelIn, bool culledByLightIn, scene::ReflectionProbe* probeIn) noexcept
: light(std::move(lightIn)),
probe(probeIn),
level(levelIn),
culledByLight(culledByLightIn) {}
LightInfo(IntrusivePtr<scene::Light> lightIn, uint32_t levelIn) noexcept
: light(std::move(lightIn)),
level(levelIn) {}
IntrusivePtr<scene::Light> light;
scene::ReflectionProbe* probe{nullptr};
uint32_t level{0};
bool culledByLight{false};
};
enum class DescriptorTypeOrder {
UNIFORM_BUFFER,
DYNAMIC_UNIFORM_BUFFER,
SAMPLER_TEXTURE,
SAMPLER,
TEXTURE,
STORAGE_BUFFER,
DYNAMIC_STORAGE_BUFFER,
STORAGE_IMAGE,
INPUT_ATTACHMENT,
};
struct Descriptor {
Descriptor() = default;
Descriptor(gfx::Type typeIn) noexcept // NOLINT
: type(typeIn) {}
gfx::Type type{gfx::Type::UNKNOWN};
uint32_t count{1};
};
struct DescriptorBlock {
ccstd::map<ccstd::string, Descriptor> descriptors;
ccstd::map<ccstd::string, gfx::UniformBlock> uniformBlocks;
uint32_t capacity{0};
uint32_t count{0};
};
struct DescriptorBlockFlattened {
ccstd::vector<ccstd::string> descriptorNames;
ccstd::vector<ccstd::string> uniformBlockNames;
ccstd::vector<Descriptor> descriptors;
ccstd::vector<gfx::UniformBlock> uniformBlocks;
uint32_t capacity{0};
uint32_t count{0};
};
struct DescriptorBlockIndex {
DescriptorBlockIndex() = default;
DescriptorBlockIndex(UpdateFrequency updateFrequencyIn, ParameterType parameterTypeIn, DescriptorTypeOrder descriptorTypeIn, gfx::ShaderStageFlagBit visibilityIn) noexcept
: updateFrequency(updateFrequencyIn),
parameterType(parameterTypeIn),
descriptorType(descriptorTypeIn),
visibility(visibilityIn) {}
UpdateFrequency updateFrequency{UpdateFrequency::PER_INSTANCE};
ParameterType parameterType{ParameterType::CONSTANTS};
DescriptorTypeOrder descriptorType{DescriptorTypeOrder::UNIFORM_BUFFER};
gfx::ShaderStageFlagBit visibility{gfx::ShaderStageFlagBit::NONE};
};
inline bool operator<(const DescriptorBlockIndex& lhs, const DescriptorBlockIndex& rhs) noexcept {
return std::forward_as_tuple(lhs.updateFrequency, lhs.parameterType, lhs.descriptorType, lhs.visibility) <
std::forward_as_tuple(rhs.updateFrequency, rhs.parameterType, rhs.descriptorType, rhs.visibility);
}
enum class ResolveFlags : uint32_t {
NONE = 0,
COLOR = 1 << 0,
DEPTH = 1 << 1,
STENCIL = 1 << 2,
};
constexpr ResolveFlags operator|(const ResolveFlags lhs, const ResolveFlags rhs) noexcept {
return static_cast<ResolveFlags>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs));
}
constexpr ResolveFlags operator&(const ResolveFlags lhs, const ResolveFlags rhs) noexcept {
return static_cast<ResolveFlags>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs));
}
constexpr ResolveFlags& operator|=(ResolveFlags& lhs, const ResolveFlags rhs) noexcept {
return lhs = lhs | rhs;
}
constexpr ResolveFlags& operator&=(ResolveFlags& lhs, const ResolveFlags rhs) noexcept {
return lhs = lhs & rhs;
}
constexpr bool operator!(ResolveFlags e) noexcept {
return e == static_cast<ResolveFlags>(0);
}
constexpr ResolveFlags operator~(ResolveFlags e) noexcept {
return static_cast<ResolveFlags>(~static_cast<std::underlying_type_t<ResolveFlags>>(e));
}
constexpr bool any(ResolveFlags e) noexcept {
return !!e;
}
struct ResolvePair {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {source.get_allocator().resource()};
}
ResolvePair(const allocator_type& alloc = boost::container::pmr::get_default_resource()) noexcept; // NOLINT
ResolvePair(ccstd::pmr::string sourceIn, ccstd::pmr::string targetIn, ResolveFlags resolveFlagsIn, gfx::ResolveMode modeIn, gfx::ResolveMode mode1In, const allocator_type& alloc = boost::container::pmr::get_default_resource()) noexcept;
ResolvePair(ResolvePair&& rhs, const allocator_type& alloc);
ResolvePair(ResolvePair const& rhs, const allocator_type& alloc);
ResolvePair(ResolvePair&& rhs) noexcept = default;
ResolvePair(ResolvePair const& rhs) = delete;
ResolvePair& operator=(ResolvePair&& rhs) = default;
ResolvePair& operator=(ResolvePair const& rhs) = default;
ccstd::pmr::string source;
ccstd::pmr::string target;
ResolveFlags resolveFlags{ResolveFlags::NONE};
gfx::ResolveMode mode{gfx::ResolveMode::SAMPLE_ZERO};
gfx::ResolveMode mode1{gfx::ResolveMode::SAMPLE_ZERO};
};
inline bool operator==(const ResolvePair& lhs, const ResolvePair& rhs) noexcept {
return std::forward_as_tuple(lhs.source, lhs.target, lhs.resolveFlags, lhs.mode, lhs.mode1) ==
std::forward_as_tuple(rhs.source, rhs.target, rhs.resolveFlags, rhs.mode, rhs.mode1);
}
inline bool operator!=(const ResolvePair& lhs, const ResolvePair& rhs) noexcept {
return !(lhs == rhs);
}
struct CopyPair {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {source.get_allocator().resource()};
}
CopyPair(const allocator_type& alloc = boost::container::pmr::get_default_resource()) noexcept; // NOLINT
CopyPair(ccstd::pmr::string sourceIn, ccstd::pmr::string targetIn, uint32_t mipLevelsIn, uint32_t numSlicesIn, uint32_t sourceMostDetailedMipIn, uint32_t sourceFirstSliceIn, uint32_t sourcePlaneSliceIn, uint32_t targetMostDetailedMipIn, uint32_t targetFirstSliceIn, uint32_t targetPlaneSliceIn, const allocator_type& alloc = boost::container::pmr::get_default_resource()) noexcept;
CopyPair(CopyPair&& rhs, const allocator_type& alloc);
CopyPair(CopyPair const& rhs, const allocator_type& alloc);
CopyPair(CopyPair&& rhs) noexcept = default;
CopyPair(CopyPair const& rhs) = delete;
CopyPair& operator=(CopyPair&& rhs) = default;
CopyPair& operator=(CopyPair const& rhs) = default;
ccstd::pmr::string source;
ccstd::pmr::string target;
uint32_t mipLevels{0xFFFFFFFF};
uint32_t numSlices{0xFFFFFFFF};
uint32_t sourceMostDetailedMip{0};
uint32_t sourceFirstSlice{0};
uint32_t sourcePlaneSlice{0};
uint32_t targetMostDetailedMip{0};
uint32_t targetFirstSlice{0};
uint32_t targetPlaneSlice{0};
};
struct UploadPair {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {target.get_allocator().resource()};
}
UploadPair(const allocator_type& alloc = boost::container::pmr::get_default_resource()) noexcept; // NOLINT
UploadPair(ccstd::vector<uint8_t> sourceIn, ccstd::pmr::string targetIn, uint32_t mipLevelsIn, uint32_t numSlicesIn, uint32_t targetMostDetailedMipIn, uint32_t targetFirstSliceIn, uint32_t targetPlaneSliceIn, const allocator_type& alloc = boost::container::pmr::get_default_resource()) noexcept;
UploadPair(UploadPair&& rhs, const allocator_type& alloc);
UploadPair(UploadPair&& rhs) noexcept = default;
UploadPair(UploadPair const& rhs) = delete;
UploadPair& operator=(UploadPair&& rhs) = default;
UploadPair& operator=(UploadPair const& rhs) = delete;
ccstd::vector<uint8_t> source;
ccstd::pmr::string target;
uint32_t mipLevels{0xFFFFFFFF};
uint32_t numSlices{0xFFFFFFFF};
uint32_t targetMostDetailedMip{0};
uint32_t targetFirstSlice{0};
uint32_t targetPlaneSlice{0};
};
struct MovePair {
using allocator_type = boost::container::pmr::polymorphic_allocator<char>;
allocator_type get_allocator() const noexcept { // NOLINT
return {source.get_allocator().resource()};
}
MovePair(const allocator_type& alloc = boost::container::pmr::get_default_resource()) noexcept; // NOLINT
MovePair(ccstd::pmr::string sourceIn, ccstd::pmr::string targetIn, uint32_t mipLevelsIn, uint32_t numSlicesIn, uint32_t targetMostDetailedMipIn, uint32_t targetFirstSliceIn, uint32_t targetPlaneSliceIn, const allocator_type& alloc = boost::container::pmr::get_default_resource()) noexcept;
MovePair(MovePair&& rhs, const allocator_type& alloc);
MovePair(MovePair const& rhs, const allocator_type& alloc);
MovePair(MovePair&& rhs) noexcept = default;
MovePair(MovePair const& rhs) = delete;
MovePair& operator=(MovePair&& rhs) = default;
MovePair& operator=(MovePair const& rhs) = default;
ccstd::pmr::string source;
ccstd::pmr::string target;
uint32_t mipLevels{0xFFFFFFFF};
uint32_t numSlices{0xFFFFFFFF};
uint32_t targetMostDetailedMip{0};
uint32_t targetFirstSlice{0};
uint32_t targetPlaneSlice{0};
};
struct PipelineStatistics {
uint32_t numRenderPasses{0};
uint32_t numManagedTextures{0};
uint32_t totalManagedTextures{0};
uint32_t numUploadBuffers{0};
uint32_t numUploadBufferViews{0};
uint32_t numFreeUploadBuffers{0};
uint32_t numFreeUploadBufferViews{0};
uint32_t numDescriptorSets{0};
uint32_t numFreeDescriptorSets{0};
uint32_t numInstancingBuffers{0};
uint32_t numInstancingUniformBlocks{0};
};
} // namespace render
} // namespace cc
namespace ccstd {
inline hash_t hash<cc::render::ResolvePair>::operator()(const cc::render::ResolvePair& val) const noexcept {
hash_t seed = 0;
hash_combine(seed, val.source);
hash_combine(seed, val.target);
hash_combine(seed, val.resolveFlags);
hash_combine(seed, val.mode);
hash_combine(seed, val.mode1);
return seed;
}
} // namespace ccstd
// clang-format on

View File

@@ -0,0 +1,131 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include "cocos/base/std/hash/hash.h"
#include "cocos/base/std/variant.h"
#include "cocos/renderer/pipeline/custom/RenderCommonFwd.h"
namespace cc {
namespace render {
struct ClearValue;
struct RasterView;
struct ComputeView;
struct ResourceDesc;
struct ResourceTraits;
struct RenderSwapchain;
struct ResourceStates;
struct ManagedBuffer;
struct PersistentBuffer;
struct ManagedTexture;
struct PersistentTexture;
struct ManagedResource;
struct Subpass;
struct SubpassGraph;
struct RasterSubpass;
struct ComputeSubpass;
struct RasterPass;
struct PersistentRenderPassAndFramebuffer;
struct ManagedTag;
struct ManagedBufferTag;
struct ManagedTextureTag;
struct PersistentBufferTag;
struct PersistentTextureTag;
struct FramebufferTag;
struct SwapchainTag;
struct SamplerTag;
struct FormatViewTag;
struct SubresourceViewTag;
struct FormatView;
struct SubresourceView;
struct ResourceGraph;
struct ComputePass;
struct ResolvePass;
struct CopyPass;
struct MovePass;
struct RaytracePass;
struct QueueTag;
struct SceneTag;
struct DispatchTag;
struct BlitTag;
struct ClearTag;
struct ViewportTag;
struct ClearView;
struct RenderQueue;
enum class CullingFlags : uint32_t;
struct SceneData;
struct Dispatch;
struct Blit;
struct RenderData;
struct RenderGraph;
} // namespace render
} // namespace cc
namespace ccstd {
template <>
struct hash<cc::render::ClearValue> {
hash_t operator()(const cc::render::ClearValue& val) const noexcept;
};
template <>
struct hash<cc::render::RasterView> {
hash_t operator()(const cc::render::RasterView& val) const noexcept;
};
template <>
struct hash<cc::render::ComputeView> {
hash_t operator()(const cc::render::ComputeView& val) const noexcept;
};
template <>
struct hash<cc::render::Subpass> {
hash_t operator()(const cc::render::Subpass& val) const noexcept;
};
template <>
struct hash<cc::render::SubpassGraph> {
hash_t operator()(const cc::render::SubpassGraph& val) const noexcept;
};
template <>
struct hash<cc::render::RasterPass> {
hash_t operator()(const cc::render::RasterPass& val) const noexcept;
};
} // namespace ccstd
// clang-format on

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,498 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#include "RenderGraphTypes.h"
namespace cc {
namespace render {
RasterView::RasterView(const allocator_type& alloc) noexcept
: slotName(alloc),
slotName1(alloc) {}
RasterView::RasterView(ccstd::pmr::string slotNameIn, AccessType accessTypeIn, AttachmentType attachmentTypeIn, gfx::LoadOp loadOpIn, gfx::StoreOp storeOpIn, gfx::ClearFlagBit clearFlagsIn, gfx::Color clearColorIn, gfx::ShaderStageFlagBit shaderStageFlagsIn, const allocator_type& alloc) noexcept // NOLINT
: slotName(std::move(slotNameIn), alloc),
slotName1(alloc),
accessType(accessTypeIn),
attachmentType(attachmentTypeIn),
loadOp(loadOpIn),
storeOp(storeOpIn),
clearFlags(clearFlagsIn),
clearColor(clearColorIn),
shaderStageFlags(shaderStageFlagsIn) {}
RasterView::RasterView(ccstd::pmr::string slotNameIn, ccstd::pmr::string slotName1In, AccessType accessTypeIn, AttachmentType attachmentTypeIn, gfx::LoadOp loadOpIn, gfx::StoreOp storeOpIn, gfx::ClearFlagBit clearFlagsIn, gfx::Color clearColorIn, gfx::ShaderStageFlagBit shaderStageFlagsIn, const allocator_type& alloc) noexcept // NOLINT
: slotName(std::move(slotNameIn), alloc),
slotName1(std::move(slotName1In), alloc),
accessType(accessTypeIn),
attachmentType(attachmentTypeIn),
loadOp(loadOpIn),
storeOp(storeOpIn),
clearFlags(clearFlagsIn),
clearColor(clearColorIn),
shaderStageFlags(shaderStageFlagsIn) {}
RasterView::RasterView(RasterView&& rhs, const allocator_type& alloc)
: slotName(std::move(rhs.slotName), alloc),
slotName1(std::move(rhs.slotName1), alloc),
accessType(rhs.accessType),
attachmentType(rhs.attachmentType),
loadOp(rhs.loadOp),
storeOp(rhs.storeOp),
clearFlags(rhs.clearFlags),
clearColor(rhs.clearColor),
slotID(rhs.slotID),
shaderStageFlags(rhs.shaderStageFlags) {}
RasterView::RasterView(RasterView const& rhs, const allocator_type& alloc)
: slotName(rhs.slotName, alloc),
slotName1(rhs.slotName1, alloc),
accessType(rhs.accessType),
attachmentType(rhs.attachmentType),
loadOp(rhs.loadOp),
storeOp(rhs.storeOp),
clearFlags(rhs.clearFlags),
clearColor(rhs.clearColor),
slotID(rhs.slotID),
shaderStageFlags(rhs.shaderStageFlags) {}
ComputeView::ComputeView(const allocator_type& alloc) noexcept
: name(alloc) {}
ComputeView::ComputeView(ccstd::pmr::string nameIn, AccessType accessTypeIn, gfx::ClearFlagBit clearFlagsIn, ClearValueType clearValueTypeIn, ClearValue clearValueIn, gfx::ShaderStageFlagBit shaderStageFlagsIn, const allocator_type& alloc) noexcept
: name(std::move(nameIn), alloc),
accessType(accessTypeIn),
clearFlags(clearFlagsIn),
clearValueType(clearValueTypeIn),
clearValue(clearValueIn),
shaderStageFlags(shaderStageFlagsIn) {}
ComputeView::ComputeView(ccstd::pmr::string nameIn, AccessType accessTypeIn, uint32_t planeIn, gfx::ClearFlagBit clearFlagsIn, ClearValueType clearValueTypeIn, ClearValue clearValueIn, gfx::ShaderStageFlagBit shaderStageFlagsIn, const allocator_type& alloc) noexcept
: name(std::move(nameIn), alloc),
accessType(accessTypeIn),
plane(planeIn),
clearFlags(clearFlagsIn),
clearValueType(clearValueTypeIn),
clearValue(clearValueIn),
shaderStageFlags(shaderStageFlagsIn) {}
ComputeView::ComputeView(ComputeView&& rhs, const allocator_type& alloc)
: name(std::move(rhs.name), alloc),
accessType(rhs.accessType),
plane(rhs.plane),
clearFlags(rhs.clearFlags),
clearValueType(rhs.clearValueType),
clearValue(rhs.clearValue),
shaderStageFlags(rhs.shaderStageFlags) {}
ComputeView::ComputeView(ComputeView const& rhs, const allocator_type& alloc)
: name(rhs.name, alloc),
accessType(rhs.accessType),
plane(rhs.plane),
clearFlags(rhs.clearFlags),
clearValueType(rhs.clearValueType),
clearValue(rhs.clearValue),
shaderStageFlags(rhs.shaderStageFlags) {}
Subpass::Subpass(const allocator_type& alloc) noexcept
: rasterViews(alloc),
computeViews(alloc),
resolvePairs(alloc) {}
Subpass::Subpass(Subpass&& rhs, const allocator_type& alloc)
: rasterViews(std::move(rhs.rasterViews), alloc),
computeViews(std::move(rhs.computeViews), alloc),
resolvePairs(std::move(rhs.resolvePairs), alloc) {}
Subpass::Subpass(Subpass const& rhs, const allocator_type& alloc)
: rasterViews(rhs.rasterViews, alloc),
computeViews(rhs.computeViews, alloc),
resolvePairs(rhs.resolvePairs, alloc) {}
SubpassGraph::SubpassGraph(const allocator_type& alloc) noexcept
: _vertices(alloc),
names(alloc),
subpasses(alloc) {}
SubpassGraph::SubpassGraph(SubpassGraph&& rhs, const allocator_type& alloc)
: _vertices(std::move(rhs._vertices), alloc),
names(std::move(rhs.names), alloc),
subpasses(std::move(rhs.subpasses), alloc) {}
SubpassGraph::SubpassGraph(SubpassGraph const& rhs, const allocator_type& alloc)
: _vertices(rhs._vertices, alloc),
names(rhs.names, alloc),
subpasses(rhs.subpasses, alloc) {}
// ContinuousContainer
void SubpassGraph::reserve(vertices_size_type sz) {
_vertices.reserve(sz);
names.reserve(sz);
subpasses.reserve(sz);
}
SubpassGraph::Vertex::Vertex(const allocator_type& alloc) noexcept
: outEdges(alloc),
inEdges(alloc) {}
SubpassGraph::Vertex::Vertex(Vertex&& rhs, const allocator_type& alloc)
: outEdges(std::move(rhs.outEdges), alloc),
inEdges(std::move(rhs.inEdges), alloc) {}
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),
resolvePairs(alloc),
subpassID(subpassIDIn),
count(countIn),
quality(qualityIn) {}
RasterSubpass::RasterSubpass(RasterSubpass&& rhs, const allocator_type& alloc)
: rasterViews(std::move(rhs.rasterViews), alloc),
computeViews(std::move(rhs.computeViews), alloc),
resolvePairs(std::move(rhs.resolvePairs), alloc),
viewport(rhs.viewport),
subpassID(rhs.subpassID),
count(rhs.count),
quality(rhs.quality),
showStatistics(rhs.showStatistics) {}
RasterSubpass::RasterSubpass(RasterSubpass const& rhs, const allocator_type& alloc)
: rasterViews(rhs.rasterViews, alloc),
computeViews(rhs.computeViews, alloc),
resolvePairs(rhs.resolvePairs, alloc),
viewport(rhs.viewport),
subpassID(rhs.subpassID),
count(rhs.count),
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),
subpassID(subpassIDIn) {}
ComputeSubpass::ComputeSubpass(ComputeSubpass&& rhs, const allocator_type& alloc)
: rasterViews(std::move(rhs.rasterViews), alloc),
computeViews(std::move(rhs.computeViews), alloc),
subpassID(rhs.subpassID) {}
ComputeSubpass::ComputeSubpass(ComputeSubpass const& rhs, const allocator_type& alloc)
: rasterViews(rhs.rasterViews, alloc),
computeViews(rhs.computeViews, alloc),
subpassID(rhs.subpassID) {}
RasterPass::RasterPass(const allocator_type& alloc) noexcept
: rasterViews(alloc),
computeViews(alloc),
attachmentIndexMap(alloc),
textures(alloc),
subpassGraph(alloc),
versionName(alloc) {}
RasterPass::RasterPass(RasterPass&& rhs, const allocator_type& alloc)
: rasterViews(std::move(rhs.rasterViews), alloc),
computeViews(std::move(rhs.computeViews), alloc),
attachmentIndexMap(std::move(rhs.attachmentIndexMap), alloc),
textures(std::move(rhs.textures), alloc),
subpassGraph(std::move(rhs.subpassGraph), alloc),
width(rhs.width),
height(rhs.height),
count(rhs.count),
quality(rhs.quality),
viewport(rhs.viewport),
versionName(std::move(rhs.versionName), alloc),
version(rhs.version),
hashValue(rhs.hashValue),
showStatistics(rhs.showStatistics) {}
RasterPass::RasterPass(RasterPass const& rhs, const allocator_type& alloc)
: rasterViews(rhs.rasterViews, alloc),
computeViews(rhs.computeViews, alloc),
attachmentIndexMap(rhs.attachmentIndexMap, alloc),
textures(rhs.textures, alloc),
subpassGraph(rhs.subpassGraph, alloc),
width(rhs.width),
height(rhs.height),
count(rhs.count),
quality(rhs.quality),
viewport(rhs.viewport),
versionName(rhs.versionName, alloc),
version(rhs.version),
hashValue(rhs.hashValue),
showStatistics(rhs.showStatistics) {}
PersistentRenderPassAndFramebuffer::PersistentRenderPassAndFramebuffer(const allocator_type& alloc) noexcept
: clearColors(alloc) {}
PersistentRenderPassAndFramebuffer::PersistentRenderPassAndFramebuffer(IntrusivePtr<gfx::RenderPass> renderPassIn, IntrusivePtr<gfx::Framebuffer> framebufferIn, const allocator_type& alloc) noexcept
: renderPass(std::move(renderPassIn)),
framebuffer(std::move(framebufferIn)),
clearColors(alloc) {}
PersistentRenderPassAndFramebuffer::PersistentRenderPassAndFramebuffer(PersistentRenderPassAndFramebuffer&& rhs, const allocator_type& alloc)
: renderPass(std::move(rhs.renderPass)),
framebuffer(std::move(rhs.framebuffer)),
clearColors(std::move(rhs.clearColors), alloc),
clearDepth(rhs.clearDepth),
clearStencil(rhs.clearStencil) {}
PersistentRenderPassAndFramebuffer::PersistentRenderPassAndFramebuffer(PersistentRenderPassAndFramebuffer const& rhs, const allocator_type& alloc)
: renderPass(rhs.renderPass),
framebuffer(rhs.framebuffer),
clearColors(rhs.clearColors, alloc),
clearDepth(rhs.clearDepth),
clearStencil(rhs.clearStencil) {}
ResourceGraph::ResourceGraph(const allocator_type& alloc) noexcept
: _vertices(alloc),
names(alloc),
descs(alloc),
traits(alloc),
states(alloc),
samplerInfo(alloc),
resources(alloc),
managedBuffers(alloc),
managedTextures(alloc),
buffers(alloc),
textures(alloc),
framebuffers(alloc),
swapchains(alloc),
formatViews(alloc),
subresourceViews(alloc),
valueIndex(alloc),
renderPasses(alloc) {}
// ContinuousContainer
void ResourceGraph::reserve(vertices_size_type sz) {
_vertices.reserve(sz);
names.reserve(sz);
descs.reserve(sz);
traits.reserve(sz);
states.reserve(sz);
samplerInfo.reserve(sz);
}
ResourceGraph::Vertex::Vertex(const allocator_type& alloc) noexcept
: outEdges(alloc),
inEdges(alloc) {}
ResourceGraph::Vertex::Vertex(Vertex&& rhs, const allocator_type& alloc)
: outEdges(std::move(rhs.outEdges), alloc),
inEdges(std::move(rhs.inEdges), alloc),
handle(std::move(rhs.handle)) {}
ResourceGraph::Vertex::Vertex(Vertex const& rhs, const allocator_type& alloc)
: outEdges(rhs.outEdges, alloc),
inEdges(rhs.inEdges, alloc),
handle(rhs.handle) {}
ComputePass::ComputePass(const allocator_type& alloc) noexcept
: computeViews(alloc),
textures(alloc) {}
ComputePass::ComputePass(ComputePass&& rhs, const allocator_type& alloc)
: computeViews(std::move(rhs.computeViews), alloc),
textures(std::move(rhs.textures), alloc) {}
ComputePass::ComputePass(ComputePass const& rhs, const allocator_type& alloc)
: computeViews(rhs.computeViews, alloc),
textures(rhs.textures, alloc) {}
ResolvePass::ResolvePass(const allocator_type& alloc) noexcept
: resolvePairs(alloc) {}
ResolvePass::ResolvePass(ResolvePass&& rhs, const allocator_type& alloc)
: resolvePairs(std::move(rhs.resolvePairs), alloc) {}
ResolvePass::ResolvePass(ResolvePass const& rhs, const allocator_type& alloc)
: resolvePairs(rhs.resolvePairs, alloc) {}
CopyPass::CopyPass(const allocator_type& alloc) noexcept
: copyPairs(alloc),
uploadPairs(alloc) {}
CopyPass::CopyPass(CopyPass&& rhs, const allocator_type& alloc)
: copyPairs(std::move(rhs.copyPairs), alloc),
uploadPairs(std::move(rhs.uploadPairs), alloc) {}
MovePass::MovePass(const allocator_type& alloc) noexcept
: movePairs(alloc) {}
MovePass::MovePass(MovePass&& rhs, const allocator_type& alloc)
: movePairs(std::move(rhs.movePairs), alloc) {}
MovePass::MovePass(MovePass const& rhs, const allocator_type& alloc)
: movePairs(rhs.movePairs, alloc) {}
RaytracePass::RaytracePass(const allocator_type& alloc) noexcept
: computeViews(alloc) {}
RaytracePass::RaytracePass(RaytracePass&& rhs, const allocator_type& alloc)
: computeViews(std::move(rhs.computeViews), alloc) {}
RaytracePass::RaytracePass(RaytracePass const& rhs, const allocator_type& alloc)
: computeViews(rhs.computeViews, alloc) {}
ClearView::ClearView(const allocator_type& alloc) noexcept
: slotName(alloc) {}
ClearView::ClearView(ccstd::pmr::string slotNameIn, gfx::ClearFlagBit clearFlagsIn, gfx::Color clearColorIn, const allocator_type& alloc) noexcept
: slotName(std::move(slotNameIn), alloc),
clearFlags(clearFlagsIn),
clearColor(clearColorIn) {}
ClearView::ClearView(ClearView&& rhs, const allocator_type& alloc)
: slotName(std::move(rhs.slotName), alloc),
clearFlags(rhs.clearFlags),
clearColor(rhs.clearColor) {}
ClearView::ClearView(ClearView const& rhs, const allocator_type& alloc)
: slotName(rhs.slotName, alloc),
clearFlags(rhs.clearFlags),
clearColor(rhs.clearColor) {}
RenderData::RenderData(const allocator_type& alloc) noexcept
: constants(alloc),
buffers(alloc),
textures(alloc),
samplers(alloc),
custom(alloc) {}
RenderData::RenderData(RenderData&& rhs, const allocator_type& alloc)
: constants(std::move(rhs.constants), alloc),
buffers(std::move(rhs.buffers), alloc),
textures(std::move(rhs.textures), alloc),
samplers(std::move(rhs.samplers), alloc),
custom(std::move(rhs.custom), alloc) {}
RenderGraph::RenderGraph(const allocator_type& alloc) noexcept
: objects(alloc),
_vertices(alloc),
names(alloc),
layoutNodes(alloc),
data(alloc),
valid(alloc),
rasterPasses(alloc),
rasterSubpasses(alloc),
computeSubpasses(alloc),
computePasses(alloc),
resolvePasses(alloc),
copyPasses(alloc),
movePasses(alloc),
raytracePasses(alloc),
renderQueues(alloc),
scenes(alloc),
blits(alloc),
dispatches(alloc),
clearViews(alloc),
viewports(alloc),
index(alloc),
sortedVertices(alloc) {}
RenderGraph::RenderGraph(RenderGraph&& rhs, const allocator_type& alloc)
: objects(std::move(rhs.objects), alloc),
_vertices(std::move(rhs._vertices), alloc),
names(std::move(rhs.names), alloc),
layoutNodes(std::move(rhs.layoutNodes), alloc),
data(std::move(rhs.data), alloc),
valid(std::move(rhs.valid), alloc),
rasterPasses(std::move(rhs.rasterPasses), alloc),
rasterSubpasses(std::move(rhs.rasterSubpasses), alloc),
computeSubpasses(std::move(rhs.computeSubpasses), alloc),
computePasses(std::move(rhs.computePasses), alloc),
resolvePasses(std::move(rhs.resolvePasses), alloc),
copyPasses(std::move(rhs.copyPasses), alloc),
movePasses(std::move(rhs.movePasses), alloc),
raytracePasses(std::move(rhs.raytracePasses), alloc),
renderQueues(std::move(rhs.renderQueues), alloc),
scenes(std::move(rhs.scenes), alloc),
blits(std::move(rhs.blits), alloc),
dispatches(std::move(rhs.dispatches), alloc),
clearViews(std::move(rhs.clearViews), alloc),
viewports(std::move(rhs.viewports), alloc),
index(std::move(rhs.index), alloc),
sortedVertices(std::move(rhs.sortedVertices), alloc) {}
// ContinuousContainer
void RenderGraph::reserve(vertices_size_type sz) {
objects.reserve(sz);
_vertices.reserve(sz);
names.reserve(sz);
layoutNodes.reserve(sz);
data.reserve(sz);
valid.reserve(sz);
}
RenderGraph::Object::Object(const allocator_type& alloc) noexcept
: children(alloc),
parents(alloc) {}
RenderGraph::Object::Object(Object&& rhs, const allocator_type& alloc)
: children(std::move(rhs.children), alloc),
parents(std::move(rhs.parents), alloc) {}
RenderGraph::Object::Object(Object const& rhs, const allocator_type& alloc)
: children(rhs.children, alloc),
parents(rhs.parents, alloc) {}
RenderGraph::Vertex::Vertex(const allocator_type& alloc) noexcept
: outEdges(alloc),
inEdges(alloc) {}
RenderGraph::Vertex::Vertex(Vertex&& rhs, const allocator_type& alloc)
: outEdges(std::move(rhs.outEdges), alloc),
inEdges(std::move(rhs.inEdges), alloc),
handle(std::move(rhs.handle)) {}
RenderGraph::Vertex::Vertex(Vertex const& rhs, const allocator_type& alloc)
: outEdges(rhs.outEdges, alloc),
inEdges(rhs.inEdges, alloc),
handle(rhs.handle) {}
} // namespace render
} // namespace cc
// clang-format on

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#pragma once
#include "cocos/base/std/variant.h"
#include "cocos/renderer/pipeline/custom/CustomFwd.h"
namespace cc {
namespace render {
class PipelineRuntime;
enum class PipelineType;
enum class SubpassCapabilities : uint32_t;
struct PipelineCapabilities;
class RenderNode;
class Setter;
class SceneBuilder;
class RenderQueueBuilder;
class BasicRenderPassBuilder;
class BasicMultisampleRenderPassBuilder;
class BasicPipeline;
class RenderSubpassBuilder;
class MultisampleRenderSubpassBuilder;
class ComputeQueueBuilder;
class ComputeSubpassBuilder;
class RenderPassBuilder;
class MultisampleRenderPassBuilder;
class ComputePassBuilder;
class Pipeline;
class PipelineBuilder;
class RenderingModule;
class Factory;
} // namespace render
} // namespace cc
// clang-format on

View File

@@ -0,0 +1,41 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
* The following section is auto-generated.
* ========================= !DO NOT CHANGE THE FOLLOWING SECTION MANUALLY! =========================
*/
// clang-format off
#include "RenderInterfaceTypes.h"
namespace cc {
namespace render {
} // namespace render
} // namespace cc
// clang-format on

Some files were not shown because too many files have changed in this diff Show More