no message

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

View File

@@ -0,0 +1,173 @@
/****************************************************************************
Copyright (c) 2019-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 "engine/EngineEvents.h"
#include "gfx-agent/DeviceAgent.h"
#include "gfx-validator/DeviceValidator.h"
#include "platform/BasePlatform.h"
// #undef CC_USE_NVN
// #undef CC_USE_VULKAN
// #undef CC_USE_METAL
// #undef CC_USE_GLES3
// #undef CC_USE_GLES2
#ifdef CC_USE_NVN
#include "gfx-nvn/NVNDevice.h"
#endif
#ifdef CC_USE_VULKAN
#include "gfx-vulkan/VKDevice.h"
#endif
#ifdef CC_USE_METAL
#include "gfx-metal/MTLDevice.h"
#endif
#ifdef CC_USE_GLES3
#include "gfx-gles3/GLES3Device.h"
#endif
#ifdef CC_USE_GLES2
#include "gfx-gles2/GLES2Device.h"
#endif
#include "gfx-empty/EmptyDevice.h"
#include "renderer/pipeline/Define.h"
namespace cc {
namespace gfx {
class CC_DLL DeviceManager final {
static constexpr bool DETACH_DEVICE_THREAD{true};
static constexpr bool FORCE_DISABLE_VALIDATION{false};
static constexpr bool FORCE_ENABLE_VALIDATION{false};
public:
static Device *create() {
DeviceInfo deviceInfo{pipeline::bindingMappingInfo};
return DeviceManager::create(deviceInfo);
}
static Device *create(const DeviceInfo &info) {
if (Device::instance) return Device::instance;
Device *device = nullptr;
#ifdef CC_USE_NVN
if (tryCreate<CCNVNDevice>(info, &device)) return device;
#endif
#ifdef CC_USE_VULKAN
bool skipVulkan = false;
#if CC_PLATFORM == CC_PLATFORM_ANDROID
auto sdkVersion = BasePlatform::getPlatform()->getSdkVersion();
skipVulkan = sdkVersion <= 27; // Android 8
#endif
if (!skipVulkan && tryCreate<CCVKDevice>(info, &device)) return device;
#endif
#ifdef CC_USE_METAL
if (tryCreate<CCMTLDevice>(info, &device)) return device;
#endif
#ifdef CC_USE_GLES3
#if CC_USE_XR || CC_USE_AR_MODULE
Device::isSupportDetachDeviceThread = false;
#endif
if (tryCreate<GLES3Device>(info, &device)) return device;
#endif
#ifdef CC_USE_GLES2
// arcore & arengine currently only supports gles, session update requires gl context
#if CC_USE_AR_MODULE
Device::isSupportDetachDeviceThread = false;
#endif
if (tryCreate<GLES2Device>(info, &device)) return device;
#endif
#ifdef CC_EDITOR
Device::isSupportDetachDeviceThread = false;
#endif
if (tryCreate<EmptyDevice>(info, &device)) return device;
return nullptr;
}
static bool isDetachDeviceThread() {
return DETACH_DEVICE_THREAD && Device::isSupportDetachDeviceThread;
}
static ccstd::string getGFXName() {
ccstd::string gfx = "unknown";
#ifdef CC_USE_NVN
gfx = "NVN";
#elif defined(CC_USE_VULKAN)
gfx = "Vulkan";
#elif defined(CC_USE_METAL)
gfx = "Metal";
#elif defined(CC_USE_GLES3)
gfx = "GLES3";
#elif defined(CC_USE_GLES2)
gfx = "GLES2";
#else
gfx = "Empty";
#endif
return gfx;
}
private:
template <typename DeviceCtor, typename Enable = std::enable_if_t<std::is_base_of<Device, DeviceCtor>::value>>
static bool tryCreate(const DeviceInfo &info, Device **pDevice) {
Device *device = ccnew DeviceCtor;
if (isDetachDeviceThread()) {
device = ccnew gfx::DeviceAgent(device);
}
#if !defined(CC_SERVER_MODE)
if (CC_DEBUG > 0 && !FORCE_DISABLE_VALIDATION || FORCE_ENABLE_VALIDATION) {
device = ccnew gfx::DeviceValidator(device);
}
#endif
if (!device->initialize(info)) {
CC_SAFE_DELETE(device);
return false;
}
*pDevice = device;
return true;
}
#ifndef CC_DEBUG
static constexpr int CC_DEBUG{0};
#endif
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,116 @@
/****************************************************************************
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 "renderer/core/MaterialInstance.h"
// #include "core/components/RenderableComponent.h"
#include "renderer/core/PassInstance.h"
namespace cc {
MaterialInstance::MaterialInstance(const IMaterialInstanceInfo &info) {
_parent = info.parent;
// _owner = info.owner;
_subModelIdx = info.subModelIdx;
copy(_parent);
}
void MaterialInstance::recompileShaders(const MacroRecord &overrides, index_t passIdx /* = CC_INVALID_INDEX */) {
auto &passes = *_passes;
if (passes.empty() || _effectAsset == nullptr) {
return;
}
if (passIdx == CC_INVALID_INDEX) {
for (const auto &pass : passes) {
pass->tryCompile(overrides);
}
} else {
if (passIdx < passes.size()) {
auto *pass = passes[passIdx].get();
pass->tryCompile(overrides);
}
}
}
void MaterialInstance::overridePipelineStates(const PassOverrides &overrides, index_t passIdx /* = CC_INVALID_INDEX */) {
auto &passes = *_passes;
if (passes.empty() || _effectAsset == nullptr) {
return;
}
ccstd::vector<IPassInfoFull> &passInfos = _effectAsset->_techniques[getTechniqueIndex()].passes;
if (passIdx == CC_INVALID_INDEX) {
for (size_t i = 0, len = passes.size(); i < len; i++) {
auto *pass = passes[i].get();
if (i >= _states.size()) {
_states.resize(i + 1);
}
auto &state = _states[i];
state.overrides(IPassInfoFull(overrides));
pass->overridePipelineStates(passInfos[pass->getPassIndex()], state);
}
} else {
if (passIdx >= _states.size()) {
_states.resize(passIdx + 1);
}
auto &state = _states[passIdx];
state.overrides(IPassInfoFull(overrides));
passes[passIdx]->overridePipelineStates(passInfos[passIdx], state);
}
}
bool MaterialInstance::destroy() {
doDestroy();
return true;
}
ccstd::vector<IntrusivePtr<scene::Pass>> MaterialInstance::createPasses() {
ccstd::vector<IntrusivePtr<scene::Pass>> passes;
auto &parentPasses = _parent->getPasses();
passes.reserve(parentPasses->size());
for (auto &parentPass : *parentPasses) {
passes.emplace_back(ccnew PassInstance(parentPass, this));
}
return passes;
}
void MaterialInstance::onPassStateChange(bool dontNotify) {
_hash = Material::getHashForMaterial(this);
if (!dontNotify) {
if (_rebuildPSOCallback != nullptr) {
_rebuildPSOCallback(_subModelIdx, this);
}
// if (_owner != nullptr) {
// _owner->onRebuildPSO(_subModelIdx, this);
// }
}
}
void MaterialInstance::setRebuildPSOCallback(const RebuildPSOCallback &cb) {
_rebuildPSOCallback = cb;
}
} // namespace cc

View File

@@ -0,0 +1,90 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "base/TypeDef.h"
#include "base/std/optional.h"
#include "core/assets/Material.h"
namespace cc {
struct IMaterialInstanceInfo {
Material *parent{nullptr};
// RenderableComponent *owner{nullptr};
index_t subModelIdx{0};
};
class PassInstance;
/**
* @zh
* 材质实例,当有材质修改需求时,根据材质资源创建的,可任意定制的实例。
*/
class MaterialInstance final : public Material {
public:
using Super = Material;
explicit MaterialInstance(const IMaterialInstanceInfo &info);
Material *getParent() const override {
return _parent.get();
}
// RenderableComponent *getOwner() const override {
// return _owner;
// }
void recompileShaders(const MacroRecord &overrides) override {
MaterialInstance::recompileShaders(overrides, CC_INVALID_INDEX);
}
void recompileShaders(const MacroRecord &overrides, index_t passIdx) override;
void overridePipelineStates(const PassOverrides &overrides) override {
MaterialInstance::overridePipelineStates(overrides, CC_INVALID_INDEX);
}
void overridePipelineStates(const PassOverrides &overrides, index_t passIdx) override;
bool destroy() override;
void onPassStateChange(bool dontNotify);
// For JS
using RebuildPSOCallback = std::function<void(index_t index, Material *material)>;
void setRebuildPSOCallback(const RebuildPSOCallback &cb);
//
protected:
ccstd::vector<IntrusivePtr<scene::Pass>> createPasses() override;
private:
IntrusivePtr<Material> _parent;
// RenderableComponent *_owner{nullptr};
index_t _subModelIdx{0};
RebuildPSOCallback _rebuildPSOCallback{nullptr};
};
} // namespace cc

View File

@@ -0,0 +1,115 @@
/****************************************************************************
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/core/PassInstance.h"
#include "cocos/renderer/core/MaterialInstance.h"
#include "cocos/renderer/core/ProgramLib.h"
#include "cocos/renderer/pipeline/InstancedBuffer.h"
#include "cocos/renderer/pipeline/custom/RenderingModule.h"
namespace cc {
PassInstance::PassInstance(scene::Pass *parent, MaterialInstance *owner)
: Super(parent->getRoot()), _parent(parent), _owner(owner) {
doInit(_parent->getPassInfoFull());
for (const auto &b : _shaderInfo->blocks) {
scene::IBlockRef &block = _blocks[b.binding];
const scene::IBlockRef &parentBlock = _parent->getBlocks()[b.binding];
CC_ASSERT(block.count == parentBlock.count);
memcpy(block.data, parentBlock.data, parentBlock.count * 4);
}
_rootBufferDirty = true;
gfx::DescriptorSet *parentDescriptorSet = _parent->getDescriptorSet();
auto *programLib = render::getProgramLibrary();
if (programLib) {
const auto &set = _shaderInfo->descriptors.at(
static_cast<size_t>(pipeline::SetIndex::MATERIAL));
for (const auto &samplerTexture : set.samplerTextures) {
for (uint32_t i = 0; i < samplerTexture.count; ++i) {
auto *sampler = parentDescriptorSet->getSampler(samplerTexture.binding, i);
auto *texture = parentDescriptorSet->getTexture(samplerTexture.binding, i);
_descriptorSet->bindSampler(samplerTexture.binding, sampler, i);
_descriptorSet->bindTexture(samplerTexture.binding, texture, i);
}
}
} else {
for (const auto &samplerTexture : _shaderInfo->samplerTextures) {
for (uint32_t i = 0; i < samplerTexture.count; ++i) {
auto *sampler = parentDescriptorSet->getSampler(samplerTexture.binding, i);
auto *texture = parentDescriptorSet->getTexture(samplerTexture.binding, i);
_descriptorSet->bindSampler(samplerTexture.binding, sampler, i);
_descriptorSet->bindTexture(samplerTexture.binding, texture, i);
}
}
}
Super::tryCompile();
}
PassInstance::~PassInstance() = default;
scene::Pass *PassInstance::getParent() const {
return _parent.get();
}
void PassInstance::overridePipelineStates(const IPassInfo &original, const PassOverrides &override) {
_blendState.reset();
_rs.reset();
_depthStencilState.reset();
scene::Pass::fillPipelineInfo(this, original);
scene::Pass::fillPipelineInfo(this, IPassInfoFull(override));
onStateChange();
}
bool PassInstance::tryCompile(const ccstd::optional<MacroRecord> &defineOverrides) {
if (defineOverrides.has_value()) {
if (!overrideMacros(_defines, defineOverrides.value())) return false;
}
bool ret = Super::tryCompile();
onStateChange();
return ret;
}
void PassInstance::beginChangeStatesSilently() {
_dontNotify = true;
}
void PassInstance::endChangeStatesSilently() {
_dontNotify = false;
}
void PassInstance::syncBatchingScheme() {
_defines["USE_INSTANCING"] = false;
_batchingScheme = scene::BatchingSchemes::NONE;
}
void PassInstance::onStateChange() {
_hash = scene::Pass::getPassHash(this);
_owner->onPassStateChange(_dontNotify);
}
} // namespace cc

View File

@@ -0,0 +1,83 @@
/****************************************************************************
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 "base/std/optional.h"
#include "scene/Pass.h"
namespace cc {
class MaterialInstance;
/**
* @en A pass instance defines an variant version of the [[Pass]]
* @zh 表示 [[Pass]] 的一种特殊实例
*/
class PassInstance final : public scene::Pass {
public:
using Super = scene::Pass;
PassInstance(scene::Pass *parent, MaterialInstance *owner);
~PassInstance() override;
/**
* @en The parent pass
* @zh 相关联的原始 Pass
*/
scene::Pass *getParent() const;
/**
* @en Override pipeline states with the given pass override info.
* This won't affect the original pass
* @zh 重载当前 Pass 的管线状态。这不会影响原始 Pass
* @param original The original pass info
* @param value The override pipeline state info
*/
void overridePipelineStates(const IPassInfo &original, const PassOverrides &override) override;
bool tryCompile(const ccstd::optional<MacroRecord> &defineOverrides) override;
/**
* @en Prepare to change states of the pass and do not notify the material to rebuild the pipeline state object
* @zh 开始静默修改 Pass 相关状态,不会通知材质去重新构建管线状态对象。
*/
void beginChangeStatesSilently() override;
/**
* @en End the silent states changing process, all state changes will be notified.
* @zh 结束静默状态修改,所有修改将会开始通知材质。
*/
void endChangeStatesSilently() override;
protected:
void syncBatchingScheme() override;
void onStateChange();
private:
IntrusivePtr<scene::Pass> _parent;
// Weak reference.
MaterialInstance *_owner{nullptr};
bool _dontNotify{false};
};
} // namespace cc

View File

@@ -0,0 +1,365 @@
/****************************************************************************
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 "renderer/core/PassUtils.h"
#include <cstdint>
#include "base/Log.h"
#include "core/Types.h"
#include "core/assets/TextureBase.h"
namespace cc {
const ccstd::unordered_map<gfx::Type, GFXTypeReaderCallback> type2reader = {
{gfx::Type::UNKNOWN, [](const float * /*a*/, MaterialProperty & /*v*/, index_t /*idx*/) {
CC_LOG_ERROR("type2reader unknown type");
}},
{gfx::Type::INT, [](const float *a, MaterialProperty &v, index_t idx) {
v = static_cast<int32_t>(a[idx]);
}},
{gfx::Type::INT2, [](const float *a, MaterialProperty &v, index_t idx) {
v = Vec2(a[idx], a[idx + 1]);
}},
{gfx::Type::INT3, [](const float *a, MaterialProperty &v, index_t idx) {
v = Vec3(a[idx], a[idx + 1], a[idx + 2]);
}},
{gfx::Type::INT4, [](const float *a, MaterialProperty &v, index_t idx) {
v = Vec4(a[idx], a[idx + 1], a[idx + 2], a[idx + 3]);
}},
{gfx::Type::FLOAT, [](const float *a, MaterialProperty &v, index_t idx) {
v = a[idx];
}},
{gfx::Type::FLOAT2, [](const float *a, MaterialProperty &v, index_t idx) {
v = Vec2(a[idx], a[idx + 1]);
}},
{gfx::Type::FLOAT3, [](const float *a, MaterialProperty &v, index_t idx) {
v = Vec3(a[idx], a[idx + 1], a[idx + 2]);
}},
{gfx::Type::FLOAT4, [](const float *a, MaterialProperty &v, index_t idx) {
v = Vec4(a[idx], a[idx + 1], a[idx + 2], a[idx + 3]);
}},
{gfx::Type::MAT3, [](const float *a, MaterialProperty &v, index_t idx) {
Mat3 mat3;
memcpy(&mat3.m[0], &a[idx], sizeof(Mat3));
v = mat3;
}},
{gfx::Type::MAT4, [](const float *a, MaterialProperty &v, index_t idx) {
Mat4 mat4;
memcpy(&mat4.m[0], &a[idx], sizeof(Mat4));
v = mat4;
}},
};
const ccstd::unordered_map<gfx::Type, GFXTypeWriterCallback> type2writer = {
{gfx::Type::UNKNOWN, [](float * /*a*/, const MaterialProperty & /*v*/, index_t /*idx*/) {
CC_LOG_ERROR("type2writer unknown type");
}},
{gfx::Type::INT, [](float *a, const MaterialProperty &v, index_t idx) {
const int32_t *p = ccstd::get_if<int32_t>(&v);
CC_ASSERT_NOT_NULL(p);
a[idx] = static_cast<float>(*p);
}},
{gfx::Type::INT2, [](float *a, const MaterialProperty &v, index_t idx) {
const auto *p = ccstd::get_if<Vec2>(&v);
CC_ASSERT_NOT_NULL(p);
a[idx] = p->x;
a[idx + 1] = p->y;
}},
{gfx::Type::INT3, [](float *a, const MaterialProperty &v, index_t idx) {
const auto *p = ccstd::get_if<Vec3>(&v);
CC_ASSERT_NOT_NULL(p);
a[idx] = p->x;
a[idx + 1] = p->y;
a[idx + 2] = p->z;
}},
{gfx::Type::INT4, [](float *a, const MaterialProperty &v, index_t idx) {
const auto *p = ccstd::get_if<Vec4>(&v);
CC_ASSERT_NOT_NULL(p);
a[idx] = p->x;
a[idx + 1] = p->y;
a[idx + 2] = p->z;
a[idx + 3] = p->w;
}},
{gfx::Type::FLOAT, [](float *a, const MaterialProperty &v, index_t idx) {
const float *p = ccstd::get_if<float>(&v);
const int32_t *pInt = nullptr;
if (p != nullptr) {
a[idx] = *p;
} else {
pInt = ccstd::get_if<int32_t>(&v);
if (pInt != nullptr) {
a[idx] = static_cast<float>(*pInt);
}
}
CC_ASSERT(p != nullptr || pInt != nullptr);
}},
{gfx::Type::FLOAT2, [](float *a, const MaterialProperty &v, index_t idx) {
const auto *p = ccstd::get_if<Vec2>(&v);
CC_ASSERT_NOT_NULL(p);
a[idx] = p->x;
a[idx + 1] = p->y;
}},
{gfx::Type::FLOAT3, [](float *a, const MaterialProperty &v, index_t idx) {
if (ccstd::holds_alternative<Vec3>(v)) {
const auto &vec3 = ccstd::get<Vec3>(v);
a[idx] = vec3.x;
a[idx + 1] = vec3.y;
a[idx + 2] = vec3.z;
} else {
CC_ABORT();
}
}},
{gfx::Type::FLOAT4, [](float *a, const MaterialProperty &v, index_t idx) {
if (ccstd::holds_alternative<Vec4>(v)) {
const auto &vec4 = ccstd::get<Vec4>(v);
a[idx] = vec4.x;
a[idx + 1] = vec4.y;
a[idx + 2] = vec4.z;
a[idx + 3] = vec4.w;
} else if (ccstd::holds_alternative<Color>(v)) {
const auto &color = ccstd::get<Color>(v);
Vec4 colorFloat{color.toVec4()};
a[idx] = colorFloat.x;
a[idx + 1] = colorFloat.y;
a[idx + 2] = colorFloat.z;
a[idx + 3] = colorFloat.w;
} else if (ccstd::holds_alternative<Quaternion>(v)) {
const auto &quat = ccstd::get<Quaternion>(v);
a[idx] = quat.x;
a[idx + 1] = quat.y;
a[idx + 2] = quat.z;
a[idx + 3] = quat.w;
} else {
CC_ABORT();
}
}},
{gfx::Type::MAT3, [](float *a, const MaterialProperty &v, index_t idx) {
const auto *p = ccstd::get_if<Mat3>(&v);
CC_ASSERT_NOT_NULL(p);
memcpy(&a[idx], &p->m[0], sizeof(Mat3));
}},
{gfx::Type::MAT4, [](float *a, const MaterialProperty &v, index_t idx) {
const auto *p = ccstd::get_if<Mat4>(&v);
CC_ASSERT_NOT_NULL(p);
memcpy(&a[idx], &p->m[0], sizeof(Mat4));
}},
};
const ccstd::unordered_map<gfx::Type, GFXTypeValidatorCallback> type2validator = {
{gfx::Type::UNKNOWN, [](const MaterialProperty & /*v*/) -> bool {
CC_LOG_ERROR("type2validator unknown type");
return false;
}},
{gfx::Type::INT, [](const MaterialProperty &v) -> bool {
const auto *p = ccstd::get_if<int32_t>(&v);
return p != nullptr;
}},
{gfx::Type::INT2, [](const MaterialProperty &v) -> bool {
const auto *p = ccstd::get_if<Vec2>(&v);
return p != nullptr;
}},
{gfx::Type::INT3, [](const MaterialProperty &v) -> bool {
const auto *p = ccstd::get_if<Vec3>(&v);
return p != nullptr;
}},
{gfx::Type::INT4, [](const MaterialProperty &v) -> bool {
const auto *p = ccstd::get_if<Vec4>(&v);
return p != nullptr;
}},
{gfx::Type::FLOAT, [](const MaterialProperty &v) -> bool {
const auto *p = ccstd::get_if<float>(&v);
const auto *pInt = ccstd::get_if<int32_t>(&v);
return p != nullptr || pInt != nullptr;
}},
{gfx::Type::FLOAT2, [](const MaterialProperty &v) -> bool {
const auto *p = ccstd::get_if<Vec2>(&v);
return p != nullptr;
}},
{gfx::Type::FLOAT3, [](const MaterialProperty &v) -> bool {
const auto *p = ccstd::get_if<Vec3>(&v);
return p != nullptr;
}},
{gfx::Type::FLOAT4, [](const MaterialProperty &v) -> bool {
const auto *p = ccstd::get_if<Vec4>(&v);
const auto *pColor = ccstd::get_if<Color>(&v);
const auto *pQuat = ccstd::get_if<Quaternion>(&v);
return p != nullptr || pColor != nullptr || pQuat != nullptr;
}},
{gfx::Type::MAT3, [](const MaterialProperty &v) -> bool {
const auto *p = ccstd::get_if<Mat3>(&v);
return p != nullptr;
}},
{gfx::Type::MAT4, [](const MaterialProperty &v) -> bool {
const auto *p = ccstd::get_if<Mat4>(&v);
return p != nullptr;
}},
};
const ccstd::vector<float> &getDefaultFloatArrayFromType(gfx::Type type) {
static const ccstd::vector<float> DEFAULT_FLOAT_VALUES[] = {
{0},
{0, 0},
{0, 0, 0, 0},
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}};
switch (type) {
case gfx::Type::BOOL:
case gfx::Type::INT:
case gfx::Type::UINT:
case gfx::Type::FLOAT:
return DEFAULT_FLOAT_VALUES[0];
case gfx::Type::BOOL2:
case gfx::Type::INT2:
case gfx::Type::UINT2:
case gfx::Type::FLOAT2:
return DEFAULT_FLOAT_VALUES[1];
case gfx::Type::BOOL4:
case gfx::Type::INT4:
case gfx::Type::UINT4:
case gfx::Type::FLOAT4:
return DEFAULT_FLOAT_VALUES[2];
case gfx::Type::MAT4:
return DEFAULT_FLOAT_VALUES[3];
default:
return DEFAULT_FLOAT_VALUES[0];
}
}
const ccstd::string &getDefaultStringFromType(gfx::Type type) {
static const ccstd::string DEFAULT_TEXTURE_STR{"default-texture"};
static const ccstd::string DEFAULT_CUBE_TEXTURE_STR{"default-cube-texture"};
switch (type) {
case gfx::Type::SAMPLER2D:
return DEFAULT_TEXTURE_STR;
case gfx::Type::SAMPLER_CUBE:
return DEFAULT_CUBE_TEXTURE_STR;
default:
return DEFAULT_TEXTURE_STR;
}
}
const ccstd::string &getStringFromType(gfx::Type type) {
static const ccstd::string TEXTURE_2D_STR{"-texture"};
static const ccstd::string TEXTURE_CUBE_STR{"-cube-texture"};
static const ccstd::string TEXTURE_2D_ARRAY_STR{"-array-texture"};
static const ccstd::string TEXTURE_3D_STR{"-3d-texture"};
static const ccstd::string UNKNOWN_STR{"-unknown"};
switch (type) {
case gfx::Type::SAMPLER2D:
return TEXTURE_2D_STR;
case gfx::Type::SAMPLER_CUBE:
return TEXTURE_CUBE_STR;
case gfx::Type::SAMPLER2D_ARRAY:
return TEXTURE_2D_ARRAY_STR;
case gfx::Type::SAMPLER3D:
return TEXTURE_3D_STR;
default:
return UNKNOWN_STR;
}
}
bool overrideMacros(MacroRecord &target, const MacroRecord &source) {
bool isDifferent = false;
for (const auto &p : source) {
if (target[p.first] != p.second) {
target[p.first] = p.second;
isDifferent = true;
}
}
return isDifferent;
}
MaterialProperty toMaterialProperty(gfx::Type type, const ccstd::vector<float> &vec) {
MaterialProperty ret;
size_t size = vec.size();
switch (type) {
case gfx::Type::FLOAT:
CC_ASSERT_GE(size, 1);
ret = vec[0];
break;
case gfx::Type::FLOAT2:
CC_ASSERT_GE(size, 2);
ret = Vec2(vec[0], vec[1]);
break;
case gfx::Type::FLOAT3:
CC_ASSERT_GE(size, 3);
ret = Vec3(vec[0], vec[1], vec[2]);
break;
case gfx::Type::FLOAT4:
CC_ASSERT_GE(size, 4);
ret = Vec4(vec[0], vec[1], vec[2], vec[3]);
break;
case gfx::Type::MAT3:
CC_ASSERT_GE(size, 9);
ret = Mat3(vec.data());
break;
case gfx::Type::MAT4:
CC_ASSERT_GE(size, 16);
ret = Mat4(vec.data());
break;
case gfx::Type::INT:
case gfx::Type::INT2:
case gfx::Type::INT3:
case gfx::Type::INT4:
default:
CC_ABORT();
break;
}
return ret;
}
bool macroRecordAsBool(const MacroRecord::mapped_type &v) {
if (ccstd::holds_alternative<bool>(v)) {
return ccstd::get<bool>(v);
}
if (ccstd::holds_alternative<int32_t>(v)) {
return ccstd::get<int32_t>(v) != 0;
}
if (ccstd::holds_alternative<ccstd::string>(v)) {
return ccstd::get<ccstd::string>(v) == "true";
}
return false;
}
ccstd::string macroRecordAsString(const MacroRecord::mapped_type &v) {
if (ccstd::holds_alternative<ccstd::string>(v)) {
return ccstd::get<ccstd::string>(v);
}
if (ccstd::holds_alternative<bool>(v)) {
return ccstd::get<bool>(v) ? "1" : "0";
}
if (ccstd::holds_alternative<int32_t>(v)) {
return std::to_string(ccstd::get<int32_t>(v));
}
return "";
}
}; // namespace cc

View File

@@ -0,0 +1,118 @@
/****************************************************************************
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 "base/Ptr.h"
#include "base/std/container/string.h"
#include "base/std/container/vector.h"
#include "base/std/variant.h"
#include "math/Color.h"
#include "math/Mat3.h"
#include "math/Mat4.h"
#include "math/Quaternion.h"
#include "math/Vec2.h"
#include "math/Vec3.h"
#include "math/Vec4.h"
#include "renderer/gfx-base/GFXDef.h"
#include "renderer/gfx-base/GFXTexture.h"
namespace cc {
class TextureBase;
constexpr uint32_t TYPE_MASK = 0xfc000000; // 6 bits => 64 types
constexpr uint32_t BINDING_MASK = 0x03f00000; // 6 bits => 64 bindings
constexpr uint32_t COUNT_MASK = 0x000ff000; // 8 bits => 256 vectors
constexpr uint32_t OFFSET_MASK = 0x00000fff; // 12 bits => 1024 vectors
constexpr uint32_t genHandle(uint32_t binding, gfx::Type type, uint32_t count, uint32_t offset = 0) {
return ((static_cast<uint32_t>(type) << 26) & TYPE_MASK) |
((binding << 20) & BINDING_MASK) |
((count << 12) & COUNT_MASK) |
(offset & OFFSET_MASK);
}
constexpr gfx::Type getTypeFromHandle(uint32_t handle) { return static_cast<gfx::Type>((handle & TYPE_MASK) >> 26); }
constexpr uint32_t getBindingFromHandle(uint32_t handle) { return (handle & BINDING_MASK) >> 20; }
constexpr uint32_t getCountFromHandle(uint32_t handle) { return (handle & COUNT_MASK) >> 12; }
constexpr uint32_t getOffsetFromHandle(uint32_t handle) { return (handle & OFFSET_MASK); }
constexpr uint32_t customizeType(uint32_t handle, gfx::Type type) {
return (handle & ~TYPE_MASK) | ((static_cast<uint32_t>(type) << 26) & TYPE_MASK);
}
using MacroValue = ccstd::variant<ccstd::monostate, int32_t, bool, ccstd::string>;
/**
* @en Combination of preprocess macros
* @zh 预处理宏组合
*/
using MacroRecord = ccstd::unordered_map<ccstd::string, MacroValue>;
using MaterialProperty = ccstd::variant<ccstd::monostate /*0*/, float /*1*/, int32_t /*2*/, Vec2 /*3*/, Vec3 /*4*/, Vec4 /*5*/, Color, /*6*/ Mat3 /*7*/, Mat4 /*8*/, Quaternion /*9*/, IntrusivePtr<TextureBase> /*10*/, IntrusivePtr<gfx::Texture> /*11*/>;
using MaterialPropertyList = ccstd::vector<MaterialProperty>;
using MaterialPropertyVariant = ccstd::variant<ccstd::monostate /*0*/, MaterialProperty /*1*/, MaterialPropertyList /*2*/>;
#define MATERIAL_PROPERTY_INDEX_SINGLE 1
#define MATERIAL_PROPERTY_INDEX_LIST 2
using GFXTypeReaderCallback = void (*)(const float *, MaterialProperty &, index_t);
using GFXTypeWriterCallback = void (*)(float *, const MaterialProperty &, index_t);
using GFXTypeValidatorCallback = bool (*)(const MaterialProperty &);
extern const ccstd::unordered_map<gfx::Type, GFXTypeReaderCallback> type2reader; // NOLINT(readability-identifier-naming)
extern const ccstd::unordered_map<gfx::Type, GFXTypeWriterCallback> type2writer; // NOLINT(readability-identifier-naming)
extern const ccstd::unordered_map<gfx::Type, GFXTypeValidatorCallback> type2validator; // NOLINT(readability-identifier-naming)
/**
* @en Gets the default values for the given type of uniform
* @zh 根据指定的 Uniform 类型来获取默认值
* @param type The type of the uniform
*/
const ccstd::vector<float> &getDefaultFloatArrayFromType(gfx::Type type);
const ccstd::string &getDefaultStringFromType(gfx::Type type);
const ccstd::string &getStringFromType(gfx::Type type);
/**
* @en Combination of preprocess macros
* @zh 预处理宏组合
*/
/**
* @en Override the preprocess macros
* @zh 覆写预处理宏
* @param target Target preprocess macros to be overridden
* @param source Preprocess macros used for override
*/
bool overrideMacros(MacroRecord &target, const MacroRecord &source);
MaterialProperty toMaterialProperty(gfx::Type type, const ccstd::vector<float> &vec);
bool macroRecordAsBool(const MacroRecord::mapped_type &v);
ccstd::string macroRecordAsString(const MacroRecord::mapped_type &v);
} // namespace cc

View File

@@ -0,0 +1,498 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "renderer/core/ProgramLib.h"
#include <algorithm>
#include <cstdint>
#include <numeric>
#include <ostream>
#include "ProgramUtils.h"
#include "base/Log.h"
#include "core/assets/EffectAsset.h"
#include "renderer/gfx-base/GFXDevice.h"
#include "renderer/pipeline/custom/RenderInterfaceTypes.h"
namespace cc {
namespace {
void insertBuiltinBindings(const IProgramInfo &tmpl, ITemplateInfo &tmplInfo, const pipeline::DescriptorSetLayoutInfos &source,
const ccstd::string &type, ccstd::vector<gfx::DescriptorSetLayoutBinding> *outBindings) {
CC_ASSERT(type == "locals" || type == "globals");
const auto &target = type == "globals" ? tmpl.builtins.globals : tmpl.builtins.locals;
// Blocks
ccstd::vector<gfx::UniformBlock> tempBlocks{};
for (const auto &b : target.blocks) {
auto infoIt = source.blocks.find(b.name);
if (infoIt == source.blocks.end()) {
CC_LOG_WARNING("builtin UBO '%s' not available !", b.name.c_str());
continue;
}
const auto &info = infoIt->second;
const auto bindingsIter = std::find_if(source.bindings.begin(), source.bindings.end(), [&info](const auto &bd) -> bool { return bd.binding == info.binding; });
if (bindingsIter == source.bindings.end()) {
CC_LOG_WARNING("builtin UBO '%s' not available !", b.name.c_str());
continue;
}
tempBlocks.emplace_back(info);
if (outBindings != nullptr && std::count_if(outBindings->begin(), outBindings->end(), [&bindingsIter](const auto &b) { return b.binding == bindingsIter->binding; }) == 0) {
outBindings->emplace_back(*bindingsIter);
}
}
tmplInfo.shaderInfo.blocks.insert(tmplInfo.shaderInfo.blocks.begin(), tempBlocks.begin(), tempBlocks.end());
// SamplerTextures
ccstd::vector<gfx::UniformSamplerTexture> tempSamplerTextures;
for (const auto &s : target.samplerTextures) {
auto infoIt = source.samplers.find(s.name);
if (infoIt == source.samplers.end()) {
CC_LOG_WARNING("builtin samplerTexture '%s' not available !", s.name.c_str());
continue;
}
const auto &info = infoIt->second;
const auto binding = std::find_if(source.bindings.begin(), source.bindings.end(), [&info](const auto &bd) {
return bd.binding == info.binding;
});
if (binding == source.bindings.end() || !(binding->descriptorType & gfx::DESCRIPTOR_SAMPLER_TYPE)) {
CC_LOG_WARNING("builtin samplerTexture '%s' not available !", s.name.c_str());
continue;
}
tempSamplerTextures.emplace_back(info);
if (outBindings != nullptr && std::count_if(outBindings->begin(), outBindings->end(), [&binding](const auto &b) { return b.binding == binding->binding; }) == 0) {
outBindings->emplace_back(*binding);
}
}
tmplInfo.shaderInfo.samplerTextures.insert(tmplInfo.shaderInfo.samplerTextures.begin(), tempSamplerTextures.begin(), tempSamplerTextures.end());
if (outBindings != nullptr) {
std::stable_sort(outBindings->begin(), outBindings->end(), [](const auto &a, const auto &b) {
return a.binding < b.binding;
});
}
}
int32_t getSize(const IBlockInfo &block) {
auto s = 0;
for (const auto &m : block.members) {
s += static_cast<int>(getTypeSize(m.type) * m.count);
}
return s;
}
} // namespace
const char *getDeviceShaderVersion(const gfx::Device *device) {
switch (device->getGfxAPI()) {
case gfx::API::GLES2:
case gfx::API::WEBGL:
return "glsl1";
case gfx::API::GLES3:
case gfx::API::WEBGL2:
return "glsl3";
default:
return "glsl4";
}
}
//
static void copyDefines(const ccstd::vector<IDefineInfo> &from, ccstd::vector<IDefineRecord> &to) {
to.resize(from.size());
for (size_t i = 0, len = from.size(); i < len; ++i) {
to[i].name = from[i].name;
to[i].type = from[i].type;
to[i].range = from[i].range;
to[i].options = from[i].options;
to[i].defaultVal = from[i].defaultVal;
}
}
// IProgramInfo
void IProgramInfo::copyFrom(const IShaderInfo &o) {
name = o.name;
hash = o.hash;
glsl4 = o.glsl4;
glsl3 = o.glsl3;
glsl1 = o.glsl1;
builtins = o.builtins;
copyDefines(o.defines, defines);
blocks = o.blocks;
samplerTextures = o.samplerTextures;
attributes = o.attributes;
samplers = o.samplers;
textures = o.textures;
buffers = o.buffers;
images = o.images;
subpassInputs = o.subpassInputs;
descriptors = o.descriptors;
}
ProgramLib::ProgramLib() {
ProgramLib::instance = this;
}
ProgramLib::~ProgramLib() {
ProgramLib::instance = nullptr;
#if CC_DEBUG
for (const auto &cache : _cache) {
if (cache.second->getRefCount() > 1) {
CC_LOG_WARNING("ProgramLib cache: %s ref_count is %d and may leak", cache.second->getName().c_str(), cache.second->getRefCount());
}
}
#endif
}
//
/*static*/
ProgramLib *ProgramLib::instance = nullptr;
ProgramLib *ProgramLib::getInstance() {
return ProgramLib::instance;
}
void ProgramLib::registerEffect(EffectAsset *effect) {
for (auto &shader : effect->_shaders) {
auto *tmpl = define(shader);
tmpl->effectName = effect->getName();
}
render::addEffectDefaultProperties(*effect);
}
IProgramInfo *ProgramLib::define(IShaderInfo &shader) {
auto itCurrTmpl = _templates.find(shader.name);
if (itCurrTmpl != _templates.end() && itCurrTmpl->second.hash == shader.hash) {
return &itCurrTmpl->second;
}
IProgramInfo &tmpl = _templates[shader.name];
tmpl.copyFrom(shader);
render::populateMacros(tmpl);
if (_templateInfos.count(tmpl.hash) == 0) {
ITemplateInfo tmplInfo{};
// cache material-specific descriptor set layout
tmplInfo.samplerStartBinding = static_cast<int32_t>(tmpl.blocks.size());
tmplInfo.bindings = {};
tmplInfo.blockSizes = {};
for (const auto &block : tmpl.blocks) {
tmplInfo.blockSizes.emplace_back(getSize(block));
tmplInfo.bindings.emplace_back();
auto &bindingsInfo = tmplInfo.bindings.back();
bindingsInfo.binding = block.binding;
bindingsInfo.descriptorType = gfx::DescriptorType::UNIFORM_BUFFER;
bindingsInfo.count = 1;
bindingsInfo.stageFlags = block.stageFlags;
ccstd::vector<gfx::Uniform> uniforms;
{
// construct uniforms
uniforms.reserve(block.members.size());
for (const auto &member : block.members) {
uniforms.emplace_back();
auto &info = uniforms.back();
info.name = member.name;
info.type = member.type;
info.count = member.count;
}
}
tmplInfo.shaderInfo.blocks.emplace_back();
auto &blocksInfo = tmplInfo.shaderInfo.blocks.back();
blocksInfo.set = static_cast<uint32_t>(pipeline::SetIndex::MATERIAL);
blocksInfo.binding = block.binding;
blocksInfo.name = block.name;
blocksInfo.members = uniforms;
blocksInfo.count = 1; // effect compiler guarantees block count = 1
}
for (const auto &samplerTexture : tmpl.samplerTextures) {
tmplInfo.bindings.emplace_back();
auto &descriptorLayoutBindingInfo = tmplInfo.bindings.back();
descriptorLayoutBindingInfo.binding = samplerTexture.binding;
descriptorLayoutBindingInfo.descriptorType = gfx::DescriptorType::SAMPLER_TEXTURE;
descriptorLayoutBindingInfo.count = samplerTexture.count;
descriptorLayoutBindingInfo.stageFlags = samplerTexture.stageFlags;
tmplInfo.shaderInfo.samplerTextures.emplace_back();
auto &samplerTextureInfo = tmplInfo.shaderInfo.samplerTextures.back();
samplerTextureInfo.set = static_cast<uint32_t>(pipeline::SetIndex::MATERIAL);
samplerTextureInfo.binding = samplerTexture.binding;
samplerTextureInfo.name = samplerTexture.name;
samplerTextureInfo.type = samplerTexture.type;
samplerTextureInfo.count = samplerTexture.count;
}
for (const auto &sampler : tmpl.samplers) {
tmplInfo.bindings.emplace_back(gfx::DescriptorSetLayoutBinding{
sampler.binding,
gfx::DescriptorType::SAMPLER,
sampler.count,
sampler.stageFlags});
tmplInfo.shaderInfo.samplers.emplace_back(gfx::UniformSampler{
static_cast<uint32_t>(pipeline::SetIndex::MATERIAL),
sampler.binding,
sampler.name,
sampler.count,
});
}
for (const auto &texture : tmpl.textures) {
tmplInfo.bindings.emplace_back(gfx::DescriptorSetLayoutBinding{
texture.binding,
gfx::DescriptorType::TEXTURE,
texture.count,
texture.stageFlags});
tmplInfo.shaderInfo.textures.emplace_back(gfx::UniformTexture{
static_cast<uint32_t>(pipeline::SetIndex::MATERIAL),
texture.binding,
texture.name,
texture.type,
texture.count,
});
}
for (const auto &buffer : tmpl.buffers) {
tmplInfo.bindings.emplace_back(gfx::DescriptorSetLayoutBinding{
buffer.binding,
gfx::DescriptorType::STORAGE_BUFFER,
1,
buffer.stageFlags});
tmplInfo.shaderInfo.buffers.emplace_back(gfx::UniformStorageBuffer{
static_cast<uint32_t>(pipeline::SetIndex::MATERIAL),
buffer.binding,
buffer.name,
1,
buffer.memoryAccess}); // effect compiler guarantees buffer count = 1
}
for (const auto &image : tmpl.images) {
tmplInfo.bindings.emplace_back(gfx::DescriptorSetLayoutBinding{
image.binding,
gfx::DescriptorType::STORAGE_IMAGE,
image.count,
image.stageFlags});
tmplInfo.shaderInfo.images.emplace_back(gfx::UniformStorageImage{
static_cast<uint32_t>(pipeline::SetIndex::MATERIAL),
image.binding,
image.name,
image.type,
image.count,
image.memoryAccess});
}
for (const auto &subpassInput : tmpl.subpassInputs) {
tmplInfo.bindings.emplace_back(gfx::DescriptorSetLayoutBinding{
subpassInput.binding,
gfx::DescriptorType::INPUT_ATTACHMENT,
subpassInput.count,
subpassInput.stageFlags});
tmplInfo.shaderInfo.subpassInputs.emplace_back(gfx::UniformInputAttachment{
static_cast<uint32_t>(pipeline::SetIndex::MATERIAL),
subpassInput.binding,
subpassInput.name,
subpassInput.count});
}
tmplInfo.gfxAttributes = {};
for (auto &attr : tmpl.attributes) {
tmplInfo.gfxAttributes.emplace_back();
auto &info = tmplInfo.gfxAttributes.back();
info.name = attr.name;
info.format = attr.format;
info.isNormalized = attr.isNormalized;
info.stream = 0;
info.isInstanced = attr.isInstanced;
info.location = attr.location;
}
insertBuiltinBindings(tmpl, tmplInfo, pipeline::localDescriptorSetLayout, "locals", nullptr);
tmplInfo.shaderInfo.stages.emplace_back();
auto &vertexShaderInfo = tmplInfo.shaderInfo.stages.back();
vertexShaderInfo.stage = gfx::ShaderStageFlagBit::VERTEX;
vertexShaderInfo.source = "";
tmplInfo.shaderInfo.stages.emplace_back();
auto &fragmentShaderInfo = tmplInfo.shaderInfo.stages.back();
fragmentShaderInfo.stage = gfx::ShaderStageFlagBit::FRAGMENT;
fragmentShaderInfo.source = "";
tmplInfo.handleMap = render::genHandles(tmpl);
tmplInfo.setLayouts = {};
_templateInfos[tmpl.hash] = tmplInfo;
}
return &tmpl;
}
/**
* @en Gets the shader template with its name
* @zh 通过名字获取 Shader 模板
* @param name Target shader name
*/
const IProgramInfo *ProgramLib::getTemplate(const ccstd::string &name) const {
auto it = _templates.find(name);
return it != _templates.end() ? &it->second : nullptr;
}
/**
* @en Gets the shader template info with its name
* @zh 通过名字获取 Shader 模版信息
* @param name Target shader name
*/
ITemplateInfo *ProgramLib::getTemplateInfo(const ccstd::string &name) {
auto it = _templates.find(name);
CC_ASSERT(it != _templates.end());
auto hash = it->second.hash;
auto itInfo = _templateInfos.find(hash);
return itInfo != _templateInfos.end() ? &itInfo->second : nullptr;
}
/**
* @en Gets the pipeline layout of the shader template given its name
* @zh 通过名字获取 Shader 模板相关联的管线布局
* @param name Target shader name
*/
gfx::DescriptorSetLayout *ProgramLib::getDescriptorSetLayout(gfx::Device *device, const ccstd::string &name, bool isLocal) {
auto itTmpl = _templates.find(name);
CC_ASSERT(itTmpl != _templates.end());
const auto &tmpl = itTmpl->second;
auto itTplInfo = _templateInfos.find(tmpl.hash);
if (itTplInfo == _templateInfos.end()) {
return nullptr;
}
auto &tmplInfo = itTplInfo->second;
if (tmplInfo.setLayouts.empty()) {
gfx::DescriptorSetLayoutInfo info;
tmplInfo.setLayouts.resize(static_cast<size_t>(pipeline::SetIndex::COUNT));
info.bindings = tmplInfo.bindings;
tmplInfo.setLayouts.replace(static_cast<index_t>(pipeline::SetIndex::MATERIAL), device->createDescriptorSetLayout(info));
info.bindings = pipeline::localDescriptorSetLayout.bindings;
tmplInfo.setLayouts.replace(static_cast<index_t>(pipeline::SetIndex::LOCAL), device->createDescriptorSetLayout(info));
}
return tmplInfo.setLayouts.at(isLocal ? static_cast<uint32_t>(pipeline::SetIndex::LOCAL) : static_cast<uint32_t>(pipeline::SetIndex::MATERIAL));
}
ccstd::string ProgramLib::getKey(const ccstd::string &name, const MacroRecord &defines) {
auto itTpl = _templates.find(name);
CC_ASSERT(itTpl != _templates.end());
auto &tmpl = itTpl->second;
return render::getVariantKey(tmpl, defines);
}
void ProgramLib::destroyShaderByDefines(const MacroRecord &defines) {
if (defines.empty()) return;
ccstd::vector<ccstd::string> defineValues;
for (const auto &i : defines) {
defineValues.emplace_back(i.first + macroRecordAsString(i.second));
}
ccstd::vector<ccstd::string> matchedKeys;
for (const auto &i : _cache) {
bool matched = true;
for (const auto &v : defineValues) {
if (i.first.find(v) == ccstd::string::npos) {
matched = false;
break;
}
}
if (matched) {
matchedKeys.emplace_back(i.first);
}
}
for (const auto &key : matchedKeys) {
CC_LOG_DEBUG("destroyed shader %s", key.c_str());
_cache[key]->destroy();
_cache.erase(key);
}
}
gfx::Shader *ProgramLib::getGFXShader(gfx::Device *device, const ccstd::string &name, MacroRecord &defines,
render::PipelineRuntime *pipeline, ccstd::string *keyOut) {
for (const auto &it : pipeline->getMacros()) {
defines[it.first] = it.second;
}
ccstd::string key;
if (!keyOut) {
key = getKey(name, defines);
} else {
key = *keyOut;
}
auto itRes = _cache.find(key);
if (itRes != _cache.end()) {
// CC_LOG_DEBUG("Found ProgramLib::_cache[%s]=%p, defines: %d", key.c_str(), itRes->second, defines.size());
return itRes->second;
}
auto itTpl = _templates.find(name);
CC_ASSERT(itTpl != _templates.end());
const auto &tmpl = itTpl->second;
const auto itTplInfo = _templateInfos.find(tmpl.hash);
CC_ASSERT(itTplInfo != _templateInfos.end());
auto &tmplInfo = itTplInfo->second;
if (!tmplInfo.pipelineLayout) {
getDescriptorSetLayout(device, name); // ensure set layouts have been created
insertBuiltinBindings(tmpl, tmplInfo, pipeline::globalDescriptorSetLayout, "globals", nullptr);
tmplInfo.setLayouts.replace(static_cast<index_t>(pipeline::SetIndex::GLOBAL), pipeline->getDescriptorSetLayout());
tmplInfo.pipelineLayout = device->createPipelineLayout(gfx::PipelineLayoutInfo{tmplInfo.setLayouts.get()});
}
ccstd::vector<IMacroInfo> macroArray = render::prepareDefines(defines, tmpl.defines);
std::stringstream ss;
ss << std::endl;
for (const auto &m : macroArray) {
ss << "#define " << m.name << " " << m.value << std::endl;
}
auto prefix = pipeline->getConstantMacros() + tmpl.constantMacros + ss.str();
const IShaderSource *src = &tmpl.glsl3;
const auto *deviceShaderVersion = getDeviceShaderVersion(device);
if (deviceShaderVersion) {
src = tmpl.getSource(deviceShaderVersion);
} else {
CC_LOG_ERROR("Invalid GFX API!");
}
tmplInfo.shaderInfo.stages[0].source = prefix + src->vert;
tmplInfo.shaderInfo.stages[1].source = prefix + src->frag;
// strip out the active attributes only, instancing depend on this
tmplInfo.shaderInfo.attributes = render::getActiveAttributes(tmpl, tmplInfo.gfxAttributes, defines);
tmplInfo.shaderInfo.name = render::getShaderInstanceName(name, macroArray);
tmplInfo.shaderInfo.hash = tmpl.hash;
auto *shader = device->createShader(tmplInfo.shaderInfo);
_cache[key] = shader;
// CC_LOG_DEBUG("ProgramLib::_cache[%s]=%p, defines: %d", key.c_str(), shader, defines.size());
return shader;
}
} // namespace cc

View File

@@ -0,0 +1,168 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include <cmath>
#include <functional>
#include <numeric>
#include <sstream>
#include "base/RefVector.h"
#include "base/std/container/string.h"
#include "base/std/container/unordered_map.h"
#include "base/std/optional.h"
#include "core/Types.h"
#include "core/assets/EffectAsset.h"
#include "renderer/gfx-base/GFXDef-common.h"
#include "renderer/pipeline/Define.h"
#include "renderer/pipeline/RenderPipeline.h"
namespace cc {
class EffectAsset;
namespace render {
class PipelineRuntime;
} // namespace render
struct IDefineRecord : public IDefineInfo {
std::function<int32_t(const MacroValue &)> map{nullptr};
int32_t offset{0};
};
struct IMacroInfo {
ccstd::string name;
ccstd::string value;
bool isDefault{false};
};
struct ITemplateInfo {
ccstd::vector<gfx::Attribute> gfxAttributes;
gfx::ShaderInfo shaderInfo;
ccstd::vector<int32_t> blockSizes;
RefVector<gfx::DescriptorSetLayout *> setLayouts;
IntrusivePtr<gfx::PipelineLayout> pipelineLayout;
ccstd::unordered_map<ccstd::string, uint32_t> handleMap;
ccstd::vector<gfx::DescriptorSetLayoutBinding> bindings;
int32_t samplerStartBinding{-1};
};
struct IProgramInfo : public IShaderInfo {
ccstd::string effectName;
ccstd::vector<IDefineRecord> defines;
ccstd::string constantMacros;
bool uber{false}; // macro number exceeds default limits, will fallback to string hash
void copyFrom(const IShaderInfo &o);
};
const char *getDeviceShaderVersion(const gfx::Device *device);
/**
* @en The global maintainer of all shader resources.
* @zh 维护 shader 资源实例的全局管理器。
*/
class ProgramLib final {
public:
static ProgramLib *getInstance();
ProgramLib();
~ProgramLib();
void registerEffect(EffectAsset *effect);
/**
* @en Register the shader template with the given info
* @zh 注册 shader 模板。
*/
IProgramInfo *define(IShaderInfo &shader);
/**
* @en Gets the shader template with its name
* @zh 通过名字获取 Shader 模板
* @param name Target shader name
*/
const IProgramInfo *getTemplate(const ccstd::string &name) const;
/**
* @en Gets the shader template info with its name
* @zh 通过名字获取 Shader 模版信息
* @param name Target shader name
*/
ITemplateInfo *getTemplateInfo(const ccstd::string &name);
/**
* @en Gets the pipeline layout of the shader template given its name
* @zh 通过名字获取 Shader 模板相关联的管线布局
* @param name Target shader name
*/
gfx::DescriptorSetLayout *getDescriptorSetLayout(gfx::Device *device, const ccstd::string &name, bool isLocal = false);
/**
* @en
* Does this library has the specified program
* @zh
* 当前是否有已注册的指定名字的 shader
* @param name Target shader name
*/
inline bool hasProgram(const ccstd::string &name) const {
return _templates.count(name) > 0;
}
/**
* @en Gets the shader key with the name and a macro combination
* @zh 根据 shader 名和预处理宏列表获取 shader key。
* @param name Target shader name
* @param defines The combination of preprocess macros
*/
ccstd::string getKey(const ccstd::string &name, const MacroRecord &defines);
/**
* @en Destroy all shader instance match the preprocess macros
* @zh 销毁所有完全满足指定预处理宏特征的 shader 实例。
* @param defines The preprocess macros as filter
*/
void destroyShaderByDefines(const MacroRecord &defines);
/**
* @en Gets the shader resource instance with given information
* @zh 获取指定 shader 的渲染资源实例
* @param name Shader name
* @param defines Preprocess macros
* @param pipeline The [[RenderPipeline]] which owns the render command
* @param key The shader cache key, if already known
*/
gfx::Shader *getGFXShader(gfx::Device *device, const ccstd::string &name, MacroRecord &defines,
render::PipelineRuntime *pipeline, ccstd::string *key = nullptr);
private:
CC_DISALLOW_COPY_MOVE_ASSIGN(ProgramLib);
static ProgramLib *instance;
ccstd::unordered_map<ccstd::string, IProgramInfo> _templates; // per shader
ccstd::unordered_map<ccstd::string, IntrusivePtr<gfx::Shader>> _cache;
ccstd::unordered_map<uint64_t, ITemplateInfo> _templateInfos;
};
} // namespace cc

View File

@@ -0,0 +1,264 @@
/****************************************************************************
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 "ProgramUtils.h"
namespace cc {
namespace render {
namespace {
int32_t getBitCount(int32_t cnt) {
return std::ceil(std::log2(std::max(cnt, 2))); // std::max checks number types
}
template <class ShaderInfoT>
ccstd::unordered_map<ccstd::string, uint32_t> genHandlesImpl(const ShaderInfoT &tmpl) {
ccstd::unordered_map<ccstd::string, uint32_t> handleMap{};
// block member handles
for (const auto &block : tmpl.blocks) {
const auto members = block.members;
uint32_t offset = 0;
for (const auto &uniform : members) {
handleMap[uniform.name] = genHandle(block.binding,
uniform.type,
uniform.count,
offset);
offset += (getTypeSize(uniform.type) >> 2) * uniform.count; // assumes no implicit padding, which is guaranteed by effect compiler
}
}
// samplerTexture handles
for (const auto &samplerTexture : tmpl.samplerTextures) {
handleMap[samplerTexture.name] = genHandle(samplerTexture.binding,
samplerTexture.type,
samplerTexture.count);
}
return handleMap;
}
} // namespace
void populateMacros(IProgramInfo &tmpl) {
// calculate option mask offset
int32_t offset = 0;
for (auto &def : tmpl.defines) {
int32_t cnt = 1;
if (def.type == "number") {
auto &range = def.range.value();
cnt = getBitCount(range[1] - range[0] + 1); // inclusive on both ends
def.map = [=](const MacroValue &value) -> int32_t {
if (ccstd::holds_alternative<int32_t>(value)) {
return ccstd::get<int32_t>(value) - range[0];
}
if (ccstd::holds_alternative<bool>(value)) {
return (ccstd::get<bool>(value) ? 1 : 0) - range[0];
}
CC_ABORT(); // We only support macro with int32_t type now.
return 0;
};
} else if (def.type == "string") {
cnt = getBitCount(static_cast<int32_t>(def.options.value().size()));
def.map = [=](const MacroValue &value) -> int32_t {
const auto *pValue = ccstd::get_if<ccstd::string>(&value);
if (pValue != nullptr) {
auto idx = static_cast<int32_t>(std::find(def.options.value().begin(), def.options.value().end(), *pValue) - def.options.value().begin());
return std::max(0, idx);
}
return 0;
};
} else if (def.type == "boolean") {
def.map = [](const MacroValue &value) -> int32_t {
const auto *pBool = ccstd::get_if<bool>(&value);
if (pBool != nullptr) {
return *pBool ? 1 : 0;
}
const auto *pInt = ccstd::get_if<int32_t>(&value);
if (pInt != nullptr) {
return *pInt ? 1 : 0;
}
const auto *pString = ccstd::get_if<ccstd::string>(&value);
if (pString != nullptr) {
return *pString != "0" || !(*pString).empty() ? 1 : 0;
}
return 0;
};
}
def.offset = offset;
offset += cnt;
}
if (offset > 31) {
tmpl.uber = true;
}
// generate constant macros
{
tmpl.constantMacros.clear();
std::stringstream ss;
for (auto &key : tmpl.builtins.statistics) {
ss << "#define " << key.first << " " << key.second << std::endl;
}
tmpl.constantMacros = ss.str();
}
}
ccstd::unordered_map<ccstd::string, uint32_t> genHandles(const IProgramInfo &tmpl) {
return genHandlesImpl(tmpl);
}
ccstd::unordered_map<ccstd::string, uint32_t> genHandles(const gfx::ShaderInfo &tmpl) {
return genHandlesImpl(tmpl);
}
ccstd::string getVariantKey(const IProgramInfo &tmpl, const MacroRecord &defines) {
const auto &tmplDefs = tmpl.defines;
if (tmpl.uber) {
std::stringstream key;
for (const auto &tmplDef : tmplDefs) {
auto itDef = defines.find(tmplDef.name);
if (itDef == defines.end() || !tmplDef.map) {
continue;
}
const auto &value = itDef->second;
auto mapped = tmplDef.map(value);
auto offset = tmplDef.offset;
key << offset << mapped << "|";
}
ccstd::string ret{key.str() + std::to_string(tmpl.hash)};
return ret;
}
uint32_t key = 0;
std::stringstream ss;
for (const auto &tmplDef : tmplDefs) {
auto itDef = defines.find(tmplDef.name);
if (itDef == defines.end() || !tmplDef.map) {
continue;
}
const auto &value = itDef->second;
auto mapped = tmplDef.map(value);
auto offset = tmplDef.offset;
key |= (mapped << offset);
}
ss << std::hex << key << "|" << std::to_string(tmpl.hash);
ccstd::string ret{ss.str()};
return ret;
}
namespace {
ccstd::string mapDefine(const IDefineInfo &info, const ccstd::optional<MacroRecord::mapped_type> &def) {
if (info.type == "boolean") {
return def.has_value() ? (macroRecordAsBool(def.value()) ? "1" : "0") : "0";
}
if (info.type == "string") {
return def.has_value() ? macroRecordAsString(def.value()) : info.options.value()[0];
}
if (info.type == "number") {
return def.has_value() ? macroRecordAsString(def.value()) : std::to_string(info.range.value()[0]);
}
CC_LOG_WARNING("unknown define type '%s', name: %s", info.type.c_str(), info.name.c_str());
return "-1"; // should neven happen
}
bool dependencyCheck(const ccstd::vector<ccstd::string> &dependencies, const MacroRecord &defines) {
for (const auto &d : dependencies) { // NOLINT(readability-use-anyofallof)
if (d[0] == '!') { // negative dependency
if (defines.find(d.substr(1)) != defines.end()) {
return false;
}
} else if (defines.count(d) == 0 ? true : !macroRecordAsBool(defines.at(d))) {
return false;
}
}
return true;
}
template <class Vector>
ccstd::vector<gfx::Attribute> getActiveAttributesImpl(
const IProgramInfo &tmpl,
const Vector &gfxAttributes, const MacroRecord &defines) {
ccstd::vector<gfx::Attribute> out{};
const auto &attributes = tmpl.attributes;
for (auto i = 0; i < attributes.size(); i++) {
if (!dependencyCheck(attributes[i].defines, defines)) {
continue;
}
out.emplace_back(gfxAttributes[i]);
}
return out;
}
} // namespace
ccstd::vector<IMacroInfo> prepareDefines(const MacroRecord &records, const ccstd::vector<IDefineRecord> &defList) {
ccstd::vector<IMacroInfo> macros{};
for (const auto &tmp : defList) {
const auto &name = tmp.name;
auto it = records.find(name);
auto value = mapDefine(tmp, it == records.end() ? ccstd::nullopt : ccstd::optional<MacroValue>(it->second));
bool isDefault = it == records.end() || (ccstd::holds_alternative<ccstd::string>(it->second) && ccstd::get<ccstd::string>(it->second) == "0");
macros.emplace_back();
auto &info = macros.back();
info.name = name;
info.value = value;
info.isDefault = isDefault;
}
return macros;
}
ccstd::vector<gfx::Attribute> getActiveAttributes(
const IProgramInfo &tmpl,
const ccstd::vector<gfx::Attribute> &gfxAttributes, const MacroRecord &defines) {
return getActiveAttributesImpl(tmpl, gfxAttributes, defines);
}
ccstd::vector<gfx::Attribute> getActiveAttributes(
const IProgramInfo &tmpl,
const ccstd::pmr::vector<gfx::Attribute> &gfxAttributes, const MacroRecord &defines) {
return getActiveAttributesImpl(tmpl, gfxAttributes, defines);
}
ccstd::string getShaderInstanceName(const ccstd::string &name, const ccstd::vector<IMacroInfo> &macros) {
std::stringstream ret;
ret << name;
for (const auto &cur : macros) {
if (!cur.isDefault) {
ret << "|" << cur.name << cur.value;
}
}
return ret.str();
}
void addEffectDefaultProperties(EffectAsset &effect) {
for (auto &tech : effect._techniques) {
for (auto &pass : tech.passes) {
// grab default property declaration if there is none
if (pass.propertyIndex.has_value() && !pass.properties.has_value()) {
pass.properties = tech.passes[pass.propertyIndex.value()].properties;
}
}
}
}
} // namespace render
} // namespace cc

View File

@@ -0,0 +1,55 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "cocos/renderer/core/ProgramLib.h"
namespace cc {
namespace render {
void populateMacros(IProgramInfo& tmpl);
ccstd::unordered_map<ccstd::string, uint32_t> genHandles(const IProgramInfo& tmpl);
ccstd::unordered_map<ccstd::string, uint32_t> genHandles(const gfx::ShaderInfo& tmpl);
ccstd::string getVariantKey(const IProgramInfo& tmpl, const MacroRecord& defines);
ccstd::vector<IMacroInfo> prepareDefines(
const MacroRecord& records, const ccstd::vector<IDefineRecord>& defList);
ccstd::vector<gfx::Attribute> getActiveAttributes(
const IProgramInfo& tmpl,
const ccstd::vector<gfx::Attribute>& gfxAttributes, const MacroRecord& defines);
ccstd::vector<gfx::Attribute> getActiveAttributes(
const IProgramInfo& tmpl,
const ccstd::pmr::vector<gfx::Attribute>& gfxAttributes, const MacroRecord& defines);
ccstd::string getShaderInstanceName(
const ccstd::string& name, const ccstd::vector<IMacroInfo>& macros);
void addEffectDefaultProperties(EffectAsset& effect);
} // namespace render
} // namespace cc

View File

@@ -0,0 +1,316 @@
/****************************************************************************
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 "renderer/core/TextureBufferPool.h"
#include <cmath>
#include "core/ArrayBuffer.h"
#include "core/TypedArray.h"
#include "renderer/gfx-base/GFXDevice.h"
namespace {
uint32_t roundUp(uint32_t n, uint32_t alignment) {
return static_cast<uint32_t>(std::ceil(n / alignment)) * alignment;
}
} // namespace
namespace cc {
TextureBufferPool::TextureBufferPool() = default;
TextureBufferPool::TextureBufferPool(gfx::Device *device) {
_device = device;
}
TextureBufferPool::~TextureBufferPool() = default;
void TextureBufferPool::initialize(const ITextureBufferPoolInfo &info) {
const auto &formatInfo = gfx::GFX_FORMAT_INFOS[static_cast<uint32_t>(info.format)];
_format = info.format;
_formatSize = formatInfo.size;
_channels = formatInfo.count;
_roundUpFn = info.roundUpFn.has_value() ? info.roundUpFn.value() : nullptr;
_alignment = info.alignment.has_value() ? info.alignment.value() : 1;
_useMcDonaldAlloc = info.alignment.has_value() && info.alignment.value();
}
void TextureBufferPool::destroy() {
for (auto &chunk : _chunks) {
CC_SAFE_DESTROY_AND_DELETE(chunk.texture);
}
_chunks.clear();
_handles.clear();
}
ITextureBufferHandle TextureBufferPool::alloc(uint32_t size) {
if (_useMcDonaldAlloc) {
return mcDonaldAlloc(size);
}
size = roundUp(size, _alignment);
index_t index = CC_INVALID_INDEX;
index_t start = CC_INVALID_INDEX;
if (start < 0) {
for (index_t i = 0; i < _chunkCount; ++i) {
index = i;
start = findAvailableSpace(size, index);
if (start >= 0) break;
}
}
if (start >= 0) {
auto chunk = _chunks[index];
chunk.start += static_cast<index_t>(size);
ITextureBufferHandle handle;
handle.chunkIdx = index;
handle.start = start;
handle.end = static_cast<index_t>(start + size);
handle.texture = chunk.texture;
_handles.emplace_back(handle);
return handle;
}
// create a new one
auto targetSize = static_cast<int32_t>(std::sqrt(size / _formatSize));
uint32_t texLength = _roundUpFn ? _roundUpFn(targetSize, _formatSize) : std::max(1024, static_cast<int>(utils::nextPOT(targetSize)));
auto newChunk = _chunks[createChunk(texLength)];
newChunk.start += static_cast<index_t>(size);
ITextureBufferHandle texHandle;
texHandle.chunkIdx = static_cast<index_t>(_chunkCount - 1);
texHandle.start = 0;
texHandle.end = static_cast<index_t>(size);
texHandle.texture = newChunk.texture;
_handles.emplace_back(texHandle);
return texHandle;
}
ITextureBufferHandle TextureBufferPool::alloc(uint32_t size, index_t chunkIdx) {
size = roundUp(size, _alignment);
index_t index = chunkIdx;
index_t start = findAvailableSpace(size, index);
if (start < 0) {
for (index_t i = 0; i < _chunkCount; ++i) {
index = i;
start = findAvailableSpace(size, index);
if (start >= 0) break;
}
}
if (start >= 0) {
auto chunk = _chunks[index];
chunk.start += static_cast<index_t>(size);
ITextureBufferHandle handle;
handle.chunkIdx = index;
handle.start = start;
handle.end = static_cast<index_t>(start + size);
handle.texture = chunk.texture;
_handles.emplace_back(handle);
return handle;
}
// create a new one
auto targetSize = static_cast<int32_t>(std::sqrt(size / _formatSize));
uint32_t texLength = _roundUpFn ? _roundUpFn(targetSize, _formatSize) : std::max(1024, static_cast<int>(utils::nextPOT(targetSize)));
auto newChunk = _chunks[createChunk(texLength)];
newChunk.start += static_cast<index_t>(size);
ITextureBufferHandle texHandle;
texHandle.chunkIdx = static_cast<index_t>(_chunkCount - 1);
texHandle.start = 0;
texHandle.end = static_cast<index_t>(size);
texHandle.texture = newChunk.texture;
_handles.emplace_back(texHandle);
return texHandle;
}
void TextureBufferPool::free(const ITextureBufferHandle &handle) {
auto iter = std::find(_handles.begin(), _handles.end(), handle);
if (iter != _handles.end()) {
_chunks[handle.chunkIdx].end = handle.end;
_handles.erase(iter);
}
}
uint32_t TextureBufferPool::createChunk(uint32_t length) {
uint32_t texSize = length * length * _formatSize;
// debug(`TextureBufferPool: Allocate chunk $device->createTexture({gfx::TextureType::TEX2D,
auto *texture = _device->createTexture({gfx::TextureType::TEX2D,
gfx::TextureUsageBit::SAMPLED | gfx::TextureUsageBit::TRANSFER_DST,
_format,
length,
length});
ITextureBuffer chunk;
chunk.texture = texture;
chunk.size = texSize;
chunk.start = 0;
chunk.end = static_cast<index_t>(texSize);
_chunks[_chunkCount] = chunk;
return _chunkCount++;
}
void TextureBufferPool::update(const ITextureBufferHandle &handle, ArrayBuffer *buffer) {
gfx::BufferDataList buffers;
uint8_t *bufferData = buffer->getData();
gfx::BufferTextureCopyList regions;
auto start = static_cast<int32_t>(handle.start / _formatSize);
uint32_t remainSize = buffer->byteLength() / _formatSize;
int32_t offsetX = start % static_cast<int32_t>(handle.texture->getWidth());
int32_t offsetY = std::floor(start / handle.texture->getWidth());
uint32_t copySize = std::min(handle.texture->getWidth() - offsetX, remainSize);
uint32_t begin = 0;
if (offsetX > 0) {
_region0.texOffset.x = offsetX;
_region0.texOffset.y = offsetY;
_region0.texExtent.width = copySize;
_region0.texExtent.height = 1;
buffers.emplace_back(bufferData + begin * _formatSize);
regions.emplace_back(_region0);
offsetX = 0;
offsetY += 1;
remainSize -= copySize;
begin += copySize;
}
if (remainSize > 0) {
_region1.texOffset.x = offsetX;
_region1.texOffset.y = offsetY;
if (remainSize > handle.texture->getWidth()) {
_region1.texExtent.width = handle.texture->getWidth();
_region1.texExtent.height = std::floor(remainSize / handle.texture->getWidth());
copySize = _region1.texExtent.width * _region1.texExtent.height;
} else {
copySize = remainSize;
_region1.texExtent.width = copySize;
_region1.texExtent.height = 1;
}
buffers.emplace_back(bufferData + begin * _formatSize);
regions.emplace_back(_region1);
offsetX = 0;
offsetY += static_cast<int32_t>(_region1.texExtent.height);
remainSize -= copySize;
begin += copySize;
}
if (remainSize > 0) {
_region2.texOffset.x = offsetX;
_region2.texOffset.y = offsetY;
_region2.texExtent.width = remainSize;
_region2.texExtent.height = 1;
buffers.emplace_back(bufferData + begin * _formatSize);
regions.emplace_back(_region2);
}
_device->copyBuffersToTexture(buffers, handle.texture, regions);
}
index_t TextureBufferPool::findAvailableSpace(uint32_t size, index_t chunkIdx) const {
auto chunk = _chunks[chunkIdx];
bool isFound = false;
index_t start = chunk.start;
if ((start + size) <= chunk.size) {
isFound = true;
} else {
start = 0; // try to find from head again
ccstd::vector<ITextureBufferHandle> handles;
for (auto h : _handles) {
if (h.chunkIdx == chunkIdx) {
handles.emplace_back(h);
}
}
std::sort(handles.begin(), handles.end(), [](const ITextureBufferHandle &a, const ITextureBufferHandle &b) { return a.start - b.start; });
for (auto handle : handles) {
if ((start + size) <= handle.start) {
isFound = true;
break;
}
start = handle.end;
}
if (!isFound && (start + size) <= chunk.size) {
isFound = true;
}
}
return isFound ? start : CC_INVALID_INDEX;
}
ITextureBufferHandle TextureBufferPool::mcDonaldAlloc(uint32_t size) {
size = roundUp(size, _alignment);
for (index_t i = 0; i < _chunkCount; ++i) {
auto chunk = _chunks[i];
bool isFound = false;
index_t start = chunk.start;
if ((start + size) <= chunk.end) {
isFound = true;
} else if (start > chunk.end) {
if ((start + size) <= chunk.size) {
isFound = true;
} else if (size <= chunk.end) {
// Try to find from head again.
start = 0;
chunk.start = 0;
isFound = true;
}
} else if (start == chunk.end) {
start = 0;
chunk.start = 0;
chunk.end = static_cast<index_t>(chunk.size);
if (size <= chunk.end) {
isFound = true;
}
}
if (isFound) {
chunk.start += static_cast<index_t>(size);
ITextureBufferHandle handle;
handle.chunkIdx = i;
handle.start = start;
handle.end = static_cast<index_t>(size);
handle.texture = chunk.texture;
_handles.emplace_back(handle);
return handle;
}
}
// create a new one
auto targetSize = static_cast<int32_t>(std::sqrt(size / _formatSize));
uint32_t texLength = _roundUpFn ? _roundUpFn(targetSize, _formatSize) : std::max(1024, static_cast<int>(utils::nextPOT(targetSize)));
auto newChunk = _chunks[createChunk(texLength)];
newChunk.start += static_cast<index_t>(size);
ITextureBufferHandle texHandle;
texHandle.chunkIdx = static_cast<index_t>(_chunkCount);
texHandle.start = 0;
texHandle.end = static_cast<index_t>(size),
texHandle.texture = newChunk.texture;
_handles.emplace_back(texHandle);
return texHandle;
}
} // namespace cc

View File

@@ -0,0 +1,97 @@
/****************************************************************************
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 <functional>
#include "audio/android/PcmBufferProvider.h"
#include "base/std/optional.h"
#include "core/ArrayBuffer.h"
#include "renderer/gfx-base/GFXDef.h"
namespace cc {
using roundUpType = std::function<uint32_t(uint32_t size, uint32_t formatSize)>;
struct ITextureBuffer {
gfx::Texture *texture{nullptr};
uint32_t size{0};
index_t start{0};
index_t end{0};
};
struct ITextureBufferHandle {
index_t chunkIdx{0};
index_t start{0};
index_t end{0};
gfx::Texture *texture{nullptr};
bool operator==(const ITextureBufferHandle &handle) const {
return chunkIdx == handle.chunkIdx && start == handle.start && end == handle.end && texture == handle.texture;
}
};
struct ITextureBufferPoolInfo {
gfx::Format format{gfx::Format::UNKNOWN}; // target texture format
ccstd::optional<bool> inOrderFree; // will the handles be freed exactly in the order of their allocation?
ccstd::optional<uint32_t> alignment; // the data alignment for each handle allocated, in bytes
ccstd::optional<roundUpType> roundUpFn; // given a target size, how will the actual texture size round up?
};
class TextureBufferPool : public RefCounted {
public:
TextureBufferPool();
explicit TextureBufferPool(gfx::Device *device);
~TextureBufferPool() override;
void initialize(const ITextureBufferPoolInfo &info);
void destroy();
ITextureBufferHandle alloc(uint32_t size);
ITextureBufferHandle alloc(uint32_t size, index_t chunkIdx);
void free(const ITextureBufferHandle &handle);
uint32_t createChunk(uint32_t length);
void update(const ITextureBufferHandle &handle, ArrayBuffer *buffer);
private:
index_t findAvailableSpace(uint32_t size, index_t chunkIdx) const;
// [McDonald 12] Efficient Buffer Management
ITextureBufferHandle mcDonaldAlloc(uint32_t size);
gfx::Device *_device{nullptr};
gfx::Format _format{gfx::Format::UNKNOWN};
uint32_t _formatSize{0};
ccstd::vector<ITextureBuffer> _chunks;
uint32_t _chunkCount{0};
ccstd::vector<ITextureBufferHandle> _handles;
gfx::BufferTextureCopy _region0;
gfx::BufferTextureCopy _region1;
gfx::BufferTextureCopy _region2;
roundUpType _roundUpFn{nullptr};
bool _useMcDonaldAlloc{false};
uint32_t _channels{4};
uint32_t _alignment{1};
CC_DISALLOW_COPY_MOVE_ASSIGN(TextureBufferPool);
};
} // namespace cc

View File

@@ -0,0 +1,85 @@
/****************************************************************************
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 "Handle.h"
#include "base/Macros.h"
#include "base/std/container/unordered_map.h"
namespace cc {
namespace framegraph {
template <typename KeyType, typename ValueType, ValueType InvalidValue>
class Blackboard final {
public:
Blackboard() = default;
~Blackboard() = default;
Blackboard(const Blackboard &) = delete;
Blackboard(Blackboard &&) noexcept = delete;
Blackboard &operator=(const Blackboard &) = delete;
Blackboard &operator=(Blackboard &&) noexcept = delete;
inline ValueType &operator[](const KeyType &name) noexcept;
inline void put(const KeyType &name, ValueType handle) noexcept;
inline ValueType get(const KeyType &name) const noexcept;
inline void clear() noexcept;
inline bool has(const KeyType &name) const noexcept;
private:
using Container = ccstd::unordered_map<KeyType, ValueType, typename KeyType::Hasher>;
Container _container;
};
//////////////////////////////////////////////////////////////////////////
template <typename KeyType, typename ValueType, ValueType InvalidValue>
ValueType &Blackboard<KeyType, ValueType, InvalidValue>::operator[](const KeyType &name) noexcept {
const auto it = _container.find(name);
return (it == _container.end() ? _container.emplace(name, InvalidValue).first : it)->second;
}
template <typename KeyType, typename ValueType, ValueType InvalidValue>
void Blackboard<KeyType, ValueType, InvalidValue>::put(const KeyType &name, ValueType const handle) noexcept {
_container[name] = handle;
}
template <typename KeyType, typename ValueType, ValueType InvalidValue>
ValueType Blackboard<KeyType, ValueType, InvalidValue>::get(const KeyType &name) const noexcept {
const auto it = _container.find(name);
return it == _container.end() ? InvalidValue : it->second;
}
template <typename KeyType, typename ValueType, ValueType InvalidValue>
void Blackboard<KeyType, ValueType, InvalidValue>::clear() noexcept {
_container.clear();
}
template <typename KeyType, typename ValueType, ValueType InvalidValue>
bool Blackboard<KeyType, ValueType, InvalidValue>::has(const KeyType &name) const noexcept {
return _container.find(name) != _container.end();
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,81 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "DevicePassResourceTable.h"
namespace cc {
namespace framegraph {
class Executable {
public:
Executable() noexcept = default;
virtual ~Executable() = default;
Executable(const Executable &) = delete;
Executable(Executable &&) noexcept = delete;
Executable &operator=(const Executable &) = delete;
Executable &operator=(Executable &&) noexcept = delete;
virtual void execute(const DevicePassResourceTable &resourceTable) noexcept = 0;
};
template <typename Data, typename ExecuteMethodType>
class CallbackPass final : public Executable {
public:
using ExecuteMethod = std::remove_reference_t<ExecuteMethodType>;
explicit CallbackPass(ExecuteMethod &execute) noexcept;
explicit CallbackPass(ExecuteMethod &&execute) noexcept;
void execute(const DevicePassResourceTable &resourceTable) noexcept override;
inline const Data &getData() const noexcept { return _data; }
inline Data &getData() noexcept { return _data; }
private:
Data _data;
ExecuteMethod _execute;
};
//////////////////////////////////////////////////////////////////////////
template <typename Data, typename ExecuteMethod>
CallbackPass<Data, ExecuteMethod>::CallbackPass(ExecuteMethod &execute) noexcept
: Executable(),
_execute(execute) {
}
template <typename Data, typename ExecuteMethod>
CallbackPass<Data, ExecuteMethod>::CallbackPass(ExecuteMethod &&execute) noexcept
: Executable(),
_execute(execute) {
}
template <typename Data, typename ExecuteMethod>
void CallbackPass<Data, ExecuteMethod>::execute(const DevicePassResourceTable &resourceTable) noexcept {
_execute(_data, resourceTable);
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,427 @@
/****************************************************************************
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 "DevicePass.h"
#include "CallbackPass.h"
#include "DevicePassResourceTable.h"
#include "FrameGraph.h"
#include "PassNode.h"
#include "ResourceNode.h"
#include "base/Utils.h"
#include "gfx-base/GFXCommandBuffer.h"
#include "gfx-base/GFXDef-common.h"
#include <algorithm>
namespace cc {
namespace framegraph {
DevicePass::DevicePass(const FrameGraph &graph, ccstd::vector<PassNode *> const &subpassNodes) {
ccstd::vector<RenderTargetAttachment> attachments;
uint32_t index = 0;
for (const PassNode *passNode : subpassNodes) {
append(graph, passNode, &attachments);
_barriers.push_back(std::cref(passNode->getBarriers()));
_subpasses.back().barrierID = index++;
}
auto *device = gfx::Device::getInstance();
// _enableAutoBarrier: auto barrier in framegraph
// barrierDeduce: deduce barrier gfx internally
// to avoid redundant instructions, either inside or outside
device->enableAutoBarrier(!gfx::ENABLE_GRAPH_AUTO_BARRIER);
// Important Notice:
// here attchment index has changed.
// _attachments is flattened previously, and it is spliced into two parts here:
// colorAttachments and depthStencilAttachment
// As a result, the indices in subpasses are INVALIDATED.
// So the attachment index in subpass should be recalculated.
// there should be only ONE depth stencil in the entire Pass
auto depthIndex = gfx::INVALID_BINDING;
auto depthNewIndex = gfx::INVALID_BINDING;
for (uint32_t id = 0; id != attachments.size(); ++id) {
if (attachments[id].desc.usage != RenderTargetAttachment::Usage::COLOR) {
CC_ASSERT_EQ(depthIndex, gfx::INVALID_BINDING);
depthIndex = id;
depthNewIndex = static_cast<uint32_t>(attachments.size() - 1);
}
}
std::stable_sort(attachments.begin(), attachments.end(), RenderTargetAttachment::Sorter());
// update subpass index
for (auto &subpass : _subpasses) {
// reindex subpass attchment index
auto &info = subpass.desc;
for (auto &id : info.inputs) {
if (id == depthIndex) {
id = depthNewIndex;
} else if (id > depthIndex) {
--id;
}
}
for (auto &id : info.resolves) {
if (id == depthIndex) {
id = depthNewIndex;
} else if (id > depthIndex) {
--id;
}
}
for (auto &id : info.preserves) {
if (id == depthIndex) {
id = depthNewIndex;
} else if (id > depthIndex) {
--id;
}
}
}
ccstd::vector<const gfx::Texture *> renderTargets;
for (auto &attachment : attachments) {
const ResourceNode &resourceNode = graph.getResourceNode(attachment.textureHandle);
CC_ASSERT(resourceNode.virtualResource);
gfx::Texture *resource = static_cast<ResourceEntry<Texture> *>(resourceNode.virtualResource)->getDeviceResource();
CC_ASSERT(resource);
_attachments.emplace_back();
_attachments.back().attachment = attachment;
_attachments.back().renderTarget = resource;
renderTargets.emplace_back(resource);
}
for (PassNode *const passNode : subpassNodes) {
_resourceTable.extract(graph, passNode, renderTargets);
}
}
void DevicePass::passDependency(gfx::RenderPassInfo &rpInfo) {
if constexpr (gfx::ENABLE_GRAPH_AUTO_BARRIER) {
uint32_t index = 0;
thread_local gfx::BufferBarrierList bufferBarriers;
thread_local gfx::TextureBarrierList textureBarriers;
thread_local gfx::BufferList buffers;
thread_local gfx::TextureList textures;
bufferBarriers.clear();
textureBarriers.clear();
buffers.clear();
textures.clear();
uint32_t lastBufferIndex{0};
uint32_t lastTextureIndex{0};
auto mergeToDependency = [&](uint32_t barrierID, uint32_t subpassIndex) {
for (const auto &frontBarrier : _barriers[barrierID].get().frontBarriers) {
const auto &res = getBarrier(frontBarrier, &_resourceTable);
if (frontBarrier.resourceType == ResourceType::BUFFER) {
bufferBarriers.emplace_back(static_cast<gfx::BufferBarrier *>(res.first));
buffers.emplace_back(static_cast<gfx::Buffer *>(res.second));
} else if (frontBarrier.resourceType == ResourceType::TEXTURE) {
textureBarriers.emplace_back(static_cast<gfx::TextureBarrier *>(res.first));
textures.emplace_back(static_cast<gfx::Texture *>(res.second));
} else {
CC_ABORT();
}
}
lastBufferIndex = static_cast<uint32_t>(buffers.size());
lastTextureIndex = static_cast<uint32_t>(textures.size());
rpInfo.dependencies.emplace_back(gfx::SubpassDependency{
subpassIndex > 1 ? subpassIndex - 1 : gfx::SUBPASS_EXTERNAL,
subpassIndex,
nullptr,
{},
{},
});
for (const auto &rearBarrier : _barriers[barrierID].get().rearBarriers) {
const auto &res = getBarrier(rearBarrier, &_resourceTable);
if (rearBarrier.resourceType == ResourceType::BUFFER) {
bufferBarriers.emplace_back(static_cast<gfx::BufferBarrier *>(res.first));
buffers.emplace_back(static_cast<gfx::Buffer *>(res.second));
} else if (rearBarrier.resourceType == ResourceType::TEXTURE) {
textureBarriers.emplace_back(static_cast<gfx::TextureBarrier *>(res.first));
textures.emplace_back(static_cast<gfx::Texture *>(res.second));
} else {
CC_ABORT();
}
}
};
if (!_subpasses.empty()) {
for (const auto &subpass : _subpasses) {
mergeToDependency(subpass.barrierID, index);
++index;
}
} else {
mergeToDependency(0, 0);
}
if (textureBarriers.size() > lastTextureIndex || bufferBarriers.size() > lastBufferIndex) {
rpInfo.dependencies.emplace_back(gfx::SubpassDependency{
_subpasses.empty() ? 0 : static_cast<uint32_t>(_subpasses.size() - 1),
gfx::SUBPASS_EXTERNAL,
nullptr,
{},
{},
});
}
}
}
void DevicePass::execute() {
auto *device = gfx::Device::getInstance();
auto *cmdBuff = device->getCommandBuffer();
begin(cmdBuff);
for (uint32_t i = 0; i < utils::toUint(_subpasses.size()); ++i) {
Subpass &subpass = _subpasses[i];
_resourceTable._subpassIndex = i;
for (LogicPass &pass : subpass.logicPasses) {
gfx::Viewport &viewport = pass.customViewport ? pass.viewport : _viewport;
gfx::Rect &scissor = pass.customViewport ? pass.scissor : _scissor;
if (viewport != _curViewport) {
cmdBuff->setViewport(viewport);
_curViewport = viewport;
}
if (scissor != _curScissor) {
cmdBuff->setScissor(scissor);
_curScissor = scissor;
}
pass.pass->execute(_resourceTable);
}
if (i < _subpasses.size() - 1) next(cmdBuff);
}
end(cmdBuff);
}
void DevicePass::append(const FrameGraph &graph, const PassNode *passNode, ccstd::vector<RenderTargetAttachment> *attachments) {
_subpasses.emplace_back();
Subpass &subpass = _subpasses.back();
do {
subpass.logicPasses.emplace_back();
LogicPass &logicPass = subpass.logicPasses.back();
logicPass.pass = passNode->_pass.get();
logicPass.customViewport = passNode->_customViewport;
logicPass.viewport = passNode->_viewport;
logicPass.scissor = passNode->_scissor;
for (const auto &attachment : passNode->_attachments) {
append(graph, attachment, attachments, &subpass.desc, passNode->_reads);
}
for (const auto &handle : passNode->_reads) {
const auto it = std::find_if(attachments->begin(), attachments->end(), [&handle](const RenderTargetAttachment &attachment) {
return attachment.textureHandle == handle;
});
if (it != attachments->end()) {
uint32_t input = utils::toUint(it - attachments->begin());
if (std::find(subpass.desc.inputs.begin(), subpass.desc.inputs.end(), input) == subpass.desc.inputs.end()) {
subpass.desc.inputs.push_back(input);
}
}
}
passNode = passNode->_next;
} while (passNode);
}
void DevicePass::append(const FrameGraph &graph, const RenderTargetAttachment &attachment,
ccstd::vector<RenderTargetAttachment> *attachments, gfx::SubpassInfo *subpass, const ccstd::vector<Handle> &reads) {
std::ignore = reads;
RenderTargetAttachment::Usage usage{attachment.desc.usage};
uint32_t slot{attachment.desc.slot};
if (attachment.desc.usage == RenderTargetAttachment::Usage::COLOR) {
// should fetch actual color slot from current subpass
slot = subpass->colors.size() > attachment.desc.slot ? subpass->colors[attachment.desc.slot] : gfx::INVALID_BINDING;
}
auto it = std::find_if(attachments->begin(), attachments->end(), [usage, slot](const RenderTargetAttachment &x) {
return usage == x.desc.usage && slot == x.desc.slot;
});
RenderTargetAttachment *output{nullptr};
if (it == attachments->end()) {
attachments->emplace_back(attachment);
output = &(attachments->back());
if (attachment.desc.usage == RenderTargetAttachment::Usage::COLOR) {
for (uint8_t i = 0; i < RenderTargetAttachment::DEPTH_STENCIL_SLOT_START; ++i) {
if ((_usedRenderTargetSlotMask & (1 << i)) == 0) {
attachments->back().desc.slot = i;
_usedRenderTargetSlotMask |= 1 << i;
break;
}
}
} else {
CC_ASSERT((_usedRenderTargetSlotMask & (1 << attachment.desc.slot)) == 0);
_usedRenderTargetSlotMask |= 1 << attachment.desc.slot;
}
} else {
const ResourceNode &resourceNodeA = graph.getResourceNode(it->textureHandle);
const ResourceNode &resourceNodeB = graph.getResourceNode(attachment.textureHandle);
if (resourceNodeA.virtualResource == resourceNodeB.virtualResource) {
output = &*it;
if (attachment.storeOp != gfx::StoreOp::DISCARD) {
output->storeOp = attachment.storeOp;
output->desc.endAccesses = attachment.desc.endAccesses;
}
} else {
CC_ASSERT(attachment.desc.usage == RenderTargetAttachment::Usage::COLOR);
attachments->emplace_back(attachment);
output = &(attachments->back());
for (uint8_t i = 0; i < RenderTargetAttachment::DEPTH_STENCIL_SLOT_START; ++i) {
if ((_usedRenderTargetSlotMask & (1 << i)) == 0) {
attachments->back().desc.slot = i;
_usedRenderTargetSlotMask |= 1 << i;
break;
}
}
}
}
if (attachment.desc.usage == RenderTargetAttachment::Usage::COLOR) {
if (std::find(subpass->colors.begin(), subpass->colors.end(), output->desc.slot) == subpass->colors.end()) {
subpass->colors.push_back(output->desc.slot);
}
} else {
subpass->depthStencil = output->desc.slot;
}
}
void DevicePass::begin(gfx::CommandBuffer *cmdBuff) {
if (_attachments.empty()) return;
gfx::RenderPassInfo rpInfo;
gfx::FramebufferInfo fboInfo;
float clearDepth = 1.F;
uint32_t clearStencil = 0;
static ccstd::vector<gfx::Color> clearColors;
clearColors.clear();
bool hasDefaultViewport{false};
for (auto &subpass : _subpasses) {
for (auto &pass : subpass.logicPasses) {
if (!pass.customViewport) {
hasDefaultViewport = true;
break;
}
}
}
if (hasDefaultViewport) {
_viewport = {};
_scissor = {0, 0, UINT_MAX, UINT_MAX};
} else { // if all passes use customize viewport
_scissor = {INT_MAX, INT_MAX, 0, 0};
for (auto &subpass : _subpasses) {
for (auto &pass : subpass.logicPasses) {
// calculate the union of all viewports as render area
_viewport.left = _scissor.x = std::min(_scissor.x, pass.viewport.left);
_viewport.top = _scissor.y = std::min(_scissor.y, pass.viewport.top);
_viewport.width = _scissor.width = std::max(_scissor.width, pass.viewport.width + pass.viewport.left - _scissor.x);
_viewport.height = _scissor.height = std::max(_scissor.height, pass.viewport.height + pass.viewport.top - _scissor.y);
}
}
}
for (const auto &attachElem : _attachments) {
gfx::Texture *attachment = attachElem.renderTarget;
if (attachElem.attachment.desc.usage == RenderTargetAttachment::Usage::COLOR) {
rpInfo.colorAttachments.emplace_back();
auto &attachmentInfo = rpInfo.colorAttachments.back();
attachmentInfo.format = attachment->getFormat();
attachmentInfo.loadOp = attachElem.attachment.desc.loadOp;
attachmentInfo.storeOp = attachElem.attachment.storeOp;
attachmentInfo.barrier = gfx::Device::getInstance()->getGeneralBarrier({attachElem.attachment.desc.beginAccesses, attachElem.attachment.desc.endAccesses});
fboInfo.colorTextures.push_back(attachElem.renderTarget);
clearColors.emplace_back(attachElem.attachment.desc.clearColor);
} else {
auto &attachmentInfo = rpInfo.depthStencilAttachment;
attachmentInfo.format = attachment->getFormat();
attachmentInfo.depthLoadOp = attachElem.attachment.desc.loadOp;
attachmentInfo.stencilLoadOp = attachElem.attachment.desc.loadOp;
attachmentInfo.depthStoreOp = attachElem.attachment.storeOp;
attachmentInfo.stencilStoreOp = attachElem.attachment.storeOp;
attachmentInfo.barrier = gfx::Device::getInstance()->getGeneralBarrier({attachElem.attachment.desc.beginAccesses, attachElem.attachment.desc.endAccesses});
fboInfo.depthStencilTexture = attachElem.renderTarget;
clearDepth = attachElem.attachment.desc.clearDepth;
clearStencil = attachElem.attachment.desc.clearStencil;
}
if (hasDefaultViewport) {
_viewport.width = _scissor.width = std::min(_scissor.width, attachment->getWidth());
_viewport.height = _scissor.height = std::min(_scissor.height, attachment->getHeight());
}
}
for (auto &subpass : _subpasses) {
rpInfo.subpasses.emplace_back(subpass.desc);
}
passDependency(rpInfo);
_renderPass = RenderPass(rpInfo);
_renderPass.createTransient();
_resourceTable._renderPass = _renderPass.get();
fboInfo.renderPass = _renderPass.get();
_fbo = Framebuffer(fboInfo);
_fbo.createTransient();
cmdBuff->beginRenderPass(_renderPass.get(), _fbo.get(), _scissor, clearColors.data(), clearDepth, clearStencil);
_curViewport = _viewport;
_curScissor = _scissor;
}
void DevicePass::next(gfx::CommandBuffer *cmdBuff) noexcept {
if (!_renderPass.get() || !_fbo.get()) return;
cmdBuff->nextSubpass();
}
void DevicePass::end(gfx::CommandBuffer *cmdBuff) {
if (!_renderPass.get() || !_fbo.get()) return;
cmdBuff->endRenderPass();
_renderPass.destroyTransient();
_fbo.destroyTransient();
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,93 @@
/****************************************************************************
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 <limits>
#include "CallbackPass.h"
#include "ImmutableState.h"
#include "RenderTargetAttachment.h"
#include "base/std/container/string.h"
#include "gfx-base/GFXDef.h"
namespace cc {
namespace framegraph {
class DevicePass final {
public:
DevicePass() = delete;
DevicePass(const FrameGraph &graph, ccstd::vector<PassNode *> const &subpassNodes);
DevicePass(const DevicePass &) = delete;
DevicePass(DevicePass &&) = delete;
~DevicePass() = default;
DevicePass &operator=(const DevicePass &) = delete;
DevicePass &operator=(DevicePass &&) = delete;
void execute();
private:
struct LogicPass final {
Executable *pass{nullptr};
bool customViewport{false};
gfx::Viewport viewport;
gfx::Rect scissor;
};
struct Subpass final {
gfx::SubpassInfo desc;
ccstd::vector<LogicPass> logicPasses{};
uint32_t barrierID{0xFFFFFFFF};
};
struct Attachment final {
RenderTargetAttachment attachment;
gfx::Texture *renderTarget{nullptr};
};
void append(const FrameGraph &graph, const PassNode *passNode, ccstd::vector<RenderTargetAttachment> *attachments);
void append(const FrameGraph &graph, const RenderTargetAttachment &attachment,
ccstd::vector<RenderTargetAttachment> *attachments, gfx::SubpassInfo *subpass, const ccstd::vector<Handle> &reads);
void begin(gfx::CommandBuffer *cmdBuff);
void next(gfx::CommandBuffer *cmdBuff) noexcept;
void end(gfx::CommandBuffer *cmdBuff);
void passDependency(gfx::RenderPassInfo &rpInfo);
ccstd::vector<Subpass> _subpasses{};
ccstd::vector<Attachment> _attachments{};
uint16_t _usedRenderTargetSlotMask{0};
DevicePassResourceTable _resourceTable;
gfx::Viewport _viewport;
gfx::Rect _scissor;
gfx::Viewport _curViewport;
gfx::Rect _curScissor;
RenderPass _renderPass;
Framebuffer _fbo;
std::vector<std::reference_wrapper<const PassBarrierPair>> _barriers;
};
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,87 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "DevicePassResourceTable.h"
#include <algorithm>
#include "FrameGraph.h"
#include "PassNode.h"
namespace cc {
namespace framegraph {
gfx::GFXObject *DevicePassResourceTable::get(const ResourceDictionary &from, Handle handle) noexcept {
const auto it = from.find(handle);
return it == from.cend() ? nullptr : it->second;
}
void DevicePassResourceTable::extract(const FrameGraph &graph,
const PassNode *passNode,
ccstd::vector<const gfx::Texture *> const &renderTargets) noexcept {
do {
extract(graph, passNode->_reads, _reads, false, renderTargets);
extract(graph, passNode->_writes, _writes, true, renderTargets);
passNode = passNode->_next;
} while (passNode);
}
void DevicePassResourceTable::extract(const FrameGraph &graph,
ccstd::vector<Handle> const &from,
ResourceDictionary &to,
bool /*ignoreRenderTarget*/,
ccstd::vector<const gfx::Texture *> const & /*renderTargets*/) noexcept {
std::for_each(from.cbegin(), from.cend(), [&](const Handle handle) {
if (to.find(handle) != to.cend()) {
return;
}
const ResourceNode &resourceNode = graph.getResourceNode(handle);
CC_ASSERT(resourceNode.virtualResource);
gfx::GFXObject *const deviceResource = resourceNode.virtualResource->getDeviceResource();
if (!deviceResource) {
return;
}
//if (ignoreRenderTarget) {
// bool const isRenderTarget =
// std::find_if(
// renderTargets.cbegin(),
// renderTargets.cend(),
// [&deviceResource](const gfx::Texture *const x) {
// return deviceResource == x;
// }) != renderTargets.cend();
// if (isRenderTarget) {
// return;
// }
//}
to[handle] = deviceResource;
});
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,88 @@
/****************************************************************************
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 "Handle.h"
#include "RenderTargetAttachment.h"
#include "Resource.h"
#include "base/std/container/unordered_map.h"
namespace cc {
namespace framegraph {
class PassNode;
class FrameGraph;
class DevicePass;
class DevicePassResourceTable final {
public:
DevicePassResourceTable() = default;
~DevicePassResourceTable() = default;
DevicePassResourceTable(const DevicePassResourceTable &) = delete;
DevicePassResourceTable(DevicePassResourceTable &&) = delete;
DevicePassResourceTable &operator=(const DevicePassResourceTable &) = delete;
DevicePassResourceTable &operator=(DevicePassResourceTable &&) = delete;
template <typename Type>
std::enable_if_t<std::is_base_of<gfx::GFXObject, typename Type::DeviceResource>::value, typename Type::DeviceResource *>
getRead(TypedHandle<Type> handle) const noexcept;
template <typename Type>
std::enable_if_t<std::is_base_of<gfx::GFXObject, typename Type::DeviceResource>::value, typename Type::DeviceResource *>
getWrite(TypedHandle<Type> handle) const noexcept;
gfx::RenderPass *getRenderPass() const { return _renderPass; }
uint32_t getSubpassIndex() const { return _subpassIndex; }
private:
using ResourceDictionary = ccstd::unordered_map<Handle, gfx::GFXObject *, Handle::Hasher>;
static gfx::GFXObject *get(const ResourceDictionary &from, Handle handle) noexcept;
void extract(const FrameGraph &graph, const PassNode *passNode, ccstd::vector<const gfx::Texture *> const &renderTargets) noexcept;
static void extract(const FrameGraph &graph, ccstd::vector<Handle> const &from, ResourceDictionary &to, bool ignoreRenderTarget, ccstd::vector<const gfx::Texture *> const &renderTargets) noexcept;
ResourceDictionary _reads{};
ResourceDictionary _writes{};
gfx::RenderPass *_renderPass{nullptr};
uint32_t _subpassIndex{0U};
friend class DevicePass;
};
template <typename Type>
std::enable_if_t<std::is_base_of<gfx::GFXObject, typename Type::DeviceResource>::value, typename Type::DeviceResource *>
DevicePassResourceTable::getRead(TypedHandle<Type> handle) const noexcept {
return static_cast<typename Type::DeviceResource *>(get(_reads, handle));
}
template <typename Type>
std::enable_if_t<std::is_base_of<gfx::GFXObject, typename Type::DeviceResource>::value, typename Type::DeviceResource *>
DevicePassResourceTable::getWrite(TypedHandle<Type> handle) const noexcept {
return static_cast<typename Type::DeviceResource *>(get(_writes, handle));
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,659 @@
/****************************************************************************
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 "FrameGraph.h"
#include <algorithm>
#include <fstream>
#include "PassNodeBuilder.h"
#include "Resource.h"
#include "base/StringUtil.h"
#include "base/std/container/set.h"
#include "frame-graph/ResourceEntry.h"
namespace cc {
namespace framegraph {
namespace {
// use function scoped static member
// to ensure correct initialization order
StringPool &getStringPool() {
static StringPool pool;
return pool;
}
} // namespace
StringHandle FrameGraph::stringToHandle(const char *const name) {
return getStringPool().stringToHandle(name);
}
const char *FrameGraph::handleToString(const StringHandle &handle) noexcept {
return getStringPool().handleToString(handle);
}
void FrameGraph::present(const TextureHandle &input, gfx::Texture *target, bool useMoveSemantic) {
static const StringHandle PRESENT_PASS{FrameGraph::stringToHandle("Present")};
const ResourceNode &resourceNode{getResourceNode(input)};
CC_ASSERT(resourceNode.writer);
struct PassDataPresent {
TextureHandle input;
};
addPass<PassDataPresent>(
resourceNode.writer->_insertPoint, PRESENT_PASS,
[&](PassNodeBuilder &builder, PassDataPresent &data) {
data.input = builder.read(input);
builder.sideEffect();
if (useMoveSemantic) {
// using a global map here so that the user don't need to worry about importing the targets every frame
static ccstd::unordered_map<uint32_t, std::pair<StringHandle, Texture>> presentTargets;
if (!presentTargets.count(target->getTypedID())) {
auto name = FrameGraph::stringToHandle(StringUtil::format("Present Target %d", target->getTypedID()).c_str());
presentTargets.emplace(std::piecewise_construct, std::forward_as_tuple(target->getTypedID()), std::forward_as_tuple(name, Texture{target}));
}
auto &resourceInfo{presentTargets[target->getTypedID()]};
TextureHandle output{getBlackboard().get(resourceInfo.first)};
if (!output.isValid()) {
output = importExternal(resourceInfo.first, resourceInfo.second);
getBlackboard().put(resourceInfo.first, output);
}
move(data.input, output, 0, 0, 0);
data.input = output;
}
},
[target](const PassDataPresent &data, const DevicePassResourceTable &table) {
auto *cmdBuff = gfx::Device::getInstance()->getCommandBuffer();
gfx::Texture *input = table.getRead(data.input);
if (input && input != target) {
gfx::TextureBlit region;
region.srcExtent.width = input->getWidth();
region.srcExtent.height = input->getHeight();
region.dstExtent.width = target->getWidth();
region.dstExtent.height = target->getHeight();
cmdBuff->blitTexture(input, target, &region, 1, gfx::Filter::POINT);
}
});
}
void FrameGraph::presentLastVersion(const VirtualResource *const virtualResource, gfx::Texture *target, bool useMoveSemantic) {
const auto it = std::find_if(_resourceNodes.rbegin(), _resourceNodes.rend(), [&virtualResource](const ResourceNode &node) {
return node.virtualResource == virtualResource;
});
CC_ASSERT(it != _resourceNodes.rend());
present(TextureHandle(static_cast<Handle::IndexType>(it.base() - _resourceNodes.begin() - 1)), target, useMoveSemantic);
}
void FrameGraph::presentFromBlackboard(const StringHandle &inputName, gfx::Texture *target, bool useMoveSemantic) {
present(TextureHandle(_blackboard.get(inputName)), target, useMoveSemantic);
}
void FrameGraph::compile() {
if (_passNodes.empty()) return;
sort();
cull();
computeResourceLifetime();
if (_merge) {
mergePassNodes();
}
computeStoreActionAndMemoryless();
generateDevicePasses();
}
void FrameGraph::execute() noexcept {
if (_passNodes.empty()) return;
for (auto &pass : _devicePasses) {
pass->execute();
}
}
void FrameGraph::reset() noexcept {
_passNodes.clear();
_resourceNodes.clear();
_virtualResources.clear();
_devicePasses.clear();
_blackboard.clear();
}
void FrameGraph::gc(uint32_t const unusedFrameCount) noexcept {
Buffer::Allocator::getInstance().gc(unusedFrameCount);
Framebuffer::Allocator::getInstance().gc(unusedFrameCount);
RenderPass::Allocator::getInstance().gc(unusedFrameCount);
Texture::Allocator::getInstance().gc(unusedFrameCount);
}
void FrameGraph::move(const TextureHandle from, const TextureHandle to, uint8_t mipmapLevel, uint8_t faceId, uint8_t arrayPosition) noexcept {
const ResourceNode &fromResourceNode = getResourceNode(from);
const ResourceNode &toResourceNode = getResourceNode(to);
CC_ASSERT(!fromResourceNode.virtualResource->isImported());
CC_ASSERT(fromResourceNode.writer);
CC_ASSERT(!toResourceNode.writer);
const gfx::TextureInfo &toTextureDesc = static_cast<ResourceEntry<Texture> *>(toResourceNode.virtualResource)->get().getDesc();
uint32_t const toTextureWidth = toTextureDesc.width >> mipmapLevel;
uint32_t const toTextureHeight = toTextureDesc.height >> mipmapLevel;
uint32_t const toTextureDepth = toTextureDesc.depth >> mipmapLevel;
CC_ASSERT(toTextureWidth && toTextureHeight && toTextureDepth);
CC_ASSERT(toTextureDesc.levelCount > mipmapLevel && toTextureDesc.layerCount > arrayPosition);
CC_ASSERT(toTextureDesc.type == gfx::TextureType::CUBE && faceId < 6 || faceId == 0);
for (ResourceNode &resourceNode : _resourceNodes) {
if (resourceNode.virtualResource == fromResourceNode.virtualResource) {
resourceNode.virtualResource = toResourceNode.virtualResource;
}
}
for (const auto &passNode : _passNodes) {
for (auto &attachment : passNode->_attachments) {
const ResourceNode &attachmentResourceNode = getResourceNode(attachment.textureHandle);
if (attachmentResourceNode.virtualResource == toResourceNode.virtualResource) {
const gfx::TextureInfo &attachmentTextureDesc = static_cast<ResourceEntry<Texture> *>(attachmentResourceNode.virtualResource)->get().getDesc();
CC_ASSERT(attachmentTextureDesc.width >> attachment.level == toTextureWidth &&
attachmentTextureDesc.height >> attachment.level == toTextureHeight &&
attachmentTextureDesc.depth >> attachment.level == toTextureDepth);
attachment.level = mipmapLevel;
attachment.layer = faceId;
attachment.index = arrayPosition;
}
}
}
}
bool FrameGraph::hasPass(StringHandle handle) {
return std::any_of(_passNodes.begin(), _passNodes.end(), [&](const auto &passNode) { return passNode->_name == handle; });
}
Handle FrameGraph::create(VirtualResource *const virtualResource) {
_virtualResources.emplace_back(virtualResource);
return createResourceNode(virtualResource);
}
PassNode &FrameGraph::createPassNode(const PassInsertPoint insertPoint, const StringHandle &name, Executable *const pass) {
_passNodes.emplace_back(ccnew PassNode(insertPoint, name, static_cast<ID>(_passNodes.size()), pass));
return *_passNodes.back();
}
Handle FrameGraph::createResourceNode(VirtualResource *const virtualResource) {
const size_t index = _resourceNodes.size();
ResourceNode resourceNode;
resourceNode.virtualResource = virtualResource;
resourceNode.version = virtualResource->_version;
_resourceNodes.emplace_back(resourceNode);
return Handle{static_cast<Handle::IndexType>(index)};
}
void FrameGraph::sort() noexcept {
std::stable_sort(_passNodes.begin(), _passNodes.end(), [](const auto &x, const auto &y) {
return x->_insertPoint < y->_insertPoint;
});
}
void FrameGraph::cull() {
for (const auto &passNode : _passNodes) {
passNode->_refCount = static_cast<uint32_t>(passNode->_writes.size()) + passNode->_sideEffect;
for (const Handle handle : passNode->_reads) {
CC_ASSERT(handle.isValid());
++_resourceNodes[handle].readerCount;
}
}
static ccstd::vector<const ResourceNode *> stack;
stack.clear();
stack.reserve(_resourceNodes.size());
for (ResourceNode &resourceNode : _resourceNodes) {
if (resourceNode.readerCount == 0 && resourceNode.writer) {
stack.push_back(&resourceNode);
}
}
while (!stack.empty()) {
PassNode *const writerPassNode = stack.back()->writer;
stack.pop_back();
if (writerPassNode) {
CC_ASSERT(writerPassNode->_refCount);
if (--writerPassNode->_refCount == 0) {
CC_ASSERT(!writerPassNode->_sideEffect);
for (const Handle handle : writerPassNode->_reads) {
ResourceNode &resourceNode = _resourceNodes[handle];
if (--resourceNode.readerCount == 0) {
stack.push_back(&resourceNode);
}
}
}
}
}
for (const ResourceNode &resourceNode : _resourceNodes) {
resourceNode.virtualResource->_refCount += resourceNode.readerCount;
}
}
void FrameGraph::computeResourceLifetime() {
for (const auto &passNode : _passNodes) {
if (passNode->_refCount == 0) {
continue;
}
for (const Handle handle : passNode->_reads) {
_resourceNodes[handle].virtualResource->updateLifetime(passNode.get());
}
for (const Handle handle : passNode->_writes) {
_resourceNodes[handle].virtualResource->updateLifetime(passNode.get());
++_resourceNodes[handle].virtualResource->_writerCount;
}
std::sort(passNode->_attachments.begin(), passNode->_attachments.end(), RenderTargetAttachment::Sorter());
}
for (const auto &resource : _virtualResources) {
CC_ASSERT(!resource->_firstUsePass == !resource->_lastUsePass);
if (!resource->_firstUsePass || !resource->_lastUsePass) {
continue;
}
if (resource->_refCount == 0 && !resource->_lastUsePass->getRenderTargetAttachment(*this, resource.get())) {
continue;
}
resource->_firstUsePass->_resourceRequestArray.push_back(resource.get());
resource->_lastUsePass->_resourceReleaseArray.push_back(resource.get());
}
}
void FrameGraph::mergePassNodes() noexcept {
const size_t count = _passNodes.size();
size_t currentPassId = 0;
size_t lastPassId = 0;
while (currentPassId < count) {
const auto &currentPassNode = _passNodes[currentPassId];
if (currentPassNode->_refCount) {
break;
}
++currentPassId;
}
lastPassId = currentPassId;
while (++currentPassId < count) {
const auto &currentPassNode = _passNodes[currentPassId];
if (currentPassNode->_refCount == 0) {
continue;
}
const auto &lastPassNode = _passNodes[lastPassId];
if (lastPassNode->canMerge(*this, *currentPassNode)) {
auto *prevPassNode = lastPassNode.get();
uint16_t distance = 1;
while (prevPassNode->_next) {
prevPassNode = prevPassNode->_next;
++distance;
}
prevPassNode->_next = currentPassNode.get();
currentPassNode->_head = lastPassNode.get();
currentPassNode->_distanceToHead = distance;
currentPassNode->_refCount = 0;
const size_t attachmentCount = lastPassNode->_attachments.size();
for (size_t i = 0; i < attachmentCount; ++i) {
const RenderTargetAttachment &attachmentInLastPassNode = lastPassNode->_attachments[i];
const RenderTargetAttachment &attachmentInCurrentPassNode = currentPassNode->_attachments[i];
ResourceNode &resourceNode = _resourceNodes[attachmentInLastPassNode.textureHandle];
uint16_t &writeCount = resourceNode.virtualResource->_writerCount;
CC_ASSERT_GT(writeCount, 1);
--writeCount;
resourceNode.readerCount += _resourceNodes[attachmentInCurrentPassNode.textureHandle].readerCount;
resourceNode.readerCount -= attachmentInCurrentPassNode.desc.loadOp == gfx::LoadOp::LOAD;
}
} else {
lastPassId = currentPassId;
}
}
}
void FrameGraph::computeStoreActionAndMemoryless() {
ID passId = 0;
bool lastPassSubpassEnable = false;
for (const auto &passNode : _passNodes) {
if (passNode->_refCount == 0) {
continue;
}
ID const oldPassId = passId;
passId += !passNode->_subpass || lastPassSubpassEnable != passNode->_subpass;
passId += oldPassId == passId ? passNode->_hasClearedAttachment * !passNode->_clearActionIgnorable : 0;
passNode->setDevicePassId(passId);
lastPassSubpassEnable = passNode->_subpass && !passNode->_subpassEnd;
}
static ccstd::set<VirtualResource *> renderTargets;
renderTargets.clear();
for (const auto &passNode : _passNodes) {
if (passNode->_refCount == 0) {
continue;
}
for (RenderTargetAttachment &attachment : passNode->_attachments) {
CC_ASSERT(attachment.textureHandle.isValid());
ResourceNode &resourceNode = getResourceNode(attachment.textureHandle);
if (resourceNode.virtualResource->isImported() || resourceNode.readerCount) {
if (passNode->_subpass) {
if (passNode->_devicePassId != resourceNode.virtualResource->_lastUsePass->_devicePassId) {
attachment.storeOp = gfx::StoreOp::STORE;
}
} else {
if (attachment.desc.writeMask) {
attachment.storeOp = gfx::StoreOp::STORE;
}
}
}
if (passNode->_subpass && attachment.desc.loadOp == gfx::LoadOp::LOAD && resourceNode.version > 1) {
ResourceNode *const resourceNodePrevVersion = getResourceNode(resourceNode.virtualResource, resourceNode.version - 1);
CC_ASSERT(resourceNodePrevVersion);
if (resourceNodePrevVersion->writer->_devicePassId == passNode->_devicePassId) {
attachment.desc.loadOp = gfx::LoadOp::DISCARD;
resourceNodePrevVersion->writer->getRenderTargetAttachment(*this, resourceNodePrevVersion->virtualResource)->storeOp = gfx::StoreOp::DISCARD;
}
}
if (attachment.desc.loadOp == gfx::LoadOp::LOAD) {
resourceNode.virtualResource->_neverLoaded = false;
}
if (attachment.storeOp == gfx::StoreOp::STORE) {
resourceNode.virtualResource->_neverStored = false;
}
renderTargets.emplace(resourceNode.virtualResource);
}
}
for (VirtualResource *const renderTarget : renderTargets) {
const gfx::TextureInfo &textureDesc = static_cast<ResourceEntry<Texture> *>(renderTarget)->get().getDesc();
renderTarget->_memoryless = renderTarget->_neverLoaded && renderTarget->_neverStored;
renderTarget->_memorylessMSAA = textureDesc.samples != gfx::SampleCount::X1 && renderTarget->_writerCount < 2;
}
}
void FrameGraph::generateDevicePasses() {
Buffer::Allocator::getInstance().tick();
Framebuffer::Allocator::getInstance().tick();
RenderPass::Allocator::getInstance().tick();
Texture::Allocator::getInstance().tick();
ID passId = 1;
static ccstd::vector<PassNode *> subpassNodes;
subpassNodes.clear();
for (const auto &passNode : _passNodes) {
if (passNode->_refCount == 0) {
continue;
}
if (passId != passNode->_devicePassId) {
_devicePasses.emplace_back(ccnew DevicePass(*this, subpassNodes));
for (PassNode *const p : subpassNodes) {
p->releaseTransientResources();
}
subpassNodes.clear();
passId = passNode->_devicePassId;
}
passNode->requestTransientResources();
subpassNodes.emplace_back(passNode.get());
}
CC_ASSERT(subpassNodes.size() == 1);
_devicePasses.emplace_back(ccnew DevicePass(*this, subpassNodes));
for (PassNode *const p : subpassNodes) {
p->releaseTransientResources();
}
}
// https://dreampuf.github.io/GraphvizOnline/
void FrameGraph::exportGraphViz(const ccstd::string &path) {
std::ofstream out(path, std::ios::out | std::ios::binary);
//out.imbue(std::locale("chs", std::locale::ctype));
if (out.fail()) {
return;
}
out << "digraph framegraph {\n";
out << "rankdir = LR\n";
out << "bgcolor = black\n";
out << "node [shape=rectangle, fontname=\"helvetica\", fontsize=10]\n\n";
for (const auto &node : _passNodes) {
if (node->_head) {
continue;
}
out << "\"P" << node->_id << "\" [label=\"" << node->_name.str();
const PassNode *currPassNode = node.get();
if (currPassNode->_head) {
out << "\\n(merged by pass " << currPassNode->_head->_name.str() << ")";
} else {
while (currPassNode->_next) {
currPassNode = currPassNode->_next;
out << " & " << currPassNode->_name.str();
}
}
out << "\\nrefs: " << node->_refCount
<< "\\nseq: " << node->_id
<< "\\ndevice pass id: " << node->_devicePassId
<< "\", style=filled, fillcolor="
<< (node->_refCount ? "darkorange" : "darkorange4") << "]\n";
}
out << "\n";
for (const ResourceNode &node : _resourceNodes) {
if (node.writer && node.writer->_head) {
continue;
}
out << "\"R" << node.virtualResource->_id << "_" << +node.version << "\""
"[label=\""
<< node.virtualResource->_name.str() << "\\n(version: " << +node.version << ")"
<< "\\nrefs:" << node.virtualResource->_refCount;
if (node.virtualResource->_memoryless) {
out << "\\nMemoryless";
}
if (node.virtualResource->_memorylessMSAA) {
out << "\\nMemorylessMSAA";
}
PassNode *const writer = (node.writer && node.writer->_head) ? node.writer->_head : node.writer;
if (writer) {
out << "\\n";
const RenderTargetAttachment *const attachment = writer->getRenderTargetAttachment(*this, node.virtualResource);
if (attachment) {
switch (attachment->desc.loadOp) {
case gfx::LoadOp::DISCARD:
out << "DontCare";
break;
case gfx::LoadOp::CLEAR:
out << "Clear";
break;
default:
out << "Load";
break;
}
out << ", ";
out << (attachment->storeOp == gfx::StoreOp::DISCARD ? "DontCare" : "Store");
out << "\\nWriteMask: 0x" << std::hex << static_cast<uint32_t>(attachment->desc.writeMask) << std::dec;
} else {
out << "Transfer";
}
}
out << "\", style=filled, fillcolor="
<< ((node.virtualResource->isImported())
? (node.virtualResource->_refCount ? "palegreen" : "palegreen4")
: (node.version == 0 ? "pink" : (node.virtualResource->_refCount ? "skyblue" : "skyblue4")))
<< "]\n";
}
out << "\n";
for (const auto &node : _passNodes) {
if (node->_head) {
continue;
}
out << "P" << node->_id << " -> { ";
for (const Handle writer : node->_writes) {
out << "R" << _resourceNodes[writer].virtualResource->_id << "_" << +_resourceNodes[writer].version << " ";
}
out << "} [color=red]\n";
}
out << "\n";
for (const ResourceNode &node : _resourceNodes) {
if (node.writer && node.writer->_head) {
continue;
}
out << "R" << node.virtualResource->_id << "_" << +node.version << " -> { ";
for (const auto &passNode : _passNodes) {
if (passNode->_head) {
continue;
}
for (Handle read : passNode->_reads) {
const ResourceNode *readResourceNode = &_resourceNodes[read];
if (readResourceNode->writer && readResourceNode->writer->_head) {
const Handle resourceNodeHandlePrevVersion = readResourceNode->writer->_head->getWriteResourceNodeHandle(*this, readResourceNode->virtualResource);
CC_ASSERT(resourceNodeHandlePrevVersion.isValid());
readResourceNode = &getResourceNode(resourceNodeHandlePrevVersion);
}
if (readResourceNode->virtualResource->_id == node.virtualResource->_id &&
readResourceNode->version == node.version) {
out << "P" << passNode->_id << " ";
}
}
}
out << "} [color=green]\n";
}
for (const ResourceNode &node : _resourceNodes) {
if (node.writer && node.writer->_head) {
continue;
}
out << "R" << node.virtualResource->_id << "_" << +node.version << " -> { ";
for (const auto &passNode : _passNodes) {
if (passNode->_head) {
continue;
}
for (const RenderTargetAttachment &attachment : passNode->_attachments) {
const ResourceNode *readResourceNode = &_resourceNodes[attachment.textureHandle];
uint16_t const distanceToHead = readResourceNode->writer->_distanceToHead;
if (readResourceNode->writer && readResourceNode->writer->_head) {
const Handle resourceNodeHandleHead = readResourceNode->writer->_head->getWriteResourceNodeHandle(*this, readResourceNode->virtualResource);
CC_ASSERT(resourceNodeHandleHead.isValid());
readResourceNode = &getResourceNode(resourceNodeHandleHead);
}
if (readResourceNode->virtualResource == node.virtualResource &&
readResourceNode->version == node.version + 1 - distanceToHead) {
out << "P" << passNode->_id << " ";
}
}
}
out << "} [color=red4]\n";
}
out << "}" << std::endl;
out.close();
}
ResourceNode *FrameGraph::getResourceNode(const VirtualResource *const virtualResource, uint8_t version) noexcept {
const auto it = std::find_if(_resourceNodes.begin(), _resourceNodes.end(), [&](const ResourceNode &node) {
return node.version == version && node.virtualResource == virtualResource;
});
return it == _resourceNodes.end() ? nullptr : &(*it);
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,144 @@
/****************************************************************************
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 "Blackboard.h"
#include "CallbackPass.h"
#include "DevicePass.h"
#include "PassNode.h"
#include "PassNodeBuilder.h"
#include "ResourceEntry.h"
#include "ResourceNode.h"
#include "base/std/container/string.h"
namespace cc {
namespace framegraph {
class FrameGraph final {
public:
using ResourceHandleBlackboard = Blackboard<StringHandle, Handle::IndexType, Handle::UNINITIALIZED>;
FrameGraph() = default;
~FrameGraph() = default;
FrameGraph(const FrameGraph &) = delete;
FrameGraph(FrameGraph &&) noexcept = delete;
FrameGraph &operator=(const FrameGraph &) = delete;
FrameGraph &operator=(FrameGraph &&) noexcept = delete;
static StringHandle stringToHandle(const char *name);
static const char *handleToString(const StringHandle &handle) noexcept;
void present(const TextureHandle &input, gfx::Texture *target, bool useMoveSemantic = true);
void presentLastVersion(const VirtualResource *virtualResource, gfx::Texture *target, bool useMoveSemantic = true);
void presentFromBlackboard(const StringHandle &inputName, gfx::Texture *target, bool useMoveSemantic = true);
void compile();
void execute() noexcept;
void reset() noexcept;
static void gc(uint32_t unusedFrameCount = 30) noexcept;
template <typename Data, typename SetupMethod, typename ExecuteMethod>
const CallbackPass<Data, ExecuteMethod> &addPass(PassInsertPoint insertPoint, const StringHandle &name, SetupMethod setup, ExecuteMethod &&execute) noexcept;
template <typename DescriptorType, typename ResourceType = typename ResourceTypeLookupTable<DescriptorType>::Resource>
TypedHandle<ResourceType> create(const StringHandle &name, const DescriptorType &desc) noexcept;
template <typename ResourceType>
TypedHandle<ResourceType> importExternal(const StringHandle &name, ResourceType &resource) noexcept;
void move(TextureHandle from, TextureHandle to, uint8_t mipmapLevel, uint8_t faceId, uint8_t arrayPosition) noexcept;
inline ResourceNode &getResourceNode(const Handle handle) noexcept { return _resourceNodes[handle]; }
inline const ResourceNode &getResourceNode(const Handle handle) const noexcept { return _resourceNodes[handle]; }
inline ResourceHandleBlackboard &getBlackboard() noexcept { return _blackboard; }
void exportGraphViz(const ccstd::string &path);
inline void enableMerge(bool enable) noexcept;
bool hasPass(StringHandle handle);
private:
Handle create(VirtualResource *virtualResource);
PassNode &createPassNode(PassInsertPoint insertPoint, const StringHandle &name, Executable *pass);
Handle createResourceNode(VirtualResource *virtualResource);
void sort() noexcept;
void cull();
void computeResourceLifetime();
void mergePassNodes() noexcept;
void computeStoreActionAndMemoryless();
void generateDevicePasses();
ResourceNode *getResourceNode(const VirtualResource *virtualResource, uint8_t version) noexcept;
ccstd::vector<std::unique_ptr<PassNode>> _passNodes{};
ccstd::vector<ResourceNode> _resourceNodes{};
ccstd::vector<std::unique_ptr<VirtualResource>> _virtualResources{};
ccstd::vector<std::unique_ptr<DevicePass>> _devicePasses{};
ResourceHandleBlackboard _blackboard;
bool _merge{true};
friend class PassNode;
friend class PassNodeBuilder;
};
//////////////////////////////////////////////////////////////////////////
template <typename Data, typename SetupMethod, typename ExecuteMethod>
const CallbackPass<Data, ExecuteMethod> &FrameGraph::addPass(const PassInsertPoint insertPoint, const StringHandle &name, SetupMethod setup, ExecuteMethod &&execute) noexcept {
static_assert(sizeof(ExecuteMethod) < 1024, "Execute() lambda is capturing too much data.");
auto *const pass = ccnew CallbackPass<Data, ExecuteMethod>(std::forward<ExecuteMethod>(execute));
PassNode &passNode = createPassNode(insertPoint, name, pass);
PassNodeBuilder builder(*this, passNode);
setup(builder, pass->getData());
return *pass;
}
template <typename DescriptorType, typename ResourceType>
TypedHandle<ResourceType> FrameGraph::create(const StringHandle &name, const DescriptorType &desc) noexcept {
auto *const virtualResource = ccnew ResourceEntry<ResourceType>(name, static_cast<ID>(_virtualResources.size()), desc);
return TypedHandle<ResourceType>(create(virtualResource));
}
template <typename ResourceType>
TypedHandle<ResourceType> FrameGraph::importExternal(const StringHandle &name, ResourceType &resource) noexcept {
CC_ASSERT(resource.get());
auto *const virtualResource = ccnew ResourceEntry<ResourceType>(name, static_cast<ID>(_virtualResources.size()), resource);
return TypedHandle<ResourceType>(create(virtualResource));
}
void FrameGraph::enableMerge(bool const enable) noexcept {
_merge = enable;
}
//////////////////////////////////////////////////////////////////////////
template <typename DescriptorType, typename ResourceType>
TypedHandle<ResourceType> PassNodeBuilder::create(const StringHandle &name, const DescriptorType &desc) const noexcept {
return _graph.create(name, desc);
}
template <typename ResourceType>
TypedHandle<ResourceType> PassNodeBuilder::importExternal(const StringHandle &name, ResourceType &resource) const noexcept {
return _graph.importExternal(name, resource);
}
} // namespace framegraph
} // namespace cc

View File

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

View File

@@ -0,0 +1,101 @@
/****************************************************************************
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 "ImmutableState.h"
#include <vector>
#include "DevicePassResourceTable.h"
#include "gfx-base/GFXBarrier.h"
namespace cc {
namespace framegraph {
using gfx::AccessFlags;
using gfx::BufferUsage;
using gfx::hasFlag;
using gfx::MemoryAccess;
using gfx::MemoryUsage;
using gfx::ShaderStageFlags;
using gfx::TextureUsage;
namespace {
AccessFlags getAccessFlags(BufferUsage usage, MemoryUsage memUsage, const AccessStatus& status) noexcept {
return gfx::getAccessFlags(usage, memUsage, status.access, status.visibility);
}
AccessFlags getAccessFlags(TextureUsage usage, const AccessStatus& status) noexcept {
return gfx::getAccessFlags(usage, status.access, status.visibility);
}
} // namespace
std::pair<gfx::GFXObject*, gfx::GFXObject*> getBarrier(const ResourceBarrier& barrierInfo, const DevicePassResourceTable* dictPtr) noexcept {
std::pair<gfx::GFXObject*, gfx::GFXObject*> res;
const auto& dict = *dictPtr;
if (barrierInfo.resourceType == ResourceType::BUFFER) {
gfx::Buffer* gfxBuffer{nullptr};
if (hasFlag(barrierInfo.endStatus.access, MemoryAccess::WRITE_ONLY)) {
gfxBuffer = dict.getWrite(static_cast<BufferHandle>(barrierInfo.handle));
} else {
gfxBuffer = dict.getRead(static_cast<BufferHandle>(barrierInfo.handle));
}
auto usage = gfxBuffer->getUsage();
auto memUsage = gfxBuffer->getMemUsage();
gfx::BufferBarrierInfo info;
info.prevAccesses = getAccessFlags(usage, memUsage, barrierInfo.beginStatus);
info.nextAccesses = getAccessFlags(usage, memUsage, barrierInfo.endStatus);
info.offset = static_cast<uint32_t>(barrierInfo.bufferRange.base);
info.size = static_cast<uint32_t>(barrierInfo.bufferRange.len);
info.type = barrierInfo.barrierType;
res.first = gfx::Device::getInstance()->getBufferBarrier(info);
res.second = gfxBuffer;
} else if (barrierInfo.resourceType == ResourceType::TEXTURE) {
gfx::Texture* gfxTexture{nullptr};
if (hasFlag(barrierInfo.beginStatus.access, MemoryAccess::WRITE_ONLY)) {
gfxTexture = dict.getWrite(static_cast<TextureHandle>(barrierInfo.handle));
} else {
gfxTexture = dict.getRead(static_cast<TextureHandle>(barrierInfo.handle));
}
auto usage = gfxTexture->getInfo().usage;
gfx::TextureBarrierInfo info;
info.type = barrierInfo.barrierType;
info.prevAccesses = getAccessFlags(usage, barrierInfo.beginStatus);
info.nextAccesses = getAccessFlags(usage, barrierInfo.endStatus);
info.range.mipLevel = static_cast<uint32_t>(barrierInfo.mipRange.base);
info.range.levelCount = static_cast<uint32_t>(barrierInfo.mipRange.len);
info.range.firstSlice = static_cast<uint32_t>(barrierInfo.layerRange.base);
info.range.numSlices = static_cast<uint32_t>(barrierInfo.layerRange.len);
res.first = gfx::Device::getInstance()->getTextureBarrier(info);
res.second = gfxTexture;
}
return res;
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,84 @@
/****************************************************************************
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 "frame-graph/Resource.h"
#include "gfx-base/GFXDef-common.h"
namespace cc {
namespace framegraph {
class DevicePassResourceTable;
struct Range {
size_t base{0};
size_t len{0};
};
struct AccessStatus {
gfx::PassType passType{gfx::PassType::RASTER};
gfx::ShaderStageFlagBit visibility{gfx::ShaderStageFlagBit::NONE};
gfx::MemoryAccessBit access{gfx::MemoryAccessBit::NONE};
};
enum class ResourceType : uint32_t {
UNKNOWN,
BUFFER,
TEXTURE,
};
struct ResourceBarrier {
ResourceType resourceType{ResourceType::UNKNOWN};
gfx::BarrierType barrierType{gfx::BarrierType::FULL};
Handle handle;
AccessStatus beginStatus;
AccessStatus endStatus;
Range layerRange;
union {
Range mipRange;
Range bufferRange;
};
};
struct PassBarrierPair {
ccstd::vector<ResourceBarrier> frontBarriers;
ccstd::vector<ResourceBarrier> rearBarriers;
};
using BarriersList = std::vector<PassBarrierPair>;
struct PassBarriers {
PassBarrierPair blockBarrier;
BarriersList subpassBarriers;
};
std::pair<gfx::GFXObject* /*barrier*/, gfx::GFXObject* /*resource*/> getBarrier(const ResourceBarrier& barrierInfo, const DevicePassResourceTable* dict) noexcept;
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,57 @@
/****************************************************************************
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 "PassInsertPointManager.h"
#include "base/Macros.h"
namespace cc {
namespace framegraph {
PassInsertPointManager &PassInsertPointManager::getInstance() {
static PassInsertPointManager instance;
return instance;
}
PassInsertPoint PassInsertPointManager::record(const char *const name, const PassInsertPoint point) {
StringHandle nameHandle = _stringPool.find(name);
if (nameHandle.isValid()) {
CC_ASSERT(point == get(nameHandle));
return get(nameHandle);
}
nameHandle = _stringPool.stringToHandle(name);
CC_ASSERT(nameHandle == _insertPoints.size());
_insertPoints.emplace_back(point);
return point;
}
PassInsertPoint PassInsertPointManager::get(const char *const name) const {
const StringHandle nameHandle = _stringPool.find(name);
CC_ASSERT(nameHandle.isValid());
return get(nameHandle);
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,64 @@
/****************************************************************************
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 "Handle.h"
#include "base/Macros.h"
namespace cc {
namespace framegraph {
using PassInsertPoint = uint16_t;
class PassInsertPointManager final {
public:
PassInsertPointManager(const PassInsertPointManager &) = delete;
PassInsertPointManager(PassInsertPointManager &&) noexcept = delete;
PassInsertPointManager &operator=(const PassInsertPointManager &) = delete;
PassInsertPointManager &operator=(PassInsertPointManager &&) noexcept = delete;
static PassInsertPointManager &getInstance();
PassInsertPoint record(const char *name, PassInsertPoint point);
PassInsertPoint get(const char *name) const;
private:
PassInsertPointManager() = default;
~PassInsertPointManager() = default;
inline PassInsertPoint get(StringHandle name) const;
StringPool _stringPool;
ccstd::vector<PassInsertPoint> _insertPoints{};
};
//////////////////////////////////////////////////////////////////////////
PassInsertPoint PassInsertPointManager::get(const StringHandle name) const {
return _insertPoints[name];
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,191 @@
/****************************************************************************
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 "PassNode.h"
#include <algorithm>
#include "FrameGraph.h"
#include "ResourceNode.h"
namespace cc {
namespace framegraph {
PassNode::PassNode(const PassInsertPoint inserPoint, const StringHandle name, const ID &id, Executable *pass)
: _pass(pass),
_name(name),
_id(id),
_insertPoint(inserPoint) {
CC_ASSERT(_name.isValid());
}
Handle PassNode::read(FrameGraph & /*graph*/, const Handle &input) {
const auto it = std::find_if(_reads.begin(), _reads.end(), [input](const Handle handle) {
return input == handle;
});
if (it == _reads.end()) {
_reads.push_back(input);
}
return input;
}
Handle PassNode::write(FrameGraph &graph, const Handle &output) {
CC_ASSERT(std::find_if(_writes.begin(), _writes.end(), [output](const Handle handle) {
return output == handle;
}) == _writes.end());
const ResourceNode &nodeOldVersion = graph.getResourceNode(output);
nodeOldVersion.virtualResource->newVersion();
_sideEffect = _sideEffect || nodeOldVersion.virtualResource->isImported();
const Handle handle = graph.createResourceNode(nodeOldVersion.virtualResource);
ResourceNode &nodeNewVersion = graph.getResourceNode(handle);
nodeNewVersion.writer = this;
_writes.push_back(handle);
return handle;
}
void PassNode::createRenderTargetAttachment(RenderTargetAttachment &&attachment) {
if (attachment.desc.usage == RenderTargetAttachment::Usage::COLOR) {
if (attachment.desc.slot == 0xff) {
for (uint8_t i = 0; i < RenderTargetAttachment::DEPTH_STENCIL_SLOT_START; ++i) {
if ((_usedRenderTargetSlotMask & (1 << i)) == 0) {
attachment.desc.slot = i;
break;
}
}
} else {
CC_ASSERT(attachment.desc.slot < RenderTargetAttachment::DEPTH_STENCIL_SLOT_START);
}
} else {
attachment.desc.slot = RenderTargetAttachment::DEPTH_STENCIL_SLOT_START + static_cast<uint8_t>(attachment.desc.usage) - 1;
if (attachment.desc.usage == RenderTargetAttachment::Usage::DEPTH_STENCIL) {
CC_ASSERT((_usedRenderTargetSlotMask & (1 << (RenderTargetAttachment::DEPTH_STENCIL_SLOT_START + static_cast<uint8_t>(RenderTargetAttachment::Usage::DEPTH) - 1))) == 0);
CC_ASSERT((_usedRenderTargetSlotMask & (1 << (RenderTargetAttachment::DEPTH_STENCIL_SLOT_START + static_cast<uint8_t>(RenderTargetAttachment::Usage::STENCIL) - 1))) == 0);
} else {
CC_ASSERT((_usedRenderTargetSlotMask & (1 << (RenderTargetAttachment::DEPTH_STENCIL_SLOT_START + static_cast<uint8_t>(attachment.desc.usage) - 1))) == 0);
}
}
CC_ASSERT((_usedRenderTargetSlotMask & (1 << attachment.desc.slot)) == 0);
_usedRenderTargetSlotMask |= (1 << attachment.desc.slot);
_attachments.emplace_back(attachment);
_hasClearedAttachment = _hasClearedAttachment || (attachment.desc.loadOp == gfx::LoadOp::CLEAR);
}
bool PassNode::canMerge(const FrameGraph &graph, const PassNode &passNode) const {
const size_t attachmentCount = _attachments.size();
if (passNode._hasClearedAttachment || attachmentCount != passNode._attachments.size()) {
return false;
}
for (size_t i = 0; i < attachmentCount; ++i) {
const RenderTargetAttachment &attachmentInPassNodeA = _attachments[i];
const RenderTargetAttachment &attachmentInPassNodeB = passNode._attachments[i];
if (attachmentInPassNodeA.desc.usage != attachmentInPassNodeB.desc.usage ||
attachmentInPassNodeA.desc.slot != attachmentInPassNodeB.desc.slot ||
attachmentInPassNodeA.desc.writeMask != attachmentInPassNodeB.desc.writeMask ||
attachmentInPassNodeA.level != attachmentInPassNodeB.level ||
attachmentInPassNodeA.layer != attachmentInPassNodeB.layer ||
attachmentInPassNodeA.index != attachmentInPassNodeB.index ||
graph.getResourceNode(attachmentInPassNodeA.textureHandle).virtualResource != graph.getResourceNode(attachmentInPassNodeB.textureHandle).virtualResource) {
return false;
}
}
return true;
}
RenderTargetAttachment *PassNode::getRenderTargetAttachment(const Handle &handle) {
const auto it = std::find_if(_attachments.begin(), _attachments.end(), [&handle](const RenderTargetAttachment &attachment) {
return attachment.textureHandle == handle;
});
return it == _attachments.end() ? nullptr : &(*it);
}
RenderTargetAttachment *PassNode::getRenderTargetAttachment(const FrameGraph &graph, const VirtualResource *const resource) {
const auto it = std::find_if(_attachments.begin(), _attachments.end(), [&](const RenderTargetAttachment &attachment) {
return graph.getResourceNode(attachment.textureHandle).virtualResource == resource;
});
return it == _attachments.end() ? nullptr : &(*it);
}
void PassNode::requestTransientResources() {
PassNode *it = this;
do {
std::for_each(it->_resourceRequestArray.begin(), it->_resourceRequestArray.end(), [](VirtualResource *const resource) {
if (!resource->isImported()) {
resource->request();
}
});
it = it->_next;
} while (it);
}
void PassNode::releaseTransientResources() {
PassNode *it = this;
do {
// resources should be release in the reverse order to stabilize usages between frames
std::for_each(it->_resourceReleaseArray.rbegin(), it->_resourceReleaseArray.rend(), [](VirtualResource *const resource) {
if (!resource->isImported()) {
resource->release();
}
});
it = it->_next;
} while (it);
}
void PassNode::setDevicePassId(ID const id) {
PassNode *it = this;
do {
it->_devicePassId = id;
it = it->_next;
} while (it);
}
Handle PassNode::getWriteResourceNodeHandle(const FrameGraph &graph, const VirtualResource *const resource) const {
const auto it = std::find_if(_writes.begin(), _writes.end(), [&](const Handle handle) {
return graph.getResourceNode(handle).virtualResource == resource;
});
return it == _writes.end() ? Handle{} : *it;
}
void PassNode::setBarrier(const PassBarrierPair &barrier) {
_barriers = barrier;
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,124 @@
/****************************************************************************
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 <memory>
#include "CallbackPass.h"
#include "Handle.h"
#include "ImmutableState.h"
#include "PassInsertPointManager.h"
#include "RenderTargetAttachment.h"
#include "VirtualResource.h"
#include "gfx-base/GFXDef.h"
namespace cc {
namespace framegraph {
class FrameGraph;
class PassNode final {
public:
PassNode(PassInsertPoint inserPoint, StringHandle name, const ID &id, Executable *pass);
~PassNode() = default;
PassNode(PassNode &&) noexcept = default;
PassNode(const PassNode &) = delete;
PassNode &operator=(const PassNode &) = delete;
PassNode &operator=(PassNode &&) noexcept = delete;
Handle read(FrameGraph &graph, const Handle &input);
Handle write(FrameGraph &graph, const Handle &output);
void createRenderTargetAttachment(RenderTargetAttachment &&attachment);
void setBarrier(const PassBarrierPair &barrier);
inline void sideEffect();
inline void subpass(bool end, bool clearActionIgnorable);
inline void setViewport(const gfx::Viewport &viewport, const gfx::Rect &scissor);
inline const PassBarrierPair &getBarriers() const;
private:
bool canMerge(const FrameGraph &graph, const PassNode &passNode) const;
RenderTargetAttachment *getRenderTargetAttachment(const Handle &handle);
RenderTargetAttachment *getRenderTargetAttachment(const FrameGraph &graph, const VirtualResource *resource);
void requestTransientResources();
void releaseTransientResources();
void setDevicePassId(ID id);
Handle getWriteResourceNodeHandle(const FrameGraph &graph, const VirtualResource *resource) const;
std::unique_ptr<Executable> _pass{nullptr};
ccstd::vector<Handle> _reads{};
ccstd::vector<Handle> _writes{};
ccstd::vector<RenderTargetAttachment> _attachments{};
ccstd::vector<VirtualResource *> _resourceRequestArray{};
ccstd::vector<VirtualResource *> _resourceReleaseArray{};
const StringHandle _name;
uint32_t _refCount{0};
PassNode *_head{nullptr};
PassNode *_next{nullptr};
uint16_t _distanceToHead{0};
uint16_t _usedRenderTargetSlotMask{0};
ID const _id{0};
ID _devicePassId{0};
const PassInsertPoint _insertPoint{0};
bool _sideEffect{false};
bool _subpass{false};
bool _subpassEnd{false};
bool _hasClearedAttachment{false};
bool _clearActionIgnorable{false};
bool _customViewport{false};
gfx::Viewport _viewport;
gfx::Rect _scissor;
PassBarrierPair _barriers;
friend class FrameGraph;
friend class DevicePass;
friend class DevicePassResourceTable;
};
//////////////////////////////////////////////////////////////////////////
const PassBarrierPair &PassNode::getBarriers() const {
return _barriers;
}
void PassNode::sideEffect() {
_sideEffect = true;
}
void PassNode::subpass(bool end, bool clearActionIgnorable) {
_subpass = true;
_subpassEnd = end;
_clearActionIgnorable = clearActionIgnorable;
}
void PassNode::setViewport(const gfx::Viewport &viewport, const gfx::Rect &scissor) {
_customViewport = true;
_viewport = viewport;
_scissor = scissor;
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,71 @@
/****************************************************************************
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 "PassNodeBuilder.h"
#include "FrameGraph.h"
namespace cc {
namespace framegraph {
PassNodeBuilder::PassNodeBuilder(FrameGraph &graph, PassNode &passNode) noexcept
: _graph(graph),
_passNode(passNode) {
}
Handle PassNodeBuilder::read(const Handle &input) const noexcept {
return _passNode.read(_graph, input);
}
TextureHandle PassNodeBuilder::write(const TextureHandle &output, uint8_t mipmapLevel, uint8_t faceId, uint8_t arrayPosition, const RenderTargetAttachment::Descriptor &attachmentDesc) const noexcept {
const TextureHandle handle(_passNode.write(_graph, output));
RenderTargetAttachment attachment;
attachment.textureHandle = handle;
attachment.desc = attachmentDesc;
attachment.level = mipmapLevel;
attachment.layer = faceId;
attachment.index = arrayPosition;
_passNode.createRenderTargetAttachment(std::forward<RenderTargetAttachment>(attachment));
if (attachmentDesc.loadOp == gfx::LoadOp::LOAD) {
ResourceNode &outputResourceNode = _graph.getResourceNode(output);
++outputResourceNode.readerCount;
}
return handle;
}
TextureHandle PassNodeBuilder::write(const TextureHandle &output, const RenderTargetAttachment::Descriptor &attachmentDesc) const noexcept {
return write(output, 0, 0, 0, attachmentDesc);
}
void PassNodeBuilder::writeToBlackboard(const StringHandle &name, const Handle &handle) const noexcept {
_graph.getBlackboard().put(name, handle);
}
Handle PassNodeBuilder::readFromBlackboard(const StringHandle &name) const noexcept {
return Handle(_graph.getBlackboard().get(name));
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,103 @@
/****************************************************************************
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 "PassNode.h"
namespace cc {
namespace framegraph {
class PassNodeBuilder final {
public:
PassNodeBuilder(FrameGraph &graph, PassNode &passNode) noexcept;
PassNodeBuilder() = delete;
~PassNodeBuilder() = default;
PassNodeBuilder(const PassNodeBuilder &) = delete;
PassNodeBuilder(PassNodeBuilder &&) = delete;
PassNodeBuilder &operator=(const PassNodeBuilder &) = delete;
PassNodeBuilder &operator=(PassNodeBuilder &&) = delete;
template <typename DescriptorType, typename ResourceType = typename ResourceTypeLookupTable<DescriptorType>::Resource>
TypedHandle<ResourceType> create(const StringHandle &name, const DescriptorType &desc) const noexcept;
template <typename ResourceType>
TypedHandle<ResourceType> importExternal(const StringHandle &name, ResourceType &resource) const noexcept;
template <typename ResourceType>
TypedHandle<ResourceType> read(TypedHandle<ResourceType> const &input) const noexcept;
template <typename ResourceType>
TypedHandle<ResourceType> write(TypedHandle<ResourceType> const &output) const noexcept;
TextureHandle write(const TextureHandle &output, uint8_t mipmapLevel, uint8_t faceId, uint8_t arrayPosition, const RenderTargetAttachment::Descriptor &attachmentDesc) const noexcept;
TextureHandle write(const TextureHandle &output, const RenderTargetAttachment::Descriptor &attachmentDesc) const noexcept;
inline void sideEffect() const noexcept;
inline void subpass(bool end = false, bool clearActionIgnorable = true) const noexcept;
inline void setViewport(const gfx::Rect &scissor) noexcept;
inline void setViewport(const gfx::Viewport &viewport, const gfx::Rect &scissor) noexcept;
inline void setBarrier(const PassBarrierPair &barrier);
void writeToBlackboard(const StringHandle &name, const Handle &handle) const noexcept;
Handle readFromBlackboard(const StringHandle &name) const noexcept;
private:
Handle read(const Handle &input) const noexcept;
FrameGraph &_graph;
PassNode &_passNode;
};
//////////////////////////////////////////////////////////////////////////
template <typename ResourceType>
TypedHandle<ResourceType> PassNodeBuilder::read(TypedHandle<ResourceType> const &input) const noexcept {
return TypedHandle<ResourceType>(read(static_cast<const Handle &>(input)));
}
template <typename ResourceType>
TypedHandle<ResourceType> PassNodeBuilder::write(TypedHandle<ResourceType> const &output) const noexcept {
return TypedHandle<ResourceType>(_passNode.write(_graph, output));
}
void PassNodeBuilder::sideEffect() const noexcept {
_passNode.sideEffect();
}
void PassNodeBuilder::subpass(bool end, bool clearActionIgnorable) const noexcept {
_passNode.subpass(end, clearActionIgnorable);
}
void PassNodeBuilder::setViewport(const gfx::Rect &scissor) noexcept {
gfx::Viewport viewport{scissor.x, scissor.y, scissor.width, scissor.height, 0.F, 1.F};
_passNode.setViewport(viewport, scissor);
}
void PassNodeBuilder::setViewport(const gfx::Viewport &viewport, const gfx::Rect &scissor) noexcept {
_passNode.setViewport(viewport, scissor);
}
void PassNodeBuilder::setBarrier(const PassBarrierPair &barrier) {
_passNode.setBarrier(barrier);
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,79 @@
/****************************************************************************
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 "Resource.h"
namespace cc {
namespace framegraph {
struct RenderTargetAttachment final {
using StoreOp = gfx::StoreOp;
using LoadOp = gfx::LoadOp;
using Color = gfx::Color;
enum class Usage : uint8_t {
COLOR,
DEPTH,
STENCIL,
DEPTH_STENCIL,
};
struct Descriptor final {
Usage usage{Usage::COLOR};
uint8_t slot{0xff};
uint8_t writeMask{0xff};
LoadOp loadOp{LoadOp::DISCARD};
Color clearColor;
float clearDepth{1.F};
uint8_t clearStencil{0U};
gfx::AccessFlags beginAccesses{gfx::AccessFlagBit::NONE};
gfx::AccessFlags endAccesses{gfx::AccessFlagBit::NONE};
};
struct Sorter {
inline bool operator()(const RenderTargetAttachment &a1, const RenderTargetAttachment &a2) const noexcept;
};
static constexpr uint8_t DEPTH_STENCIL_SLOT_START{13};
TextureHandle textureHandle{};
Descriptor desc;
uint8_t level{0};
uint8_t layer{0};
uint8_t index{0};
StoreOp storeOp{StoreOp::DISCARD};
};
inline bool RenderTargetAttachment::Sorter::operator()(const RenderTargetAttachment &a1, const RenderTargetAttachment &a2) const noexcept {
if (a1.desc.usage == a2.desc.usage) {
return a1.desc.slot < a2.desc.slot;
}
return a1.desc.usage < a2.desc.usage;
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,155 @@
/****************************************************************************
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 "ResourceAllocator.h"
#include "Handle.h"
#include "renderer/gfx-base/GFXBuffer.h"
#include "renderer/gfx-base/GFXDevice.h"
#include "renderer/gfx-base/GFXFramebuffer.h"
#include "renderer/gfx-base/GFXRenderPass.h"
#include "renderer/gfx-base/GFXTexture.h"
namespace cc {
namespace framegraph {
template <typename DeviceResourceType, typename DescriptorType>
struct DeviceResourceCreator final {
inline DeviceResourceType *operator()(const DescriptorType & /*desc*/) const {
return nullptr;
}
};
template <typename DescriptorType>
struct ResourceTypeLookupTable final {};
template <typename DeviceResourceType, typename DescriptorType,
typename DeviceResourceCreatorType = DeviceResourceCreator<DeviceResourceType, DescriptorType>>
class Resource final {
public:
using Allocator = ResourceAllocator<DeviceResourceType, DescriptorType, DeviceResourceCreatorType>;
using DeviceResource = DeviceResourceType;
using Descriptor = DescriptorType;
Resource() = default;
explicit Resource(const Descriptor &desc);
~Resource() = default;
Resource(const Resource &) = default;
Resource(Resource &&) noexcept = default;
Resource &operator=(const Resource &) = default;
Resource &operator=(Resource &&) noexcept = default;
void createTransient() noexcept;
void createPersistent() noexcept;
void destroyTransient() noexcept;
void destroyPersistent() noexcept;
inline DeviceResourceType *get() const noexcept;
inline const Descriptor &getDesc() const noexcept;
private:
explicit Resource(DeviceResourceType *external);
Descriptor _desc;
DeviceResourceType *_deviceObject{nullptr};
friend class FrameGraph;
};
//////////////////////////////////////////////////////////////////////////
template <typename DeviceResourceType, typename DescriptorType, typename DeviceResourceCreatorType>
Resource<DeviceResourceType, DescriptorType, DeviceResourceCreatorType>::Resource(const Descriptor &desc)
: _desc(desc) {
}
template <typename DeviceResourceType, typename DescriptorType, typename DeviceResourceCreatorType>
Resource<DeviceResourceType, DescriptorType, DeviceResourceCreatorType>::Resource(DeviceResourceType *external)
: _desc(external->getInfo()), _deviceObject(external) {
}
template <typename DeviceResourceType, typename DescriptorType, typename DeviceResourceCreatorType>
void Resource<DeviceResourceType, DescriptorType, DeviceResourceCreatorType>::createTransient() noexcept {
_deviceObject = Allocator::getInstance().alloc(_desc);
}
template <typename DeviceResourceType, typename DescriptorType, typename DeviceResourceCreatorType>
void Resource<DeviceResourceType, DescriptorType, DeviceResourceCreatorType>::createPersistent() noexcept {
if (!_deviceObject) {
DeviceResourceCreatorType creator;
_deviceObject = creator(_desc);
_deviceObject->addRef();
}
}
template <typename DeviceResourceType, typename DescriptorType, typename DeviceResourceCreatorType>
void Resource<DeviceResourceType, DescriptorType, DeviceResourceCreatorType>::destroyTransient() noexcept {
Allocator::getInstance().free(_deviceObject);
_deviceObject = nullptr;
}
template <typename DeviceResourceType, typename DescriptorType, typename DeviceResourceCreatorType>
void Resource<DeviceResourceType, DescriptorType, DeviceResourceCreatorType>::destroyPersistent() noexcept {
if (_deviceObject) {
_deviceObject->release();
_deviceObject = nullptr;
}
}
template <typename DeviceResourceType, typename DescriptorType, typename DeviceResourceCreatorType>
DeviceResourceType *Resource<DeviceResourceType, DescriptorType, DeviceResourceCreatorType>::get() const noexcept {
return _deviceObject;
}
template <typename DeviceResourceType, typename DescriptorType, typename DeviceResourceCreatorType>
const DescriptorType &Resource<DeviceResourceType, DescriptorType, DeviceResourceCreatorType>::getDesc() const noexcept {
return _desc;
}
//////////////////////////////////////////////////////////////////////////
#define DEFINE_GFX_RESOURCE(Type) \
template <> \
struct DeviceResourceCreator<gfx::Type, gfx::Type##Info> final { \
inline gfx::Type *operator()(const gfx::Type##Info &desc) const { \
return gfx::Device::getInstance()->create##Type(desc); \
} \
}; \
using Type = Resource<gfx::Type, gfx::Type##Info>; \
using Type##Handle = TypedHandle<Type>; \
template <> \
struct ResourceTypeLookupTable<gfx::Type##Info> final { \
using Resource = Type; \
};
// Descriptors must have std::hash specialization and == operators
DEFINE_GFX_RESOURCE(Buffer)
DEFINE_GFX_RESOURCE(Framebuffer)
DEFINE_GFX_RESOURCE(RenderPass)
DEFINE_GFX_RESOURCE(Texture)
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,269 @@
/****************************************************************************
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 <algorithm>
#include "base/RefVector.h"
#include "base/memory/Memory.h"
#include "base/std/container/unordered_map.h"
#include "gfx-base/GFXDef.h"
namespace cc {
namespace framegraph {
template <typename DeviceResourceType, typename DescriptorType, typename DeviceResourceCreatorType>
class ResourceAllocator final {
public:
using DeviceResourceCreator = DeviceResourceCreatorType;
ResourceAllocator(const ResourceAllocator &) = delete;
ResourceAllocator(ResourceAllocator &&) noexcept = delete;
ResourceAllocator &operator=(const ResourceAllocator &) = delete;
ResourceAllocator &operator=(ResourceAllocator &&) noexcept = delete;
static ResourceAllocator &getInstance() noexcept;
DeviceResourceType *alloc(const DescriptorType &desc) noexcept;
void free(DeviceResourceType *resource) noexcept;
inline void tick() noexcept;
void gc(uint32_t unusedFrameCount) noexcept;
private:
using DeviceResourcePool = RefVector<DeviceResourceType *>;
ResourceAllocator() noexcept = default;
~ResourceAllocator() = default;
ccstd::unordered_map<DescriptorType, DeviceResourcePool, gfx::Hasher<DescriptorType>> _pool{};
ccstd::unordered_map<DeviceResourceType *, int64_t> _ages{};
uint64_t _age{0};
};
//////////////////////////////////////////////////////////////////////////
template <typename DeviceResourceType, typename DescriptorType, typename DeviceResourceCreatorType>
ResourceAllocator<DeviceResourceType, DescriptorType, DeviceResourceCreatorType> &
ResourceAllocator<DeviceResourceType, DescriptorType, DeviceResourceCreatorType>::getInstance() noexcept {
static ResourceAllocator instance;
return instance;
}
template <typename DeviceResourceType, typename DescriptorType, typename DeviceResourceCreatorType>
DeviceResourceType *ResourceAllocator<DeviceResourceType, DescriptorType, DeviceResourceCreatorType>::alloc(const DescriptorType &desc) noexcept {
DeviceResourcePool &pool{_pool[desc]};
DeviceResourceType *resource{nullptr};
for (DeviceResourceType *res : pool) {
if (_ages[res] >= 0) {
resource = res;
break;
}
}
if (!resource) {
DeviceResourceCreator creator;
resource = creator(desc);
pool.pushBack(resource);
}
_ages[resource] = -1;
return resource;
}
template <typename DeviceResourceType, typename DescriptorType, typename DeviceResourceCreatorType>
void ResourceAllocator<DeviceResourceType, DescriptorType, DeviceResourceCreatorType>::free(DeviceResourceType *const resource) noexcept {
CC_ASSERT(_ages.count(resource) && _ages[resource] < 0);
_ages[resource] = _age;
}
template <typename DeviceResourceType, typename DescriptorType, typename DeviceResourceCreatorType>
void ResourceAllocator<DeviceResourceType, DescriptorType, DeviceResourceCreatorType>::tick() noexcept {
++_age;
}
template <typename DeviceResourceType, typename DescriptorType, typename DeviceResourceCreatorType>
void ResourceAllocator<DeviceResourceType, DescriptorType, DeviceResourceCreatorType>::gc(uint32_t const unusedFrameCount) noexcept {
for (auto &pair : _pool) {
DeviceResourcePool &pool = pair.second;
auto count = static_cast<int>(pool.size());
if (!count) {
continue;
}
int destroyBegin = count - 1;
for (int i = 0; i < count; ++i) {
int64_t ageI = _ages[pool.at(i)];
if (ageI < 0 || _age - ageI < unusedFrameCount) {
continue;
}
int j = destroyBegin;
for (; j > i; --j) {
int64_t ageJ = _ages[pool.at(j)];
if (ageJ < 0 || _age - ageJ < unusedFrameCount) {
std::swap(pool.at(i), pool.at(j));
destroyBegin = j - 1;
break;
}
}
if (i >= j) {
destroyBegin = i - 1;
}
if (i >= destroyBegin) {
break;
}
}
while (++destroyBegin < count) {
auto *resource = pool.back();
_ages.erase(resource);
pool.popBack();
}
}
}
template <typename DeviceResourceType, typename DeviceResourceCreatorType>
class ResourceAllocator<DeviceResourceType, gfx::FramebufferInfo, DeviceResourceCreatorType> final {
public:
using DeviceResourceCreator = DeviceResourceCreatorType;
ResourceAllocator(const ResourceAllocator &) = delete;
ResourceAllocator(ResourceAllocator &&) noexcept = delete;
ResourceAllocator &operator=(const ResourceAllocator &) = delete;
ResourceAllocator &operator=(ResourceAllocator &&) noexcept = delete;
static ResourceAllocator &getInstance() noexcept;
DeviceResourceType *alloc(const gfx::FramebufferInfo &desc) noexcept;
void free(DeviceResourceType *resource) noexcept;
inline void tick() noexcept;
void gc(uint32_t unusedFrameCount) noexcept;
private:
using DeviceResourcePool = RefVector<DeviceResourceType *>;
ResourceAllocator() noexcept = default;
~ResourceAllocator() = default;
std::unordered_map<ccstd::hash_t, DeviceResourcePool> _pool{};
std::unordered_map<DeviceResourceType *, int64_t> _ages{};
uint64_t _age{0};
};
//////////////////////////////////////////////////////////////////////////
template <typename DeviceResourceType, typename DeviceResourceCreatorType>
ResourceAllocator<DeviceResourceType, gfx::FramebufferInfo, DeviceResourceCreatorType> &
ResourceAllocator<DeviceResourceType, gfx::FramebufferInfo, DeviceResourceCreatorType>::getInstance() noexcept {
static ResourceAllocator instance;
return instance;
}
template <typename DeviceResourceType, typename DeviceResourceCreatorType>
DeviceResourceType *ResourceAllocator<DeviceResourceType, gfx::FramebufferInfo, DeviceResourceCreatorType>::alloc(const gfx::FramebufferInfo &desc) noexcept {
ccstd::hash_t hash = gfx::Hasher<gfx::FramebufferInfo>()(desc);
DeviceResourcePool &pool{_pool[hash]};
DeviceResourceType *resource{nullptr};
for (DeviceResourceType *res : pool) {
if (_ages[res] >= 0) {
resource = res;
break;
}
}
if (!resource) {
DeviceResourceCreator creator;
resource = creator(desc);
pool.pushBack(resource);
}
_ages[resource] = -1;
return resource;
}
template <typename DeviceResourceType, typename DeviceResourceCreatorType>
void ResourceAllocator<DeviceResourceType, gfx::FramebufferInfo, DeviceResourceCreatorType>::free(DeviceResourceType *const resource) noexcept {
CC_ASSERT(_ages.count(resource) && _ages[resource] < 0);
_ages[resource] = _age;
}
template <typename DeviceResourceType, typename DeviceResourceCreatorType>
void ResourceAllocator<DeviceResourceType, gfx::FramebufferInfo, DeviceResourceCreatorType>::tick() noexcept {
++_age;
}
template <typename DeviceResourceType, typename DeviceResourceCreatorType>
void ResourceAllocator<DeviceResourceType, gfx::FramebufferInfo, DeviceResourceCreatorType>::gc(uint32_t const unusedFrameCount) noexcept {
for (auto &pair : _pool) {
DeviceResourcePool &pool = pair.second;
auto count = static_cast<int>(pool.size());
if (!count) {
continue;
}
int destroyBegin = count - 1;
for (int i = 0; i < count; ++i) {
int64_t ageI = _ages[pool.at(i)];
if (ageI < 0 || _age - ageI < unusedFrameCount) {
continue;
}
int j = destroyBegin;
for (; j > i; --j) {
int64_t ageJ = _ages[pool.at(j)];
if (ageJ < 0 || _age - ageJ < unusedFrameCount) {
std::swap(pool.at(i), pool.at(j));
destroyBegin = j - 1;
break;
}
}
if (i >= j) {
destroyBegin = i - 1;
}
if (i >= destroyBegin) {
break;
}
}
while (++destroyBegin < count) {
auto *resource = pool.back();
// delete resource;
_ages.erase(resource);
pool.popBack();
}
}
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,84 @@
/****************************************************************************
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 "VirtualResource.h"
namespace cc {
namespace framegraph {
template <typename ResourceType, typename Enable = std::enable_if_t<std::is_base_of<gfx::GFXObject, typename ResourceType::DeviceResource>::value>>
class ResourceEntry final : public VirtualResource {
public:
explicit ResourceEntry(StringHandle name, ID id, const typename ResourceType::Descriptor &desc) noexcept;
ResourceEntry(StringHandle name, ID id, const ResourceType &resource) noexcept;
ResourceEntry() = delete;
~ResourceEntry() override = default;
ResourceEntry(const ResourceEntry &) = delete;
ResourceEntry(ResourceEntry &&) noexcept = delete;
ResourceEntry &operator=(const ResourceEntry &) = delete;
ResourceEntry &operator=(ResourceEntry &&) noexcept = delete;
void request() noexcept override;
void release() noexcept override;
typename ResourceType::DeviceResource *getDeviceResource() const noexcept override;
inline const ResourceType &get() const noexcept { return _resource; }
private:
ResourceType _resource;
};
//////////////////////////////////////////////////////////////////////////
template <typename ResourceType, typename Enable>
ResourceEntry<ResourceType, Enable>::ResourceEntry(const StringHandle name, ID const id, const typename ResourceType::Descriptor &desc) noexcept
: VirtualResource(name, id, false),
_resource(desc) {
}
template <typename ResourceType, typename Enable>
ResourceEntry<ResourceType, Enable>::ResourceEntry(const StringHandle name, ID const id, const ResourceType &resource) noexcept
: VirtualResource(name, id, true),
_resource(resource) {
}
template <typename ResourceType, typename Enable>
void ResourceEntry<ResourceType, Enable>::request() noexcept {
_resource.createTransient();
}
template <typename ResourceType, typename Enable>
void ResourceEntry<ResourceType, Enable>::release() noexcept {
_resource.destroyTransient();
}
template <typename ResourceType, typename Enable>
typename ResourceType::DeviceResource *ResourceEntry<ResourceType, Enable>::getDeviceResource() const noexcept {
return _resource.get();
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,40 @@
/****************************************************************************
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 "VirtualResource.h"
namespace cc {
namespace framegraph {
struct ResourceNode final {
VirtualResource *virtualResource{nullptr};
PassNode *writer{nullptr};
uint32_t readerCount{0};
uint8_t version{0};
};
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,43 @@
/****************************************************************************
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 "VirtualResource.h"
namespace cc {
namespace framegraph {
VirtualResource::VirtualResource(const StringHandle name, ID const id, bool const imported) noexcept
: _name(name),
_id(id),
_imported(imported) {
CC_ASSERT(_name.isValid());
}
void VirtualResource::updateLifetime(PassNode *const passNode) noexcept {
_firstUsePass = _firstUsePass ? _firstUsePass : passNode;
_lastUsePass = passNode;
}
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,73 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "Handle.h"
#include "renderer/gfx-base/GFXObject.h"
namespace cc {
namespace framegraph {
class PassNode;
using ID = uint16_t;
class VirtualResource {
public:
VirtualResource(StringHandle name, ID id, bool imported) noexcept;
VirtualResource() noexcept = delete;
virtual ~VirtualResource() = default;
VirtualResource(const VirtualResource &) = delete;
VirtualResource(VirtualResource &&) noexcept = delete;
VirtualResource &operator=(const VirtualResource &) = delete;
VirtualResource &operator=(VirtualResource &&) noexcept = delete;
virtual void request() noexcept = 0;
virtual void release() noexcept = 0;
bool isImported() const noexcept { return _imported; }
void updateLifetime(PassNode *passNode) noexcept;
void newVersion() noexcept { ++_version; }
virtual gfx::GFXObject *getDeviceResource() const noexcept = 0;
private:
PassNode *_firstUsePass{nullptr};
PassNode *_lastUsePass{nullptr};
const StringHandle _name;
uint32_t _refCount{0};
uint16_t _writerCount{0};
ID _id{0};
uint8_t _version{0};
bool const _imported{false};
bool _neverLoaded{true};
bool _neverStored{true};
bool _memoryless{false};
bool _memorylessMSAA{false};
friend class FrameGraph;
};
} // namespace framegraph
} // namespace cc

View File

@@ -0,0 +1,170 @@
/****************************************************************************
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/memory/Memory.h"
#include <cstring>
#include "BufferAgent.h"
#include "DeviceAgent.h"
namespace cc {
namespace gfx {
BufferAgent::BufferAgent(Buffer *actor)
: Agent<Buffer>(actor) {
_typedID = actor->getTypedID();
}
BufferAgent::~BufferAgent() {
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(),
BufferDestruct,
actor, _actor,
stagingBuffer, std::move(_stagingBuffer),
{
CC_SAFE_DELETE(actor);
});
}
void BufferAgent::doInit(const BufferInfo &info) {
uint32_t size = getSize();
if (hasFlag(info.flags, BufferFlagBit::ENABLE_STAGING_WRITE) || (size > STAGING_BUFFER_THRESHOLD && hasFlag(_memUsage, MemoryUsageBit::HOST))) {
_stagingBuffer = std::make_unique<uint8_t[]>(size * DeviceAgent::MAX_FRAME_INDEX);
}
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(),
BufferInit,
actor, getActor(),
info, info,
{
actor->initialize(info);
});
}
void BufferAgent::doInit(const BufferViewInfo &info) {
BufferViewInfo actorInfo = info;
actorInfo.buffer = static_cast<BufferAgent *>(info.buffer)->getActor();
// buffer views don't need staging buffers
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(),
BufferViewInit,
actor, getActor(),
info, actorInfo,
{
actor->initialize(info);
});
}
void BufferAgent::doResize(uint32_t size, uint32_t /*count*/) {
auto *mq = DeviceAgent::getInstance()->getMessageQueue();
if (_stagingBuffer) {
ENQUEUE_MESSAGE_1(
mq, BufferFreeStagingBuffer,
stagingBuffer, std::move(_stagingBuffer),
{});
}
if (hasFlag(_flags, BufferFlagBit::ENABLE_STAGING_WRITE) || (size > STAGING_BUFFER_THRESHOLD && hasFlag(_memUsage, MemoryUsageBit::HOST))) {
_stagingBuffer = std::make_unique<uint8_t[]>(size * DeviceAgent::MAX_FRAME_INDEX);
}
ENQUEUE_MESSAGE_2(
mq, BufferResize,
actor, getActor(),
size, size,
{
actor->resize(size);
});
}
void BufferAgent::doDestroy() {
auto *mq = DeviceAgent::getInstance()->getMessageQueue();
ENQUEUE_MESSAGE_2(
mq, BufferDestroy,
actor, getActor(),
stagingBuffer, std::move(_stagingBuffer),
{
actor->destroy();
});
}
void BufferAgent::update(const void *buffer, uint32_t size) {
uint8_t *actorBuffer{nullptr};
bool needFreeing{false};
auto *mq{DeviceAgent::getInstance()->getMessageQueue()};
getActorBuffer(this, mq, size, &actorBuffer, &needFreeing);
memcpy(actorBuffer, buffer, size);
ENQUEUE_MESSAGE_4(
mq, BufferUpdate,
actor, getActor(),
buffer, actorBuffer,
size, size,
needFreeing, needFreeing,
{
actor->update(buffer, size);
if (needFreeing) free(buffer);
});
}
void BufferAgent::flush(const uint8_t *buffer) {
auto *mq = DeviceAgent::getInstance()->getMessageQueue();
ENQUEUE_MESSAGE_3(
mq, BufferUpdate,
actor, getActor(),
buffer, buffer,
size, _size,
{
actor->update(buffer, size);
});
}
void BufferAgent::getActorBuffer(const BufferAgent *buffer, MessageQueue *mq, uint32_t size, uint8_t **pActorBuffer, bool *pNeedFreeing) {
if (buffer->_stagingBuffer) { // for frequent updates on big buffers
uint32_t frameIndex = DeviceAgent::getInstance()->getCurrentIndex();
*pActorBuffer = buffer->_stagingBuffer.get() + frameIndex * buffer->_size;
} else if (size > STAGING_BUFFER_THRESHOLD) { // less frequent updates on big buffers
*pActorBuffer = reinterpret_cast<uint8_t *>(malloc(size));
*pNeedFreeing = true;
} else { // for small enough buffers
*pActorBuffer = mq->allocate<uint8_t>(size);
}
}
uint8_t *BufferAgent::getStagingAddress() const {
if (!_stagingBuffer) {
return nullptr;
}
uint32_t frameIndex = DeviceAgent::getInstance()->getCurrentIndex();
return _stagingBuffer.get() + _size * frameIndex;
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,61 @@
/****************************************************************************
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/Agent.h"
#include "base/threading/MessageQueue.h"
#include "gfx-base/GFXBuffer.h"
namespace cc {
class ThreadSafeLinearAllocator;
namespace gfx {
class CC_DLL BufferAgent final : public Agent<Buffer> {
public:
explicit BufferAgent(Buffer *actor);
~BufferAgent() override;
void update(const void *buffer, uint32_t size) override;
static void getActorBuffer(const BufferAgent *buffer, MessageQueue *mq, uint32_t size, uint8_t **pActorBuffer, bool *pNeedFreeing);
private:
void doInit(const BufferInfo &info) override;
void doInit(const BufferViewInfo &info) override;
void doResize(uint32_t size, uint32_t count) override;
void doDestroy() override;
void flush(const uint8_t *buffer) override;
uint8_t *getStagingAddress() const override;
static constexpr uint32_t STAGING_BUFFER_THRESHOLD = MessageQueue::MEMORY_CHUNK_SIZE / 2;
std::unique_ptr<uint8_t[]> _stagingBuffer;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,595 @@
/****************************************************************************
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 "CommandBufferAgent.h"
#include <cstring>
#include "BufferAgent.h"
#include "DescriptorSetAgent.h"
#include "DeviceAgent.h"
#include "FramebufferAgent.h"
#include "InputAssemblerAgent.h"
#include "PipelineStateAgent.h"
#include "QueryPoolAgent.h"
#include "QueueAgent.h"
#include "RenderPassAgent.h"
#include "TextureAgent.h"
#include "base/Utils.h"
#include "base/job-system/JobSystem.h"
#include "base/threading/MessageQueue.h"
#include "base/threading/ThreadSafeLinearAllocator.h"
namespace cc {
namespace gfx {
CommandBufferAgent::CommandBufferAgent(CommandBuffer *actor)
: Agent<CommandBuffer>(actor) {
_typedID = actor->getTypedID();
}
void CommandBufferAgent::flushCommands(uint32_t count, CommandBufferAgent *const *cmdBuffs, bool multiThreaded) {
// don't even touch the job system if we are only recording sequentially
if (count == 1) {
cmdBuffs[0]->getMessageQueue()->flushMessages();
return;
}
uint32_t jobThreadCount = JobSystem::getInstance()->threadCount();
uint32_t workForThisThread = (count - 1) / jobThreadCount + 1; // ceil(count / jobThreadCount)
if (count > workForThisThread + 1 && multiThreaded) { // more than one job to dispatch
JobGraph g(JobSystem::getInstance());
g.createForEachIndexJob(workForThisThread, count, 1U, [cmdBuffs](uint32_t i) {
cmdBuffs[i]->getMessageQueue()->flushMessages();
});
g.run();
for (uint32_t i = 0U; i < workForThisThread; ++i) {
cmdBuffs[i]->getMessageQueue()->flushMessages();
}
g.waitForAll();
} else {
for (uint32_t i = 0U; i < count; ++i) {
cmdBuffs[i]->getMessageQueue()->flushMessages();
}
}
}
CommandBufferAgent::~CommandBufferAgent() {
destroyMessageQueue();
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(), CommandBufferDestruct,
actor, _actor,
{
CC_SAFE_DELETE(actor);
});
}
void CommandBufferAgent::initMessageQueue() {
DeviceAgent *device = DeviceAgent::getInstance();
device->_cmdBuffRefs.insert(this);
_messageQueue = ccnew MessageQueue;
if (device->_multithreaded) _messageQueue->setImmediateMode(false);
}
void CommandBufferAgent::destroyMessageQueue() {
DeviceAgent::getInstance()->getMessageQueue()->kickAndWait();
CC_SAFE_DELETE(_messageQueue);
DeviceAgent::getInstance()->_cmdBuffRefs.erase(this);
}
void CommandBufferAgent::initAgent() {
initMessageQueue();
}
void CommandBufferAgent::destroyAgent() {
destroyMessageQueue();
}
void CommandBufferAgent::doInit(const CommandBufferInfo &info) {
initMessageQueue();
CommandBufferInfo actorInfo = info;
actorInfo.queue = static_cast<QueueAgent *>(info.queue)->getActor();
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(), CommandBufferInit,
actor, getActor(),
info, actorInfo,
{
actor->initialize(info);
});
}
void CommandBufferAgent::doDestroy() {
destroyMessageQueue();
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(), CommandBufferDestroy,
actor, getActor(),
{
actor->destroy();
});
}
void CommandBufferAgent::begin(RenderPass *renderPass, uint32_t subpass, Framebuffer *frameBuffer) {
ENQUEUE_MESSAGE_4(
_messageQueue,
CommandBufferBegin,
actor, getActor(),
renderPass, renderPass ? static_cast<RenderPassAgent *>(renderPass)->getActor() : nullptr,
subpass, subpass,
frameBuffer, frameBuffer ? static_cast<FramebufferAgent *>(frameBuffer)->getActor() : nullptr,
{
actor->begin(renderPass, subpass, frameBuffer);
});
}
void CommandBufferAgent::end() {
ENQUEUE_MESSAGE_1(
_messageQueue, CommandBufferEnd,
actor, getActor(),
{
actor->end();
});
}
void CommandBufferAgent::beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const Color *colors, float depth, uint32_t stencil, CommandBuffer *const *secondaryCBs, uint32_t secondaryCBCount) {
auto attachmentCount = utils::toUint(renderPass->getColorAttachments().size());
Color *actorColors = nullptr;
if (attachmentCount) {
actorColors = _messageQueue->allocate<Color>(attachmentCount);
memcpy(actorColors, colors, sizeof(Color) * attachmentCount);
}
CommandBuffer **actorSecondaryCBs = nullptr;
if (secondaryCBCount) {
actorSecondaryCBs = _messageQueue->allocate<CommandBuffer *>(secondaryCBCount);
for (uint32_t i = 0; i < secondaryCBCount; ++i) {
actorSecondaryCBs[i] = static_cast<CommandBufferAgent *>(secondaryCBs[i])->getActor();
}
}
ENQUEUE_MESSAGE_9(
_messageQueue, CommandBufferBeginRenderPass,
actor, getActor(),
renderPass, static_cast<RenderPassAgent *>(renderPass)->getActor(),
fbo, static_cast<FramebufferAgent *>(fbo)->getActor(),
renderArea, renderArea,
colors, actorColors,
depth, depth,
stencil, stencil,
secondaryCBCount, secondaryCBCount,
secondaryCBs, actorSecondaryCBs,
{
actor->beginRenderPass(renderPass, fbo, renderArea, colors, depth, stencil, secondaryCBs, secondaryCBCount);
});
}
void CommandBufferAgent::endRenderPass() {
ENQUEUE_MESSAGE_1(
_messageQueue, CommandBufferEndRenderPass,
actor, getActor(),
{
actor->endRenderPass();
});
}
void CommandBufferAgent::insertMarker(const MarkerInfo &marker) {
ENQUEUE_MESSAGE_2(
_messageQueue, CommandBufferInsertMarker,
actor, getActor(),
marker, marker,
{
actor->insertMarker(marker);
});
}
void CommandBufferAgent::beginMarker(const MarkerInfo &marker) {
ENQUEUE_MESSAGE_2(
_messageQueue, CommandBufferBeginMarker,
actor, getActor(),
marker, marker,
{
actor->beginMarker(marker);
});
}
void CommandBufferAgent::endMarker() {
ENQUEUE_MESSAGE_1(
_messageQueue, CommandBufferEndMarker,
actor, getActor(),
{
actor->endMarker();
});
}
void CommandBufferAgent::execute(CommandBuffer *const *cmdBuffs, uint32_t count) {
if (!count) return;
auto **actorCmdBuffs = _messageQueue->allocate<CommandBuffer *>(count);
for (uint32_t i = 0; i < count; ++i) {
actorCmdBuffs[i] = static_cast<CommandBufferAgent *>(cmdBuffs[i])->getActor();
}
ENQUEUE_MESSAGE_3(
_messageQueue, CommandBufferExecute,
actor, getActor(),
cmdBuffs, actorCmdBuffs,
count, count,
{
actor->execute(cmdBuffs, count);
});
}
void CommandBufferAgent::bindPipelineState(PipelineState *pso) {
ENQUEUE_MESSAGE_2(
_messageQueue, CommandBufferBindPipelineState,
actor, getActor(),
pso, static_cast<PipelineStateAgent *>(pso)->getActor(),
{
actor->bindPipelineState(pso);
});
}
void CommandBufferAgent::bindDescriptorSet(uint32_t set, DescriptorSet *descriptorSet, uint32_t dynamicOffsetCount, const uint32_t *dynamicOffsets) {
uint32_t *actorDynamicOffsets = nullptr;
if (dynamicOffsetCount) {
actorDynamicOffsets = _messageQueue->allocate<uint32_t>(dynamicOffsetCount);
memcpy(actorDynamicOffsets, dynamicOffsets, dynamicOffsetCount * sizeof(uint32_t));
}
ENQUEUE_MESSAGE_5(
_messageQueue, CommandBufferBindDescriptorSet,
actor, getActor(),
set, set,
descriptorSet, static_cast<DescriptorSetAgent *>(descriptorSet)->getActor(),
dynamicOffsetCount, dynamicOffsetCount,
dynamicOffsets, actorDynamicOffsets,
{
actor->bindDescriptorSet(set, descriptorSet, dynamicOffsetCount, dynamicOffsets);
});
}
void CommandBufferAgent::bindInputAssembler(InputAssembler *ia) {
ENQUEUE_MESSAGE_2(
_messageQueue, CommandBufferBindInputAssembler,
actor, getActor(),
ia, static_cast<InputAssemblerAgent *>(ia)->getActor(),
{
actor->bindInputAssembler(ia);
});
}
void CommandBufferAgent::setViewport(const Viewport &vp) {
ENQUEUE_MESSAGE_2(
_messageQueue, CommandBufferSetViewport,
actor, getActor(),
vp, vp,
{
actor->setViewport(vp);
});
}
void CommandBufferAgent::setScissor(const Rect &rect) {
ENQUEUE_MESSAGE_2(
_messageQueue, CommandBufferSetScissor,
actor, getActor(),
rect, rect,
{
actor->setScissor(rect);
});
}
void CommandBufferAgent::setLineWidth(float width) {
ENQUEUE_MESSAGE_2(
_messageQueue, CommandBufferSetLineWidth,
actor, getActor(),
width, width,
{
actor->setLineWidth(width);
});
}
void CommandBufferAgent::setDepthBias(float constant, float clamp, float slope) {
ENQUEUE_MESSAGE_4(
_messageQueue, CommandBufferSetDepthBias,
actor, getActor(),
constant, constant,
clamp, clamp,
slope, slope,
{
actor->setDepthBias(constant, clamp, slope);
});
}
void CommandBufferAgent::setBlendConstants(const Color &constants) {
ENQUEUE_MESSAGE_2(
_messageQueue, CommandBufferSetBlendConstants,
actor, getActor(),
constants, constants,
{
actor->setBlendConstants(constants);
});
}
void CommandBufferAgent::setDepthBound(float minBounds, float maxBounds) {
ENQUEUE_MESSAGE_3(
_messageQueue, CommandBufferSetDepthBound,
actor, getActor(),
minBounds, minBounds,
maxBounds, maxBounds,
{
actor->setDepthBound(minBounds, maxBounds);
});
}
void CommandBufferAgent::setStencilWriteMask(StencilFace face, uint32_t mask) {
ENQUEUE_MESSAGE_3(
_messageQueue, CommandBufferSetStencilWriteMask,
actor, getActor(),
face, face,
mask, mask,
{
actor->setStencilWriteMask(face, mask);
});
}
void CommandBufferAgent::setStencilCompareMask(StencilFace face, uint32_t ref, uint32_t mask) {
ENQUEUE_MESSAGE_4(
_messageQueue, CommandBufferSetStencilCompareMask,
actor, getActor(),
face, face,
ref, ref,
mask, mask,
{
actor->setStencilCompareMask(face, ref, mask);
});
}
void CommandBufferAgent::nextSubpass() {
ENQUEUE_MESSAGE_1(
_messageQueue, CommandBufferNextSubpass,
actor, getActor(),
{
actor->nextSubpass();
});
}
void CommandBufferAgent::draw(const DrawInfo &info) {
ENQUEUE_MESSAGE_2(
_messageQueue, CommandBufferDraw,
actor, getActor(),
info, info,
{
actor->draw(info);
});
}
void CommandBufferAgent::updateBuffer(Buffer *buff, const void *data, uint32_t size) {
auto *bufferAgent = static_cast<BufferAgent *>(buff);
uint8_t *actorBuffer{nullptr};
bool needFreeing{false};
BufferAgent::getActorBuffer(bufferAgent, _messageQueue, size, &actorBuffer, &needFreeing);
memcpy(actorBuffer, data, size);
ENQUEUE_MESSAGE_5(
_messageQueue, CommandBufferUpdateBuffer,
actor, getActor(),
buff, bufferAgent->getActor(),
data, actorBuffer,
size, size,
needFreeing, needFreeing,
{
actor->updateBuffer(buff, data, size);
if (needFreeing) free(data);
});
}
void CommandBufferAgent::resolveTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) {
Texture *actorSrcTexture = nullptr;
Texture *actorDstTexture = nullptr;
if (srcTexture) actorSrcTexture = static_cast<TextureAgent *>(srcTexture)->getActor();
if (dstTexture) actorDstTexture = static_cast<TextureAgent *>(dstTexture)->getActor();
auto *actorRegions = _messageQueue->allocate<TextureCopy>(count);
memcpy(actorRegions, regions, count * sizeof(TextureCopy));
ENQUEUE_MESSAGE_5(
_messageQueue, CommandBufferBlitTexture,
actor, getActor(),
srcTexture, actorSrcTexture,
dstTexture, actorDstTexture,
regions, actorRegions,
count, count,
{
actor->resolveTexture(srcTexture, dstTexture, regions, count);
});
}
void CommandBufferAgent::copyTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) {
Texture *actorSrcTexture = nullptr;
Texture *actorDstTexture = nullptr;
if (srcTexture) actorSrcTexture = static_cast<TextureAgent *>(srcTexture)->getActor();
if (dstTexture) actorDstTexture = static_cast<TextureAgent *>(dstTexture)->getActor();
auto *actorRegions = _messageQueue->allocate<TextureCopy>(count);
memcpy(actorRegions, regions, count * sizeof(TextureCopy));
ENQUEUE_MESSAGE_5(
_messageQueue, CommandBufferBlitTexture,
actor, getActor(),
srcTexture, actorSrcTexture,
dstTexture, actorDstTexture,
regions, actorRegions,
count, count,
{
actor->copyTexture(srcTexture, dstTexture, regions, count);
});
}
void CommandBufferAgent::blitTexture(Texture *srcTexture, Texture *dstTexture, const TextureBlit *regions, uint32_t count, Filter filter) {
Texture *actorSrcTexture = nullptr;
Texture *actorDstTexture = nullptr;
if (srcTexture) actorSrcTexture = static_cast<TextureAgent *>(srcTexture)->getActor();
if (dstTexture) actorDstTexture = static_cast<TextureAgent *>(dstTexture)->getActor();
auto *actorRegions = _messageQueue->allocate<TextureBlit>(count);
memcpy(actorRegions, regions, count * sizeof(TextureBlit));
ENQUEUE_MESSAGE_6(
_messageQueue, CommandBufferBlitTexture,
actor, getActor(),
srcTexture, actorSrcTexture,
dstTexture, actorDstTexture,
regions, actorRegions,
count, count,
filter, filter,
{
actor->blitTexture(srcTexture, dstTexture, regions, count, filter);
});
}
void CommandBufferAgent::dispatch(const DispatchInfo &info) {
DispatchInfo actorInfo = info;
if (info.indirectBuffer) actorInfo.indirectBuffer = static_cast<BufferAgent *>(info.indirectBuffer)->getActor();
ENQUEUE_MESSAGE_2(
_messageQueue, CommandBufferDispatch,
actor, getActor(),
info, actorInfo,
{
actor->dispatch(info);
});
}
void CommandBufferAgent::pipelineBarrier(const GeneralBarrier *barrier, const BufferBarrier *const *bufferBarriers, const Buffer *const *buffers, uint32_t bufferBarrierCount, const TextureBarrier *const *textureBarriers, const Texture *const *textures, uint32_t textureBarrierCount) {
TextureBarrier **actorTextureBarriers = nullptr;
Texture **actorTextures = nullptr;
BufferBarrier **actorBufferBarriers = nullptr;
Buffer **actorBuffers = nullptr;
if (textureBarrierCount) {
actorTextureBarriers = _messageQueue->allocate<TextureBarrier *>(textureBarrierCount);
memcpy(actorTextureBarriers, textureBarriers, textureBarrierCount * sizeof(uintptr_t));
actorTextures = _messageQueue->allocate<Texture *>(textureBarrierCount);
for (uint32_t i = 0U; i < textureBarrierCount; ++i) {
actorTextures[i] = textures[i] ? static_cast<const TextureAgent *>(textures[i])->getActor() : nullptr;
}
}
if (bufferBarrierCount) {
actorBufferBarriers = _messageQueue->allocateAndZero<BufferBarrier *>(bufferBarrierCount);
memcpy(actorBufferBarriers, bufferBarriers, bufferBarrierCount * sizeof(uintptr_t));
actorBuffers = _messageQueue->allocate<Buffer *>(bufferBarrierCount);
for (uint32_t i = 0; i < bufferBarrierCount; ++i) {
actorBuffers[i] = buffers[i] ? static_cast<const BufferAgent *>(buffers[i])->getActor() : nullptr;
}
}
ENQUEUE_MESSAGE_8(
_messageQueue, CommandBufferPipelineBarrier,
actor, getActor(),
barrier, barrier,
bufferBarriers, actorBufferBarriers,
buffers, actorBuffers,
bufferBarrierCount, bufferBarrierCount,
textureBarriers, actorTextureBarriers,
textures, actorTextures,
textureBarrierCount, textureBarrierCount,
{
actor->pipelineBarrier(barrier, bufferBarriers, buffers, bufferBarrierCount, textureBarriers, textures, textureBarrierCount);
});
}
void CommandBufferAgent::beginQuery(QueryPool *queryPool, uint32_t id) {
auto *actorQueryPool = static_cast<QueryPoolAgent *>(queryPool)->getActor();
ENQUEUE_MESSAGE_3(
_messageQueue, CommandBufferBeginQuery,
actor, getActor(),
queryPool, actorQueryPool,
id, id,
{
actor->beginQuery(queryPool, id);
});
}
void CommandBufferAgent::endQuery(QueryPool *queryPool, uint32_t id) {
auto *actorQueryPool = static_cast<QueryPoolAgent *>(queryPool)->getActor();
ENQUEUE_MESSAGE_3(
_messageQueue, CommandBufferEndQuery,
actor, getActor(),
queryPool, actorQueryPool,
id, id,
{
actor->endQuery(queryPool, id);
});
}
void CommandBufferAgent::resetQueryPool(QueryPool *queryPool) {
auto *actorQueryPool = static_cast<QueryPoolAgent *>(queryPool)->getActor();
ENQUEUE_MESSAGE_2(
_messageQueue, CommandBufferResetQueryPool,
actor, getActor(),
queryPool, actorQueryPool,
{
actor->resetQueryPool(queryPool);
});
}
void CommandBufferAgent::completeQueryPool(QueryPool *queryPool) {
auto *actorQueryPool = static_cast<QueryPoolAgent *>(queryPool)->getActor();
ENQUEUE_MESSAGE_2(
_messageQueue, CommandBufferCompleteQueryPool,
actor, getActor(),
queryPool, actorQueryPool,
{
actor->completeQueryPool(queryPool);
});
}
void CommandBufferAgent::customCommand(CustomCommand &&cmd) {
ENQUEUE_MESSAGE_2(
_messageQueue, CommandBufferCompleteQueryPool,
actor, getActor(),
cmd, cmd,
{
actor->customCommand(std::move(cmd));
});
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,98 @@
/****************************************************************************
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/Agent.h"
#include "gfx-base/GFXCommandBuffer.h"
namespace cc {
class MessageQueue;
namespace gfx {
class CC_DLL CommandBufferAgent final : public Agent<CommandBuffer> {
public:
explicit CommandBufferAgent(CommandBuffer *actor);
~CommandBufferAgent() override;
static void flushCommands(uint32_t count, CommandBufferAgent *const *cmdBuffs, bool multiThreaded);
void begin(RenderPass *renderPass, uint32_t subpass, Framebuffer *frameBuffer) override;
void end() override;
void beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const Color *colors, float depth, uint32_t stencil, CommandBuffer *const *secondaryCBs, uint32_t secondaryCBCount) override;
void endRenderPass() override;
void insertMarker(const MarkerInfo &marker) override;
void beginMarker(const MarkerInfo &marker) override;
void endMarker() override;
void bindPipelineState(PipelineState *pso) override;
void bindDescriptorSet(uint32_t set, DescriptorSet *descriptorSet, uint32_t dynamicOffsetCount, const uint32_t *dynamicOffsets) override;
void bindInputAssembler(InputAssembler *ia) override;
void setViewport(const Viewport &vp) override;
void setScissor(const Rect &rect) override;
void setLineWidth(float width) override;
void setDepthBias(float constant, float clamp, float slope) override;
void setBlendConstants(const Color &constants) override;
void setDepthBound(float minBounds, float maxBounds) override;
void setStencilWriteMask(StencilFace face, uint32_t mask) override;
void setStencilCompareMask(StencilFace face, uint32_t ref, uint32_t mask) override;
void nextSubpass() override;
void draw(const DrawInfo &info) override;
void updateBuffer(Buffer *buff, const void *data, uint32_t size) override;
void copyBuffersToTexture(const uint8_t *const *buffers, Texture *texture, const BufferTextureCopy *regions, uint32_t count) override;
void blitTexture(Texture *srcTexture, Texture *dstTexture, const TextureBlit *regions, uint32_t count, Filter filter) override;
void copyTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) override;
void resolveTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) override;
void execute(CommandBuffer *const *cmdBuffs, uint32_t count) override;
void dispatch(const DispatchInfo &info) override;
void pipelineBarrier(const GeneralBarrier *barrier, const BufferBarrier *const *bufferBarriers, const Buffer *const *buffers, uint32_t bufferBarrierCount, const TextureBarrier *const *textureBarriers, const Texture *const *textures, uint32_t textureBarrierCount) override;
void beginQuery(QueryPool *queryPool, uint32_t id) override;
void endQuery(QueryPool *queryPool, uint32_t id) override;
void resetQueryPool(QueryPool *queryPool) override;
void completeQueryPool(QueryPool *queryPool) override;
void customCommand(CustomCommand &&cmd) override;
uint32_t getNumDrawCalls() const override { return _actor->getNumDrawCalls(); }
uint32_t getNumInstances() const override { return _actor->getNumInstances(); }
uint32_t getNumTris() const override { return _actor->getNumTris(); }
inline MessageQueue *getMessageQueue() { return _messageQueue; }
protected:
friend class DeviceAgent;
void initAgent();
void destroyAgent();
void doInit(const CommandBufferInfo &info) override;
void doDestroy() override;
void initMessageQueue();
void destroyMessageQueue();
MessageQueue *_messageQueue = nullptr;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,149 @@
/****************************************************************************
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/threading/MessageQueue.h"
#include "BufferAgent.h"
#include "DescriptorSetAgent.h"
#include "DescriptorSetLayoutAgent.h"
#include "DeviceAgent.h"
#include "TextureAgent.h"
namespace cc {
namespace gfx {
DescriptorSetAgent::DescriptorSetAgent(DescriptorSet *actor)
: Agent<DescriptorSet>(actor) {
_typedID = actor->getTypedID();
}
DescriptorSetAgent::~DescriptorSetAgent() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
DescriptorSetDestruct,
actor, _actor,
{
CC_SAFE_DELETE(actor);
});
}
void DescriptorSetAgent::doInit(const DescriptorSetInfo &info) {
DescriptorSetInfo actorInfo;
actorInfo.layout = static_cast<const DescriptorSetLayoutAgent *>(info.layout)->getActor();
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(),
DescriptorSetInit,
actor, getActor(),
info, actorInfo,
{
actor->initialize(info);
});
}
void DescriptorSetAgent::doDestroy() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
DescriptorSetDestroy,
actor, getActor(),
{
actor->destroy();
});
}
void DescriptorSetAgent::update() {
// Avoid enqueueing unnecessary command
if (!_isDirty) return;
_isDirty = false;
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
DescriptorSetUpdate,
actor, getActor(),
{
actor->update();
});
}
void DescriptorSetAgent::forceUpdate() {
_isDirty = false;
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
DescriptorSetForceUpdate,
actor, getActor(),
{
actor->forceUpdate();
});
}
void DescriptorSetAgent::bindBuffer(uint32_t binding, Buffer *buffer, uint32_t index, AccessFlags flags) {
DescriptorSet::bindBuffer(binding, buffer, index, flags);
ENQUEUE_MESSAGE_5(
DeviceAgent::getInstance()->getMessageQueue(),
DescriptorSetBindBuffer,
actor, getActor(),
binding, binding,
buffer, static_cast<BufferAgent *>(buffer)->getActor(),
index, index,
flags, flags,
{
actor->bindBuffer(binding, buffer, index, flags);
});
}
void DescriptorSetAgent::bindTexture(uint32_t binding, Texture *texture, uint32_t index, AccessFlags flags) {
DescriptorSet::bindTexture(binding, texture, index, flags);
ENQUEUE_MESSAGE_5(
DeviceAgent::getInstance()->getMessageQueue(),
DescriptorSetBindTexture,
actor, getActor(),
binding, binding,
texture, static_cast<TextureAgent *>(texture)->getActor(),
index, index,
flags, flags,
{
actor->bindTexture(binding, texture, index, flags);
});
}
void DescriptorSetAgent::bindSampler(uint32_t binding, Sampler *sampler, uint32_t index) {
DescriptorSet::bindSampler(binding, sampler, index);
ENQUEUE_MESSAGE_4(
DeviceAgent::getInstance()->getMessageQueue(),
DescriptorSetBindSampler,
actor, getActor(),
binding, binding,
sampler, sampler,
index, index,
{
actor->bindSampler(binding, sampler, index);
});
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,51 @@
/****************************************************************************
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/Agent.h"
#include "gfx-base/GFXDescriptorSet.h"
namespace cc {
namespace gfx {
class CC_DLL DescriptorSetAgent final : public Agent<DescriptorSet> {
public:
explicit DescriptorSetAgent(DescriptorSet *actor);
~DescriptorSetAgent() override;
void update() override;
void forceUpdate() override;
void bindBuffer(uint32_t binding, Buffer *buffer, uint32_t index, AccessFlags flags) override;
void bindTexture(uint32_t binding, Texture *texture, uint32_t index, AccessFlags flags) override;
void bindSampler(uint32_t binding, Sampler *sampler, uint32_t index) override;
protected:
void doInit(const DescriptorSetInfo &info) override;
void doDestroy() override;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,70 @@
/****************************************************************************
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/threading/MessageQueue.h"
#include "DescriptorSetLayoutAgent.h"
#include "DeviceAgent.h"
namespace cc {
namespace gfx {
DescriptorSetLayoutAgent::DescriptorSetLayoutAgent(DescriptorSetLayout *actor)
: Agent<DescriptorSetLayout>(actor) {
_typedID = actor->getTypedID();
}
DescriptorSetLayoutAgent::~DescriptorSetLayoutAgent() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
DescriptorSetLayoutDestruct,
actor, _actor,
{
CC_SAFE_DELETE(actor);
});
}
void DescriptorSetLayoutAgent::doInit(const DescriptorSetLayoutInfo &info) {
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(),
DescriptorSetLayoutInit,
actor, getActor(),
info, info,
{
actor->initialize(info);
});
}
void DescriptorSetLayoutAgent::doDestroy() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
DescriptorSetLayoutDestroy,
actor, getActor(),
{
actor->destroy();
});
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,44 @@
/****************************************************************************
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/Agent.h"
#include "gfx-base/GFXDescriptorSetLayout.h"
namespace cc {
namespace gfx {
class CC_DLL DescriptorSetLayoutAgent final : public Agent<DescriptorSetLayout> {
public:
explicit DescriptorSetLayoutAgent(DescriptorSetLayout *actor);
~DescriptorSetLayoutAgent() override;
protected:
void doInit(const DescriptorSetLayoutInfo &info) override;
void doDestroy() override;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,463 @@
/****************************************************************************
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 <boost/align/align_up.hpp>
#include <cstring>
#include "application/ApplicationManager.h"
#include "base/Log.h"
#include "base/threading/MessageQueue.h"
#include "base/threading/ThreadSafeLinearAllocator.h"
#include "platform/interfaces/modules/IXRInterface.h"
#include "BufferAgent.h"
#include "CommandBufferAgent.h"
#include "DescriptorSetAgent.h"
#include "DescriptorSetLayoutAgent.h"
#include "DeviceAgent.h"
#include "FramebufferAgent.h"
#include "InputAssemblerAgent.h"
#include "PipelineLayoutAgent.h"
#include "PipelineStateAgent.h"
#include "QueryPoolAgent.h"
#include "QueueAgent.h"
#include "RenderPassAgent.h"
#include "ShaderAgent.h"
#include "SwapchainAgent.h"
#include "TextureAgent.h"
namespace cc {
namespace gfx {
DeviceAgent *DeviceAgent::instance = nullptr;
DeviceAgent *DeviceAgent::getInstance() {
return DeviceAgent::instance;
}
DeviceAgent::DeviceAgent(Device *device) : Agent(device) {
DeviceAgent::instance = this;
}
DeviceAgent::~DeviceAgent() {
CC_SAFE_DELETE(_actor);
DeviceAgent::instance = nullptr;
}
bool DeviceAgent::doInit(const DeviceInfo &info) {
if (!_actor->initialize(info)) {
return false;
}
_xr = CC_GET_XR_INTERFACE();
_api = _actor->getGfxAPI();
_deviceName = _actor->getDeviceName();
_queue = ccnew QueueAgent(_actor->getQueue());
_queryPool = ccnew QueryPoolAgent(_actor->getQueryPool());
_cmdBuff = ccnew CommandBufferAgent(_actor->getCommandBuffer());
_renderer = _actor->getRenderer();
_vendor = _actor->getVendor();
_caps = _actor->_caps;
memcpy(_features.data(), _actor->_features.data(), static_cast<uint32_t>(Feature::COUNT) * sizeof(bool));
memcpy(_formatFeatures.data(), _actor->_formatFeatures.data(), static_cast<uint32_t>(Format::COUNT) * sizeof(FormatFeatureBit));
_mainMessageQueue = ccnew MessageQueue;
static_cast<CommandBufferAgent *>(_cmdBuff)->_queue = _queue;
static_cast<CommandBufferAgent *>(_cmdBuff)->initAgent();
setMultithreaded(true);
return true;
}
void DeviceAgent::doDestroy() {
if (!_mainMessageQueue) {
_actor->destroy();
} else {
ENQUEUE_MESSAGE_1(
_mainMessageQueue, DeviceDestroy,
actor, _actor,
{
actor->destroy();
});
}
if (_cmdBuff) {
static_cast<CommandBufferAgent *>(_cmdBuff)->destroyAgent();
static_cast<CommandBufferAgent *>(_cmdBuff)->_actor = nullptr;
delete _cmdBuff;
_cmdBuff = nullptr;
}
if (_queryPool) {
static_cast<QueryPoolAgent *>(_queryPool)->_actor = nullptr;
delete _queryPool;
_queryPool = nullptr;
}
if (_queue) {
static_cast<QueueAgent *>(_queue)->_actor = nullptr;
delete _queue;
_queue = nullptr;
}
if (_mainMessageQueue) {
_mainMessageQueue->terminateConsumerThread();
delete _mainMessageQueue;
_mainMessageQueue = nullptr;
}
}
void DeviceAgent::acquire(Swapchain *const *swapchains, uint32_t count) {
auto *actorSwapchains = _mainMessageQueue->allocate<Swapchain *>(count);
for (uint32_t i = 0; i < count; ++i) {
actorSwapchains[i] = static_cast<SwapchainAgent *>(swapchains[i])->getActor();
}
ENQUEUE_MESSAGE_4(
_mainMessageQueue, DevicePresent,
device, this,
actor, _actor,
swapchains, actorSwapchains,
count, count,
{
if (device->_onAcquire) device->_onAcquire->execute();
actor->acquire(swapchains, count);
});
}
void DeviceAgent::present() {
if (_xr) {
ENQUEUE_MESSAGE_1(
_mainMessageQueue, DevicePresent,
actor, _actor,
{
actor->present();
});
} else {
ENQUEUE_MESSAGE_2(
_mainMessageQueue, DevicePresent,
actor, _actor,
frameBoundarySemaphore, &_frameBoundarySemaphore,
{
actor->present();
frameBoundarySemaphore->signal();
});
MessageQueue::freeChunksInFreeQueue(_mainMessageQueue);
_mainMessageQueue->finishWriting();
_currentIndex = (_currentIndex + 1) % MAX_FRAME_INDEX;
_frameBoundarySemaphore.wait();
}
}
void DeviceAgent::setMultithreaded(bool multithreaded) {
if (multithreaded == _multithreaded) return;
_multithreaded = multithreaded;
if (multithreaded) {
_mainMessageQueue->setImmediateMode(false);
_actor->bindContext(false);
_mainMessageQueue->runConsumerThread();
ENQUEUE_MESSAGE_1(
_mainMessageQueue, DeviceMakeCurrentTrue,
actor, _actor,
{
actor->bindContext(true);
CC_LOG_INFO("Device thread detached.");
});
for (CommandBufferAgent *cmdBuff : _cmdBuffRefs) {
cmdBuff->_messageQueue->setImmediateMode(false);
}
} else {
ENQUEUE_MESSAGE_1(
_mainMessageQueue, DeviceMakeCurrentFalse,
actor, _actor,
{
actor->bindContext(false);
});
_mainMessageQueue->terminateConsumerThread();
_mainMessageQueue->setImmediateMode(true);
_actor->bindContext(true);
for (CommandBufferAgent *cmdBuff : _cmdBuffRefs) {
cmdBuff->_messageQueue->setImmediateMode(true);
}
CC_LOG_INFO("Device thread joined.");
}
}
CommandBuffer *DeviceAgent::createCommandBuffer(const CommandBufferInfo &info, bool /*hasAgent*/) {
CommandBuffer *actor = _actor->createCommandBuffer(info, true);
return ccnew CommandBufferAgent(actor);
}
Queue *DeviceAgent::createQueue() {
Queue *actor = _actor->createQueue();
return ccnew QueueAgent(actor);
}
QueryPool *DeviceAgent::createQueryPool() {
QueryPool *actor = _actor->createQueryPool();
return ccnew QueryPoolAgent(actor);
}
Swapchain *DeviceAgent::createSwapchain() {
Swapchain *actor = _actor->createSwapchain();
return ccnew SwapchainAgent(actor);
}
Buffer *DeviceAgent::createBuffer() {
Buffer *actor = _actor->createBuffer();
return ccnew BufferAgent(actor);
}
Texture *DeviceAgent::createTexture() {
Texture *actor = _actor->createTexture();
return ccnew TextureAgent(actor);
}
Shader *DeviceAgent::createShader() {
Shader *actor = _actor->createShader();
return ccnew ShaderAgent(actor);
}
InputAssembler *DeviceAgent::createInputAssembler() {
InputAssembler *actor = _actor->createInputAssembler();
return ccnew InputAssemblerAgent(actor);
}
RenderPass *DeviceAgent::createRenderPass() {
RenderPass *actor = _actor->createRenderPass();
return ccnew RenderPassAgent(actor);
}
Framebuffer *DeviceAgent::createFramebuffer() {
Framebuffer *actor = _actor->createFramebuffer();
return ccnew FramebufferAgent(actor);
}
DescriptorSet *DeviceAgent::createDescriptorSet() {
DescriptorSet *actor = _actor->createDescriptorSet();
return ccnew DescriptorSetAgent(actor);
}
DescriptorSetLayout *DeviceAgent::createDescriptorSetLayout() {
DescriptorSetLayout *actor = _actor->createDescriptorSetLayout();
return ccnew DescriptorSetLayoutAgent(actor);
}
PipelineLayout *DeviceAgent::createPipelineLayout() {
PipelineLayout *actor = _actor->createPipelineLayout();
return ccnew PipelineLayoutAgent(actor);
}
PipelineState *DeviceAgent::createPipelineState() {
PipelineState *actor = _actor->createPipelineState();
return ccnew PipelineStateAgent(actor);
}
Sampler *DeviceAgent::getSampler(const SamplerInfo &info) {
return _actor->getSampler(info);
}
GeneralBarrier *DeviceAgent::getGeneralBarrier(const GeneralBarrierInfo &info) {
return _actor->getGeneralBarrier(info);
}
TextureBarrier *DeviceAgent::getTextureBarrier(const TextureBarrierInfo &info) {
return _actor->getTextureBarrier(info);
}
BufferBarrier *DeviceAgent::getBufferBarrier(const BufferBarrierInfo &info) {
return _actor->getBufferBarrier(info);
}
template <typename T>
void doBufferTextureCopy(const uint8_t *const *buffers, Texture *texture, const BufferTextureCopy *regions, uint32_t count, MessageQueue *mq, T *actor) {
uint32_t bufferCount = 0U;
for (uint32_t i = 0U; i < count; i++) {
bufferCount += regions[i].texSubres.layerCount;
}
Format format = texture->getFormat();
constexpr uint32_t alignment = 16;
size_t totalSize = boost::alignment::align_up(sizeof(BufferTextureCopy) * count + sizeof(uint8_t *) * bufferCount, alignment);
for (uint32_t i = 0U; i < count; i++) {
const BufferTextureCopy &region = regions[i];
uint32_t size = formatSize(texture->getFormat(), region.texExtent.width, region.texExtent.height, region.texExtent.depth);
totalSize += boost::alignment::align_up(size, alignment) * region.texSubres.layerCount;
}
auto *allocator = ccnew ThreadSafeLinearAllocator(totalSize, alignment);
auto *actorRegions = allocator->allocate<BufferTextureCopy>(count);
memcpy(actorRegions, regions, count * sizeof(BufferTextureCopy));
const auto **actorBuffers = allocator->allocate<const uint8_t *>(bufferCount);
const auto blockHeight = formatAlignment(format).second;
for (uint32_t i = 0U, n = 0U; i < count; i++) {
const BufferTextureCopy &region = regions[i];
uint32_t width = region.texExtent.width;
uint32_t height = region.texExtent.height;
uint32_t depth = region.texExtent.depth;
uint32_t rowStride = region.buffStride > 0 ? region.buffStride : region.texExtent.width;
uint32_t heightStride = region.buffTexHeight > 0 ? region.buffTexHeight : region.texExtent.height;
uint32_t rowStrideSize = formatSize(format, rowStride, 1, 1);
uint32_t sliceStrideSize = formatSize(format, rowStride, heightStride, 1);
uint32_t destRowStrideSize = formatSize(format, width, 1, 1);
uint32_t size = formatSize(format, width, height, depth);
for (uint32_t l = 0; l < region.texSubres.layerCount; l++) {
auto *buffer = allocator->allocate<uint8_t>(size, alignment);
uint32_t destOffset = 0;
uint32_t buffOffset = 0;
for (uint32_t d = 0; d < depth; d++) {
buffOffset = region.buffOffset + sliceStrideSize * d;
for (uint32_t h = 0; h < height; h += blockHeight) {
memcpy(buffer + destOffset, buffers[n] + buffOffset, destRowStrideSize);
destOffset += destRowStrideSize;
buffOffset += rowStrideSize;
}
}
actorBuffers[n++] = buffer;
}
actorRegions[i].buffOffset = 0;
actorRegions[i].buffStride = 0;
actorRegions[i].buffTexHeight = 0;
}
ENQUEUE_MESSAGE_6(
mq, DeviceCopyBuffersToTexture,
actor, actor,
buffers, actorBuffers,
dst, static_cast<TextureAgent *>(texture)->getActor(),
regions, actorRegions,
count, count,
allocator, allocator,
{
actor->copyBuffersToTexture(buffers, dst, regions, count);
delete allocator;
});
}
void DeviceAgent::copyBuffersToTexture(const uint8_t *const *buffers, Texture *dst, const BufferTextureCopy *regions, uint32_t count) {
doBufferTextureCopy(buffers, dst, regions, count, _mainMessageQueue, _actor);
}
void CommandBufferAgent::copyBuffersToTexture(const uint8_t *const *buffers, Texture *texture, const BufferTextureCopy *regions, uint32_t count) {
doBufferTextureCopy(buffers, texture, regions, count, _messageQueue, _actor);
}
void DeviceAgent::copyTextureToBuffers(Texture *srcTexture, uint8_t *const *buffers, const BufferTextureCopy *regions, uint32_t count) {
ENQUEUE_MESSAGE_5(
_mainMessageQueue,
DeviceCopyTextureToBuffers,
actor, getActor(),
src, static_cast<TextureAgent *>(srcTexture)->getActor(),
buffers, buffers,
regions, regions,
count, count,
{
actor->copyTextureToBuffers(src, buffers, regions, count);
});
_mainMessageQueue->kickAndWait();
}
void DeviceAgent::flushCommands(CommandBuffer *const *cmdBuffs, uint32_t count) {
if (!_multithreaded) return; // all command buffers are immediately executed
auto **agentCmdBuffs = _mainMessageQueue->allocate<CommandBufferAgent *>(count);
for (uint32_t i = 0; i < count; ++i) {
agentCmdBuffs[i] = static_cast<CommandBufferAgent *const>(cmdBuffs[i]);
MessageQueue::freeChunksInFreeQueue(agentCmdBuffs[i]->_messageQueue);
agentCmdBuffs[i]->_messageQueue->finishWriting();
}
ENQUEUE_MESSAGE_3(
_mainMessageQueue, DeviceFlushCommands,
count, count,
cmdBuffs, agentCmdBuffs,
multiThreaded, _actor->_multithreadedCommandRecording,
{
CommandBufferAgent::flushCommands(count, cmdBuffs, multiThreaded);
});
}
void DeviceAgent::getQueryPoolResults(QueryPool *queryPool) {
QueryPool *actorQueryPool = static_cast<QueryPoolAgent *>(queryPool)->getActor();
ENQUEUE_MESSAGE_2(
_mainMessageQueue, DeviceGetQueryPoolResults,
actor, getActor(),
queryPool, actorQueryPool,
{
actor->getQueryPoolResults(queryPool);
});
auto *actorQueryPoolAgent = static_cast<QueryPoolAgent *>(actorQueryPool);
auto *queryPoolAgent = static_cast<QueryPoolAgent *>(queryPool);
std::lock_guard<std::mutex> lock(actorQueryPoolAgent->_mutex);
queryPoolAgent->_results = actorQueryPoolAgent->_results;
}
void DeviceAgent::enableAutoBarrier(bool en) {
ENQUEUE_MESSAGE_2(
_mainMessageQueue, enableAutoBarrier,
actor, getActor(),
en, en,
{
actor->enableAutoBarrier(en);
});
}
void DeviceAgent::presentSignal() {
_frameBoundarySemaphore.signal();
}
void DeviceAgent::presentWait() {
MessageQueue::freeChunksInFreeQueue(_mainMessageQueue);
_mainMessageQueue->finishWriting();
_currentIndex = (_currentIndex + 1) % MAX_FRAME_INDEX;
_frameBoundarySemaphore.wait();
}
void DeviceAgent::frameSync() {
ENQUEUE_MESSAGE_1(
_mainMessageQueue, FrameSync,
actor, _actor,
{
actor->frameSync();
});
}
SampleCount DeviceAgent::getMaxSampleCount(Format format, TextureUsage usage, TextureFlags flags) const {
return _actor->getMaxSampleCount(format, usage, flags);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,136 @@
/****************************************************************************
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/Agent.h"
#include "base/std/container/unordered_set.h"
#include "base/threading/Semaphore.h"
#include "gfx-base/GFXDevice.h"
namespace cc {
class IXRInterface;
class MessageQueue;
namespace gfx {
class CommandBuffer;
class CommandBufferAgent;
class CC_DLL DeviceAgent final : public Agent<Device> {
public:
static DeviceAgent *getInstance();
static constexpr uint32_t MAX_CPU_FRAME_AHEAD = 1;
static constexpr uint32_t MAX_FRAME_INDEX = MAX_CPU_FRAME_AHEAD + 1;
~DeviceAgent() override;
using Device::copyBuffersToTexture;
using Device::createBuffer;
using Device::createCommandBuffer;
using Device::createDescriptorSet;
using Device::createDescriptorSetLayout;
using Device::createFramebuffer;
using Device::createGeneralBarrier;
using Device::createInputAssembler;
using Device::createPipelineLayout;
using Device::createPipelineState;
using Device::createQueryPool;
using Device::createQueue;
using Device::createRenderPass;
using Device::createSampler;
using Device::createShader;
using Device::createTexture;
using Device::createTextureBarrier;
void frameSync() override;
void acquire(Swapchain *const *swapchains, uint32_t count) override;
void present() override;
CommandBuffer *createCommandBuffer(const CommandBufferInfo &info, bool hasAgent) override;
Queue *createQueue() override;
QueryPool *createQueryPool() override;
Swapchain *createSwapchain() override;
Buffer *createBuffer() override;
Texture *createTexture() override;
Shader *createShader() override;
InputAssembler *createInputAssembler() override;
RenderPass *createRenderPass() override;
Framebuffer *createFramebuffer() override;
DescriptorSet *createDescriptorSet() override;
DescriptorSetLayout *createDescriptorSetLayout() override;
PipelineLayout *createPipelineLayout() override;
PipelineState *createPipelineState() override;
Sampler *getSampler(const SamplerInfo &info) override;
GeneralBarrier *getGeneralBarrier(const GeneralBarrierInfo &info) override;
TextureBarrier *getTextureBarrier(const TextureBarrierInfo &info) override;
BufferBarrier *getBufferBarrier(const BufferBarrierInfo &info) override;
void copyBuffersToTexture(const uint8_t *const *buffers, Texture *dst, const BufferTextureCopy *regions, uint32_t count) override;
void copyTextureToBuffers(Texture *src, uint8_t *const *buffers, const BufferTextureCopy *region, uint32_t count) override;
void flushCommands(CommandBuffer *const *cmdBuffs, uint32_t count) override;
void getQueryPoolResults(QueryPool *queryPool) override;
MemoryStatus &getMemoryStatus() override { return _actor->getMemoryStatus(); }
uint32_t getNumDrawCalls() const override { return _actor->getNumDrawCalls(); }
uint32_t getNumInstances() const override { return _actor->getNumInstances(); }
uint32_t getNumTris() const override { return _actor->getNumTris(); }
uint32_t getCurrentIndex() const { return _currentIndex; }
void setMultithreaded(bool multithreaded);
inline MessageQueue *getMessageQueue() const { return _mainMessageQueue; }
void presentWait();
void presentSignal();
void enableAutoBarrier(bool en) override;
SampleCount getMaxSampleCount(Format format, TextureUsage usage, TextureFlags flags) const override;
protected:
static DeviceAgent *instance;
friend class DeviceManager;
friend class CommandBufferAgent;
explicit DeviceAgent(Device *device);
bool doInit(const DeviceInfo &info) override;
void doDestroy() override;
bool _multithreaded{false};
MessageQueue *_mainMessageQueue{nullptr};
uint32_t _currentIndex = 0U;
#if CC_USE_XR
Semaphore _frameBoundarySemaphore{0};
#else
Semaphore _frameBoundarySemaphore{MAX_CPU_FRAME_AHEAD};
#endif
ccstd::unordered_set<CommandBufferAgent *> _cmdBuffRefs;
IXRInterface *_xr{nullptr};
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,86 @@
/****************************************************************************
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/threading/MessageQueue.h"
#include "DeviceAgent.h"
#include "FramebufferAgent.h"
#include "RenderPassAgent.h"
#include "TextureAgent.h"
namespace cc {
namespace gfx {
FramebufferAgent::FramebufferAgent(Framebuffer *actor)
: Agent<Framebuffer>(actor) {
_typedID = actor->getTypedID();
}
FramebufferAgent::~FramebufferAgent() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
FramebufferDestruct,
actor, _actor,
{
CC_SAFE_DELETE(actor);
});
}
void FramebufferAgent::doInit(const FramebufferInfo &info) {
FramebufferInfo actorInfo = info;
for (uint32_t i = 0U; i < info.colorTextures.size(); ++i) {
if (info.colorTextures[i]) {
actorInfo.colorTextures[i] = static_cast<TextureAgent *>(info.colorTextures[i])->getActor();
}
}
if (info.depthStencilTexture) {
actorInfo.depthStencilTexture = static_cast<TextureAgent *>(info.depthStencilTexture)->getActor();
}
if (info.depthStencilResolveTexture) {
actorInfo.depthStencilResolveTexture = static_cast<TextureAgent *>(info.depthStencilResolveTexture)->getActor();
}
actorInfo.renderPass = static_cast<RenderPassAgent *>(info.renderPass)->getActor();
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(),
FramebufferInit,
actor, getActor(),
info, actorInfo,
{
actor->initialize(info);
});
}
void FramebufferAgent::doDestroy() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
FramebufferDestroy,
actor, getActor(),
{
actor->destroy();
});
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,44 @@
/****************************************************************************
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/Agent.h"
#include "gfx-base/GFXFramebuffer.h"
namespace cc {
namespace gfx {
class CC_DLL FramebufferAgent final : public Agent<Framebuffer> {
public:
explicit FramebufferAgent(Framebuffer *actor);
~FramebufferAgent() override;
protected:
void doInit(const FramebufferInfo &info) override;
void doDestroy() override;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,82 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "base/threading/MessageQueue.h"
#include "BufferAgent.h"
#include "DeviceAgent.h"
#include "InputAssemblerAgent.h"
namespace cc {
namespace gfx {
InputAssemblerAgent::InputAssemblerAgent(InputAssembler *actor)
: Agent<InputAssembler>(actor) {
_typedID = actor->getTypedID();
}
InputAssemblerAgent::~InputAssemblerAgent() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
InputAssemblerDestruct,
actor, _actor,
{
CC_SAFE_DELETE(actor);
});
}
void InputAssemblerAgent::doInit(const InputAssemblerInfo &info) {
InputAssemblerInfo actorInfo = info;
for (auto &vertexBuffer : actorInfo.vertexBuffers) {
vertexBuffer = static_cast<BufferAgent *>(vertexBuffer)->getActor();
}
if (actorInfo.indexBuffer) {
actorInfo.indexBuffer = static_cast<BufferAgent *>(actorInfo.indexBuffer)->getActor();
}
if (actorInfo.indirectBuffer) {
actorInfo.indirectBuffer = static_cast<BufferAgent *>(actorInfo.indirectBuffer)->getActor();
}
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(),
InputAssemblerInit,
actor, getActor(),
info, actorInfo,
{
actor->initialize(info);
});
}
void InputAssemblerAgent::doDestroy() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
InputAssemblerDestroy,
actor, getActor(),
{
actor->destroy();
});
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,44 @@
/****************************************************************************
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/Agent.h"
#include "gfx-base/GFXInputAssembler.h"
namespace cc {
namespace gfx {
class CC_DLL InputAssemblerAgent final : public Agent<InputAssembler> {
public:
explicit InputAssemblerAgent(InputAssembler *actor);
~InputAssemblerAgent() override;
protected:
void doInit(const InputAssemblerInfo &info) override;
void doDestroy() override;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,77 @@
/****************************************************************************
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/threading/MessageQueue.h"
#include "DescriptorSetLayoutAgent.h"
#include "DeviceAgent.h"
#include "PipelineLayoutAgent.h"
namespace cc {
namespace gfx {
PipelineLayoutAgent::PipelineLayoutAgent(PipelineLayout *actor)
: Agent<PipelineLayout>(actor) {
_typedID = actor->getTypedID();
}
PipelineLayoutAgent::~PipelineLayoutAgent() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
PipelineLayoutDestruct,
actor, _actor,
{
CC_SAFE_DELETE(actor);
});
}
void PipelineLayoutAgent::doInit(const PipelineLayoutInfo &info) {
PipelineLayoutInfo actorInfo;
actorInfo.setLayouts.resize(info.setLayouts.size());
for (uint32_t i = 0U; i < info.setLayouts.size(); i++) {
actorInfo.setLayouts[i] = static_cast<DescriptorSetLayoutAgent *>(info.setLayouts[i])->getActor();
}
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(),
PipelineLayoutInit,
actor, getActor(),
info, actorInfo,
{
actor->initialize(info);
});
}
void PipelineLayoutAgent::doDestroy() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
PipelineLayoutDestroy,
actor, getActor(),
{
actor->destroy();
});
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,44 @@
/****************************************************************************
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/Agent.h"
#include "gfx-base/GFXPipelineLayout.h"
namespace cc {
namespace gfx {
class CC_DLL PipelineLayoutAgent final : public Agent<PipelineLayout> {
public:
explicit PipelineLayoutAgent(PipelineLayout *actor);
~PipelineLayoutAgent() override;
protected:
void doInit(const PipelineLayoutInfo &info) override;
void doDestroy() override;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,78 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "base/threading/MessageQueue.h"
#include "DeviceAgent.h"
#include "PipelineLayoutAgent.h"
#include "PipelineStateAgent.h"
#include "RenderPassAgent.h"
#include "ShaderAgent.h"
namespace cc {
namespace gfx {
PipelineStateAgent::PipelineStateAgent(PipelineState *actor)
: Agent<PipelineState>(actor) {
_typedID = actor->getTypedID();
}
PipelineStateAgent::~PipelineStateAgent() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
PipelineStateDestruct,
actor, _actor,
{
CC_SAFE_DELETE(actor);
});
}
void PipelineStateAgent::doInit(const PipelineStateInfo &info) {
PipelineStateInfo actorInfo = info;
actorInfo.shader = static_cast<ShaderAgent *>(info.shader)->getActor();
actorInfo.pipelineLayout = static_cast<PipelineLayoutAgent *>(info.pipelineLayout)->getActor();
if (info.renderPass) actorInfo.renderPass = static_cast<RenderPassAgent *>(info.renderPass)->getActor();
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(),
PipelineStateInit,
actor, getActor(),
info, actorInfo,
{
actor->initialize(info);
});
}
void PipelineStateAgent::doDestroy() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
PipelineStateDestroy,
actor, getActor(),
{
actor->destroy();
});
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,44 @@
/****************************************************************************
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/Agent.h"
#include "gfx-base/GFXPipelineState.h"
namespace cc {
namespace gfx {
class CC_DLL PipelineStateAgent final : public Agent<PipelineState> {
public:
explicit PipelineStateAgent(PipelineState *actor);
~PipelineStateAgent() override;
protected:
void doInit(const PipelineStateInfo &info) override;
void doDestroy() override;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,74 @@
/****************************************************************************
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/job-system/JobSystem.h"
#include "base/threading/MessageQueue.h"
#include "CommandBufferAgent.h"
#include "DeviceAgent.h"
#include "QueryPoolAgent.h"
namespace cc {
namespace gfx {
QueryPoolAgent::QueryPoolAgent(QueryPool *actor)
: Agent<QueryPool>(actor) {
_typedID = actor->getTypedID();
_type = actor->getType();
_maxQueryObjects = actor->getMaxQueryObjects();
}
QueryPoolAgent::~QueryPoolAgent() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
QueryDestruct,
actor, _actor,
{
CC_SAFE_DELETE(actor);
});
}
void QueryPoolAgent::doInit(const QueryPoolInfo &info) {
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(),
QueryInit,
actor, getActor(),
info, info,
{
actor->initialize(info);
});
}
void QueryPoolAgent::doDestroy() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
QueryDestroy,
actor, getActor(),
{
actor->destroy();
});
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,46 @@
/****************************************************************************
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/Agent.h"
#include "gfx-base/GFXQueryPool.h"
namespace cc {
namespace gfx {
class CC_DLL QueryPoolAgent final : public Agent<QueryPool> {
public:
explicit QueryPoolAgent(QueryPool *actor);
~QueryPoolAgent() override;
protected:
friend class DeviceAgent;
void doInit(const QueryPoolInfo &info) override;
void doDestroy() override;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,103 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "base/job-system/JobSystem.h"
#include "base/threading/MessageQueue.h"
#include "CommandBufferAgent.h"
#include "DeviceAgent.h"
#include "QueueAgent.h"
namespace cc {
namespace gfx {
QueueAgent::QueueAgent(Queue *actor)
: Agent<Queue>(actor) {
_typedID = actor->getTypedID();
}
QueueAgent::~QueueAgent() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
QueueDestruct,
actor, _actor,
{
CC_SAFE_DELETE(actor);
});
}
void QueueAgent::doInit(const QueueInfo &info) {
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(),
QueueInit,
actor, getActor(),
info, info,
{
actor->initialize(info);
});
}
void QueueAgent::doDestroy() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
QueueDestroy,
actor, getActor(),
{
actor->destroy();
});
}
void QueueAgent::submit(CommandBuffer *const *cmdBuffs, uint32_t count) {
if (!count) return;
MessageQueue *msgQ = DeviceAgent::getInstance()->getMessageQueue();
auto **actorCmdBuffs = msgQ->allocate<CommandBuffer *>(count);
for (uint32_t i = 0U; i < count; ++i) {
actorCmdBuffs[i] = static_cast<CommandBufferAgent *>(cmdBuffs[i])->getActor();
}
ENQUEUE_MESSAGE_3(
DeviceAgent::getInstance()->getMessageQueue(),
QueueSubmit,
actor, getActor(),
actorCmdBuffs, actorCmdBuffs,
count, count,
{
//auto startTime = std::chrono::steady_clock::now();
//auto endTime = std::chrono::steady_clock::now();
//float dt = std::chrono::duration_cast<std::chrono::nanoseconds>(endTime - startTime).count() / 1e6;
//static float timeAcc = 0.f;
//if (!timeAcc) timeAcc = dt;
//else timeAcc = timeAcc * 0.95f + dt * 0.05f;
//CC_LOG_INFO("---------- %.2fms", timeAcc);
//CC_LOG_INFO("======== one round ========");
actor->submit(actorCmdBuffs, count);
});
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,50 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "base/Agent.h"
#include "gfx-base/GFXQueue.h"
namespace cc {
namespace gfx {
class CC_DLL QueueAgent final : public Agent<Queue> {
public:
using Queue::submit;
explicit QueueAgent(Queue *actor);
~QueueAgent() override;
void submit(CommandBuffer *const *cmdBuffs, uint32_t count) override;
protected:
friend class DeviceAgent;
void doInit(const QueueInfo &info) override;
void doDestroy() override;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,70 @@
/****************************************************************************
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/threading/MessageQueue.h"
#include "DeviceAgent.h"
#include "RenderPassAgent.h"
namespace cc {
namespace gfx {
RenderPassAgent::RenderPassAgent(RenderPass *actor)
: Agent<RenderPass>(actor) {
_typedID = actor->getTypedID();
}
RenderPassAgent::~RenderPassAgent() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
RenderPassDestruct,
actor, _actor,
{
CC_SAFE_DELETE(actor);
});
}
void RenderPassAgent::doInit(const RenderPassInfo &info) {
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(),
RenderPassInit,
actor, getActor(),
info, info,
{
actor->initialize(info);
});
}
void RenderPassAgent::doDestroy() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
RenderPassDestroy,
actor, getActor(),
{
actor->destroy();
});
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,44 @@
/****************************************************************************
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/Agent.h"
#include "gfx-base/GFXRenderPass.h"
namespace cc {
namespace gfx {
class CC_DLL RenderPassAgent final : public Agent<RenderPass> {
public:
explicit RenderPassAgent(RenderPass *actor);
~RenderPassAgent() override;
protected:
void doInit(const RenderPassInfo &info) override;
void doDestroy() override;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,70 @@
/****************************************************************************
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/threading/MessageQueue.h"
#include "DeviceAgent.h"
#include "ShaderAgent.h"
namespace cc {
namespace gfx {
ShaderAgent::ShaderAgent(Shader *actor)
: Agent<Shader>(actor) {
_typedID = actor->getTypedID();
}
ShaderAgent::~ShaderAgent() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
ShaderDestruct,
actor, _actor,
{
CC_SAFE_DELETE(actor);
});
}
void ShaderAgent::doInit(const ShaderInfo &info) {
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(),
ShaderInit,
actor, getActor(),
info, info,
{
actor->initialize(info);
});
}
void ShaderAgent::doDestroy() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
ShaderDestroy,
actor, getActor(),
{
actor->destroy();
});
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,44 @@
/****************************************************************************
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/Agent.h"
#include "gfx-base/GFXShader.h"
namespace cc {
namespace gfx {
class CC_DLL ShaderAgent final : public Agent<Shader> {
public:
explicit ShaderAgent(Shader *actor);
~ShaderAgent() override;
protected:
void doInit(const ShaderInfo &info) override;
void doDestroy() override;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,151 @@
/****************************************************************************
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/threading/MessageQueue.h"
#include "DeviceAgent.h"
#include "SwapchainAgent.h"
#include "gfx-agent/TextureAgent.h"
namespace cc {
namespace gfx {
SwapchainAgent::SwapchainAgent(Swapchain *actor)
: Agent<Swapchain>(actor) {
_typedID = actor->getTypedID();
_preRotationEnabled = static_cast<SwapchainAgent *>(actor)->_preRotationEnabled;
}
SwapchainAgent::~SwapchainAgent() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(), SwapchainDestruct,
actor, _actor,
{
CC_SAFE_DELETE(actor);
});
}
void SwapchainAgent::doInit(const SwapchainInfo &info) {
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(), SwapchainInit,
actor, getActor(),
info, info,
{
actor->initialize(info);
});
DeviceAgent::getInstance()->getMessageQueue()->kickAndWait();
auto *colorTexture = ccnew TextureAgent(_actor->getColorTexture());
colorTexture->renounceOwnership();
_colorTexture = colorTexture;
auto *depthStencilTexture = ccnew TextureAgent(_actor->getDepthStencilTexture());
depthStencilTexture->renounceOwnership();
_depthStencilTexture = depthStencilTexture;
SwapchainTextureInfo textureInfo;
textureInfo.swapchain = this;
textureInfo.format = _actor->getColorTexture()->getFormat();
textureInfo.width = _actor->getWidth();
textureInfo.height = _actor->getHeight();
initTexture(textureInfo, _colorTexture);
textureInfo.format = _actor->getDepthStencilTexture()->getFormat();
initTexture(textureInfo, _depthStencilTexture);
_transform = _actor->getSurfaceTransform();
}
void SwapchainAgent::doDestroy() {
_depthStencilTexture = nullptr;
_colorTexture = nullptr;
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(), SwapchainDestroy,
actor, getActor(),
{
actor->destroy();
});
}
void SwapchainAgent::doResize(uint32_t width, uint32_t height, SurfaceTransform transform) {
auto *mq = DeviceAgent::getInstance()->getMessageQueue();
ENQUEUE_MESSAGE_4(
mq, SwapchainResize,
actor, getActor(),
width, width,
height, height,
transform, transform,
{
actor->resize(width, height, transform);
});
mq->kickAndWait();
updateInfo();
}
void SwapchainAgent::updateInfo() {
_generation = _actor->getGeneration();
SwapchainTextureInfo textureInfo;
textureInfo.swapchain = this;
textureInfo.format = _actor->getColorTexture()->getFormat();
textureInfo.width = _actor->getWidth();
textureInfo.height = _actor->getHeight();
updateTextureInfo(textureInfo, _colorTexture);
textureInfo.format = _actor->getDepthStencilTexture()->getFormat();
updateTextureInfo(textureInfo, _depthStencilTexture);
_transform = _actor->getSurfaceTransform();
}
void SwapchainAgent::doDestroySurface() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(), SwapchaindestroySurface,
actor, getActor(),
{
actor->destroySurface();
});
DeviceAgent::getInstance()->getMessageQueue()->kickAndWait();
}
void SwapchainAgent::doCreateSurface(void *windowHandle) {
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(), SwapchaincreateSurface,
actor, getActor(),
windowHandle, windowHandle,
{
actor->createSurface(windowHandle);
});
DeviceAgent::getInstance()->getMessageQueue()->kickAndWait();
updateInfo();
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,48 @@
/****************************************************************************
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/Agent.h"
#include "gfx-base/GFXSwapchain.h"
namespace cc {
namespace gfx {
class CC_DLL SwapchainAgent final : public Agent<Swapchain> {
public:
explicit SwapchainAgent(Swapchain *actor);
~SwapchainAgent() override;
protected:
void doInit(const SwapchainInfo &info) override;
void doDestroy() override;
void doResize(uint32_t width, uint32_t height, SurfaceTransform transform) override;
void doDestroySurface() override;
void doCreateSurface(void *windowHandle) override;
void updateInfo();
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,104 @@
/****************************************************************************
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/threading/MessageQueue.h"
#include "DeviceAgent.h"
#include "TextureAgent.h"
#include "gfx-agent/SwapchainAgent.h"
#include "gfx-base/GFXDef.h"
namespace cc {
namespace gfx {
TextureAgent::TextureAgent(Texture *actor)
: Agent<Texture>(actor) {
_typedID = actor->getTypedID();
}
TextureAgent::~TextureAgent() {
if (_ownTheActor) {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
TextureDestruct,
actor, _actor,
{
CC_SAFE_DELETE(actor);
});
}
}
void TextureAgent::doInit(const TextureInfo &info) {
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(),
TextureInit,
actor, getActor(),
info, info,
{
actor->initialize(info);
});
}
void TextureAgent::doInit(const TextureViewInfo &info) {
TextureViewInfo actorInfo = info;
actorInfo.texture = static_cast<TextureAgent *>(info.texture)->getActor();
ENQUEUE_MESSAGE_2(
DeviceAgent::getInstance()->getMessageQueue(),
TextureViewInit,
actor, getActor(),
info, actorInfo,
{
actor->initialize(info);
});
}
void TextureAgent::doInit(const SwapchainTextureInfo &info) {
// the actor is already initialized
}
void TextureAgent::doDestroy() {
ENQUEUE_MESSAGE_1(
DeviceAgent::getInstance()->getMessageQueue(),
TextureDestroy,
actor, getActor(),
{
actor->destroy();
});
}
void TextureAgent::doResize(uint32_t width, uint32_t height, uint32_t /*size*/) {
ENQUEUE_MESSAGE_3(
DeviceAgent::getInstance()->getMessageQueue(),
TextureResize,
actor, getActor(),
width, width,
height, height,
{
actor->resize(width, height);
});
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,57 @@
/****************************************************************************
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "base/Agent.h"
#include "gfx-base/GFXTexture.h"
namespace cc {
namespace gfx {
class CC_DLL TextureAgent : public Agent<Texture> {
public:
explicit TextureAgent(Texture *actor);
~TextureAgent() override;
inline void renounceOwnership() { _ownTheActor = false; }
const Texture *getRaw() const override { return _actor->getRaw(); }
uint32_t getGLTextureHandle() const noexcept override { return _actor->getGLTextureHandle(); }
protected:
friend class SwapchainAgent;
void doInit(const TextureInfo &info) override;
void doInit(const TextureViewInfo &info) override;
void doInit(const SwapchainTextureInfo &info) override;
void doDestroy() override;
void doResize(uint32_t width, uint32_t height, uint32_t size) override;
bool _ownTheActor = true;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,905 @@
/****************************************************************************
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 "GFXBarrier.h"
#include <algorithm>
#include <array>
namespace cc {
namespace gfx {
namespace {
template <unsigned char... indices>
constexpr uint64_t setbit() {
return ((1ULL << indices) | ... | 0ULL);
}
template <typename T, size_t... indices>
constexpr uint64_t setbits(const std::integer_sequence<T, indices...>& intSeq) {
std::ignore = intSeq;
return setbit<indices...>();
}
template <std::size_t N>
constexpr uint64_t setbits() {
using index_seq = std::make_index_sequence<N>;
return setbits(index_seq{});
}
template <unsigned char first, unsigned char end>
constexpr uint64_t setbitBetween() {
static_assert(first >= end);
return setbits<first>() ^ setbits<end>();
}
template <uint32_t N>
constexpr uint8_t highestBitPosOffset() {
if constexpr (N == 0) {
return 0;
} else {
return highestBitPosOffset<(N >> 1)>() + 1;
}
}
enum class ResourceType : uint32_t {
UNKNOWN,
BUFFER,
TEXTURE,
};
enum class CommonUsage : uint32_t {
NONE = 0,
COPY_SRC = 1 << 1,
COPY_DST = 1 << 2,
ROM = 1 << 3, // sampled or UNIFORM
STORAGE = 1 << 4,
IB_OR_CA = 1 << 5,
VB_OR_DS = 1 << 6,
INDIRECT_OR_INPUT = 1 << 7,
SHADING_RATE = 1 << 8,
LAST_ONE = SHADING_RATE,
};
CC_ENUM_BITWISE_OPERATORS(CommonUsage);
constexpr CommonUsage textureUsageToCommonUsage(TextureUsage usage) {
CommonUsage res{0};
if (hasFlag(usage, TextureUsage::TRANSFER_SRC)) {
res |= CommonUsage::COPY_SRC;
}
if (hasFlag(usage, TextureUsage::TRANSFER_DST)) {
res |= CommonUsage::COPY_DST;
}
if (hasFlag(usage, TextureUsage::SAMPLED)) {
res |= CommonUsage::ROM;
}
if (hasFlag(usage, TextureUsage::STORAGE)) {
res |= CommonUsage::STORAGE;
}
if (hasFlag(usage, TextureUsage::COLOR_ATTACHMENT)) {
res |= CommonUsage::IB_OR_CA;
}
if (hasFlag(usage, TextureUsage::DEPTH_STENCIL_ATTACHMENT)) {
res |= CommonUsage::VB_OR_DS;
}
if (hasFlag(usage, TextureUsage::INPUT_ATTACHMENT)) {
res |= CommonUsage::INDIRECT_OR_INPUT;
}
if (hasFlag(usage, TextureUsage::SHADING_RATE)) {
res |= CommonUsage::SHADING_RATE;
}
return res;
}
constexpr CommonUsage bufferUsageToCommonUsage(BufferUsage usage) {
CommonUsage res{0};
if (hasFlag(usage, BufferUsage::NONE)) {
res |= CommonUsage::NONE;
}
if (hasFlag(usage, BufferUsage::TRANSFER_SRC)) {
res |= CommonUsage::COPY_SRC;
}
if (hasFlag(usage, BufferUsage::TRANSFER_DST)) {
res |= CommonUsage::COPY_DST;
}
if (hasFlag(usage, BufferUsage::UNIFORM)) {
res |= CommonUsage::ROM;
}
if (hasFlag(usage, BufferUsage::STORAGE)) {
res |= CommonUsage::STORAGE;
}
if (hasFlag(usage, BufferUsage::INDEX)) {
res |= CommonUsage::IB_OR_CA;
}
if (hasFlag(usage, BufferUsage::VERTEX)) {
res |= CommonUsage::VB_OR_DS;
}
if (hasFlag(usage, BufferUsage::INDIRECT)) {
res |= CommonUsage::INDIRECT_OR_INPUT;
}
return res;
}
struct AccessElem {
uint32_t mask{0xFFFFFFFF};
uint32_t key{0xFFFFFFFF};
AccessFlags access{AccessFlags::NONE};
uint32_t mutex{0x0}; // optional mutually exclusive flag
};
#define OPERABLE(val) static_cast<std::underlying_type<decltype(val)>::type>(val)
constexpr uint8_t COMMON_USAGE_COUNT = highestBitPosOffset<OPERABLE(CommonUsage::LAST_ONE)>();
constexpr uint8_t SHADER_STAGE_RESERVE_COUNT = 6;
constexpr uint8_t RESOURCE_TYPE_COUNT = 2;
constexpr uint8_t MEM_TYPE_COUNT = 2;
constexpr uint8_t ACCESS_TYPE_COUNT = 2;
constexpr auto CMN_NONE = OPERABLE(CommonUsage::NONE);
constexpr auto CMN_COPY_SRC = OPERABLE(CommonUsage::COPY_SRC);
constexpr auto CMN_COPY_DST = OPERABLE(CommonUsage::COPY_DST);
constexpr auto CMN_ROM = OPERABLE(CommonUsage::ROM);
constexpr auto CMN_STORAGE = OPERABLE(CommonUsage::STORAGE);
constexpr auto CMN_IB_OR_CA = OPERABLE(CommonUsage::IB_OR_CA);
constexpr auto CMN_VB_OR_DS = OPERABLE(CommonUsage::VB_OR_DS);
constexpr auto CMN_INDIRECT_OR_INPUT = OPERABLE(CommonUsage::INDIRECT_OR_INPUT);
constexpr auto CMN_SHADING_RATE = OPERABLE(CommonUsage::SHADING_RATE);
constexpr auto SHADER_STAGE_BIT_POPS = COMMON_USAGE_COUNT;
constexpr auto SHADERSTAGE_NONE = 0;
constexpr auto SHADERSTAGE_VERT = 1 << (0 + SHADER_STAGE_BIT_POPS);
constexpr auto SHADERSTAGE_CTRL = 1 << (1 + SHADER_STAGE_BIT_POPS);
constexpr auto SHADERSTAGE_EVAL = 1 << (2 + SHADER_STAGE_BIT_POPS);
constexpr auto SHADERSTAGE_GEOM = 1 << (3 + SHADER_STAGE_BIT_POPS);
constexpr auto SHADERSTAGE_FRAG = 1 << (4 + SHADER_STAGE_BIT_POPS);
constexpr auto SHADERSTAGE_COMP = 1 << (5 + SHADER_STAGE_BIT_POPS);
constexpr auto RESOURCE_TYPE_BIT_POS = COMMON_USAGE_COUNT + SHADER_STAGE_RESERVE_COUNT;
constexpr auto RES_TEXTURE = OPERABLE(ResourceType::TEXTURE) << RESOURCE_TYPE_BIT_POS;
constexpr auto RES_BUFFER = OPERABLE(ResourceType::BUFFER) << RESOURCE_TYPE_BIT_POS;
constexpr auto MEM_TYPE_BIT_POS = COMMON_USAGE_COUNT + SHADER_STAGE_RESERVE_COUNT + RESOURCE_TYPE_COUNT;
constexpr auto MEM_HOST = OPERABLE(MemoryUsage::HOST) << MEM_TYPE_BIT_POS;
constexpr auto MEM_DEVICE = OPERABLE(MemoryUsage::DEVICE) << MEM_TYPE_BIT_POS;
constexpr auto ACCESS_TYPE_BIT_POS = COMMON_USAGE_COUNT + SHADER_STAGE_RESERVE_COUNT + RESOURCE_TYPE_COUNT + MEM_TYPE_COUNT;
constexpr auto ACCESS_WRITE = OPERABLE(MemoryAccess::WRITE_ONLY) << ACCESS_TYPE_BIT_POS;
constexpr auto ACCESS_READ = OPERABLE(MemoryAccess::READ_ONLY) << ACCESS_TYPE_BIT_POS;
constexpr uint8_t USED_BIT_COUNT = COMMON_USAGE_COUNT + SHADER_STAGE_RESERVE_COUNT + RESOURCE_TYPE_COUNT + MEM_TYPE_COUNT + ACCESS_TYPE_COUNT;
// 20 and above :reserved
// 18 ~ 19: MemoryAccess
// 16 ~ 17: MemoryUsage
// 14 ~ 15: ResourceType
// 8 ~ 13: ShaderStageFlags
// 0 ~ 7: CommonUsage
constexpr uint32_t CARE_NONE = 0x0;
constexpr uint32_t CARE_CMNUSAGE = setbitBetween<SHADER_STAGE_BIT_POPS, 0>();
constexpr uint32_t CARE_SHADERSTAGE = setbitBetween<RESOURCE_TYPE_BIT_POS, SHADER_STAGE_BIT_POPS>();
constexpr uint32_t CARE_RESTYPE = setbitBetween<MEM_TYPE_BIT_POS, RESOURCE_TYPE_BIT_POS>();
constexpr uint32_t CARE_MEMUSAGE = setbitBetween<ACCESS_TYPE_BIT_POS, MEM_TYPE_BIT_POS>();
constexpr uint32_t CARE_MEMACCESS = setbitBetween<USED_BIT_COUNT, ACCESS_TYPE_BIT_POS>();
constexpr uint32_t IGNORE_NONE = 0xFFFFFFFF;
constexpr uint32_t IGNORE_CMNUSAGE = ~CARE_CMNUSAGE;
constexpr uint32_t IGNORE_SHADERSTAGE = ~CARE_SHADERSTAGE;
constexpr uint32_t IGNORE_RESTYPE = ~CARE_RESTYPE;
constexpr uint32_t IGNORE_MEMUSAGE = ~CARE_MEMUSAGE;
constexpr uint32_t IGNORE_MEMACCESS = ~CARE_MEMACCESS;
constexpr AccessElem ACCESS_MAP[] = {
{CARE_MEMACCESS,
0x0,
AccessFlags::NONE},
{CARE_MEMUSAGE,
0x0,
AccessFlags::NONE},
{CARE_RESTYPE | CARE_CMNUSAGE,
RES_BUFFER | CMN_INDIRECT_OR_INPUT,
AccessFlags::INDIRECT_BUFFER},
{CARE_RESTYPE | CARE_CMNUSAGE,
RES_BUFFER | CMN_IB_OR_CA,
AccessFlags::INDEX_BUFFER}, // buffer usage indicates what it is, so shader stage ignored.
{CARE_RESTYPE | CARE_CMNUSAGE,
ACCESS_READ | RES_BUFFER | CMN_VB_OR_DS,
AccessFlags::VERTEX_BUFFER}, // ditto
{IGNORE_MEMUSAGE,
ACCESS_READ | RES_BUFFER | SHADERSTAGE_VERT | CMN_ROM,
AccessFlags::VERTEX_SHADER_READ_UNIFORM_BUFFER},
{IGNORE_MEMUSAGE,
ACCESS_READ | RES_TEXTURE | SHADERSTAGE_VERT | CMN_ROM,
AccessFlags::VERTEX_SHADER_READ_TEXTURE},
{IGNORE_MEMUSAGE & IGNORE_RESTYPE,
ACCESS_READ | ACCESS_WRITE | SHADERSTAGE_VERT | CMN_STORAGE,
AccessFlags::VERTEX_SHADER_READ_OTHER},
{IGNORE_MEMUSAGE,
ACCESS_READ | RES_BUFFER | SHADERSTAGE_FRAG | CMN_ROM,
AccessFlags::FRAGMENT_SHADER_READ_UNIFORM_BUFFER},
{CARE_MEMACCESS | CARE_RESTYPE | CARE_SHADERSTAGE | CARE_CMNUSAGE,
ACCESS_READ | RES_TEXTURE | SHADERSTAGE_FRAG | CMN_ROM,
AccessFlags::FRAGMENT_SHADER_READ_TEXTURE,
CMN_VB_OR_DS},
{IGNORE_MEMUSAGE,
ACCESS_READ | RES_TEXTURE | SHADERSTAGE_FRAG | CMN_IB_OR_CA | CMN_INDIRECT_OR_INPUT,
AccessFlags::FRAGMENT_SHADER_READ_COLOR_INPUT_ATTACHMENT},
{IGNORE_MEMUSAGE,
ACCESS_READ | RES_TEXTURE | SHADERSTAGE_FRAG | CMN_VB_OR_DS | CMN_INDIRECT_OR_INPUT,
AccessFlags::FRAGMENT_SHADER_READ_DEPTH_STENCIL_INPUT_ATTACHMENT},
{IGNORE_MEMUSAGE & IGNORE_RESTYPE,
ACCESS_READ | ACCESS_WRITE | SHADERSTAGE_FRAG | CMN_STORAGE,
AccessFlags::FRAGMENT_SHADER_READ_OTHER,
CMN_SHADING_RATE},
//{IGNORE_MEMUSAGE,
// ACCESS_READ | RES_TEXTURE | SHADERSTAGE_FRAG | CMN_IB_OR_CA,
// AccessFlags::COLOR_ATTACHMENT_READ},
{CARE_MEMACCESS | CARE_RESTYPE | CARE_CMNUSAGE | CARE_SHADERSTAGE,
ACCESS_READ | RES_TEXTURE | CMN_VB_OR_DS | CMN_ROM,
AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ},
{IGNORE_MEMUSAGE,
ACCESS_READ | RES_BUFFER | SHADERSTAGE_COMP | CMN_ROM,
AccessFlags::COMPUTE_SHADER_READ_UNIFORM_BUFFER},
{IGNORE_MEMUSAGE,
ACCESS_READ | RES_TEXTURE | SHADERSTAGE_COMP | CMN_ROM,
AccessFlags::COMPUTE_SHADER_READ_TEXTURE,
CMN_VB_OR_DS},
// shading rate has its own flag
{CARE_MEMACCESS | CARE_SHADERSTAGE | CARE_CMNUSAGE,
ACCESS_READ | ACCESS_WRITE | SHADERSTAGE_COMP | CMN_STORAGE,
AccessFlags::COMPUTE_SHADER_READ_OTHER,
CMN_ROM},
{CARE_MEMACCESS | CARE_CMNUSAGE,
ACCESS_READ | CMN_COPY_SRC,
AccessFlags::TRANSFER_READ},
{CARE_MEMACCESS | CARE_MEMUSAGE,
ACCESS_READ | MEM_HOST,
AccessFlags::HOST_READ},
{CARE_MEMACCESS | CARE_SHADERSTAGE | CARE_CMNUSAGE,
ACCESS_READ | SHADERSTAGE_FRAG | CMN_SHADING_RATE,
AccessFlags::SHADING_RATE},
//{CARE_CMNUSAGE | CARE_RESTYPE,
// RES_TEXTURE | CMN_NONE,
// AccessFlags::PRESENT},
{CARE_MEMACCESS | CARE_SHADERSTAGE | CARE_CMNUSAGE,
ACCESS_WRITE | SHADERSTAGE_VERT | CMN_STORAGE,
AccessFlags::VERTEX_SHADER_WRITE},
{CARE_MEMACCESS | CARE_SHADERSTAGE | CARE_CMNUSAGE,
ACCESS_WRITE | SHADERSTAGE_FRAG | CMN_STORAGE,
AccessFlags::FRAGMENT_SHADER_WRITE},
{IGNORE_MEMUSAGE,
ACCESS_WRITE | RES_TEXTURE | SHADERSTAGE_FRAG | CMN_IB_OR_CA,
AccessFlags::COLOR_ATTACHMENT_WRITE},
{IGNORE_NONE,
ACCESS_WRITE | MEM_DEVICE | RES_TEXTURE | SHADERSTAGE_FRAG | CMN_VB_OR_DS,
AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE},
{CARE_MEMACCESS | CARE_SHADERSTAGE | CARE_CMNUSAGE,
ACCESS_WRITE | SHADERSTAGE_COMP | CMN_STORAGE,
AccessFlags::COMPUTE_SHADER_WRITE},
{CARE_MEMACCESS | CARE_CMNUSAGE,
ACCESS_WRITE | CMN_COPY_DST,
AccessFlags::TRANSFER_WRITE},
{CARE_MEMACCESS | CARE_MEMUSAGE,
ACCESS_WRITE | MEM_HOST,
AccessFlags::HOST_WRITE},
};
constexpr bool validateAccess(ResourceType type, CommonUsage usage, MemoryAccess access, ShaderStageFlags visibility) {
bool res = true;
if (type == ResourceType::BUFFER) {
uint32_t conflicts[] = {
hasFlag(usage, CommonUsage::ROM) && hasFlag(access, MemoryAccess::WRITE_ONLY), // uniform has write access.
hasAnyFlags(usage, CommonUsage::IB_OR_CA | CommonUsage::VB_OR_DS) && !hasFlag(visibility, ShaderStageFlags::VERTEX), // color/ds/input not in fragment
hasAllFlags(usage, CommonUsage::ROM | CommonUsage::STORAGE), // storage ^ sampled
hasFlag(usage, CommonUsage::COPY_SRC) && hasAllFlags(MemoryAccess::READ_ONLY, access), // transfer src ==> read_only
hasFlag(usage, CommonUsage::COPY_DST) && hasAllFlags(MemoryAccess::WRITE_ONLY, access), // transfer dst ==> write_only
hasAllFlags(usage, CommonUsage::COPY_SRC | CommonUsage::COPY_DST), // both src and dst
hasFlag(usage, CommonUsage::VB_OR_DS) && hasAnyFlags(usage, CommonUsage::IB_OR_CA | CommonUsage::INDIRECT_OR_INPUT),
hasFlag(usage, CommonUsage::IB_OR_CA) && hasAnyFlags(usage, CommonUsage::VB_OR_DS | CommonUsage::INDIRECT_OR_INPUT),
hasFlag(usage, CommonUsage::INDIRECT_OR_INPUT) && hasAnyFlags(usage, CommonUsage::IB_OR_CA | CommonUsage::VB_OR_DS),
// exlusive
};
res = !(*std::max_element(std::begin(conflicts), std::end(conflicts)));
} else if (type == ResourceType::TEXTURE) {
uint32_t conflicts[] = {
// hasAnyFlags(usage, CommonUsage::IB_OR_CA | CommonUsage::VB_OR_DS | CommonUsage::INDIRECT_OR_INPUT) && !hasFlag(visibility, ShaderStageFlags::FRAGMENT), // color/ds/input not in fragment
hasFlag(usage, CommonUsage::INDIRECT_OR_INPUT) && !hasFlag(access, MemoryAccess::READ_ONLY), // input needs read
hasAllFlags(usage, CommonUsage::IB_OR_CA | CommonUsage::STORAGE), // storage ^ sampled
hasFlag(usage, CommonUsage::COPY_SRC) && !hasAllFlags(MemoryAccess::READ_ONLY, access), // transfer src ==> read_only
hasFlag(usage, CommonUsage::COPY_DST) && !hasAllFlags(MemoryAccess::WRITE_ONLY, access),
hasFlag(usage, CommonUsage::INDIRECT_OR_INPUT) && !hasAnyFlags(usage, CommonUsage::IB_OR_CA | CommonUsage::VB_OR_DS), // input needs to specify color or ds // transfer dst ==> write_only
hasAllFlags(usage, CommonUsage::COPY_SRC | CommonUsage::COPY_DST), // both src and dst
};
res = !(*std::max_element(std::begin(conflicts), std::end(conflicts)));
}
return res;
}
constexpr AccessFlags getAccessFlagsImpl(
BufferUsage usage, MemoryUsage memUsage,
MemoryAccess access,
ShaderStageFlags visibility) noexcept {
AccessFlags flags{AccessFlags::NONE};
CommonUsage cmnUsage = bufferUsageToCommonUsage(usage);
if (validateAccess(ResourceType::BUFFER, cmnUsage, access, visibility)) {
uint32_t info = 0xFFFFFFFF;
info &= ((OPERABLE(access) << ACCESS_TYPE_BIT_POS) | IGNORE_MEMACCESS);
info &= ((OPERABLE(memUsage) << MEM_TYPE_BIT_POS) | IGNORE_MEMUSAGE);
info &= ((OPERABLE(ResourceType::TEXTURE) << RESOURCE_TYPE_BIT_POS) | IGNORE_RESTYPE);
info &= ((OPERABLE(visibility) << SHADER_STAGE_BIT_POPS) | IGNORE_SHADERSTAGE);
info &= OPERABLE(cmnUsage) | IGNORE_CMNUSAGE;
for (const auto& elem : ACCESS_MAP) {
auto testFlag = info & elem.mask;
// hasKey
if ((testFlag & elem.key) == elem.key) {
flags |= elem.access;
}
}
} else {
flags = INVALID_ACCESS_FLAGS;
}
return flags;
}
constexpr AccessFlags getAccessFlagsImpl(
TextureUsage usage,
MemoryAccess access,
ShaderStageFlags visibility) noexcept {
AccessFlags flags{AccessFlags::NONE};
CommonUsage cmnUsage = textureUsageToCommonUsage(usage);
if (validateAccess(ResourceType::TEXTURE, cmnUsage, access, visibility)) {
if (usage == gfx::TextureUsageBit::NONE) {
return gfx::AccessFlagBit::PRESENT;
}
uint32_t info = 0xFFFFFFFF;
info &= ((OPERABLE(access) << ACCESS_TYPE_BIT_POS) | IGNORE_MEMACCESS);
info &= ((OPERABLE(MemoryUsage::DEVICE) << MEM_TYPE_BIT_POS) | IGNORE_MEMUSAGE);
info &= ((OPERABLE(ResourceType::TEXTURE) << RESOURCE_TYPE_BIT_POS) | IGNORE_RESTYPE);
info &= ((OPERABLE(visibility) << (SHADER_STAGE_BIT_POPS)) | IGNORE_SHADERSTAGE);
info &= OPERABLE(cmnUsage) | IGNORE_CMNUSAGE;
for (const auto& elem : ACCESS_MAP) {
auto testFlag = info & elem.mask;
// hasKey && no mutex flag
if (((testFlag & elem.key) == elem.key) && ((testFlag & elem.mutex) == 0)) {
flags |= elem.access;
}
}
} else {
flags = INVALID_ACCESS_FLAGS;
}
// CC_ASSERT(flags != INVALID_ACCESS_FLAGS);
return flags;
}
} // namespace
AccessFlags getAccessFlags(
BufferUsage usage, MemoryUsage memUsage,
MemoryAccess access,
ShaderStageFlags visibility) noexcept {
return getAccessFlagsImpl(usage, memUsage, access, visibility);
}
AccessFlags getAccessFlags(
TextureUsage usage,
MemoryAccess access,
ShaderStageFlags visibility) noexcept {
return getAccessFlagsImpl(usage, access, visibility);
}
namespace {
constexpr AccessFlags getDeviceAccessFlagsImpl(
TextureUsage usage,
MemoryAccess access,
ShaderStageFlags visibility) {
// Special Present Usage
if (usage == TextureUsage::NONE) {
return AccessFlags::PRESENT;
}
// not read or write access
if (access == MemoryAccess::NONE) {
return INVALID_ACCESS_FLAGS;
}
// input attachment requires color or depth stencil
if (hasAnyFlags(usage, TextureUsage::INPUT_ATTACHMENT) &&
!hasAnyFlags(usage, TextureUsage::COLOR_ATTACHMENT | TextureUsage::DEPTH_STENCIL_ATTACHMENT)) {
return INVALID_ACCESS_FLAGS;
}
const bool bWrite = hasAnyFlags(access, MemoryAccess::WRITE_ONLY);
const bool bRead = hasAnyFlags(access, MemoryAccess::READ_ONLY);
if (bWrite) { // single write
const auto writeMask =
TextureUsage::TRANSFER_DST |
TextureUsage::STORAGE |
TextureUsage::COLOR_ATTACHMENT |
TextureUsage::DEPTH_STENCIL_ATTACHMENT;
const auto usage1 = usage & writeMask;
// see https://stackoverflow.com/questions/51094594/how-to-check-if-exactly-one-bit-is-set-in-an-int
constexpr auto hasOnebit = [](uint32_t bits) -> bool {
return bits && !(bits & (bits - 1));
};
if (!hasOnebit(static_cast<uint32_t>(usage1))) {
return INVALID_ACCESS_FLAGS;
}
const auto readMask =
TextureUsage::SAMPLED |
TextureUsage::TRANSFER_SRC;
if (hasAnyFlags(usage, readMask)) {
return INVALID_ACCESS_FLAGS;
}
}
auto flags = AccessFlags::NONE;
if (hasAnyFlags(usage, TextureUsage::COLOR_ATTACHMENT)) {
if (hasAnyFlags(visibility, ShaderStageFlags::ALL & ~ShaderStageFlags::FRAGMENT)) {
return INVALID_ACCESS_FLAGS;
}
if (bWrite) {
flags |= AccessFlags::COLOR_ATTACHMENT_WRITE;
}
if (bRead) {
flags |= AccessFlags::COLOR_ATTACHMENT_READ;
}
if (hasAnyFlags(usage, TextureUsage::INPUT_ATTACHMENT)) {
if (!bRead) {
return INVALID_ACCESS_FLAGS;
}
flags |= AccessFlags::FRAGMENT_SHADER_READ_COLOR_INPUT_ATTACHMENT;
}
if (bWrite) {
return flags;
}
} else if (hasAnyFlags(usage, TextureUsage::DEPTH_STENCIL_ATTACHMENT)) {
if (hasAnyFlags(visibility, ShaderStageFlags::ALL & ~ShaderStageFlags::FRAGMENT)) {
return INVALID_ACCESS_FLAGS;
}
if (bWrite) {
flags |= AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE;
}
if (bRead) {
flags |= AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ;
}
if (hasAnyFlags(usage, TextureUsage::INPUT_ATTACHMENT)) {
if (!bRead) {
return INVALID_ACCESS_FLAGS;
}
flags |= AccessFlags::FRAGMENT_SHADER_READ_DEPTH_STENCIL_INPUT_ATTACHMENT;
}
if (bWrite) {
return flags;
}
} else if (bWrite) {
if (hasAnyFlags(usage, TextureUsage::SAMPLED)) {
return INVALID_ACCESS_FLAGS;
}
const bool bUnorderedAccess = hasAnyFlags(usage, TextureUsage::STORAGE);
const bool bCopyTarget = hasAnyFlags(usage, TextureUsage::TRANSFER_DST);
if (!(bUnorderedAccess ^ bCopyTarget)) {
return INVALID_ACCESS_FLAGS;
}
if (bCopyTarget) {
if (bRead || hasAnyFlags(usage, TextureUsage::TRANSFER_SRC)) {
return INVALID_ACCESS_FLAGS; // both copy source and target
}
flags |= AccessFlags::TRANSFER_WRITE;
} else {
if (hasAnyFlags(visibility, ShaderStageFlags::VERTEX)) {
flags |= AccessFlags::VERTEX_SHADER_WRITE;
if (bRead) {
flags |= AccessFlags::VERTEX_SHADER_READ_TEXTURE;
}
} else if (hasAnyFlags(visibility, ShaderStageFlags::FRAGMENT)) {
flags |= AccessFlags::FRAGMENT_SHADER_WRITE;
if (bRead) {
flags |= AccessFlags::FRAGMENT_SHADER_READ_TEXTURE;
}
} else if (hasAnyFlags(visibility, ShaderStageFlags::COMPUTE)) {
flags |= AccessFlags::COMPUTE_SHADER_WRITE;
if (bRead) {
flags |= AccessFlags::COMPUTE_SHADER_READ_TEXTURE;
}
}
}
return flags;
}
if (bWrite) {
return INVALID_ACCESS_FLAGS;
}
// ReadOnly
if (hasAnyFlags(usage, TextureUsage::TRANSFER_SRC)) {
flags |= AccessFlags::TRANSFER_READ;
}
if (hasAnyFlags(usage, TextureUsage::SAMPLED | TextureUsage::STORAGE)) {
if (hasAnyFlags(visibility, ShaderStageFlags::VERTEX)) {
flags |= AccessFlags::VERTEX_SHADER_READ_TEXTURE;
}
if (hasAnyFlags(visibility, ShaderStageFlags::FRAGMENT)) {
flags |= AccessFlags::FRAGMENT_SHADER_READ_TEXTURE;
}
if (hasAnyFlags(visibility, ShaderStageFlags::COMPUTE)) {
flags |= AccessFlags::COMPUTE_SHADER_READ_TEXTURE;
}
}
return flags;
}
static_assert(
(AccessFlags::VERTEX_SHADER_WRITE | AccessFlags::VERTEX_SHADER_READ_OTHER) ==
getAccessFlagsImpl(
TextureUsage::STORAGE,
MemoryAccess::READ_WRITE,
ShaderStageFlags::VERTEX));
static_assert(
(AccessFlags::FRAGMENT_SHADER_WRITE | AccessFlags::FRAGMENT_SHADER_READ_OTHER) ==
getAccessFlagsImpl(
TextureUsage::STORAGE,
MemoryAccess::READ_WRITE,
ShaderStageFlags::FRAGMENT));
static_assert(
(AccessFlags::COMPUTE_SHADER_WRITE | AccessFlags::COMPUTE_SHADER_READ_OTHER) ==
getAccessFlagsImpl(
TextureUsage::STORAGE,
MemoryAccess::READ_WRITE,
ShaderStageFlags::COMPUTE));
static_assert(
INVALID_ACCESS_FLAGS ==
getAccessFlagsImpl(
TextureUsage::COLOR_ATTACHMENT | TextureUsage::INPUT_ATTACHMENT | TextureUsage::STORAGE,
MemoryAccess::READ_ONLY,
ShaderStageFlags::FRAGMENT));
static_assert(
INVALID_ACCESS_FLAGS ==
getAccessFlagsImpl(
TextureUsage::COLOR_ATTACHMENT | TextureUsage::INPUT_ATTACHMENT | TextureUsage::SAMPLED | TextureUsage::STORAGE,
MemoryAccess::READ_ONLY,
ShaderStageFlags::FRAGMENT));
static_assert(
(AccessFlags::TRANSFER_WRITE | AccessFlags::COLOR_ATTACHMENT_WRITE) ==
getAccessFlagsImpl(
TextureUsage::TRANSFER_DST | TextureUsage::COLOR_ATTACHMENT,
MemoryAccess::WRITE_ONLY,
ShaderStageFlags::ALL));
////////////////////////////////////
// VERTEX_SHADER_WRITE
static_assert(
AccessFlags::VERTEX_SHADER_WRITE ==
getDeviceAccessFlagsImpl(
TextureUsage::STORAGE,
MemoryAccess::WRITE_ONLY,
ShaderStageFlags::VERTEX));
static_assert(
(AccessFlags::VERTEX_SHADER_WRITE | AccessFlags::VERTEX_SHADER_READ_TEXTURE) ==
getDeviceAccessFlagsImpl(
TextureUsage::STORAGE,
MemoryAccess::READ_WRITE,
ShaderStageFlags::VERTEX));
static_assert(
INVALID_ACCESS_FLAGS ==
getDeviceAccessFlagsImpl(
TextureUsage::STORAGE | TextureUsage::SAMPLED, // both storage write and sampling
MemoryAccess::READ_WRITE,
ShaderStageFlags::VERTEX));
static_assert(
INVALID_ACCESS_FLAGS ==
getDeviceAccessFlagsImpl(
TextureUsage::SAMPLED, // Sampled cannot be write
MemoryAccess::READ_WRITE,
ShaderStageFlags::VERTEX));
// FRAGMENT_SHADER_WRITE
static_assert(
AccessFlags::FRAGMENT_SHADER_WRITE ==
getDeviceAccessFlagsImpl(
TextureUsage::STORAGE,
MemoryAccess::WRITE_ONLY,
ShaderStageFlags::FRAGMENT));
static_assert(
(AccessFlags::FRAGMENT_SHADER_WRITE | AccessFlags::FRAGMENT_SHADER_READ_TEXTURE) ==
getDeviceAccessFlagsImpl(
TextureUsage::STORAGE,
MemoryAccess::READ_WRITE,
ShaderStageFlags::FRAGMENT));
// COLOR_ATTACHMENT_WRITE
static_assert(
AccessFlags::COLOR_ATTACHMENT_WRITE ==
getDeviceAccessFlagsImpl(
TextureUsage::COLOR_ATTACHMENT,
MemoryAccess::WRITE_ONLY,
ShaderStageFlags::FRAGMENT));
static_assert(
INVALID_ACCESS_FLAGS ==
getDeviceAccessFlagsImpl(
TextureUsage::COLOR_ATTACHMENT,
MemoryAccess::WRITE_ONLY,
ShaderStageFlags::VERTEX)); // not fragment stage
static_assert(
INVALID_ACCESS_FLAGS ==
getDeviceAccessFlagsImpl(
TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLED, // both color attachment and sampled texture
MemoryAccess::WRITE_ONLY,
ShaderStageFlags::FRAGMENT));
static_assert(
(AccessFlags::COLOR_ATTACHMENT_WRITE | AccessFlags::COLOR_ATTACHMENT_READ) ==
getDeviceAccessFlagsImpl(
TextureUsage::COLOR_ATTACHMENT,
MemoryAccess::READ_WRITE,
ShaderStageFlags::FRAGMENT));
static_assert(
AccessFlags::COLOR_ATTACHMENT_READ ==
getDeviceAccessFlagsImpl(
TextureUsage::COLOR_ATTACHMENT,
MemoryAccess::READ_ONLY,
ShaderStageFlags::FRAGMENT));
static_assert(
(AccessFlags::COLOR_ATTACHMENT_READ | AccessFlags::FRAGMENT_SHADER_READ_COLOR_INPUT_ATTACHMENT) ==
getDeviceAccessFlagsImpl(
TextureUsage::COLOR_ATTACHMENT | TextureUsage::INPUT_ATTACHMENT,
MemoryAccess::READ_ONLY,
ShaderStageFlags::FRAGMENT));
static_assert(
(AccessFlags::COLOR_ATTACHMENT_WRITE | AccessFlags::COLOR_ATTACHMENT_READ | AccessFlags::FRAGMENT_SHADER_READ_COLOR_INPUT_ATTACHMENT) ==
getDeviceAccessFlagsImpl(
TextureUsage::COLOR_ATTACHMENT | TextureUsage::INPUT_ATTACHMENT,
MemoryAccess::READ_WRITE,
ShaderStageFlags::FRAGMENT));
static_assert(
INVALID_ACCESS_FLAGS ==
getDeviceAccessFlagsImpl(
TextureUsage::COLOR_ATTACHMENT | TextureUsage::INPUT_ATTACHMENT,
MemoryAccess::WRITE_ONLY, // INPUT_ATTACHMENT needs read access
ShaderStageFlags::FRAGMENT));
// DEPTH_STENCIL_ATTACHMENT_WRITE
static_assert(
AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE ==
getDeviceAccessFlagsImpl(
TextureUsage::DEPTH_STENCIL_ATTACHMENT,
MemoryAccess::WRITE_ONLY,
ShaderStageFlags::FRAGMENT));
static_assert(
INVALID_ACCESS_FLAGS ==
getDeviceAccessFlagsImpl(
TextureUsage::DEPTH_STENCIL_ATTACHMENT,
MemoryAccess::WRITE_ONLY,
ShaderStageFlags::VERTEX)); // not fragment stage
static_assert(
INVALID_ACCESS_FLAGS ==
getDeviceAccessFlagsImpl(
TextureUsage::DEPTH_STENCIL_ATTACHMENT | TextureUsage::SAMPLED, // both color attachment and sampled texture
MemoryAccess::WRITE_ONLY,
ShaderStageFlags::FRAGMENT));
static_assert(
(AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE | AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ) ==
getDeviceAccessFlagsImpl(
TextureUsage::DEPTH_STENCIL_ATTACHMENT,
MemoryAccess::READ_WRITE,
ShaderStageFlags::FRAGMENT));
static_assert(
AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ ==
getDeviceAccessFlagsImpl(
TextureUsage::DEPTH_STENCIL_ATTACHMENT,
MemoryAccess::READ_ONLY,
ShaderStageFlags::FRAGMENT));
static_assert(
(AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ | AccessFlags::FRAGMENT_SHADER_READ_DEPTH_STENCIL_INPUT_ATTACHMENT) ==
getDeviceAccessFlagsImpl(
TextureUsage::DEPTH_STENCIL_ATTACHMENT | TextureUsage::INPUT_ATTACHMENT,
MemoryAccess::READ_ONLY,
ShaderStageFlags::FRAGMENT));
static_assert(
(AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE | AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ | AccessFlags::FRAGMENT_SHADER_READ_DEPTH_STENCIL_INPUT_ATTACHMENT) ==
getDeviceAccessFlagsImpl(
TextureUsage::DEPTH_STENCIL_ATTACHMENT | TextureUsage::INPUT_ATTACHMENT,
MemoryAccess::READ_WRITE,
ShaderStageFlags::FRAGMENT));
static_assert(
INVALID_ACCESS_FLAGS ==
getDeviceAccessFlagsImpl(
TextureUsage::DEPTH_STENCIL_ATTACHMENT | TextureUsage::INPUT_ATTACHMENT,
MemoryAccess::WRITE_ONLY, // INPUT_ATTACHMENT needs read access
ShaderStageFlags::FRAGMENT));
// COMPUTE_SHADER_WRITE
static_assert(
AccessFlags::COMPUTE_SHADER_WRITE ==
getDeviceAccessFlagsImpl(
TextureUsage::STORAGE,
MemoryAccess::WRITE_ONLY,
ShaderStageFlags::COMPUTE));
static_assert(
(AccessFlags::COMPUTE_SHADER_WRITE | AccessFlags::COMPUTE_SHADER_READ_TEXTURE) ==
getDeviceAccessFlagsImpl(
TextureUsage::STORAGE,
MemoryAccess::READ_WRITE,
ShaderStageFlags::COMPUTE));
static_assert(
INVALID_ACCESS_FLAGS ==
getDeviceAccessFlagsImpl(
TextureUsage::STORAGE | TextureUsage::SAMPLED, // cannot be sampled
MemoryAccess::WRITE_ONLY,
ShaderStageFlags::COMPUTE));
static_assert(
INVALID_ACCESS_FLAGS ==
getDeviceAccessFlagsImpl(
TextureUsage::STORAGE | TextureUsage::SAMPLED, // cannot be sampled
MemoryAccess::READ_WRITE,
ShaderStageFlags::COMPUTE));
// TRANSFER_WRITE
static_assert(
AccessFlags::TRANSFER_WRITE ==
getDeviceAccessFlagsImpl(
TextureUsage::TRANSFER_DST,
MemoryAccess::WRITE_ONLY,
ShaderStageFlags::ALL)); // ShaderStageFlags not used
static_assert(
INVALID_ACCESS_FLAGS ==
getDeviceAccessFlagsImpl(
TextureUsage::TRANSFER_DST,
MemoryAccess::READ_WRITE,
ShaderStageFlags::ALL)); // ShaderStageFlags not used
static_assert(
INVALID_ACCESS_FLAGS ==
getDeviceAccessFlagsImpl(
TextureUsage::TRANSFER_DST | TextureUsage::TRANSFER_SRC, // both source and target
MemoryAccess::READ_WRITE, // both read and write
ShaderStageFlags::ALL));
static_assert(
INVALID_ACCESS_FLAGS ==
getDeviceAccessFlagsImpl(
TextureUsage::TRANSFER_DST | TextureUsage::TRANSFER_SRC, // both source and target
MemoryAccess::WRITE_ONLY,
ShaderStageFlags::ALL));
static_assert(
INVALID_ACCESS_FLAGS ==
getDeviceAccessFlagsImpl(
TextureUsage::TRANSFER_DST | TextureUsage::COLOR_ATTACHMENT, // cannot be sampled
MemoryAccess::WRITE_ONLY,
ShaderStageFlags::ALL));
// Read
// COLOR_ATTACHMENT_READ
static_assert(
INVALID_ACCESS_FLAGS ==
getDeviceAccessFlagsImpl(
TextureUsage::INPUT_ATTACHMENT, // INPUT_ATTACHMENT needs COLOR_ATTACHMENT or DEPTH_STENCIL_ATTACHMENT
MemoryAccess::READ_ONLY,
ShaderStageFlags::FRAGMENT));
static_assert(
(AccessFlags::COLOR_ATTACHMENT_READ | AccessFlags::FRAGMENT_SHADER_READ_COLOR_INPUT_ATTACHMENT | AccessFlags::FRAGMENT_SHADER_READ_TEXTURE) ==
getDeviceAccessFlagsImpl(
TextureUsage::COLOR_ATTACHMENT | TextureUsage::INPUT_ATTACHMENT | TextureUsage::SAMPLED,
MemoryAccess::READ_ONLY,
ShaderStageFlags::FRAGMENT));
static_assert(
(AccessFlags::COLOR_ATTACHMENT_READ | AccessFlags::FRAGMENT_SHADER_READ_COLOR_INPUT_ATTACHMENT | AccessFlags::FRAGMENT_SHADER_READ_TEXTURE) ==
getDeviceAccessFlagsImpl(
TextureUsage::COLOR_ATTACHMENT | TextureUsage::INPUT_ATTACHMENT | TextureUsage::STORAGE,
MemoryAccess::READ_ONLY,
ShaderStageFlags::FRAGMENT));
static_assert(
(AccessFlags::COLOR_ATTACHMENT_READ | AccessFlags::FRAGMENT_SHADER_READ_COLOR_INPUT_ATTACHMENT | AccessFlags::FRAGMENT_SHADER_READ_TEXTURE) ==
getDeviceAccessFlagsImpl(
TextureUsage::COLOR_ATTACHMENT | TextureUsage::INPUT_ATTACHMENT | TextureUsage::SAMPLED | TextureUsage::STORAGE,
MemoryAccess::READ_ONLY,
ShaderStageFlags::FRAGMENT));
static_assert(
(AccessFlags::COLOR_ATTACHMENT_READ | AccessFlags::FRAGMENT_SHADER_READ_COLOR_INPUT_ATTACHMENT | AccessFlags::TRANSFER_READ) ==
getDeviceAccessFlagsImpl(
TextureUsage::COLOR_ATTACHMENT | TextureUsage::INPUT_ATTACHMENT | TextureUsage::TRANSFER_SRC,
MemoryAccess::READ_ONLY,
ShaderStageFlags::FRAGMENT));
} // namespace
AccessFlags getDeviceAccessFlags(
TextureUsage usage,
MemoryAccess access,
ShaderStageFlags visibility) {
return getDeviceAccessFlagsImpl(usage, access, visibility);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,51 @@
/****************************************************************************
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.
****************************************************************************/
#pragma once
#include "GFXDef-common.h"
namespace cc {
namespace gfx {
AccessFlags getAccessFlags(
BufferUsage usage, MemoryUsage memUsage,
MemoryAccess access,
ShaderStageFlags visibility) noexcept;
AccessFlags getAccessFlags(
TextureUsage usage,
MemoryAccess access,
ShaderStageFlags visibility) noexcept;
constexpr AccessFlags INVALID_ACCESS_FLAGS = static_cast<AccessFlags>(0xFFFFFFFF);
AccessFlags getDeviceAccessFlags(
TextureUsage usage,
MemoryAccess access,
ShaderStageFlags visibility);
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,106 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXBuffer.h"
#include "GFXDevice.h"
namespace cc {
namespace gfx {
Buffer::Buffer()
: GFXObject(ObjectType::BUFFER) {
}
Buffer::~Buffer() = default;
ccstd::hash_t Buffer::computeHash(const BufferInfo &info) {
return Hasher<BufferInfo>()(info);
}
void Buffer::initialize(const BufferInfo &info) {
_usage = info.usage;
_memUsage = info.memUsage;
_size = info.size;
_flags = info.flags;
_stride = std::max(info.stride, 1U);
_count = _size / _stride;
doInit(info);
if (hasFlag(info.flags, BufferFlagBit::ENABLE_STAGING_WRITE) && getStagingAddress() == nullptr) {
_data = std::make_unique<uint8_t[]>(_size);
}
}
void Buffer::initialize(const BufferViewInfo &info) {
_usage = info.buffer->getUsage();
_memUsage = info.buffer->getMemUsage();
_flags = info.buffer->getFlags();
_offset = info.offset;
_size = _stride = info.range;
_count = 1U;
_isBufferView = true;
doInit(info);
}
void Buffer::destroy() {
doDestroy();
_offset = _size = _stride = _count = 0U;
}
void Buffer::resize(uint32_t size) {
if (size != _size) {
uint32_t count = size / _stride;
doResize(size, count);
_size = size;
_count = count;
}
}
void Buffer::write(const uint8_t *value, uint32_t offset, uint32_t size) const {
CC_ASSERT(hasFlag(_flags, BufferFlagBit::ENABLE_STAGING_WRITE));
uint8_t *dst = getStagingAddress();
if (dst == nullptr || offset + size > _size) {
return;
}
memcpy(dst + offset, value, size);
}
void Buffer::update() {
flush(getStagingAddress());
}
uint8_t *Buffer::getBufferStagingAddress(Buffer *buffer) {
return buffer->getStagingAddress();
}
void Buffer::flushBuffer(Buffer *buffer, const uint8_t *data) {
buffer->flush(data);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,91 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXObject.h"
#include "base/RefCounted.h"
namespace cc {
namespace gfx {
class CC_DLL Buffer : public GFXObject, public RefCounted {
public:
Buffer();
~Buffer() override;
static ccstd::hash_t computeHash(const BufferInfo &info);
void initialize(const BufferInfo &info);
void initialize(const BufferViewInfo &info);
void resize(uint32_t size);
void destroy();
template <typename T>
void write(const T &value, uint32_t offset) const {
write(reinterpret_cast<const uint8_t *>(&value), offset, sizeof(T));
}
void write(const uint8_t *value, uint32_t offset, uint32_t size) const;
virtual void update(const void *buffer, uint32_t size) = 0;
inline void update(const void *buffer) { update(buffer, _size); }
void update();
inline BufferUsage getUsage() const { return _usage; }
inline MemoryUsage getMemUsage() const { return _memUsage; }
inline uint32_t getStride() const { return _stride; }
inline uint32_t getCount() const { return _count; }
inline uint32_t getSize() const { return _size; }
inline BufferFlags getFlags() const { return _flags; }
inline bool isBufferView() const { return _isBufferView; }
protected:
virtual void doInit(const BufferInfo &info) = 0;
virtual void doInit(const BufferViewInfo &info) = 0;
virtual void doResize(uint32_t size, uint32_t count) = 0;
virtual void doDestroy() = 0;
static uint8_t *getBufferStagingAddress(Buffer *buffer);
static void flushBuffer(Buffer *buffer, const uint8_t *data);
virtual void flush(const uint8_t *data) { update(reinterpret_cast<const void *>(data), _size); }
virtual uint8_t *getStagingAddress() const { return _data.get(); }
BufferUsage _usage = BufferUsageBit::NONE;
MemoryUsage _memUsage = MemoryUsageBit::NONE;
uint32_t _stride = 0U;
uint32_t _count = 0U;
uint32_t _size = 0U;
uint32_t _offset = 0U;
BufferFlags _flags = BufferFlagBit::NONE;
bool _isBufferView = false;
uint8_t _rsv[3] = {0};
std::unique_ptr<uint8_t[]> _data;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,52 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXCommandBuffer.h"
#include "GFXObject.h"
namespace cc {
namespace gfx {
CommandBuffer::CommandBuffer()
: GFXObject(ObjectType::COMMAND_BUFFER) {
}
CommandBuffer::~CommandBuffer() = default;
void CommandBuffer::initialize(const CommandBufferInfo &info) {
_type = info.type;
_queue = info.queue;
doInit(info);
}
void CommandBuffer::destroy() {
doDestroy();
_type = CommandBufferType::PRIMARY;
_queue = nullptr;
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,194 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXBuffer.h"
#include "GFXInputAssembler.h"
#include "GFXObject.h"
#include "base/RefCounted.h"
#include "base/Utils.h"
#include "base/std/container/vector.h"
namespace cc {
namespace gfx {
class CC_DLL CommandBuffer : public GFXObject, public RefCounted {
public:
CommandBuffer();
~CommandBuffer() override;
void initialize(const CommandBufferInfo &info);
void destroy();
virtual void begin(RenderPass *renderPass, uint32_t subpass, Framebuffer *frameBuffer) = 0;
virtual void end() = 0;
virtual void beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const Color *colors, float depth, uint32_t stencil, CommandBuffer *const *secondaryCBs, uint32_t secondaryCBCount) = 0;
virtual void endRenderPass() = 0;
virtual void insertMarker(const MarkerInfo &marker) = 0;
virtual void beginMarker(const MarkerInfo &marker) = 0;
virtual void endMarker() = 0;
virtual void bindPipelineState(PipelineState *pso) = 0;
virtual void bindDescriptorSet(uint32_t set, DescriptorSet *descriptorSet, uint32_t dynamicOffsetCount, const uint32_t *dynamicOffsets) = 0;
virtual void bindInputAssembler(InputAssembler *ia) = 0;
virtual void setViewport(const Viewport &vp) = 0;
virtual void setScissor(const Rect &rect) = 0;
virtual void setLineWidth(float width) = 0;
virtual void setDepthBias(float constant, float clamp, float slope) = 0;
virtual void setBlendConstants(const Color &constants) = 0;
virtual void setDepthBound(float minBounds, float maxBounds) = 0;
virtual void setStencilWriteMask(StencilFace face, uint32_t mask) = 0;
virtual void setStencilCompareMask(StencilFace face, uint32_t ref, uint32_t mask) = 0;
virtual void nextSubpass() = 0;
virtual void draw(const DrawInfo &info) = 0;
virtual void updateBuffer(Buffer *buff, const void *data, uint32_t size) = 0;
virtual void copyBuffersToTexture(const uint8_t *const *buffers, Texture *texture, const BufferTextureCopy *regions, uint32_t count) = 0;
virtual void blitTexture(Texture *srcTexture, Texture *dstTexture, const TextureBlit *regions, uint32_t count, Filter filter) = 0;
virtual void copyTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) = 0;
virtual void resolveTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) = 0;
virtual void execute(CommandBuffer *const *cmdBuffs, uint32_t count) = 0;
virtual void dispatch(const DispatchInfo &info) = 0;
virtual void beginQuery(QueryPool *queryPool, uint32_t id) = 0;
virtual void endQuery(QueryPool *queryPool, uint32_t id) = 0;
virtual void resetQueryPool(QueryPool *queryPool) = 0;
virtual void completeQueryPool(QueryPool *queryPool) {}
using CustomCommand = std::function<void(void *)>;
virtual void customCommand(CustomCommand &&cmd) {}
// barrier: excutionBarrier
// bufferBarriers: array of BufferBarrier*, descriptions of access of buffers
// buffers: array of MTL/VK/GLES buffers
// bufferBarrierCount: number of barrier, should be equal to number of buffers
// textureBarriers: array of TextureBarrier*, descriptions of access of textures
// textures: array of MTL/VK/GLES textures
// textureBarrierCount: number of barrier, should be equal to number of textures
virtual void pipelineBarrier(const GeneralBarrier *barrier, const BufferBarrier *const *bufferBarriers, const Buffer *const *buffers, uint32_t bufferBarrierCount, const TextureBarrier *const *textureBarriers, const Texture *const *textures, uint32_t textureBarrierCount) = 0;
inline void begin();
inline void begin(RenderPass *renderPass);
inline void begin(RenderPass *renderPass, uint32_t subpass);
inline void updateBuffer(Buffer *buff, const void *data);
inline void execute(const CommandBufferList &cmdBuffs, uint32_t count);
inline void bindDescriptorSet(uint32_t set, DescriptorSet *descriptorSet);
inline void bindDescriptorSet(uint32_t set, DescriptorSet *descriptorSet, const ccstd::vector<uint32_t> &dynamicOffsets);
inline void beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const ColorList &colors, float depth, uint32_t stencil, const CommandBufferList &secondaryCBs);
inline void beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const ColorList &colors, float depth, uint32_t stencil);
inline void beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const Color *colors, float depth, uint32_t stencil);
inline void draw(InputAssembler *ia);
inline void copyBuffersToTexture(const BufferDataList &buffers, Texture *texture, const BufferTextureCopyList &regions);
inline void blitTexture(Texture *srcTexture, Texture *dstTexture, const TextureBlitList &regions, Filter filter);
inline void pipelineBarrier(const GeneralBarrier *barrier);
inline void pipelineBarrier(const GeneralBarrier *barrier, const BufferBarrierList &bufferBarriers, const BufferList &buffers, const TextureBarrierList &textureBarriers, const TextureList &textures);
inline Queue *getQueue() const { return _queue; }
inline CommandBufferType getType() const { return _type; }
virtual uint32_t getNumDrawCalls() const { return _numDrawCalls; }
virtual uint32_t getNumInstances() const { return _numInstances; }
virtual uint32_t getNumTris() const { return _numTriangles; }
protected:
virtual void doInit(const CommandBufferInfo &info) = 0;
virtual void doDestroy() = 0;
Queue *_queue = nullptr;
CommandBufferType _type = CommandBufferType::PRIMARY;
uint32_t _numDrawCalls = 0;
uint32_t _numInstances = 0;
uint32_t _numTriangles = 0;
};
//////////////////////////////////////////////////////////////////////////
void CommandBuffer::begin() {
begin(nullptr, 0, nullptr);
}
void CommandBuffer::begin(RenderPass *renderPass) {
begin(renderPass, 0, nullptr);
}
void CommandBuffer::begin(RenderPass *renderPass, uint32_t subpass) {
begin(renderPass, subpass, nullptr);
}
void CommandBuffer::updateBuffer(Buffer *buff, const void *data) {
updateBuffer(buff, data, buff->getSize());
}
void CommandBuffer::execute(const CommandBufferList &cmdBuffs, uint32_t count) {
execute(cmdBuffs.data(), count);
}
void CommandBuffer::bindDescriptorSet(uint32_t set, DescriptorSet *descriptorSet) {
bindDescriptorSet(set, descriptorSet, 0, nullptr);
}
void CommandBuffer::bindDescriptorSet(uint32_t set, DescriptorSet *descriptorSet, const ccstd::vector<uint32_t> &dynamicOffsets) {
bindDescriptorSet(set, descriptorSet, utils::toUint(dynamicOffsets.size()), dynamicOffsets.data());
}
void CommandBuffer::beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const ColorList &colors, float depth, uint32_t stencil, const CommandBufferList &secondaryCBs) {
beginRenderPass(renderPass, fbo, renderArea, colors.data(), depth, stencil, secondaryCBs.data(), utils::toUint(secondaryCBs.size()));
}
void CommandBuffer::beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const ColorList &colors, float depth, uint32_t stencil) {
beginRenderPass(renderPass, fbo, renderArea, colors.data(), depth, stencil, nullptr, 0);
}
void CommandBuffer::beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const Color *colors, float depth, uint32_t stencil) {
beginRenderPass(renderPass, fbo, renderArea, colors, depth, stencil, nullptr, 0);
}
void CommandBuffer::draw(InputAssembler *ia) {
draw(ia->getDrawInfo());
}
void CommandBuffer::copyBuffersToTexture(const BufferDataList &buffers, Texture *texture, const BufferTextureCopyList &regions) {
copyBuffersToTexture(buffers.data(), texture, regions.data(), utils::toUint(regions.size()));
}
void CommandBuffer::blitTexture(Texture *srcTexture, Texture *dstTexture, const TextureBlitList &regions, Filter filter) {
blitTexture(srcTexture, dstTexture, regions.data(), utils::toUint(regions.size()), filter);
}
void CommandBuffer::pipelineBarrier(const GeneralBarrier *barrier) {
pipelineBarrier(barrier, nullptr, nullptr, 0, nullptr, nullptr, 0U);
}
void CommandBuffer::pipelineBarrier(const GeneralBarrier *barrier, const BufferBarrierList &bufferBarriers, const BufferList &buffers, const TextureBarrierList &textureBarriers, const TextureList &textures) {
pipelineBarrier(barrier, bufferBarriers.data(), buffers.data(), utils::toUint(bufferBarriers.size()), textureBarriers.data(), textures.data(), utils::toUint(textureBarriers.size()));
}
} // namespace gfx
} // namespace cc

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,664 @@
/****************************************************************************
Copyright (c) 2019-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/Utils.h"
#include "base/std/container/array.h"
#include "base/std/hash/hash.h"
#include "GFXDef.h"
#include "GFXRenderPass.h"
#include "GFXTexture.h"
namespace cc {
namespace gfx {
// T must have no implicit padding
template <typename T>
ccstd::hash_t quickHashTrivialStruct(const T *info, size_t count = 1) {
static_assert(std::is_trivially_copyable<T>::value && sizeof(T) % 8 == 0, "T must be 8 bytes aligned and trivially copyable");
return ccstd::hash_range(reinterpret_cast<const uint64_t *>(info), reinterpret_cast<const uint64_t *>(info + count));
}
template <>
ccstd::hash_t Hasher<ColorAttachment>::operator()(const ColorAttachment &info) const {
return quickHashTrivialStruct(&info);
}
bool operator==(const ColorAttachment &lhs, const ColorAttachment &rhs) {
return !memcmp(&lhs, &rhs, sizeof(ColorAttachment));
}
template <>
ccstd::hash_t Hasher<DepthStencilAttachment>::operator()(const DepthStencilAttachment &info) const {
return quickHashTrivialStruct(&info);
}
bool operator==(const DepthStencilAttachment &lhs, const DepthStencilAttachment &rhs) {
return !memcmp(&lhs, &rhs, sizeof(DepthStencilAttachment));
}
template <>
ccstd::hash_t Hasher<SubpassDependency>::operator()(const SubpassDependency &info) const {
ccstd::hash_t seed = 8;
ccstd::hash_combine(seed, info.dstSubpass);
ccstd::hash_combine(seed, info.srcSubpass);
ccstd::hash_combine(seed, info.generalBarrier);
ccstd::hash_combine(seed, info.prevAccesses);
ccstd::hash_combine(seed, info.nextAccesses);
return seed;
}
bool operator==(const SubpassDependency &lhs, const SubpassDependency &rhs) {
return lhs.srcSubpass == rhs.srcSubpass &&
lhs.dstSubpass == rhs.dstSubpass &&
lhs.generalBarrier == rhs.generalBarrier &&
lhs.prevAccesses == rhs.prevAccesses &&
lhs.nextAccesses == rhs.nextAccesses;
}
template <>
ccstd::hash_t Hasher<SubpassInfo>::operator()(const SubpassInfo &info) const {
ccstd::hash_t seed = 8;
ccstd::hash_combine(seed, info.inputs);
ccstd::hash_combine(seed, info.colors);
ccstd::hash_combine(seed, info.resolves);
ccstd::hash_combine(seed, info.preserves);
ccstd::hash_combine(seed, info.depthStencil);
ccstd::hash_combine(seed, info.depthStencilResolve);
ccstd::hash_combine(seed, info.depthResolveMode);
ccstd::hash_combine(seed, info.stencilResolveMode);
return seed;
}
bool operator==(const SubpassInfo &lhs, const SubpassInfo &rhs) {
return lhs.inputs == rhs.inputs &&
lhs.colors == rhs.colors &&
lhs.resolves == rhs.resolves &&
lhs.preserves == rhs.preserves &&
lhs.depthStencil == rhs.depthStencil &&
lhs.depthStencilResolve == rhs.depthStencilResolve &&
lhs.depthResolveMode == rhs.depthResolveMode &&
lhs.stencilResolveMode == rhs.stencilResolveMode;
}
template <>
ccstd::hash_t Hasher<RenderPassInfo>::operator()(const RenderPassInfo &info) const {
ccstd::hash_t seed = 4;
ccstd::hash_combine(seed, info.colorAttachments);
ccstd::hash_combine(seed, info.depthStencilAttachment);
ccstd::hash_combine(seed, info.depthStencilResolveAttachment);
ccstd::hash_combine(seed, info.subpasses);
ccstd::hash_combine(seed, info.dependencies);
return seed;
}
bool operator==(const RenderPassInfo &lhs, const RenderPassInfo &rhs) {
return lhs.colorAttachments == rhs.colorAttachments &&
lhs.depthStencilAttachment == rhs.depthStencilAttachment &&
lhs.depthStencilResolveAttachment == rhs.depthStencilResolveAttachment &&
lhs.subpasses == rhs.subpasses &&
lhs.dependencies == rhs.dependencies;
}
template <>
ccstd::hash_t Hasher<FramebufferInfo>::operator()(const FramebufferInfo &info) const {
// render pass is mostly irrelevant
ccstd::hash_t seed = static_cast<ccstd::hash_t>(info.colorTextures.size()) +
static_cast<ccstd::hash_t>(info.depthStencilTexture != nullptr) +
static_cast<ccstd::hash_t>(info.depthStencilResolveTexture != nullptr);
if (info.depthStencilTexture) {
ccstd::hash_combine(seed, info.depthStencilTexture->getObjectID());
ccstd::hash_combine(seed, info.depthStencilTexture->getHash());
}
if (info.depthStencilResolveTexture) {
ccstd::hash_combine(seed, info.depthStencilResolveTexture->getObjectID());
ccstd::hash_combine(seed, info.depthStencilResolveTexture->getHash());
}
for (auto *colorTexture : info.colorTextures) {
ccstd::hash_combine(seed, colorTexture->getObjectID());
ccstd::hash_combine(seed, colorTexture->getHash());
}
ccstd::hash_combine(seed, info.renderPass->getHash());
return seed;
}
bool operator==(const FramebufferInfo &lhs, const FramebufferInfo &rhs) {
// render pass is mostly irrelevant
bool res = false;
res = lhs.colorTextures == rhs.colorTextures;
if (res) {
res = lhs.depthStencilTexture == rhs.depthStencilTexture;
}
if (res) {
res = lhs.depthStencilResolveTexture == rhs.depthStencilResolveTexture;
}
if (res) {
for (size_t i = 0; i < lhs.colorTextures.size(); ++i) {
res = lhs.colorTextures[i]->getRaw() == rhs.colorTextures[i]->getRaw() &&
lhs.colorTextures[i]->getHash() == rhs.colorTextures[i]->getHash();
if (!res) {
break;
}
}
res = lhs.renderPass->getHash() == rhs.renderPass->getHash();
if (res) {
res = lhs.depthStencilTexture->getRaw() == rhs.depthStencilTexture->getRaw() &&
lhs.depthStencilTexture->getHash() == rhs.depthStencilTexture->getHash();
}
}
return res;
}
template <>
ccstd::hash_t Hasher<TextureInfo>::operator()(const TextureInfo &info) const {
return quickHashTrivialStruct(&info);
}
bool operator==(const TextureInfo &lhs, const TextureInfo &rhs) {
return !memcmp(&lhs, &rhs, sizeof(TextureInfo));
}
template <>
ccstd::hash_t Hasher<TextureViewInfo>::operator()(const TextureViewInfo &info) const {
return quickHashTrivialStruct(&info);
}
bool operator==(const TextureViewInfo &lhs, const TextureViewInfo &rhs) {
return !memcmp(&lhs, &rhs, sizeof(TextureViewInfo));
}
template <>
ccstd::hash_t Hasher<BufferInfo>::operator()(const BufferInfo &info) const {
return quickHashTrivialStruct(&info);
}
bool operator==(const BufferInfo &lhs, const BufferInfo &rhs) {
return !memcmp(&lhs, &rhs, sizeof(BufferInfo));
}
template <>
ccstd::hash_t Hasher<SamplerInfo>::operator()(const SamplerInfo &info) const {
// return quickHashTrivialStruct(&info);
// the hash may be used to reconstruct the original struct
auto hash = static_cast<uint32_t>(info.minFilter);
hash |= static_cast<uint32_t>(info.magFilter) << 2;
hash |= static_cast<uint32_t>(info.mipFilter) << 4;
hash |= static_cast<uint32_t>(info.addressU) << 6;
hash |= static_cast<uint32_t>(info.addressV) << 8;
hash |= static_cast<uint32_t>(info.addressW) << 10;
hash |= static_cast<uint32_t>(info.maxAnisotropy) << 12;
hash |= static_cast<uint32_t>(info.cmpFunc) << 16;
return static_cast<ccstd::hash_t>(hash);
}
bool operator==(const SamplerInfo &lhs, const SamplerInfo &rhs) {
return !memcmp(&lhs, &rhs, sizeof(SamplerInfo));
}
template <>
ccstd::hash_t Hasher<GeneralBarrierInfo>::operator()(const GeneralBarrierInfo &info) const {
return quickHashTrivialStruct(&info);
}
bool operator==(const GeneralBarrierInfo &lhs, const GeneralBarrierInfo &rhs) {
return !memcmp(&lhs, &rhs, sizeof(GeneralBarrierInfo));
}
template <>
ccstd::hash_t Hasher<TextureBarrierInfo>::operator()(const TextureBarrierInfo &info) const {
return quickHashTrivialStruct(&info);
}
bool operator==(const TextureBarrierInfo &lhs, const TextureBarrierInfo &rhs) {
return !memcmp(&lhs, &rhs, sizeof(TextureBarrierInfo));
}
template <>
ccstd::hash_t Hasher<BufferBarrierInfo>::operator()(const BufferBarrierInfo &info) const {
return quickHashTrivialStruct(&info);
}
bool operator==(const BufferBarrierInfo &lhs, const BufferBarrierInfo &rhs) {
return !memcmp(&lhs, &rhs, sizeof(BufferBarrierInfo));
}
///////////////////////////////////////////////////////////////////////////////
bool operator==(const Viewport &lhs, const Viewport &rhs) {
return !memcmp(&lhs, &rhs, sizeof(Viewport));
}
bool operator==(const Rect &lhs, const Rect &rhs) {
return !memcmp(&lhs, &rhs, sizeof(Rect));
}
bool operator==(const Color &lhs, const Color &rhs) {
return !memcmp(&lhs, &rhs, sizeof(Color));
}
bool operator==(const Offset &lhs, const Offset &rhs) {
return !memcmp(&lhs, &rhs, sizeof(Offset));
}
bool operator==(const Extent &lhs, const Extent &rhs) {
return !memcmp(&lhs, &rhs, sizeof(Extent));
}
bool operator==(const Size &lhs, const Size &rhs) {
return !memcmp(&lhs, &rhs, sizeof(Size));
}
const FormatInfo GFX_FORMAT_INFOS[] = {
{"UNKNOWN", 0, 0, FormatType::NONE, false, false, false, false},
{"A8", 1, 1, FormatType::UNORM, true, false, false, false},
{"L8", 1, 1, FormatType::UNORM, false, false, false, false},
{"LA8", 1, 2, FormatType::UNORM, false, false, false, false},
{"R8", 1, 1, FormatType::UNORM, false, false, false, false},
{"R8SN", 1, 1, FormatType::SNORM, false, false, false, false},
{"R8UI", 1, 1, FormatType::UINT, false, false, false, false},
{"R8I", 1, 1, FormatType::INT, false, false, false, false},
{"R16F", 2, 1, FormatType::FLOAT, false, false, false, false},
{"R16UI", 2, 1, FormatType::UINT, false, false, false, false},
{"R16I", 2, 1, FormatType::INT, false, false, false, false},
{"R32F", 4, 1, FormatType::FLOAT, false, false, false, false},
{"R32UI", 4, 1, FormatType::UINT, false, false, false, false},
{"R32I", 4, 1, FormatType::INT, false, false, false, false},
{"RG8", 2, 2, FormatType::UNORM, false, false, false, false},
{"RG8SN", 2, 2, FormatType::SNORM, false, false, false, false},
{"RG8UI", 2, 2, FormatType::UINT, false, false, false, false},
{"RG8I", 2, 2, FormatType::INT, false, false, false, false},
{"RG16F", 4, 2, FormatType::FLOAT, false, false, false, false},
{"RG16UI", 4, 2, FormatType::UINT, false, false, false, false},
{"RG16I", 4, 2, FormatType::INT, false, false, false, false},
{"RG32F", 8, 2, FormatType::FLOAT, false, false, false, false},
{"RG32UI", 8, 2, FormatType::UINT, false, false, false, false},
{"RG32I", 8, 2, FormatType::INT, false, false, false, false},
{"RGB8", 3, 3, FormatType::UNORM, false, false, false, false},
{"SRGB8", 3, 3, FormatType::UNORM, false, false, false, false},
{"RGB8SN", 3, 3, FormatType::SNORM, false, false, false, false},
{"RGB8UI", 3, 3, FormatType::UINT, false, false, false, false},
{"RGB8I", 3, 3, FormatType::INT, false, false, false, false},
{"RGB16F", 6, 3, FormatType::FLOAT, false, false, false, false},
{"RGB16UI", 6, 3, FormatType::UINT, false, false, false, false},
{"RGB16I", 6, 3, FormatType::INT, false, false, false, false},
{"RGB32F", 12, 3, FormatType::FLOAT, false, false, false, false},
{"RGB32UI", 12, 3, FormatType::UINT, false, false, false, false},
{"RGB32I", 12, 3, FormatType::INT, false, false, false, false},
{"RGBA8", 4, 4, FormatType::UNORM, true, false, false, false},
{"BGRA8", 4, 4, FormatType::UNORM, true, false, false, false},
{"SRGB8_A8", 4, 4, FormatType::UNORM, true, false, false, false},
{"RGBA8SN", 4, 4, FormatType::SNORM, true, false, false, false},
{"RGBA8UI", 4, 4, FormatType::UINT, true, false, false, false},
{"RGBA8I", 4, 4, FormatType::INT, true, false, false, false},
{"RGBA16F", 8, 4, FormatType::FLOAT, true, false, false, false},
{"RGBA16UI", 8, 4, FormatType::UINT, true, false, false, false},
{"RGBA16I", 8, 4, FormatType::INT, true, false, false, false},
{"RGBA32F", 16, 4, FormatType::FLOAT, true, false, false, false},
{"RGBA32UI", 16, 4, FormatType::UINT, true, false, false, false},
{"RGBA32I", 16, 4, FormatType::INT, true, false, false, false},
{"R5G6B5", 2, 3, FormatType::UNORM, false, false, false, false},
{"R11G11B10F", 4, 3, FormatType::FLOAT, false, false, false, false},
{"RGB5A1", 2, 4, FormatType::UNORM, true, false, false, false},
{"RGBA4", 2, 4, FormatType::UNORM, true, false, false, false},
{"RGB10A2", 2, 4, FormatType::UNORM, true, false, false, false},
{"RGB10A2UI", 2, 4, FormatType::UINT, true, false, false, false},
{"RGB9E5", 2, 4, FormatType::FLOAT, true, false, false, false},
{"DEPTH", 4, 1, FormatType::FLOAT, false, true, false, false},
{"DEPTH_STENCIL", 5, 2, FormatType::FLOAT, false, true, true, false},
{"BC1", 1, 3, FormatType::UNORM, false, false, false, true},
{"BC1_ALPHA", 1, 4, FormatType::UNORM, true, false, false, true},
{"BC1_SRGB", 1, 3, FormatType::UNORM, false, false, false, true},
{"BC1_SRGB_ALPHA", 1, 4, FormatType::UNORM, true, false, false, true},
{"BC2", 1, 4, FormatType::UNORM, true, false, false, true},
{"BC2_SRGB", 1, 4, FormatType::UNORM, true, false, false, true},
{"BC3", 1, 4, FormatType::UNORM, true, false, false, true},
{"BC3_SRGB", 1, 4, FormatType::UNORM, true, false, false, true},
{"BC4", 1, 1, FormatType::UNORM, false, false, false, true},
{"BC4_SNORM", 1, 1, FormatType::SNORM, false, false, false, true},
{"BC5", 1, 2, FormatType::UNORM, false, false, false, true},
{"BC5_SNORM", 1, 2, FormatType::SNORM, false, false, false, true},
{"BC6H_UF16", 1, 3, FormatType::UFLOAT, false, false, false, true},
{"BC6H_SF16", 1, 3, FormatType::FLOAT, false, false, false, true},
{"BC7", 1, 4, FormatType::UNORM, true, false, false, true},
{"BC7_SRGB", 1, 4, FormatType::UNORM, true, false, false, true},
{"ETC_RGB8", 1, 3, FormatType::UNORM, false, false, false, true},
{"ETC2_RGB8", 1, 3, FormatType::UNORM, false, false, false, true},
{"ETC2_SRGB8", 1, 3, FormatType::UNORM, false, false, false, true},
{"ETC2_RGB8_A1", 1, 4, FormatType::UNORM, true, false, false, true},
{"ETC2_SRGB8_A1", 1, 4, FormatType::UNORM, true, false, false, true},
{"EAC_R11", 1, 1, FormatType::UNORM, false, false, false, true},
{"EAC_R11SN", 1, 1, FormatType::SNORM, false, false, false, true},
{"EAC_RG11", 2, 2, FormatType::UNORM, false, false, false, true},
{"EAC_RG11SN", 2, 2, FormatType::SNORM, false, false, false, true},
{"PVRTC_RGB2", 2, 3, FormatType::UNORM, false, false, false, true},
{"PVRTC_RGBA2", 2, 4, FormatType::UNORM, true, false, false, true},
{"PVRTC_RGB4", 2, 3, FormatType::UNORM, false, false, false, true},
{"PVRTC_RGBA4", 2, 4, FormatType::UNORM, true, false, false, true},
{"PVRTC2_2BPP", 2, 4, FormatType::UNORM, true, false, false, true},
{"PVRTC2_4BPP", 2, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_RGBA_4X4", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_RGBA_5X4", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_RGBA_5X5", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_RGBA_6X5", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_RGBA_6X6", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_RGBA_8X5", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_RGBA_8X6", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_RGBA_8X8", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_RGBA_10X5", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_RGBA_10X6", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_RGBA_10X8", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_RGBA_10X10", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_RGBA_12X10", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_RGBA_12X12", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_SRGBA_4X4", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_SRGBA_5X4", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_SRGBA_5X5", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_SRGBA_6X5", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_SRGBA_6X6", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_SRGBA_8X5", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_SRGBA_8X6", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_SRGBA_8X8", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_SRGBA_10X5", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_SRGBA_10X6", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_SRGBA_10X8", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_SRGBA_10X10", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_SRGBA_12X10", 1, 4, FormatType::UNORM, true, false, false, true},
{"ASTC_SRGBA_12X12", 1, 4, FormatType::UNORM, true, false, false, true},
};
bool isCombinedImageSampler(Type type) { return type >= Type::SAMPLER1D && type <= Type::SAMPLER_CUBE; }
bool isSampledImage(Type type) { return type >= Type::TEXTURE1D && type <= Type::TEXTURE_CUBE; }
bool isStorageImage(Type type) { return type >= Type::IMAGE1D && type <= Type::IMAGE_CUBE; }
uint32_t ceilDiv(uint32_t x, uint32_t y) { return (x - 1) / y + 1; }
uint32_t formatSize(Format format, uint32_t width, uint32_t height, uint32_t depth) {
if (!GFX_FORMAT_INFOS[static_cast<uint32_t>(format)].isCompressed) {
return (width * height * depth * GFX_FORMAT_INFOS[static_cast<uint32_t>(format)].size);
}
switch (format) {
case Format::BC1:
case Format::BC1_ALPHA:
case Format::BC1_SRGB:
case Format::BC1_SRGB_ALPHA:
return ceilDiv(width, 4) * ceilDiv(height, 4) * 8 * depth;
case Format::BC2:
case Format::BC2_SRGB:
case Format::BC3:
case Format::BC3_SRGB:
case Format::BC4:
case Format::BC4_SNORM:
case Format::BC6H_SF16:
case Format::BC6H_UF16:
case Format::BC7:
case Format::BC7_SRGB:
return ceilDiv(width, 4) * ceilDiv(height, 4) * 16 * depth;
case Format::BC5:
case Format::BC5_SNORM:
return ceilDiv(width, 4) * ceilDiv(height, 4) * 32 * depth;
case Format::ETC_RGB8:
case Format::ETC2_RGB8:
case Format::ETC2_SRGB8:
case Format::ETC2_RGB8_A1:
case Format::EAC_R11:
case Format::EAC_R11SN:
return ceilDiv(width, 4) * ceilDiv(height, 4) * 8 * depth;
case Format::ETC2_RGBA8:
case Format::ETC2_SRGB8_A1:
case Format::EAC_RG11:
case Format::EAC_RG11SN:
return ceilDiv(width, 4) * ceilDiv(height, 4) * 16 * depth;
case Format::PVRTC_RGB2:
case Format::PVRTC_RGBA2:
case Format::PVRTC2_2BPP:
return ceilDiv(width, 8) * ceilDiv(height, 4) * 8 * depth;
case Format::PVRTC_RGB4:
case Format::PVRTC_RGBA4:
case Format::PVRTC2_4BPP:
return ceilDiv(width, 4) * ceilDiv(height, 4) * 8 * depth;
case Format::ASTC_RGBA_4X4:
case Format::ASTC_SRGBA_4X4:
return ceilDiv(width, 4) * ceilDiv(height, 4) * 16 * depth;
case Format::ASTC_RGBA_5X4:
case Format::ASTC_SRGBA_5X4:
return ceilDiv(width, 5) * ceilDiv(height, 4) * 16 * depth;
case Format::ASTC_RGBA_5X5:
case Format::ASTC_SRGBA_5X5:
return ceilDiv(width, 5) * ceilDiv(height, 5) * 16 * depth;
case Format::ASTC_RGBA_6X5:
case Format::ASTC_SRGBA_6X5:
return ceilDiv(width, 6) * ceilDiv(height, 5) * 16 * depth;
case Format::ASTC_RGBA_6X6:
case Format::ASTC_SRGBA_6X6:
return ceilDiv(width, 6) * ceilDiv(height, 6) * 16 * depth;
case Format::ASTC_RGBA_8X5:
case Format::ASTC_SRGBA_8X5:
return ceilDiv(width, 8) * ceilDiv(height, 5) * 16 * depth;
case Format::ASTC_RGBA_8X6:
case Format::ASTC_SRGBA_8X6:
return ceilDiv(width, 8) * ceilDiv(height, 6) * 16 * depth;
case Format::ASTC_RGBA_8X8:
case Format::ASTC_SRGBA_8X8:
return ceilDiv(width, 8) * ceilDiv(height, 8) * 16 * depth;
case Format::ASTC_RGBA_10X5:
case Format::ASTC_SRGBA_10X5:
return ceilDiv(width, 10) * ceilDiv(height, 5) * 16 * depth;
case Format::ASTC_RGBA_10X6:
case Format::ASTC_SRGBA_10X6:
return ceilDiv(width, 10) * ceilDiv(height, 6) * 16 * depth;
case Format::ASTC_RGBA_10X8:
case Format::ASTC_SRGBA_10X8:
return ceilDiv(width, 10) * ceilDiv(height, 8) * 16 * depth;
case Format::ASTC_RGBA_10X10:
case Format::ASTC_SRGBA_10X10:
return ceilDiv(width, 10) * ceilDiv(height, 10) * 16 * depth;
case Format::ASTC_RGBA_12X10:
case Format::ASTC_SRGBA_12X10:
return ceilDiv(width, 12) * ceilDiv(height, 10) * 16 * depth;
case Format::ASTC_RGBA_12X12:
case Format::ASTC_SRGBA_12X12:
return ceilDiv(width, 12) * ceilDiv(height, 12) * 16 * depth;
default:
return 0;
}
}
std::pair<uint32_t, uint32_t> formatAlignment(Format format) {
switch (format) {
case Format::BC1:
case Format::BC1_ALPHA:
case Format::BC1_SRGB:
case Format::BC1_SRGB_ALPHA:
case Format::BC2:
case Format::BC2_SRGB:
case Format::BC3:
case Format::BC3_SRGB:
case Format::BC4:
case Format::BC4_SNORM:
case Format::BC6H_SF16:
case Format::BC6H_UF16:
case Format::BC7:
case Format::BC7_SRGB:
case Format::BC5:
case Format::BC5_SNORM:
case Format::ETC_RGB8:
case Format::ETC2_RGB8:
case Format::ETC2_SRGB8:
case Format::ETC2_RGB8_A1:
case Format::EAC_R11:
case Format::EAC_R11SN:
case Format::ETC2_RGBA8:
case Format::ETC2_SRGB8_A1:
case Format::EAC_RG11:
case Format::EAC_RG11SN:
return std::make_pair(4, 4);
case Format::PVRTC_RGB2:
case Format::PVRTC_RGBA2:
case Format::PVRTC2_2BPP:
return std::make_pair(8, 4);
case Format::PVRTC_RGB4:
case Format::PVRTC_RGBA4:
case Format::PVRTC2_4BPP:
return std::make_pair(4, 4);
case Format::ASTC_RGBA_4X4:
case Format::ASTC_SRGBA_4X4:
return std::make_pair(4, 4);
case Format::ASTC_RGBA_5X4:
case Format::ASTC_SRGBA_5X4:
return std::make_pair(5, 4);
case Format::ASTC_RGBA_5X5:
case Format::ASTC_SRGBA_5X5:
return std::make_pair(5, 5);
case Format::ASTC_RGBA_6X5:
case Format::ASTC_SRGBA_6X5:
return std::make_pair(6, 5);
case Format::ASTC_RGBA_6X6:
case Format::ASTC_SRGBA_6X6:
return std::make_pair(6, 6);
case Format::ASTC_RGBA_8X5:
case Format::ASTC_SRGBA_8X5:
return std::make_pair(8, 5);
case Format::ASTC_RGBA_8X6:
case Format::ASTC_SRGBA_8X6:
return std::make_pair(8, 6);
case Format::ASTC_RGBA_8X8:
case Format::ASTC_SRGBA_8X8:
return std::make_pair(8, 8);
case Format::ASTC_RGBA_10X5:
case Format::ASTC_SRGBA_10X5:
return std::make_pair(10, 5);
case Format::ASTC_RGBA_10X6:
case Format::ASTC_SRGBA_10X6:
return std::make_pair(10, 6);
case Format::ASTC_RGBA_10X8:
case Format::ASTC_SRGBA_10X8:
return std::make_pair(10, 8);
case Format::ASTC_RGBA_10X10:
case Format::ASTC_SRGBA_10X10:
return std::make_pair(10, 10);
case Format::ASTC_RGBA_12X10:
case Format::ASTC_SRGBA_12X10:
return std::make_pair(12, 10);
case Format::ASTC_RGBA_12X12:
case Format::ASTC_SRGBA_12X12:
return std::make_pair(12, 12);
default:
return std::make_pair(1, 1);
}
}
static constexpr ccstd::array<uint32_t, static_cast<size_t>(Type::COUNT)> GFX_TYPE_SIZES = {
0, // UNKNOWN
4, // BOOL
8, // BOOL2
12, // BOOL3
16, // BOOL4
4, // INT
8, // INT2
12, // INT3
16, // INT4
4, // UINT
8, // UINT2
12, // UINT3
16, // UINT4
4, // FLOAT
8, // FLOAT2
12, // FLOAT3
16, // FLOAT4
16, // MAT2
24, // MAT2X3
32, // MAT2X4
24, // MAT3X2
36, // MAT3
48, // MAT3X4
32, // MAT4X2
48, // MAT4X3
64, // MAT4
4, // SAMPLER1D
4, // SAMPLER1D_ARRAY
4, // SAMPLER2D
4, // SAMPLER2D_ARRAY
4, // SAMPLER3D
4, // SAMPLER_CUBE
};
/**
* @en Get the memory size of the specified type.
* @zh 得到 GFX 数据类型的大小。
* @param type The target type.
*/
uint32_t getTypeSize(Type type) {
if (type < Type::COUNT) {
return GFX_TYPE_SIZES[toNumber(type)];
}
return 0;
}
uint32_t formatSurfaceSize(Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t mips) {
uint32_t size = 0;
for (uint32_t i = 0; i < mips; ++i) {
size += formatSize(format, width, height, depth);
width = std::max(width >> 1, 1U);
height = std::max(height >> 1, 1U);
}
return size;
}
uint32_t gcd(uint32_t a, uint32_t b) {
while (b) {
uint32_t t = a % b;
a = b;
b = t;
}
return a;
}
uint32_t lcm(uint32_t a, uint32_t b) {
return a * b / gcd(a, b);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,150 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXDef-common.h"
#include "base/std/hash/hash.h"
namespace cc {
namespace gfx {
template <typename T, typename Enable = std::enable_if_t<std::is_class<T>::value>>
struct Hasher final {
// NOTE: ccstd::hash_t is a typedef of uint32_t now, sizeof(ccstd::hash_t) == sizeof(size_t) on 32 bits architecture device,
// sizeof(ccstd::hash_t) < sizeof(size_t) on 64 bits architecture device.
// STL containers like ccstd::unordered_map<K, V, Hasher> expects the custom Hasher function to return size_t.
// So it's safe to return ccstd::hash_t for operator() function now.
// If we need to define ccstd::hash_t to uint64_t someday, we must take care of the return value of operator(),
// it should be size_t and we need to convert hash value from uint64_t to uint32_t for 32 bit architecture device.
ccstd::hash_t operator()(const T &info) const;
};
// make this ccstd::hash compatible
template <typename T, typename Enable = std::enable_if_t<std::is_class<T>::value>>
ccstd::hash_t hash_value(const T &info) { return Hasher<T>()(info); } // NOLINT(readability-identifier-naming)
#define DEFINE_CMP_OP(type) \
bool operator==(const type &lhs, const type &rhs); \
inline bool operator!=(const type &lhs, const type &rhs) { return !(lhs == rhs); }
DEFINE_CMP_OP(DepthStencilAttachment)
DEFINE_CMP_OP(SubpassInfo)
DEFINE_CMP_OP(SubpassDependency)
DEFINE_CMP_OP(RenderPassInfo)
DEFINE_CMP_OP(FramebufferInfo)
DEFINE_CMP_OP(Viewport)
DEFINE_CMP_OP(Rect)
DEFINE_CMP_OP(Color)
DEFINE_CMP_OP(Offset)
DEFINE_CMP_OP(Extent)
DEFINE_CMP_OP(Size)
DEFINE_CMP_OP(TextureInfo)
DEFINE_CMP_OP(TextureViewInfo)
DEFINE_CMP_OP(BufferInfo)
DEFINE_CMP_OP(SamplerInfo)
DEFINE_CMP_OP(GeneralBarrierInfo)
DEFINE_CMP_OP(TextureBarrierInfo)
DEFINE_CMP_OP(BufferBarrierInfo)
#undef DEFINE_CMP_OP
class Executable {
public:
virtual ~Executable() = default;
virtual void execute() = 0;
};
template <typename ExecuteMethodType>
class CallbackExecutable final : public Executable {
public:
using ExecuteMethod = std::remove_reference_t<ExecuteMethodType>;
explicit CallbackExecutable(ExecuteMethod &execute) : Executable(), _execute(execute) {}
explicit CallbackExecutable(ExecuteMethod &&execute) : Executable(), _execute(execute) {}
void execute() override { _execute(); }
private:
ExecuteMethod _execute;
};
struct SwapchainTextureInfo final {
Swapchain *swapchain{nullptr};
Format format{Format::UNKNOWN};
uint32_t width{0};
uint32_t height{0};
};
constexpr TextureUsage TEXTURE_USAGE_TRANSIENT = static_cast<TextureUsage>(
static_cast<uint32_t>(TextureUsageBit::COLOR_ATTACHMENT) |
static_cast<uint32_t>(TextureUsageBit::DEPTH_STENCIL_ATTACHMENT) |
static_cast<uint32_t>(TextureUsageBit::INPUT_ATTACHMENT));
constexpr DescriptorType DESCRIPTOR_BUFFER_TYPE = static_cast<DescriptorType>(
static_cast<uint32_t>(DescriptorType::STORAGE_BUFFER) |
static_cast<uint32_t>(DescriptorType::DYNAMIC_STORAGE_BUFFER) |
static_cast<uint32_t>(DescriptorType::UNIFORM_BUFFER) |
static_cast<uint32_t>(DescriptorType::DYNAMIC_UNIFORM_BUFFER));
constexpr DescriptorType DESCRIPTOR_TEXTURE_TYPE = static_cast<DescriptorType>(
static_cast<uint32_t>(DescriptorType::SAMPLER_TEXTURE) |
static_cast<uint32_t>(DescriptorType::SAMPLER) |
static_cast<uint32_t>(DescriptorType::TEXTURE) |
static_cast<uint32_t>(DescriptorType::STORAGE_IMAGE) |
static_cast<uint32_t>(DescriptorType::INPUT_ATTACHMENT));
constexpr DescriptorType DESCRIPTOR_SAMPLER_TYPE = static_cast<DescriptorType>(
static_cast<uint32_t>(DescriptorType::SAMPLER_TEXTURE) |
static_cast<uint32_t>(DescriptorType::SAMPLER) |
static_cast<uint32_t>(DescriptorType::TEXTURE) |
static_cast<uint32_t>(DescriptorType::STORAGE_IMAGE) |
static_cast<uint32_t>(DescriptorType::INPUT_ATTACHMENT));
constexpr DescriptorType DESCRIPTOR_DYNAMIC_TYPE = static_cast<DescriptorType>(
static_cast<uint32_t>(DescriptorType::DYNAMIC_STORAGE_BUFFER) |
static_cast<uint32_t>(DescriptorType::DYNAMIC_UNIFORM_BUFFER));
extern const FormatInfo GFX_FORMAT_INFOS[];
std::pair<uint32_t, uint32_t> formatAlignment(Format format);
uint32_t formatSize(Format format, uint32_t width, uint32_t height, uint32_t depth);
uint32_t formatSurfaceSize(Format format, uint32_t width, uint32_t height, uint32_t depth, uint32_t mips);
/**
* @en Get the memory size of the specified type.
* @zh 得到 GFX 数据类型的大小。
* @param type The target type.
*/
uint32_t getTypeSize(gfx::Type type);
uint32_t gcd(uint32_t a, uint32_t b);
uint32_t lcm(uint32_t a, uint32_t b);
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,143 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXDescriptorSet.h"
#include "GFXBuffer.h"
#include "GFXDescriptorSetLayout.h"
#include "GFXObject.h"
#include "GFXTexture.h"
#include "states/GFXSampler.h"
namespace cc {
namespace gfx {
DescriptorSet::DescriptorSet()
: GFXObject(ObjectType::DESCRIPTOR_SET) {
}
DescriptorSet::~DescriptorSet() = default;
void DescriptorSet::initialize(const DescriptorSetInfo &info) {
CC_ASSERT(info.layout);
_layout = info.layout;
uint32_t descriptorCount = _layout->getDescriptorCount();
_buffers.resize(descriptorCount);
_textures.resize(descriptorCount);
_samplers.resize(descriptorCount);
doInit(info);
}
void DescriptorSet::destroy() {
doDestroy();
_layout = nullptr;
// have to clear these or else it might not be properly updated when reused
_buffers.clear();
_textures.clear();
_samplers.clear();
}
void DescriptorSet::bindBuffer(uint32_t binding, Buffer *buffer, uint32_t index) {
bindBuffer(binding, buffer, index, AccessFlagBit::NONE);
}
void DescriptorSet::bindTexture(uint32_t binding, Texture *texture, uint32_t index) {
bindTexture(binding, texture, index, AccessFlagBit::NONE);
}
void DescriptorSet::bindTexture(uint32_t binding, Texture *texture, uint32_t index, AccessFlags flags) {
const uint32_t descriptorIndex = _layout->getDescriptorIndices()[binding] + index;
const uint32_t newId = getObjectID(texture);
if (_textures[descriptorIndex].id != newId) {
_textures[descriptorIndex].ptr = texture;
_textures[descriptorIndex].id = newId;
_textures[descriptorIndex].flags = flags;
_isDirty = true;
}
}
void DescriptorSet::bindBuffer(uint32_t binding, Buffer *buffer, uint32_t index, AccessFlags flags) {
const uint32_t descriptorIndex = _layout->getDescriptorIndices()[binding] + index;
const uint32_t newId = getObjectID(buffer);
if (_buffers[descriptorIndex].id != newId) {
_buffers[descriptorIndex].ptr = buffer;
_buffers[descriptorIndex].id = newId;
_buffers[descriptorIndex].flags = flags;
_isDirty = true;
}
}
void DescriptorSet::bindSampler(uint32_t binding, Sampler *sampler, uint32_t index) {
const uint32_t descriptorIndex = _layout->getDescriptorIndices()[binding] + index;
const uint32_t newId = getObjectID(sampler);
if (_samplers[descriptorIndex].id != newId) {
_samplers[descriptorIndex].ptr = sampler;
_samplers[descriptorIndex].id = newId;
_isDirty = true;
}
}
bool DescriptorSet::bindBufferJSB(uint32_t binding, Buffer *buffer, uint32_t index) {
bindBuffer(binding, buffer, index);
return _isDirty;
}
bool DescriptorSet::bindTextureJSB(uint32_t binding, Texture *texture, uint32_t index, AccessFlags flags) {
bindTexture(binding, texture, index, flags);
return _isDirty;
}
bool DescriptorSet::bindSamplerJSB(uint32_t binding, Sampler *sampler, uint32_t index) {
bindSampler(binding, sampler, index);
return _isDirty;
}
Buffer *DescriptorSet::getBuffer(uint32_t binding, uint32_t index) const {
const ccstd::vector<uint32_t> &descriptorIndices = _layout->getDescriptorIndices();
if (binding >= descriptorIndices.size()) return nullptr;
const uint32_t descriptorIndex = descriptorIndices[binding] + index;
if (descriptorIndex >= _buffers.size()) return nullptr;
return _buffers[descriptorIndex].ptr;
}
Texture *DescriptorSet::getTexture(uint32_t binding, uint32_t index) const {
const ccstd::vector<uint32_t> &descriptorIndices = _layout->getDescriptorIndices();
if (binding >= descriptorIndices.size()) return nullptr;
const uint32_t descriptorIndex = descriptorIndices[binding] + index;
if (descriptorIndex >= _textures.size()) return nullptr;
return _textures[descriptorIndex].ptr;
}
Sampler *DescriptorSet::getSampler(uint32_t binding, uint32_t index) const {
const ccstd::vector<uint32_t> &descriptorIndices = _layout->getDescriptorIndices();
if (binding >= descriptorIndices.size()) return nullptr;
const uint32_t descriptorIndex = descriptorIndices[binding] + index;
if (descriptorIndex >= _samplers.size()) return nullptr;
return _samplers[descriptorIndex].ptr;
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,89 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXObject.h"
#include "base/RefCounted.h"
namespace cc {
namespace gfx {
class CC_DLL DescriptorSet : public GFXObject, public RefCounted {
public:
DescriptorSet();
~DescriptorSet() override;
void initialize(const DescriptorSetInfo &info);
void destroy();
virtual void update() = 0;
virtual void forceUpdate() = 0;
virtual void bindBuffer(uint32_t binding, Buffer *buffer, uint32_t index, AccessFlags flags);
virtual void bindSampler(uint32_t binding, Sampler *sampler, uint32_t index);
virtual void bindTexture(uint32_t binding, Texture *texture, uint32_t index, AccessFlags flags);
void bindBuffer(uint32_t binding, Buffer *buffer, uint32_t index);
void bindTexture(uint32_t binding, Texture *texture, uint32_t index);
// Functions invoked by JSB adapter
bool bindBufferJSB(uint32_t binding, Buffer *buffer, uint32_t index);
bool bindTextureJSB(uint32_t binding, Texture *texture, uint32_t index, AccessFlags flags);
bool bindSamplerJSB(uint32_t binding, Sampler *sampler, uint32_t index);
Buffer *getBuffer(uint32_t binding, uint32_t index) const;
Texture *getTexture(uint32_t binding, uint32_t index) const;
Sampler *getSampler(uint32_t binding, uint32_t index) const;
inline const DescriptorSetLayout *getLayout() const { return _layout; }
inline void bindBuffer(uint32_t binding, Buffer *buffer) { bindBuffer(binding, buffer, 0U); }
inline void bindTexture(uint32_t binding, Texture *texture) { bindTexture(binding, texture, 0U); }
inline void bindSampler(uint32_t binding, Sampler *sampler) { bindSampler(binding, sampler, 0U); }
inline Buffer *getBuffer(uint32_t binding) const { return getBuffer(binding, 0U); }
inline Texture *getTexture(uint32_t binding) const { return getTexture(binding, 0U); }
inline Sampler *getSampler(uint32_t binding) const { return getSampler(binding, 0U); }
protected:
virtual void doInit(const DescriptorSetInfo &info) = 0;
virtual void doDestroy() = 0;
template <typename T>
struct ObjectWithId {
T *ptr = nullptr;
uint32_t id = INVALID_OBJECT_ID;
AccessFlags flags = AccessFlagBit::NONE;
};
const DescriptorSetLayout *_layout = nullptr;
ccstd::vector<ObjectWithId<Buffer>> _buffers;
ccstd::vector<ObjectWithId<Texture>> _textures;
ccstd::vector<ObjectWithId<Sampler>> _samplers;
bool _isDirty = false;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,81 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXObject.h"
#include "base/Utils.h"
#include "GFXDescriptorSetLayout.h"
namespace cc {
namespace gfx {
DescriptorSetLayout::DescriptorSetLayout()
: GFXObject(ObjectType::DESCRIPTOR_SET_LAYOUT) {
}
DescriptorSetLayout::~DescriptorSetLayout() = default;
void DescriptorSetLayout::initialize(const DescriptorSetLayoutInfo &info) {
_bindings = info.bindings;
auto bindingCount = utils::toUint(_bindings.size());
_descriptorCount = 0U;
if (bindingCount) {
uint32_t maxBinding = 0U;
ccstd::vector<uint32_t> flattenedIndices(bindingCount);
for (uint32_t i = 0U; i < bindingCount; i++) {
const DescriptorSetLayoutBinding &binding = _bindings[i];
if (binding.binding > maxBinding) maxBinding = binding.binding;
flattenedIndices[i] = _descriptorCount;
_descriptorCount += binding.count;
}
_bindingIndices.resize(maxBinding + 1, INVALID_BINDING);
_descriptorIndices.resize(maxBinding + 1, INVALID_BINDING);
for (uint32_t i = 0U; i < bindingCount; i++) {
const DescriptorSetLayoutBinding &binding = _bindings[i];
_bindingIndices[binding.binding] = i;
_descriptorIndices[binding.binding] = flattenedIndices[i];
if (hasFlag(DESCRIPTOR_DYNAMIC_TYPE, binding.descriptorType)) {
for (uint32_t j = 0U; j < binding.count; ++j) {
_dynamicBindings.push_back(binding.binding);
}
}
}
}
doInit(info);
}
void DescriptorSetLayout::destroy() {
doDestroy();
_bindings.clear();
_descriptorCount = 0U;
_bindingIndices.clear();
_descriptorIndices.clear();
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,59 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXObject.h"
#include "base/RefCounted.h"
namespace cc {
namespace gfx {
class CC_DLL DescriptorSetLayout : public GFXObject, public RefCounted {
public:
DescriptorSetLayout();
~DescriptorSetLayout() override;
void initialize(const DescriptorSetLayoutInfo &info);
void destroy();
inline const DescriptorSetLayoutBindingList &getBindings() const { return _bindings; }
inline const ccstd::vector<uint32_t> &getDynamicBindings() const { return _dynamicBindings; }
inline const ccstd::vector<uint32_t> &getBindingIndices() const { return _bindingIndices; }
inline const ccstd::vector<uint32_t> &getDescriptorIndices() const { return _descriptorIndices; }
inline uint32_t getDescriptorCount() const { return _descriptorCount; }
protected:
virtual void doInit(const DescriptorSetLayoutInfo &info) = 0;
virtual void doDestroy() = 0;
DescriptorSetLayoutBindingList _bindings;
uint32_t _descriptorCount = 0U;
ccstd::vector<uint32_t> _bindingIndices;
ccstd::vector<uint32_t> _descriptorIndices;
ccstd::vector<uint32_t> _dynamicBindings;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,200 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXDevice.h"
#include "GFXObject.h"
#include "base/memory/Memory.h"
#include "platform/BasePlatform.h"
#include "platform/interfaces/modules/ISystemWindow.h"
#include "platform/interfaces/modules/ISystemWindowManager.h"
namespace cc {
namespace gfx {
Device *Device::instance = nullptr;
bool Device::isSupportDetachDeviceThread = true;
Device *Device::getInstance() {
return Device::instance;
}
Device::Device() {
Device::instance = this;
// Device instance is created and hold by TS. Native should hold it too
// to make sure it exists after JavaScript virtual machine is destroyed.
// Then will destroy the Device instance in native.
addRef();
_features.fill(false);
_formatFeatures.fill(FormatFeature::NONE);
}
Device::~Device() {
Device::instance = nullptr;
CC_SAFE_RELEASE(_cmdBuff);
CC_SAFE_RELEASE(_queue);
}
bool Device::initialize(const DeviceInfo &info) {
_bindingMappingInfo = info.bindingMappingInfo;
#if CC_CPU_ARCH == CC_CPU_ARCH_32
static_assert(sizeof(void *) == 4, "pointer size assumption broken");
#else
static_assert(sizeof(void *) == 8, "pointer size assumption broken");
#endif
bool result = doInit(info);
CC_SAFE_ADD_REF(_cmdBuff);
CC_SAFE_ADD_REF(_queue);
return result;
}
void Device::destroy() {
for (auto pair : _samplers) {
CC_SAFE_DELETE(pair.second);
}
_samplers.clear();
for (auto pair : _generalBarriers) {
CC_SAFE_DELETE(pair.second);
}
_generalBarriers.clear();
for (auto pair : _textureBarriers) {
CC_SAFE_DELETE(pair.second);
}
_textureBarriers.clear();
for (auto pair : _bufferBarriers) {
CC_SAFE_DELETE(pair.second);
}
_bufferBarriers.clear();
doDestroy();
CC_SAFE_DELETE(_onAcquire);
}
Sampler *Device::getSampler(const SamplerInfo &info) {
if (!_samplers.count(info)) {
_samplers[info] = createSampler(info);
}
return _samplers[info];
}
GeneralBarrier *Device::getGeneralBarrier(const GeneralBarrierInfo &info) {
if (!_generalBarriers.count(info)) {
_generalBarriers[info] = createGeneralBarrier(info);
}
return _generalBarriers[info];
}
TextureBarrier *Device::getTextureBarrier(const TextureBarrierInfo &info) {
if (!_textureBarriers.count(info)) {
_textureBarriers[info] = createTextureBarrier(info);
}
return _textureBarriers[info];
}
BufferBarrier *Device::getBufferBarrier(const BufferBarrierInfo &info) {
if (!_bufferBarriers.count(info)) {
_bufferBarriers[info] = createBufferBarrier(info);
}
return _bufferBarriers[info];
}
DefaultResource::DefaultResource(Device *device) {
uint32_t bufferSize = 64;
ccstd::vector<uint8_t> buffer(bufferSize, 255);
const uint8_t *bufferData = buffer.data();
if (device->getCapabilities().maxTextureSize >= 2) {
_texture2D = device->createTexture({TextureType::TEX2D, TextureUsageBit::STORAGE | TextureUsageBit::SAMPLED | TextureUsageBit::TRANSFER_DST,
Format::RGBA8, 2, 2, TextureFlagBit::NONE});
BufferTextureCopy region = {0, 0, 0, {0, 0, 0}, {2, 2, 1}, {0, 0, 1}};
device->copyBuffersToTexture(&bufferData, _texture2D, &region, 1);
}
if (device->getCapabilities().maxTextureSize >= 2) {
_textureCube = device->createTexture({TextureType::CUBE, TextureUsageBit::STORAGE | TextureUsageBit::SAMPLED | TextureUsageBit::TRANSFER_DST,
Format::RGBA8, 2, 2, TextureFlagBit::NONE, 6});
BufferTextureCopy region = {0, 0, 0, {0, 0, 0}, {2, 2, 1}, {0, 0, 1}};
device->copyBuffersToTexture(&bufferData, _textureCube, &region, 1);
region.texSubres.baseArrayLayer = 1;
device->copyBuffersToTexture(&bufferData, _textureCube, &region, 1);
region.texSubres.baseArrayLayer = 2;
device->copyBuffersToTexture(&bufferData, _textureCube, &region, 1);
region.texSubres.baseArrayLayer = 3;
device->copyBuffersToTexture(&bufferData, _textureCube, &region, 1);
region.texSubres.baseArrayLayer = 4;
device->copyBuffersToTexture(&bufferData, _textureCube, &region, 1);
region.texSubres.baseArrayLayer = 5;
device->copyBuffersToTexture(&bufferData, _textureCube, &region, 1);
}
if (device->getCapabilities().max3DTextureSize >= 2) {
_texture3D = device->createTexture({TextureType::TEX3D, TextureUsageBit::STORAGE | TextureUsageBit::SAMPLED | TextureUsageBit::TRANSFER_DST,
Format::RGBA8, 2, 2, TextureFlagBit::NONE, 1, 1, SampleCount::X1, 2});
BufferTextureCopy region = {0, 0, 0, {0, 0, 0}, {2, 2, 2}, {0, 0, 1}};
device->copyBuffersToTexture(&bufferData, _texture3D, &region, 1);
}
if (device->getCapabilities().maxArrayTextureLayers >= 2) {
_texture2DArray = device->createTexture({TextureType::TEX2D_ARRAY, TextureUsageBit::STORAGE | TextureUsageBit::SAMPLED | TextureUsageBit::TRANSFER_DST,
Format::RGBA8, 2, 2, TextureFlagBit::NONE, 2});
BufferTextureCopy region = {0, 0, 0, {0, 0, 0}, {2, 2, 1}, {0, 0, 1}};
device->copyBuffersToTexture(&bufferData, _texture2DArray, &region, 1);
region.texSubres.baseArrayLayer = 1;
device->copyBuffersToTexture(&bufferData, _texture2DArray, &region, 1);
}
{
BufferInfo bufferInfo = {};
bufferInfo.usage = BufferUsageBit::STORAGE | BufferUsageBit::TRANSFER_DST | BufferUsageBit::TRANSFER_SRC | BufferUsageBit::VERTEX | BufferUsageBit::INDEX | BufferUsageBit::INDIRECT;
bufferInfo.memUsage = MemoryUsageBit::DEVICE | MemoryUsageBit::HOST;
bufferInfo.size = 5 * sizeof(uint32_t); // for indirect command buffer
bufferInfo.stride = bufferInfo.size;
_buffer = device->createBuffer(bufferInfo);
}
}
Texture *DefaultResource::getTexture(TextureType type) const {
switch (type) {
case TextureType::TEX2D:
return _texture2D;
case TextureType::CUBE:
return _textureCube;
case TextureType::TEX3D:
return _texture3D;
case TextureType::TEX2D_ARRAY:
return _texture2DArray;
default:
CC_ABORT();
return nullptr;
}
}
Buffer *DefaultResource::getBuffer() const {
return _buffer;
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,339 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXBuffer.h"
#include "GFXCommandBuffer.h"
#include "GFXDescriptorSet.h"
#include "GFXDescriptorSetLayout.h"
#include "GFXFramebuffer.h"
#include "GFXInputAssembler.h"
#include "GFXObject.h"
#include "GFXPipelineLayout.h"
#include "GFXPipelineState.h"
#include "GFXQueryPool.h"
#include "GFXQueue.h"
#include "GFXRenderPass.h"
#include "GFXShader.h"
#include "GFXSwapchain.h"
#include "GFXTexture.h"
#include "base/RefCounted.h"
#include "base/std/container/array.h"
#include "states/GFXBufferBarrier.h"
#include "states/GFXGeneralBarrier.h"
#include "states/GFXSampler.h"
#include "states/GFXTextureBarrier.h"
namespace cc {
namespace gfx {
class CC_DLL Device : public RefCounted {
public:
static Device *getInstance();
~Device() override;
bool initialize(const DeviceInfo &info);
void destroy();
// aim to ensure waiting for work on gpu done when cpu encodes ahead of gpu certain frame(s).
virtual void frameSync() = 0;
virtual void acquire(Swapchain *const *swapchains, uint32_t count) = 0;
virtual void present() = 0;
virtual void flushCommands(CommandBuffer *const *cmdBuffs, uint32_t count) {}
virtual MemoryStatus &getMemoryStatus() { return _memoryStatus; }
virtual uint32_t getNumDrawCalls() const { return _numDrawCalls; }
virtual uint32_t getNumInstances() const { return _numInstances; }
virtual uint32_t getNumTris() const { return _numTriangles; }
inline CommandBuffer *createCommandBuffer(const CommandBufferInfo &info);
inline Queue *createQueue(const QueueInfo &info);
inline QueryPool *createQueryPool(const QueryPoolInfo &info);
inline Swapchain *createSwapchain(const SwapchainInfo &info);
inline const ccstd::vector<Swapchain *> &getSwapchains() const { return _swapchains; }
inline Buffer *createBuffer(const BufferInfo &info);
inline Buffer *createBuffer(const BufferViewInfo &info);
inline Texture *createTexture(const TextureInfo &info);
inline Texture *createTexture(const TextureViewInfo &info);
inline Shader *createShader(const ShaderInfo &info);
inline InputAssembler *createInputAssembler(const InputAssemblerInfo &info);
inline RenderPass *createRenderPass(const RenderPassInfo &info);
inline Framebuffer *createFramebuffer(const FramebufferInfo &info);
inline DescriptorSet *createDescriptorSet(const DescriptorSetInfo &info);
inline DescriptorSetLayout *createDescriptorSetLayout(const DescriptorSetLayoutInfo &info);
inline PipelineLayout *createPipelineLayout(const PipelineLayoutInfo &info);
inline PipelineState *createPipelineState(const PipelineStateInfo &info);
virtual Sampler *getSampler(const SamplerInfo &info);
virtual GeneralBarrier *getGeneralBarrier(const GeneralBarrierInfo &info);
virtual TextureBarrier *getTextureBarrier(const TextureBarrierInfo &info);
virtual BufferBarrier *getBufferBarrier(const BufferBarrierInfo &info);
virtual void copyBuffersToTexture(const uint8_t *const *buffers, Texture *dst, const BufferTextureCopy *regions, uint32_t count) = 0;
virtual void copyTextureToBuffers(Texture *src, uint8_t *const *buffers, const BufferTextureCopy *region, uint32_t count) = 0;
virtual void getQueryPoolResults(QueryPool *queryPool) = 0;
inline void copyTextureToBuffers(Texture *src, BufferSrcList &buffers, const BufferTextureCopyList &regions);
inline void copyBuffersToTexture(const BufferDataList &buffers, Texture *dst, const BufferTextureCopyList &regions);
inline void flushCommands(const ccstd::vector<CommandBuffer *> &cmdBuffs);
inline void acquire(const ccstd::vector<Swapchain *> &swapchains);
inline Queue *getQueue() const { return _queue; }
inline QueryPool *getQueryPool() const { return _queryPool; }
inline CommandBuffer *getCommandBuffer() const { return _cmdBuff; }
inline const DeviceCaps &getCapabilities() const { return _caps; }
inline API getGfxAPI() const { return _api; }
inline const ccstd::string &getDeviceName() const { return _deviceName; }
inline const ccstd::string &getRenderer() const { return _renderer; }
inline const ccstd::string &getVendor() const { return _vendor; }
inline bool hasFeature(Feature feature) const { return _features[toNumber(feature)]; }
inline FormatFeature getFormatFeatures(Format format) const { return _formatFeatures[toNumber(format)]; }
inline const BindingMappingInfo &bindingMappingInfo() const { return _bindingMappingInfo; }
// for external update operations which has to be performed on the device thread.
// AR camera texture update, etc.
template <typename ExecuteMethod>
void registerOnAcquireCallback(ExecuteMethod &&execute);
virtual void enableAutoBarrier(bool en) { _options.enableBarrierDeduce = en; }
virtual SampleCount getMaxSampleCount(Format format, TextureUsage usage, TextureFlags flags) const {
std::ignore = format;
std::ignore = usage;
std::ignore = flags;
return SampleCount::X1;
};
protected:
static Device *instance;
static bool isSupportDetachDeviceThread;
friend class DeviceAgent;
friend class DeviceValidator;
friend class DeviceManager;
Device();
virtual bool doInit(const DeviceInfo &info) = 0;
virtual void doDestroy() = 0;
virtual CommandBuffer *createCommandBuffer(const CommandBufferInfo &info, bool hasAgent) = 0;
virtual Queue *createQueue() = 0;
virtual QueryPool *createQueryPool() = 0;
virtual Swapchain *createSwapchain() = 0;
virtual Buffer *createBuffer() = 0;
virtual Texture *createTexture() = 0;
virtual Shader *createShader() = 0;
virtual InputAssembler *createInputAssembler() = 0;
virtual RenderPass *createRenderPass() = 0;
virtual Framebuffer *createFramebuffer() = 0;
virtual DescriptorSet *createDescriptorSet() = 0;
virtual DescriptorSetLayout *createDescriptorSetLayout() = 0;
virtual PipelineLayout *createPipelineLayout() = 0;
virtual PipelineState *createPipelineState() = 0;
virtual Sampler *createSampler(const SamplerInfo &info) { return ccnew Sampler(info); }
virtual GeneralBarrier *createGeneralBarrier(const GeneralBarrierInfo &info) { return ccnew GeneralBarrier(info); }
virtual TextureBarrier *createTextureBarrier(const TextureBarrierInfo &info) { return ccnew TextureBarrier(info); }
virtual BufferBarrier *createBufferBarrier(const BufferBarrierInfo &info) { return ccnew BufferBarrier(info); }
// For context switching between threads
virtual void bindContext(bool bound) {}
ccstd::string _deviceName;
ccstd::string _renderer;
ccstd::string _vendor;
ccstd::string _version;
API _api{API::UNKNOWN};
DeviceCaps _caps;
BindingMappingInfo _bindingMappingInfo;
DeviceOptions _options;
bool _multithreadedCommandRecording{true};
ccstd::array<bool, static_cast<size_t>(Feature::COUNT)> _features;
ccstd::array<FormatFeature, static_cast<size_t>(Format::COUNT)> _formatFeatures;
Queue *_queue{nullptr};
QueryPool *_queryPool{nullptr};
CommandBuffer *_cmdBuff{nullptr};
Executable *_onAcquire{nullptr};
uint32_t _numDrawCalls{0U};
uint32_t _numInstances{0U};
uint32_t _numTriangles{0U};
MemoryStatus _memoryStatus;
ccstd::unordered_map<SamplerInfo, Sampler *, Hasher<SamplerInfo>> _samplers;
ccstd::unordered_map<GeneralBarrierInfo, GeneralBarrier *, Hasher<GeneralBarrierInfo>> _generalBarriers;
ccstd::unordered_map<TextureBarrierInfo, TextureBarrier *, Hasher<TextureBarrierInfo>> _textureBarriers;
ccstd::unordered_map<BufferBarrierInfo, BufferBarrier *, Hasher<BufferBarrierInfo>> _bufferBarriers;
private:
ccstd::vector<Swapchain *> _swapchains; // weak reference
};
class DefaultResource {
public:
explicit DefaultResource(Device *device);
~DefaultResource() = default;
Texture *getTexture(TextureType type) const;
Buffer *getBuffer() const;
private:
IntrusivePtr<Texture> _texture2D;
IntrusivePtr<Texture> _texture2DArray;
IntrusivePtr<Texture> _textureCube;
IntrusivePtr<Texture> _texture3D;
IntrusivePtr<Buffer> _buffer;
};
//////////////////////////////////////////////////////////////////////////
CommandBuffer *Device::createCommandBuffer(const CommandBufferInfo &info) {
CommandBuffer *res = createCommandBuffer(info, false);
res->initialize(info);
return res;
}
Queue *Device::createQueue(const QueueInfo &info) {
Queue *res = createQueue();
res->initialize(info);
return res;
}
QueryPool *Device::createQueryPool(const QueryPoolInfo &info) {
QueryPool *res = createQueryPool();
res->initialize(info);
return res;
}
Swapchain *Device::createSwapchain(const SwapchainInfo &info) {
Swapchain *res = createSwapchain();
res->initialize(info);
_swapchains.push_back(res);
return res;
}
Buffer *Device::createBuffer(const BufferInfo &info) {
Buffer *res = createBuffer();
res->initialize(info);
return res;
}
Buffer *Device::createBuffer(const BufferViewInfo &info) {
Buffer *res = createBuffer();
res->initialize(info);
return res;
}
Texture *Device::createTexture(const TextureInfo &info) {
Texture *res = createTexture();
res->initialize(info);
return res;
}
Texture *Device::createTexture(const TextureViewInfo &info) {
Texture *res = createTexture();
res->initialize(info);
return res;
}
Shader *Device::createShader(const ShaderInfo &info) {
Shader *res = createShader();
res->initialize(info);
return res;
}
InputAssembler *Device::createInputAssembler(const InputAssemblerInfo &info) {
InputAssembler *res = createInputAssembler();
res->initialize(info);
return res;
}
RenderPass *Device::createRenderPass(const RenderPassInfo &info) {
RenderPass *res = createRenderPass();
res->initialize(info);
return res;
}
Framebuffer *Device::createFramebuffer(const FramebufferInfo &info) {
Framebuffer *res = createFramebuffer();
res->initialize(info);
return res;
}
DescriptorSet *Device::createDescriptorSet(const DescriptorSetInfo &info) {
DescriptorSet *res = createDescriptorSet();
res->initialize(info);
return res;
}
DescriptorSetLayout *Device::createDescriptorSetLayout(const DescriptorSetLayoutInfo &info) {
DescriptorSetLayout *res = createDescriptorSetLayout();
res->initialize(info);
return res;
}
PipelineLayout *Device::createPipelineLayout(const PipelineLayoutInfo &info) {
PipelineLayout *res = createPipelineLayout();
res->initialize(info);
return res;
}
PipelineState *Device::createPipelineState(const PipelineStateInfo &info) {
PipelineState *res = createPipelineState();
res->initialize(info);
return res;
}
void Device::copyBuffersToTexture(const BufferDataList &buffers, Texture *dst, const BufferTextureCopyList &regions) {
copyBuffersToTexture(buffers.data(), dst, regions.data(), utils::toUint(regions.size()));
}
void Device::copyTextureToBuffers(Texture *src, BufferSrcList &buffers, const BufferTextureCopyList &regions) {
copyTextureToBuffers(src, buffers.data(), regions.data(), utils::toUint(regions.size()));
}
void Device::flushCommands(const ccstd::vector<CommandBuffer *> &cmdBuffs) {
flushCommands(cmdBuffs.data(), utils::toUint(cmdBuffs.size()));
}
void Device::acquire(const ccstd::vector<Swapchain *> &swapchains) {
acquire(swapchains.data(), utils::toUint(swapchains.size()));
}
template <typename ExecuteMethod>
void Device::registerOnAcquireCallback(ExecuteMethod &&execute) {
_onAcquire = ccnew CallbackExecutable<ExecuteMethod>(std::forward<ExecuteMethod>(execute));
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,71 @@
/****************************************************************************
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 <atomic>
#include "base/Macros.h"
#include "base/Ptr.h"
namespace cc {
namespace gfx {
struct DefaultDeleter {
template <typename T>
void operator()(T *ptr) const {
delete ptr;
}
};
template <typename Deleter = DefaultDeleter>
class GFXDeviceObject {
public:
virtual ~GFXDeviceObject() noexcept = default;
void addRef() const noexcept {
++_referenceCount;
}
void release() const noexcept {
// atomic::operator _Ty uses load(memory_order_seq_cst), all threads observe all modifications in the same order.
auto count = static_cast<int32_t>(--_referenceCount);
CC_ASSERT_GE(count, 0);
if (count == 0) {
Deleter()(this);
}
}
uint32_t getRefCount() const noexcept {
return static_cast<uint32_t>(_referenceCount);
}
protected:
GFXDeviceObject() noexcept = default;
mutable std::atomic_uint32_t _referenceCount{0};
};
template <typename T>
using ConstPtr = IntrusivePtr<const T>;
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,62 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXFramebuffer.h"
#include "GFXRenderPass.h"
#include "GFXTexture.h"
#include "base/Utils.h"
namespace cc {
namespace gfx {
Framebuffer::Framebuffer()
: GFXObject(ObjectType::FRAMEBUFFER) {
}
Framebuffer::~Framebuffer() = default;
ccstd::hash_t Framebuffer::computeHash(const FramebufferInfo &info) {
return Hasher<FramebufferInfo>()(info);
}
void Framebuffer::initialize(const FramebufferInfo &info) {
_renderPass = info.renderPass;
_colorTextures = info.colorTextures;
_depthStencilTexture = info.depthStencilTexture;
_depthStencilResolveTexture = info.depthStencilResolveTexture;
doInit(info);
}
void Framebuffer::destroy() {
doDestroy();
_renderPass = nullptr;
_colorTextures.clear();
_depthStencilTexture = nullptr;
_depthStencilResolveTexture = nullptr;
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,64 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXObject.h"
#include "base/Ptr.h"
#include "base/RefCounted.h"
#include "base/RefVector.h"
namespace cc {
namespace gfx {
class CC_DLL Framebuffer : public GFXObject, public RefCounted {
public:
Framebuffer();
~Framebuffer() override;
static ccstd::hash_t computeHash(const FramebufferInfo &info);
void initialize(const FramebufferInfo &info);
void destroy();
inline RenderPass *getRenderPass() const { return _renderPass; }
inline const TextureList &getColorTextures() const { return _colorTextures; }
inline Texture *getDepthStencilTexture() const { return _depthStencilTexture; }
inline Texture *getDepthStencilResolveTexture() const { return _depthStencilResolveTexture; }
protected:
virtual void doInit(const FramebufferInfo &info) = 0;
virtual void doDestroy() = 0;
// weak reference
RenderPass *_renderPass{nullptr};
// weak reference
TextureList _colorTextures;
// weak reference
Texture *_depthStencilTexture{nullptr};
Texture *_depthStencilResolveTexture{nullptr};
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,86 @@
/****************************************************************************
Copyright (c) 2019-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/hash/hash.h"
#include "GFXBuffer.h"
#include "GFXInputAssembler.h"
#include "GFXObject.h"
namespace cc {
namespace gfx {
InputAssembler::InputAssembler()
: GFXObject(ObjectType::INPUT_ASSEMBLER) {
}
InputAssembler::~InputAssembler() = default;
ccstd::hash_t InputAssembler::computeAttributesHash() const {
ccstd::hash_t seed = static_cast<uint32_t>(_attributes.size()) * 6;
for (const auto &attribute : _attributes) {
ccstd::hash_combine(seed, attribute.name);
ccstd::hash_combine(seed, attribute.format);
ccstd::hash_combine(seed, attribute.isNormalized);
ccstd::hash_combine(seed, attribute.stream);
ccstd::hash_combine(seed, attribute.isInstanced);
ccstd::hash_combine(seed, attribute.location);
}
return seed;
}
void InputAssembler::initialize(const InputAssemblerInfo &info) {
_attributes = info.attributes;
_vertexBuffers = info.vertexBuffers;
_indexBuffer = info.indexBuffer;
_indirectBuffer = info.indirectBuffer;
_attributesHash = computeAttributesHash();
if (_indexBuffer) {
_drawInfo.indexCount = _indexBuffer->getCount();
_drawInfo.firstIndex = 0;
} else if (!_vertexBuffers.empty()) {
_drawInfo.vertexCount = _vertexBuffers[0]->getCount();
_drawInfo.firstVertex = 0;
_drawInfo.vertexOffset = 0;
}
doInit(info);
}
void InputAssembler::destroy() {
doDestroy();
_attributes.clear();
_attributesHash = 0U;
_vertexBuffers.clear();
_indexBuffer = nullptr;
_indirectBuffer = nullptr;
_drawInfo = DrawInfo();
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,83 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXObject.h"
#include "base/RefCounted.h"
namespace cc {
namespace gfx {
class CC_DLL InputAssembler : public GFXObject, public RefCounted {
public:
InputAssembler();
~InputAssembler() override;
void initialize(const InputAssemblerInfo &info);
void destroy();
inline const AttributeList &getAttributes() const { return _attributes; }
inline const BufferList &getVertexBuffers() const { return _vertexBuffers; }
inline Buffer *getIndexBuffer() const { return _indexBuffer; }
inline Buffer *getIndirectBuffer() const { return _indirectBuffer; }
inline ccstd::hash_t getAttributesHash() const { return _attributesHash; }
inline const DrawInfo &getDrawInfo() const { return _drawInfo; }
inline void setDrawInfo(const DrawInfo &info) { _drawInfo = info; }
inline void setVertexCount(uint32_t count) { _drawInfo.vertexCount = count; }
inline void setFirstVertex(uint32_t first) { _drawInfo.firstVertex = first; }
inline void setIndexCount(uint32_t count) { _drawInfo.indexCount = count; }
inline void setFirstIndex(uint32_t first) { _drawInfo.firstIndex = first; }
inline void setVertexOffset(int32_t offset) { _drawInfo.vertexOffset = offset; }
inline void setInstanceCount(uint32_t count) { _drawInfo.instanceCount = count; }
inline void setFirstInstance(uint32_t first) { _drawInfo.firstInstance = first; }
inline uint32_t getVertexCount() const { return _drawInfo.vertexCount; }
inline uint32_t getFirstVertex() const { return _drawInfo.firstVertex; }
inline uint32_t getIndexCount() const { return _drawInfo.indexCount; }
inline uint32_t getFirstIndex() const { return _drawInfo.firstIndex; }
inline uint32_t getVertexOffset() const { return _drawInfo.vertexOffset; }
inline uint32_t getInstanceCount() const { return _drawInfo.instanceCount; }
inline uint32_t getFirstInstance() const { return _drawInfo.firstInstance; }
protected:
virtual void doInit(const InputAssemblerInfo &info) = 0;
virtual void doDestroy() = 0;
ccstd::hash_t computeAttributesHash() const;
AttributeList _attributes;
ccstd::hash_t _attributesHash = 0;
BufferList _vertexBuffers;
Buffer *_indexBuffer{nullptr};
Buffer *_indirectBuffer{nullptr};
DrawInfo _drawInfo;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,35 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXObject.h"
namespace cc {
namespace gfx {
GFXObject::GFXObject(ObjectType type)
: _objectType(type),
_objectID(generateObjectID<GFXObject>()) {}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,59 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXDef.h"
namespace cc {
namespace gfx {
class GFXObject {
public:
explicit GFXObject(ObjectType type);
virtual ~GFXObject() = default;
inline ObjectType getObjectType() const { return _objectType; }
inline uint32_t getObjectID() const { return _objectID; }
inline uint32_t getTypedID() const { return _typedID; }
inline static uint32_t getObjectID(const GFXObject *obj) {
return obj == nullptr ? INVALID_OBJECT_ID : obj->getObjectID();
}
protected:
template <typename T>
static uint32_t generateObjectID() noexcept {
static uint32_t generator = 1 << 16;
return ++generator;
}
static constexpr uint32_t INVALID_OBJECT_ID = 0;
ObjectType _objectType = ObjectType::UNKNOWN;
uint32_t _objectID = 0U;
uint32_t _typedID = 0U; // inited by sub-classes
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,50 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXPipelineLayout.h"
#include "GFXObject.h"
namespace cc {
namespace gfx {
PipelineLayout::PipelineLayout()
: GFXObject(ObjectType::PIPELINE_LAYOUT) {
}
PipelineLayout::~PipelineLayout() = default;
void PipelineLayout::initialize(const PipelineLayoutInfo &info) {
_setLayouts = info.setLayouts;
doInit(info);
}
void PipelineLayout::destroy() {
doDestroy();
_setLayouts.clear();
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,51 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXObject.h"
#include "base/RefCounted.h"
namespace cc {
namespace gfx {
class CC_DLL PipelineLayout : public GFXObject, public RefCounted {
public:
PipelineLayout();
~PipelineLayout() override;
void initialize(const PipelineLayoutInfo &info);
void destroy();
inline const DescriptorSetLayoutList &getSetLayouts() const { return _setLayouts; }
protected:
virtual void doInit(const PipelineLayoutInfo &info) = 0;
virtual void doDestroy() = 0;
DescriptorSetLayoutList _setLayouts;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,62 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXPipelineState.h"
#include "GFXObject.h"
namespace cc {
namespace gfx {
PipelineState::PipelineState()
: GFXObject(ObjectType::PIPELINE_STATE) {
}
PipelineState::~PipelineState() = default;
void PipelineState::initialize(const PipelineStateInfo &info) {
_primitive = info.primitive;
_shader = info.shader;
_inputState = info.inputState;
_rasterizerState = info.rasterizerState;
_depthStencilState = info.depthStencilState;
_bindPoint = info.bindPoint;
_blendState = info.blendState;
_dynamicStates = info.dynamicStates;
_renderPass = info.renderPass;
_subpass = info.subpass;
_pipelineLayout = info.pipelineLayout;
doInit(info);
}
void PipelineState::destroy() {
doDestroy();
_shader = nullptr;
_renderPass = nullptr;
_pipelineLayout = nullptr;
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,70 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXObject.h"
#include "base/RefCounted.h"
namespace cc {
namespace gfx {
class CC_DLL PipelineState : public GFXObject, public RefCounted {
public:
PipelineState();
~PipelineState() override;
void initialize(const PipelineStateInfo &info);
void destroy();
inline Shader *getShader() const { return _shader; }
inline PipelineBindPoint getBindPoint() const { return _bindPoint; }
inline PrimitiveMode getPrimitive() const { return _primitive; }
inline DynamicStateFlags getDynamicStates() const { return _dynamicStates; }
inline const InputState &getInputState() const { return _inputState; }
inline const RasterizerState &getRasterizerState() const { return _rasterizerState; }
inline const DepthStencilState &getDepthStencilState() const { return _depthStencilState; }
inline const BlendState &getBlendState() const { return _blendState; }
inline const RenderPass *getRenderPass() const { return _renderPass; }
inline const PipelineLayout *getPipelineLayout() const { return _pipelineLayout; }
protected:
virtual void doInit(const PipelineStateInfo &info) = 0;
virtual void doDestroy() = 0;
Shader *_shader = nullptr;
PipelineBindPoint _bindPoint = PipelineBindPoint::GRAPHICS;
PrimitiveMode _primitive = PrimitiveMode::TRIANGLE_LIST;
DynamicStateFlags _dynamicStates = DynamicStateFlags::NONE;
InputState _inputState;
RasterizerState _rasterizerState;
DepthStencilState _depthStencilState;
BlendState _blendState;
RenderPass *_renderPass = nullptr;
uint32_t _subpass = 0U;
PipelineLayout *_pipelineLayout = nullptr;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,52 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXQueryPool.h"
namespace cc {
namespace gfx {
QueryPool::QueryPool()
: GFXObject(ObjectType::QUERY_POOL) {
}
QueryPool::~QueryPool() = default;
void QueryPool::initialize(const QueryPoolInfo &info) {
_type = info.type;
_maxQueryObjects = info.maxQueryObjects;
_forceWait = info.forceWait;
doInit(info);
}
void QueryPool::destroy() {
doDestroy();
_type = QueryType::OCCLUSION;
_maxQueryObjects = 0;
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,74 @@
/****************************************************************************
Copyright (c) 2019-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 <mutex>
#include "GFXObject.h"
#include "base/std/container/unordered_map.h"
namespace cc {
namespace gfx {
/**
* QueryPool usage:
* Update
* Render
* getQueryPoolResults
* resetQueryPool
* for each renderObject
* beginQuery
* drawObject
* endQuery
* completeQueryPool
*/
class CC_DLL QueryPool : public GFXObject {
public:
QueryPool();
~QueryPool() override;
void initialize(const QueryPoolInfo &info);
void destroy();
inline bool hasResult(uint32_t id) { return _results.count(id) != 0; }
inline uint64_t getResult(uint32_t id) { return _results[id]; }
inline QueryType getType() const { return _type; }
inline uint32_t getMaxQueryObjects() const { return _maxQueryObjects; }
inline bool getForceWait() const { return _forceWait; }
protected:
virtual void doInit(const QueryPoolInfo &info) = 0;
virtual void doDestroy() = 0;
QueryType _type{QueryType::OCCLUSION};
uint32_t _maxQueryObjects{0};
bool _forceWait{true};
std::mutex _mutex;
ccstd::unordered_map<uint32_t, uint64_t> _results;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,50 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXQueue.h"
#include "GFXObject.h"
namespace cc {
namespace gfx {
Queue::Queue()
: GFXObject(ObjectType::QUEUE) {
}
Queue::~Queue() = default;
void Queue::initialize(const QueueInfo &info) {
_type = info.type;
doInit(info);
}
void Queue::destroy() {
doDestroy();
_type = QueueType::GRAPHICS;
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,56 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXObject.h"
#include "base/RefCounted.h"
#include "base/Utils.h"
namespace cc {
namespace gfx {
class CC_DLL Queue : public GFXObject, public RefCounted {
public:
Queue();
~Queue() override;
void initialize(const QueueInfo &info);
void destroy();
virtual void submit(CommandBuffer *const *cmdBuffs, uint32_t count) = 0;
inline void submit(const CommandBufferList &cmdBuffs) { submit(cmdBuffs.data(), utils::toUint(cmdBuffs.size())); }
inline QueueType getType() const { return _type; }
protected:
virtual void doInit(const QueueInfo &info) = 0;
virtual void doDestroy() = 0;
QueueType _type = QueueType::GRAPHICS;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,78 @@
/****************************************************************************
Copyright (c) 2019-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/hash/hash.h"
#include "GFXObject.h"
#include "GFXRenderPass.h"
#include "base/Utils.h"
#include "gfx-base/GFXDef-common.h"
namespace cc {
namespace gfx {
RenderPass::RenderPass()
: GFXObject(ObjectType::RENDER_PASS) {
}
RenderPass::~RenderPass() = default;
// Based on render pass compatibility
ccstd::hash_t RenderPass::computeHash() {
ccstd::hash_t seed = static_cast<uint32_t>(_colorAttachments.size()) * 2 + 3;
for (const ColorAttachment &ca : _colorAttachments) {
ccstd::hash_combine(seed, ca);
}
ccstd::hash_combine(seed, _depthStencilAttachment);
ccstd::hash_combine(seed, _depthStencilResolveAttachment);
ccstd::hash_combine(seed, _subpasses);
return seed;
}
ccstd::hash_t RenderPass::computeHash(const RenderPassInfo &info) {
return Hasher<RenderPassInfo>()(info);
}
void RenderPass::initialize(const RenderPassInfo &info) {
_colorAttachments = info.colorAttachments;
_depthStencilAttachment = info.depthStencilAttachment;
_depthStencilResolveAttachment = info.depthStencilResolveAttachment;
_subpasses = info.subpasses;
_dependencies = info.dependencies;
_hash = computeHash();
doInit(info);
}
void RenderPass::destroy() {
doDestroy();
_colorAttachments.clear();
_subpasses.clear();
_hash = 0U;
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,65 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXObject.h"
#include "base/RefCounted.h"
namespace cc {
namespace gfx {
class CC_DLL RenderPass : public GFXObject, public RefCounted {
public:
RenderPass();
~RenderPass() override;
static ccstd::hash_t computeHash(const RenderPassInfo &info);
void initialize(const RenderPassInfo &info);
void destroy();
inline const ColorAttachmentList &getColorAttachments() const { return _colorAttachments; }
inline const DepthStencilAttachment &getDepthStencilAttachment() const { return _depthStencilAttachment; }
inline const DepthStencilAttachment &getDepthStencilResolveAttachment() const { return _depthStencilResolveAttachment; }
inline const SubpassInfoList &getSubpasses() const { return _subpasses; }
inline const SubpassDependencyList &getDependencies() const { return _dependencies; }
inline ccstd::hash_t getHash() const { return _hash; }
protected:
ccstd::hash_t computeHash();
virtual void doInit(const RenderPassInfo &info) = 0;
virtual void doDestroy() = 0;
ColorAttachmentList _colorAttachments;
DepthStencilAttachment _depthStencilAttachment;
DepthStencilAttachment _depthStencilResolveAttachment;
SubpassInfoList _subpasses;
SubpassDependencyList _dependencies;
ccstd::hash_t _hash = 0;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,68 @@
/****************************************************************************
Copyright (c) 2019-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 "GFXShader.h"
#include "GFXDevice.h"
#include "GFXObject.h"
namespace cc {
namespace gfx {
Shader::Shader()
: GFXObject(ObjectType::SHADER) {
}
Shader::~Shader() = default;
void Shader::initialize(const ShaderInfo &info) {
_name = info.name;
_stages = info.stages;
_attributes = info.attributes;
_blocks = info.blocks;
_buffers = info.buffers;
_samplerTextures = info.samplerTextures;
_samplers = info.samplers;
_textures = info.textures;
_images = info.images;
_subpassInputs = info.subpassInputs;
_hash = info.hash;
doInit(info);
}
void Shader::destroy() {
doDestroy();
_stages.clear();
_attributes.clear();
_blocks.clear();
_buffers.clear();
_samplerTextures.clear();
_samplers.clear();
_textures.clear();
_images.clear();
_subpassInputs.clear();
}
} // namespace gfx
} // namespace cc

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