no message
This commit is contained in:
894
cocos/renderer/pipeline/ClusterLightCulling.cpp
Normal file
894
cocos/renderer/pipeline/ClusterLightCulling.cpp
Normal 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
|
||||
143
cocos/renderer/pipeline/ClusterLightCulling.h
Normal file
143
cocos/renderer/pipeline/ClusterLightCulling.h
Normal 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
|
||||
67
cocos/renderer/pipeline/DebugView.cpp
Normal file
67
cocos/renderer/pipeline/DebugView.cpp
Normal 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 ¯oValue = iter->second;
|
||||
const int32_t *macroPtr = ccstd::get_if<int32_t>(¯oValue);
|
||||
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
|
||||
260
cocos/renderer/pipeline/DebugView.h
Normal file
260
cocos/renderer/pipeline/DebugView.h
Normal 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
|
||||
694
cocos/renderer/pipeline/Define.cpp
Normal file
694
cocos/renderer/pipeline/Define.cpp
Normal 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
|
||||
693
cocos/renderer/pipeline/Define.h
Normal file
693
cocos/renderer/pipeline/Define.h
Normal 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
|
||||
45
cocos/renderer/pipeline/Enum.h
Normal file
45
cocos/renderer/pipeline/Enum.h
Normal 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
|
||||
};
|
||||
879
cocos/renderer/pipeline/GeometryRenderer.cpp
Normal file
879
cocos/renderer/pipeline/GeometryRenderer.cpp
Normal 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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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
|
||||
117
cocos/renderer/pipeline/GeometryRenderer.h
Normal file
117
cocos/renderer/pipeline/GeometryRenderer.h
Normal 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 ¢er, float size, gfx::Color color, bool depthTest = true);
|
||||
void addFrustum(const geometry::Frustum &frustum, gfx::Color color, bool depthTest = true);
|
||||
void addCapsule(const Vec3 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, float radius, gfx::Color color, uint32_t segments = 32U, bool depthTest = true, bool useTransform = false, const Mat4 &transform = Mat4());
|
||||
void addArc(const Vec3 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, const ccstd::vector<Vec3> &vertices, gfx::Color color, bool depthTest = true, bool useTransform = false, const Mat4 &transform = Mat4());
|
||||
void addIndexedMesh(const Vec3 ¢er, 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
|
||||
245
cocos/renderer/pipeline/GlobalDescriptorSetManager.cpp
Normal file
245
cocos/renderer/pipeline/GlobalDescriptorSetManager.cpp
Normal 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
|
||||
84
cocos/renderer/pipeline/GlobalDescriptorSetManager.h
Normal file
84
cocos/renderer/pipeline/GlobalDescriptorSetManager.h
Normal 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
|
||||
176
cocos/renderer/pipeline/InstancedBuffer.cpp
Normal file
176
cocos/renderer/pipeline/InstancedBuffer.cpp
Normal 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
|
||||
90
cocos/renderer/pipeline/InstancedBuffer.h
Normal file
90
cocos/renderer/pipeline/InstancedBuffer.h
Normal 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
|
||||
188
cocos/renderer/pipeline/PipelineSceneData.cpp
Normal file
188
cocos/renderer/pipeline/PipelineSceneData.cpp
Normal 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
|
||||
159
cocos/renderer/pipeline/PipelineSceneData.h
Normal file
159
cocos/renderer/pipeline/PipelineSceneData.h
Normal 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
|
||||
79
cocos/renderer/pipeline/PipelineStateManager.cpp
Normal file
79
cocos/renderer/pipeline/PipelineStateManager.cpp
Normal 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
|
||||
50
cocos/renderer/pipeline/PipelineStateManager.h
Normal file
50
cocos/renderer/pipeline/PipelineStateManager.h
Normal 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
|
||||
611
cocos/renderer/pipeline/PipelineUBO.cpp
Normal file
611
cocos/renderer/pipeline/PipelineUBO.cpp
Normal 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
|
||||
96
cocos/renderer/pipeline/PipelineUBO.h
Normal file
96
cocos/renderer/pipeline/PipelineUBO.h
Normal 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
|
||||
166
cocos/renderer/pipeline/PlanarShadowQueue.cpp
Normal file
166
cocos/renderer/pipeline/PlanarShadowQueue.cpp
Normal 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
|
||||
72
cocos/renderer/pipeline/PlanarShadowQueue.h
Normal file
72
cocos/renderer/pipeline/PlanarShadowQueue.h
Normal 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
|
||||
215
cocos/renderer/pipeline/ReflectionProbeBatchedQueue.cpp
Normal file
215
cocos/renderer/pipeline/ReflectionProbeBatchedQueue.cpp
Normal 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
|
||||
79
cocos/renderer/pipeline/ReflectionProbeBatchedQueue.h
Normal file
79
cocos/renderer/pipeline/ReflectionProbeBatchedQueue.h
Normal 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
|
||||
530
cocos/renderer/pipeline/RenderAdditiveLightQueue.cpp
Normal file
530
cocos/renderer/pipeline/RenderAdditiveLightQueue.cpp
Normal 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
|
||||
108
cocos/renderer/pipeline/RenderAdditiveLightQueue.h
Normal file
108
cocos/renderer/pipeline/RenderAdditiveLightQueue.h
Normal 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
|
||||
82
cocos/renderer/pipeline/RenderFlow.cpp
Normal file
82
cocos/renderer/pipeline/RenderFlow.cpp
Normal 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
|
||||
78
cocos/renderer/pipeline/RenderFlow.h
Normal file
78
cocos/renderer/pipeline/RenderFlow.h
Normal 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
|
||||
103
cocos/renderer/pipeline/RenderInstancedQueue.cpp
Normal file
103
cocos/renderer/pipeline/RenderInstancedQueue.cpp
Normal 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
|
||||
65
cocos/renderer/pipeline/RenderInstancedQueue.h
Normal file
65
cocos/renderer/pipeline/RenderInstancedQueue.h
Normal 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
|
||||
362
cocos/renderer/pipeline/RenderPipeline.cpp
Normal file
362
cocos/renderer/pipeline/RenderPipeline.cpp
Normal 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
|
||||
210
cocos/renderer/pipeline/RenderPipeline.h
Normal file
210
cocos/renderer/pipeline/RenderPipeline.h
Normal 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
|
||||
122
cocos/renderer/pipeline/RenderQueue.cpp
Normal file
122
cocos/renderer/pipeline/RenderQueue.cpp
Normal 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
|
||||
56
cocos/renderer/pipeline/RenderQueue.h
Normal file
56
cocos/renderer/pipeline/RenderQueue.h
Normal 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
|
||||
57
cocos/renderer/pipeline/RenderStage.cpp
Normal file
57
cocos/renderer/pipeline/RenderStage.cpp
Normal 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
|
||||
93
cocos/renderer/pipeline/RenderStage.h
Normal file
93
cocos/renderer/pipeline/RenderStage.h
Normal 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
|
||||
276
cocos/renderer/pipeline/SceneCulling.cpp
Normal file
276
cocos/renderer/pipeline/SceneCulling.cpp
Normal 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
|
||||
52
cocos/renderer/pipeline/SceneCulling.h
Normal file
52
cocos/renderer/pipeline/SceneCulling.h
Normal 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
|
||||
171
cocos/renderer/pipeline/ShadowMapBatchedQueue.cpp
Normal file
171
cocos/renderer/pipeline/ShadowMapBatchedQueue.cpp
Normal 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
|
||||
69
cocos/renderer/pipeline/ShadowMapBatchedQueue.h
Normal file
69
cocos/renderer/pipeline/ShadowMapBatchedQueue.h
Normal 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
|
||||
67
cocos/renderer/pipeline/UIPhase.cpp
Normal file
67
cocos/renderer/pipeline/UIPhase.cpp
Normal 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
|
||||
52
cocos/renderer/pipeline/UIPhase.h
Normal file
52
cocos/renderer/pipeline/UIPhase.h
Normal 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
|
||||
45
cocos/renderer/pipeline/custom/ArchiveFwd.h
Normal file
45
cocos/renderer/pipeline/custom/ArchiveFwd.h
Normal 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
|
||||
41
cocos/renderer/pipeline/custom/ArchiveTypes.cpp
Normal file
41
cocos/renderer/pipeline/custom/ArchiveTypes.cpp
Normal 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
|
||||
74
cocos/renderer/pipeline/custom/ArchiveTypes.h
Normal file
74
cocos/renderer/pipeline/custom/ArchiveTypes.h
Normal 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
|
||||
93
cocos/renderer/pipeline/custom/BinaryArchive.h
Normal file
93
cocos/renderer/pipeline/custom/BinaryArchive.h
Normal 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
|
||||
53
cocos/renderer/pipeline/custom/CustomFwd.h
Normal file
53
cocos/renderer/pipeline/custom/CustomFwd.h
Normal 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
|
||||
41
cocos/renderer/pipeline/custom/CustomTypes.cpp
Normal file
41
cocos/renderer/pipeline/custom/CustomTypes.cpp
Normal 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
|
||||
130
cocos/renderer/pipeline/custom/CustomTypes.h
Normal file
130
cocos/renderer/pipeline/custom/CustomTypes.h
Normal 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
|
||||
962
cocos/renderer/pipeline/custom/FGDispatcherGraphs.h
Normal file
962
cocos/renderer/pipeline/custom/FGDispatcherGraphs.h
Normal 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
|
||||
174
cocos/renderer/pipeline/custom/FGDispatcherTypes.cpp
Normal file
174
cocos/renderer/pipeline/custom/FGDispatcherTypes.cpp
Normal 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
|
||||
506
cocos/renderer/pipeline/custom/FGDispatcherTypes.h
Normal file
506
cocos/renderer/pipeline/custom/FGDispatcherTypes.h
Normal 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
|
||||
2643
cocos/renderer/pipeline/custom/FrameGraphDispatcher.cpp
Normal file
2643
cocos/renderer/pipeline/custom/FrameGraphDispatcher.cpp
Normal file
File diff suppressed because it is too large
Load Diff
81
cocos/renderer/pipeline/custom/LayoutGraphFwd.h
Normal file
81
cocos/renderer/pipeline/custom/LayoutGraphFwd.h
Normal 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
|
||||
2059
cocos/renderer/pipeline/custom/LayoutGraphGraphs.h
Normal file
2059
cocos/renderer/pipeline/custom/LayoutGraphGraphs.h
Normal file
File diff suppressed because it is too large
Load Diff
73
cocos/renderer/pipeline/custom/LayoutGraphNames.h
Normal file
73
cocos/renderer/pipeline/custom/LayoutGraphNames.h
Normal 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
|
||||
405
cocos/renderer/pipeline/custom/LayoutGraphSerialization.h
Normal file
405
cocos/renderer/pipeline/custom/LayoutGraphSerialization.h
Normal 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
|
||||
280
cocos/renderer/pipeline/custom/LayoutGraphTypes.cpp
Normal file
280
cocos/renderer/pipeline/custom/LayoutGraphTypes.cpp
Normal 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
|
||||
729
cocos/renderer/pipeline/custom/LayoutGraphTypes.h
Normal file
729
cocos/renderer/pipeline/custom/LayoutGraphTypes.h
Normal 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
|
||||
511
cocos/renderer/pipeline/custom/LayoutGraphUtils.cpp
Normal file
511
cocos/renderer/pipeline/custom/LayoutGraphUtils.cpp
Normal 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
|
||||
74
cocos/renderer/pipeline/custom/LayoutGraphUtils.h
Normal file
74
cocos/renderer/pipeline/custom/LayoutGraphUtils.h
Normal 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
|
||||
900
cocos/renderer/pipeline/custom/NativeBuiltinUtils.cpp
Normal file
900
cocos/renderer/pipeline/custom/NativeBuiltinUtils.cpp
Normal 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
|
||||
122
cocos/renderer/pipeline/custom/NativeBuiltinUtils.h
Normal file
122
cocos/renderer/pipeline/custom/NativeBuiltinUtils.h
Normal 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
|
||||
2108
cocos/renderer/pipeline/custom/NativeExecutor.cpp
Normal file
2108
cocos/renderer/pipeline/custom/NativeExecutor.cpp
Normal file
File diff suppressed because it is too large
Load Diff
96
cocos/renderer/pipeline/custom/NativeFactory.cpp
Normal file
96
cocos/renderer/pipeline/custom/NativeFactory.cpp
Normal 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
|
||||
47
cocos/renderer/pipeline/custom/NativeFwd.h
Normal file
47
cocos/renderer/pipeline/custom/NativeFwd.h
Normal 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
|
||||
1559
cocos/renderer/pipeline/custom/NativePipeline.cpp
Normal file
1559
cocos/renderer/pipeline/custom/NativePipeline.cpp
Normal file
File diff suppressed because it is too large
Load Diff
130
cocos/renderer/pipeline/custom/NativePipelineFwd.h
Normal file
130
cocos/renderer/pipeline/custom/NativePipelineFwd.h
Normal 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
|
||||
39
cocos/renderer/pipeline/custom/NativePipelineGraphs.h
Normal file
39
cocos/renderer/pipeline/custom/NativePipelineGraphs.h
Normal 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
|
||||
265
cocos/renderer/pipeline/custom/NativePipelineTypes.cpp
Normal file
265
cocos/renderer/pipeline/custom/NativePipelineTypes.cpp
Normal 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
|
||||
1760
cocos/renderer/pipeline/custom/NativePipelineTypes.h
Normal file
1760
cocos/renderer/pipeline/custom/NativePipelineTypes.h
Normal file
File diff suppressed because it is too large
Load Diff
149
cocos/renderer/pipeline/custom/NativePools.cpp
Normal file
149
cocos/renderer/pipeline/custom/NativePools.cpp
Normal 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
|
||||
1614
cocos/renderer/pipeline/custom/NativeProgramLibrary.cpp
Normal file
1614
cocos/renderer/pipeline/custom/NativeProgramLibrary.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1391
cocos/renderer/pipeline/custom/NativeRenderGraph.cpp
Normal file
1391
cocos/renderer/pipeline/custom/NativeRenderGraph.cpp
Normal file
File diff suppressed because it is too large
Load Diff
327
cocos/renderer/pipeline/custom/NativeRenderGraphUtils.cpp
Normal file
327
cocos/renderer/pipeline/custom/NativeRenderGraphUtils.cpp
Normal 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
|
||||
229
cocos/renderer/pipeline/custom/NativeRenderGraphUtils.h
Normal file
229
cocos/renderer/pipeline/custom/NativeRenderGraphUtils.h
Normal 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
|
||||
271
cocos/renderer/pipeline/custom/NativeRenderQueue.cpp
Normal file
271
cocos/renderer/pipeline/custom/NativeRenderQueue.cpp
Normal 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
|
||||
55
cocos/renderer/pipeline/custom/NativeRenderingModule.cpp
Normal file
55
cocos/renderer/pipeline/custom/NativeRenderingModule.cpp
Normal 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
|
||||
455
cocos/renderer/pipeline/custom/NativeResourceGraph.cpp
Normal file
455
cocos/renderer/pipeline/custom/NativeResourceGraph.cpp
Normal 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
|
||||
816
cocos/renderer/pipeline/custom/NativeSceneCulling.cpp
Normal file
816
cocos/renderer/pipeline/custom/NativeSceneCulling.cpp
Normal 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 = ≶
|
||||
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
|
||||
335
cocos/renderer/pipeline/custom/NativeSetter.cpp
Normal file
335
cocos/renderer/pipeline/custom/NativeSetter.cpp
Normal 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
|
||||
77
cocos/renderer/pipeline/custom/NativeTypes.cpp
Normal file
77
cocos/renderer/pipeline/custom/NativeTypes.cpp
Normal 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
|
||||
91
cocos/renderer/pipeline/custom/NativeTypes.h
Normal file
91
cocos/renderer/pipeline/custom/NativeTypes.h
Normal 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
|
||||
168
cocos/renderer/pipeline/custom/NativeUtils.cpp
Normal file
168
cocos/renderer/pipeline/custom/NativeUtils.cpp
Normal 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
|
||||
87
cocos/renderer/pipeline/custom/NativeUtils.h
Normal file
87
cocos/renderer/pipeline/custom/NativeUtils.h
Normal 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
|
||||
46
cocos/renderer/pipeline/custom/PrivateFwd.h
Normal file
46
cocos/renderer/pipeline/custom/PrivateFwd.h
Normal 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
|
||||
41
cocos/renderer/pipeline/custom/PrivateTypes.cpp
Normal file
41
cocos/renderer/pipeline/custom/PrivateTypes.cpp
Normal 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
|
||||
90
cocos/renderer/pipeline/custom/PrivateTypes.h
Normal file
90
cocos/renderer/pipeline/custom/PrivateTypes.h
Normal 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
|
||||
96
cocos/renderer/pipeline/custom/RenderCommonFwd.h
Normal file
96
cocos/renderer/pipeline/custom/RenderCommonFwd.h
Normal 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
|
||||
496
cocos/renderer/pipeline/custom/RenderCommonJsb.cpp
Normal file
496
cocos/renderer/pipeline/custom/RenderCommonJsb.cpp
Normal 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
|
||||
76
cocos/renderer/pipeline/custom/RenderCommonJsb.h
Normal file
76
cocos/renderer/pipeline/custom/RenderCommonJsb.h
Normal 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
|
||||
165
cocos/renderer/pipeline/custom/RenderCommonNames.h
Normal file
165
cocos/renderer/pipeline/custom/RenderCommonNames.h
Normal 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
|
||||
202
cocos/renderer/pipeline/custom/RenderCommonSerialization.h
Normal file
202
cocos/renderer/pipeline/custom/RenderCommonSerialization.h
Normal 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
|
||||
158
cocos/renderer/pipeline/custom/RenderCommonTypes.cpp
Normal file
158
cocos/renderer/pipeline/custom/RenderCommonTypes.cpp
Normal 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
|
||||
480
cocos/renderer/pipeline/custom/RenderCommonTypes.h
Normal file
480
cocos/renderer/pipeline/custom/RenderCommonTypes.h
Normal 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
|
||||
131
cocos/renderer/pipeline/custom/RenderGraphFwd.h
Normal file
131
cocos/renderer/pipeline/custom/RenderGraphFwd.h
Normal 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
|
||||
4746
cocos/renderer/pipeline/custom/RenderGraphGraphs.h
Normal file
4746
cocos/renderer/pipeline/custom/RenderGraphGraphs.h
Normal file
File diff suppressed because it is too large
Load Diff
498
cocos/renderer/pipeline/custom/RenderGraphTypes.cpp
Normal file
498
cocos/renderer/pipeline/custom/RenderGraphTypes.cpp
Normal 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
|
||||
1262
cocos/renderer/pipeline/custom/RenderGraphTypes.h
Normal file
1262
cocos/renderer/pipeline/custom/RenderGraphTypes.h
Normal file
File diff suppressed because it is too large
Load Diff
68
cocos/renderer/pipeline/custom/RenderInterfaceFwd.h
Normal file
68
cocos/renderer/pipeline/custom/RenderInterfaceFwd.h
Normal 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
|
||||
41
cocos/renderer/pipeline/custom/RenderInterfaceTypes.cpp
Normal file
41
cocos/renderer/pipeline/custom/RenderInterfaceTypes.cpp
Normal 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
Reference in New Issue
Block a user