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,208 @@
/****************************************************************************
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 "BufferValidator.h"
#include <cstring>
#include "DeviceValidator.h"
#include "ValidationUtils.h"
#include "base/Log.h"
namespace cc {
namespace gfx {
BufferValidator::BufferValidator(Buffer *actor)
: Agent<Buffer>(actor) {
_typedID = actor->getTypedID();
}
BufferValidator::~BufferValidator() {
DeviceResourceTracker<Buffer>::erase(this);
if (_source != nullptr) {
CC_ASSERT(_isBufferView);
_source->removeView(this);
}
for (auto *view : _views) {
CC_ASSERT(view->isBufferView());
view->onExpire();
}
CC_SAFE_DELETE(_actor);
uint64_t lifeTime = DeviceValidator::getInstance()->currentFrame() - _creationFrame;
// skip those that have never been updated
if (!_isBufferView && hasFlag(_memUsage, MemoryUsageBit::HOST) && _totalUpdateTimes && _totalUpdateTimes < lifeTime / 3) {
CC_LOG_WARNING("Triple buffer enabled for infrequently-updated buffer, consider using MemoryUsageBit::DEVICE instead");
CC_LOG_DEBUG("Init Stacktrace: %s", _initStack.c_str());
}
}
void BufferValidator::doInit(const BufferInfo &info) {
// Initialize twice?
CC_ASSERT(!isInited());
_inited = true;
CC_ASSERT_NE(info.usage, BufferUsageBit::NONE);
CC_ASSERT_NE(info.memUsage, MemoryUsageBit::NONE);
CC_ASSERT(info.size);
CC_ASSERT(info.size / info.stride * info.stride == info.size);
_initStack = utils::getStacktraceJS();
_creationFrame = DeviceValidator::getInstance()->currentFrame();
_totalUpdateTimes = 0U;
if (hasFlag(info.usage, BufferUsageBit::VERTEX) && !info.stride) {
// Invalid stride for vertex buffer.
CC_ABORT();
}
/////////// execute ///////////
_actor->initialize(info);
}
void BufferValidator::doInit(const BufferViewInfo &info) {
// Initialize twice?
CC_ASSERT(!isInited());
_inited = true;
auto *vBuffer = static_cast<BufferValidator *>(info.buffer);
// Already been destroyed?
CC_ASSERT(vBuffer != nullptr && vBuffer->isInited());
CC_ASSERT(info.offset + info.range <= info.buffer->getSize());
// zero-sized buffer?
CC_ASSERT(info.range);
uint32_t stride = info.buffer->getStride();
// Offset is not multiple of stride?
CC_ASSERT(info.offset / stride * stride == info.offset);
/////////// execute ///////////
BufferViewInfo actorInfo = info;
actorInfo.buffer = vBuffer->getActor();
_source = vBuffer;
_source->addView(this);
_actor->initialize(actorInfo);
}
void BufferValidator::doResize(uint32_t size, uint32_t /*count*/) {
// Already been destroyed?
CC_ASSERT(isInited());
// Cannot resize through buffer views.
CC_ASSERT(!_isBufferView);
CC_ASSERT(size);
for (auto *view : _views) {
view->onExpire();
}
_views.clear();
/////////// execute ///////////
_actor->resize(size);
}
void BufferValidator::doDestroy() {
// Be destroyed twice?"
CC_ASSERT(isInited());
_inited = false;
/////////// execute ///////////
_actor->destroy();
}
void BufferValidator::update(const void *buffer, uint32_t size) {
CC_ASSERT(isInited());
// Cannot update through buffer views.
CC_ASSERT(!_isBufferView);
CC_ASSERT(size && size <= _size);
CC_ASSERT(buffer);
if (hasFlag(_usage, BufferUsageBit::INDIRECT)) {
const auto *drawInfo = static_cast<const DrawInfo *>(buffer);
const size_t drawInfoCount = size / sizeof(DrawInfo);
const bool isIndexed = drawInfoCount > 0 && drawInfo->indexCount > 0;
for (size_t i = 1U; i < drawInfoCount; ++i) {
if ((++drawInfo)->indexCount > 0 != isIndexed) {
// Inconsistent indirect draw infos on using index buffer.
CC_ABORT();
}
}
}
sanityCheck(buffer, size);
++_totalUpdateTimes; // only count direct updates
/////////// execute ///////////
_actor->update(buffer, size);
}
void BufferValidator::sanityCheck(const void *buffer, uint32_t size) {
uint64_t cur = DeviceValidator::getInstance()->currentFrame();
if (cur == _lastUpdateFrame) {
// FIXME: minggo: as current implementation need to update some buffers more than once, so disable it.
// Should enable it when it is fixed.
// CC_LOG_WARNING(utils::getStacktraceJS().c_str());
// CC_LOG_WARNING("performance warning: buffer updated more than once per frame");
}
if (DeviceValidator::getInstance()->isRecording()) {
_buffer.resize(_size);
memcpy(_buffer.data(), buffer, size);
}
_lastUpdateFrame = cur;
}
void BufferValidator::addView(BufferValidator *view) {
_views.emplace_back(view);
}
void BufferValidator::removeView(BufferValidator *view) {
_views.erase(std::remove(_views.begin(), _views.end(), view), _views.end());
}
void BufferValidator::onExpire() {
_source = nullptr;
_expired = true;
}
void BufferValidator::flush(const uint8_t *buffer) {
Buffer::flushBuffer(_actor, buffer);
}
uint8_t *BufferValidator::getStagingAddress() const {
return Buffer::getBufferStagingAddress(_actor);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,75 @@
/****************************************************************************
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/GFXBuffer.h"
namespace cc {
namespace gfx {
class CC_DLL BufferValidator final : public Agent<Buffer> {
public:
explicit BufferValidator(Buffer *actor);
~BufferValidator() override;
void update(const void *buffer, uint32_t size) override;
void sanityCheck(const void *buffer, uint32_t size);
inline bool isInited() const { return _inited; }
inline bool isValid() const { return !_expired; }
protected:
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;
void addView(BufferValidator *view);
void removeView(BufferValidator *view);
void onExpire();
ccstd::vector<uint8_t> _buffer;
BufferValidator *_source{nullptr};
ccstd::vector<BufferValidator *> _views; // weak reference
uint64_t _lastUpdateFrame{0U};
uint64_t _totalUpdateTimes{0U};
uint64_t _creationFrame{0U};
bool _inited{false};
bool _expired{false};
ccstd::string _initStack;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,619 @@
/****************************************************************************
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/Macros.h"
#include "base/job-system/JobSystem.h"
#include "BufferValidator.h"
#include "CommandBufferValidator.h"
#include "DescriptorSetValidator.h"
#include "DeviceValidator.h"
#include "FramebufferValidator.h"
#include "InputAssemblerValidator.h"
#include "PipelineStateValidator.h"
#include "QueryPoolValidator.h"
#include "QueueValidator.h"
#include "RenderPassValidator.h"
#include "TextureValidator.h"
#include "ValidationUtils.h"
#include "gfx-base/GFXCommandBuffer.h"
namespace cc {
namespace gfx {
CommandBufferValidator::CommandBufferValidator(CommandBuffer *actor)
: Agent<CommandBuffer>(actor) {
_typedID = actor->getTypedID();
}
CommandBufferValidator::~CommandBufferValidator() {
DeviceResourceTracker<CommandBuffer>::erase(this);
CC_SAFE_DELETE(_actor);
}
void CommandBufferValidator::initValidator() {
CC_ASSERT(!isInited());
_inited = true;
size_t descriptorSetCount = DeviceValidator::getInstance()->bindingMappingInfo().setIndices.size();
_curStates.descriptorSets.resize(descriptorSetCount);
_curStates.dynamicOffsets.resize(descriptorSetCount);
}
void CommandBufferValidator::destroyValidator() {
}
void CommandBufferValidator::doInit(const CommandBufferInfo &info) {
initValidator();
// Already been destroyed?
CC_ASSERT(info.queue && static_cast<QueueValidator *>(info.queue)->isInited());
/////////// execute ///////////
CommandBufferInfo actorInfo = info;
actorInfo.queue = static_cast<QueueValidator *>(info.queue)->getActor();
_actor->initialize(actorInfo);
}
void CommandBufferValidator::doDestroy() {
// Destroy twice?
CC_ASSERT(isInited());
_inited = false;
/////////// execute ///////////
_actor->destroy();
}
void CommandBufferValidator::begin(RenderPass *renderPass, uint32_t subpass, Framebuffer *framebuffer) {
CC_ASSERT(isInited());
CC_ASSERT(!renderPass || static_cast<RenderPassValidator *>(renderPass)->isInited());
CC_ASSERT(!framebuffer || static_cast<FramebufferValidator *>(framebuffer)->isInited());
CC_ASSERT(!_insideRenderPass);
// Primary command buffer cannot inherit render passes.
CC_ASSERT(_type != CommandBufferType::PRIMARY || !renderPass);
// secondary command buffers enter the render pass right here
_insideRenderPass = !!renderPass;
_commandsFlushed = false;
_recorder.clear();
_curStates.descriptorSets.assign(_curStates.descriptorSets.size(), nullptr);
/////////// execute ///////////
RenderPass *renderPassActor = renderPass ? static_cast<RenderPassValidator *>(renderPass)->getActor() : nullptr;
Framebuffer *framebufferActor = framebuffer ? static_cast<FramebufferValidator *>(framebuffer)->getActor() : nullptr;
_actor->begin(renderPassActor, subpass, framebufferActor);
}
void CommandBufferValidator::end() {
// Alread been destroyed?
CC_ASSERT(isInited());
// Still inside a render pass?
CC_ASSERT(_type != CommandBufferType::PRIMARY || !_insideRenderPass);
_insideRenderPass = false;
/////////// execute ///////////
_actor->end();
}
void CommandBufferValidator::beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const Color *colors, float depth, uint32_t stencil, CommandBuffer *const *secondaryCBs, uint32_t secondaryCBCount) {
CC_ASSERT(isInited());
CC_ASSERT(renderPass && static_cast<RenderPassValidator *>(renderPass)->isInited());
CC_ASSERT(fbo && static_cast<FramebufferValidator *>(fbo)->isInited());
// Command 'endRenderPass' must be recorded in primary command buffers.
CC_ASSERT_EQ(_type, CommandBufferType::PRIMARY);
CC_ASSERT(!_insideRenderPass);
for (size_t i = 0; i < renderPass->getColorAttachments().size(); ++i) {
const auto &desc = renderPass->getColorAttachments()[i];
const auto *tex = fbo->getColorTextures()[i];
CC_ASSERT(tex->getFormat() == desc.format);
}
if (fbo->getDepthStencilTexture()) {
CC_ASSERT(fbo->getDepthStencilTexture()->getFormat() == renderPass->getDepthStencilAttachment().format);
}
_insideRenderPass = true;
_curSubpass = 0U;
_curStates.renderPass = renderPass;
_curStates.framebuffer = fbo;
_curStates.renderArea = renderArea;
_curStates.clearDepth = depth;
_curStates.clearStencil = stencil;
size_t clearColorCount = renderPass->getColorAttachments().size();
if (clearColorCount) {
_curStates.clearColors.assign(colors, colors + clearColorCount);
}
if (DeviceValidator::getInstance()->isRecording()) {
_recorder.recordBeginRenderPass(_curStates);
}
/////////// execute ///////////
static ccstd::vector<CommandBuffer *> secondaryCBActors;
secondaryCBActors.resize(secondaryCBCount);
CommandBuffer **actorSecondaryCBs = nullptr;
if (secondaryCBCount) {
actorSecondaryCBs = secondaryCBActors.data();
for (uint32_t i = 0; i < secondaryCBCount; ++i) {
actorSecondaryCBs[i] = static_cast<CommandBufferValidator *>(secondaryCBs[i])->getActor();
}
}
RenderPass *renderPassActor = static_cast<RenderPassValidator *>(renderPass)->getActor();
Framebuffer *framebufferActor = static_cast<FramebufferValidator *>(fbo)->getActor();
_actor->beginRenderPass(renderPassActor, framebufferActor, renderArea, colors, depth, stencil, actorSecondaryCBs, secondaryCBCount);
}
void CommandBufferValidator::nextSubpass() {
CC_ASSERT(isInited());
++_curSubpass;
/////////// execute ///////////
_actor->nextSubpass();
}
void CommandBufferValidator::endRenderPass() {
CC_ASSERT(isInited());
// Command 'endRenderPass' must be recorded in primary command buffers.
CC_ASSERT_EQ(_type, CommandBufferType::PRIMARY);
CC_ASSERT(_insideRenderPass);
_insideRenderPass = false;
if (DeviceValidator::getInstance()->isRecording()) {
_recorder.recordEndRenderPass();
}
/////////// execute ///////////
_actor->endRenderPass();
}
void CommandBufferValidator::insertMarker(const MarkerInfo &marker) {
_actor->insertMarker(marker);
}
void CommandBufferValidator::beginMarker(const MarkerInfo &marker) {
_actor->beginMarker(marker);
}
void CommandBufferValidator::endMarker() {
_actor->endMarker();
}
void CommandBufferValidator::execute(CommandBuffer *const *cmdBuffs, uint32_t count) {
CC_ASSERT(isInited());
if (!count) return; // be more lenient on this for now
// Command 'execute' must be recorded in primary command buffers.
CC_ASSERT_EQ(_type, CommandBufferType::PRIMARY);
for (uint32_t i = 0U; i < count; ++i) {
CC_ASSERT(cmdBuffs[i] && static_cast<CommandBufferValidator *>(cmdBuffs[i])->isInited());
}
/////////// execute ///////////
static ccstd::vector<CommandBuffer *> cmdBuffActors;
cmdBuffActors.resize(count);
for (uint32_t i = 0U; i < count; ++i) {
cmdBuffActors[i] = static_cast<CommandBufferValidator *>(cmdBuffs[i])->getActor();
}
_actor->execute(cmdBuffActors.data(), count);
}
void CommandBufferValidator::bindPipelineState(PipelineState *pso) {
CC_ASSERT(isInited());
CC_ASSERT(pso && static_cast<PipelineStateValidator *>(pso)->isInited());
_curStates.pipelineState = pso;
/////////// execute ///////////
_actor->bindPipelineState(static_cast<PipelineStateValidator *>(pso)->getActor());
}
void CommandBufferValidator::bindDescriptorSet(uint32_t set, DescriptorSet *descriptorSet, uint32_t dynamicOffsetCount, const uint32_t *dynamicOffsets) {
CC_ASSERT(isInited());
CC_ASSERT(descriptorSet && static_cast<DescriptorSetValidator *>(descriptorSet)->isInited());
CC_ASSERT(set < DeviceValidator::getInstance()->bindingMappingInfo().setIndices.size());
// CC_ASSERT(descriptorSet->getLayout()->getDynamicBindings().size() == dynamicOffsetCount); // be more lenient on this
_curStates.descriptorSets[set] = descriptorSet;
_curStates.dynamicOffsets[set].assign(dynamicOffsets, dynamicOffsets + dynamicOffsetCount);
/////////// execute ///////////
_actor->bindDescriptorSet(set, static_cast<DescriptorSetValidator *>(descriptorSet)->getActor(), dynamicOffsetCount, dynamicOffsets);
}
void CommandBufferValidator::bindInputAssembler(InputAssembler *ia) {
CC_ASSERT(isInited());
CC_ASSERT(ia && static_cast<InputAssemblerValidator *>(ia)->isInited());
_curStates.inputAssembler = ia;
/////////// execute ///////////
_actor->bindInputAssembler(static_cast<InputAssemblerValidator *>(ia)->getActor());
}
void CommandBufferValidator::setViewport(const Viewport &vp) {
CC_ASSERT(isInited());
_curStates.viewport = vp;
/////////// execute ///////////
_actor->setViewport(vp);
}
void CommandBufferValidator::setScissor(const Rect &rect) {
CC_ASSERT(isInited());
_curStates.scissor = rect;
/////////// execute ///////////
_actor->setScissor(rect);
}
void CommandBufferValidator::setLineWidth(float width) {
CC_ASSERT(isInited());
_curStates.lineWidth = width;
/////////// execute ///////////
_actor->setLineWidth(width);
}
void CommandBufferValidator::setDepthBias(float constant, float clamp, float slope) {
CC_ASSERT(isInited());
_curStates.depthBiasConstant = constant;
_curStates.depthBiasClamp = clamp;
_curStates.depthBiasSlope = slope;
/////////// execute ///////////
_actor->setDepthBias(constant, clamp, slope);
}
void CommandBufferValidator::setBlendConstants(const Color &constants) {
CC_ASSERT(isInited());
_curStates.blendConstant = constants;
/////////// execute ///////////
_actor->setBlendConstants(constants);
}
void CommandBufferValidator::setDepthBound(float minBounds, float maxBounds) {
CC_ASSERT(isInited());
_curStates.depthMinBounds = minBounds;
_curStates.depthMaxBounds = maxBounds;
/////////// execute ///////////
_actor->setDepthBound(minBounds, maxBounds);
}
void CommandBufferValidator::setStencilWriteMask(StencilFace face, uint32_t mask) {
CC_ASSERT(isInited());
if (hasFlag(face, StencilFace::FRONT)) {
_curStates.stencilStatesFront.writeMask = mask;
}
if (hasFlag(face, StencilFace::BACK)) {
_curStates.stencilStatesBack.writeMask = mask;
}
/////////// execute ///////////
_actor->setStencilWriteMask(face, mask);
}
void CommandBufferValidator::setStencilCompareMask(StencilFace face, uint32_t ref, uint32_t mask) {
CC_ASSERT(isInited());
if (hasFlag(face, StencilFace::FRONT)) {
_curStates.stencilStatesFront.reference = ref;
_curStates.stencilStatesFront.compareMask = mask;
}
if (hasFlag(face, StencilFace::BACK)) {
_curStates.stencilStatesBack.reference = ref;
_curStates.stencilStatesBack.compareMask = mask;
}
/////////// execute ///////////
_actor->setStencilCompareMask(face, ref, mask);
}
void CommandBufferValidator::draw(const DrawInfo &info) {
CC_ASSERT(isInited());
// Command 'draw' must be recorded inside render passes.
CC_ASSERT(_insideRenderPass);
if (DeviceValidator::getInstance()->isRecording()) {
_recorder.recordDrawcall(_curStates);
}
const auto &psoLayouts = _curStates.pipelineState->getPipelineLayout()->getSetLayouts();
for (size_t i = 0; i < psoLayouts.size(); ++i) {
if (!_curStates.descriptorSets[i]) continue; // there may be inactive sets
const auto &dsBindings = _curStates.descriptorSets[i]->getLayout()->getBindings();
const auto &psoBindings = psoLayouts[i]->getBindings();
CC_ASSERT(psoBindings.size() == dsBindings.size());
}
/////////// execute ///////////
_actor->draw(info);
}
void CommandBufferValidator::updateBuffer(Buffer *buff, const void *data, uint32_t size) {
CC_ASSERT(isInited());
CC_ASSERT(buff && static_cast<BufferValidator *>(buff)->isInited());
// Command 'updateBuffer' must be recorded in primary command buffers.
CC_ASSERT_EQ(_type, CommandBufferType::PRIMARY);
// Command 'updateBuffer' must be recorded outside render passes.
CC_ASSERT(!_insideRenderPass);
auto *bufferValidator = static_cast<BufferValidator *>(buff);
bufferValidator->sanityCheck(data, size);
/////////// execute ///////////
_actor->updateBuffer(bufferValidator->getActor(), data, size);
}
void CommandBufferValidator::copyBuffersToTexture(const uint8_t *const *buffers, Texture *texture, const BufferTextureCopy *regions, uint32_t count) {
CC_ASSERT(isInited());
CC_ASSERT(texture && static_cast<TextureValidator *>(texture)->isInited());
// Command 'copyBuffersToTexture' must be recorded in primary command buffers.
CC_ASSERT_EQ(_type, CommandBufferType::PRIMARY);
// Command 'copyBuffersToTexture' must be recorded outside render passes.
CC_ASSERT(!_insideRenderPass);
auto *textureValidator = static_cast<TextureValidator *>(texture);
textureValidator->sanityCheck();
/////////// execute ///////////
_actor->copyBuffersToTexture(buffers, textureValidator->getActor(), regions, count);
}
void CommandBufferValidator::resolveTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) {
CC_ASSERT(isInited());
CC_ASSERT(srcTexture && static_cast<TextureValidator *>(srcTexture)->isInited());
CC_ASSERT(dstTexture && static_cast<TextureValidator *>(dstTexture)->isInited());
const auto &srcInfo = srcTexture->getInfo();
const auto &dstInfo = dstTexture->getInfo();
CC_ASSERT(srcInfo.format == dstInfo.format);
CC_ASSERT(srcInfo.format != Format::DEPTH_STENCIL &&
srcInfo.format != Format::DEPTH);
CC_ASSERT(srcInfo.samples > SampleCount::X1 &&
dstInfo.samples == SampleCount::X1);
CC_ASSERT(!_insideRenderPass);
for (uint32_t i = 0; i < count; ++i) {
const auto &region = regions[i];
CC_ASSERT(region.srcOffset.x + region.extent.width <= srcInfo.width);
CC_ASSERT(region.srcOffset.y + region.extent.height <= srcInfo.height);
CC_ASSERT(region.srcOffset.z + region.extent.depth <= srcInfo.depth);
CC_ASSERT(region.dstOffset.x + region.extent.width <= dstInfo.width);
CC_ASSERT(region.dstOffset.y + region.extent.height <= dstInfo.height);
CC_ASSERT(region.dstOffset.z + region.extent.depth <= dstInfo.depth);
}
Texture *actorSrcTexture = nullptr;
Texture *actorDstTexture = nullptr;
if (srcTexture) actorSrcTexture = static_cast<TextureValidator *>(srcTexture)->getActor();
if (dstTexture) actorDstTexture = static_cast<TextureValidator *>(dstTexture)->getActor();
_actor->resolveTexture(actorSrcTexture, actorDstTexture, regions, count);
}
void CommandBufferValidator::copyTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) {
CC_ASSERT(isInited());
CC_ASSERT(srcTexture && static_cast<TextureValidator *>(srcTexture)->isInited());
CC_ASSERT(dstTexture && static_cast<TextureValidator *>(dstTexture)->isInited());
const auto &srcInfo = srcTexture->getInfo();
const auto &dstInfo = dstTexture->getInfo();
CC_ASSERT(!_insideRenderPass);
for (uint32_t i = 0; i < count; ++i) {
const auto &region = regions[i];
CC_ASSERT(region.srcOffset.x + region.extent.width <= srcInfo.width);
CC_ASSERT(region.srcOffset.y + region.extent.height <= srcInfo.height);
CC_ASSERT(region.srcOffset.z + region.extent.depth <= srcInfo.depth);
CC_ASSERT(region.dstOffset.x + region.extent.width <= dstInfo.width);
CC_ASSERT(region.dstOffset.y + region.extent.height <= dstInfo.height);
CC_ASSERT(region.dstOffset.z + region.extent.depth <= dstInfo.depth);
}
/////////// execute ///////////
Texture *actorSrcTexture = nullptr;
Texture *actorDstTexture = nullptr;
if (srcTexture) actorSrcTexture = static_cast<TextureValidator *>(srcTexture)->getActor();
if (dstTexture) actorDstTexture = static_cast<TextureValidator *>(dstTexture)->getActor();
_actor->copyTexture(actorSrcTexture, actorDstTexture, regions, count);
}
void CommandBufferValidator::blitTexture(Texture *srcTexture, Texture *dstTexture, const TextureBlit *regions, uint32_t count, Filter filter) {
CC_ASSERT(isInited());
CC_ASSERT(srcTexture && static_cast<TextureValidator *>(srcTexture)->isInited());
CC_ASSERT(dstTexture && static_cast<TextureValidator *>(dstTexture)->isInited());
// Blit on multisampled texture is not allowed.
CC_ASSERT(srcTexture->getInfo().samples == SampleCount::X1);
// blit on multisampled texture is not allowed.
CC_ASSERT(dstTexture->getInfo().samples == SampleCount::X1);
// Command 'blitTexture' must be recorded outside render passes.
CC_ASSERT(!_insideRenderPass);
for (uint32_t i = 0; i < count; ++i) {
const auto &region = regions[i];
CC_ASSERT(region.srcOffset.x + region.srcExtent.width <= srcTexture->getInfo().width);
CC_ASSERT(region.srcOffset.y + region.srcExtent.height <= srcTexture->getInfo().height);
CC_ASSERT(region.srcOffset.z + region.srcExtent.depth <= srcTexture->getInfo().depth);
CC_ASSERT(region.dstOffset.x + region.dstExtent.width <= dstTexture->getInfo().width);
CC_ASSERT(region.dstOffset.y + region.dstExtent.height <= dstTexture->getInfo().height);
CC_ASSERT(region.dstOffset.z + region.dstExtent.depth <= dstTexture->getInfo().depth);
}
/////////// execute ///////////
Texture *actorSrcTexture = nullptr;
Texture *actorDstTexture = nullptr;
if (srcTexture) actorSrcTexture = static_cast<TextureValidator *>(srcTexture)->getActor();
if (dstTexture) actorDstTexture = static_cast<TextureValidator *>(dstTexture)->getActor();
_actor->blitTexture(actorSrcTexture, actorDstTexture, regions, count, filter);
}
void CommandBufferValidator::dispatch(const DispatchInfo &info) {
CC_ASSERT(isInited());
// Command 'dispatch' must be recorded outside render passes.
CC_ASSERT(!_insideRenderPass);
/////////// execute ///////////
DispatchInfo actorInfo = info;
if (info.indirectBuffer) actorInfo.indirectBuffer = static_cast<BufferValidator *>(info.indirectBuffer)->getActor();
_actor->dispatch(info);
}
void CommandBufferValidator::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) {
CC_ASSERT(isInited());
for (uint32_t i = 0U; i < textureBarrierCount; ++i) {
CC_ASSERT(textures[i] && static_cast<const TextureValidator *>(textures[i])->isInited());
}
for (uint32_t i = 0U; i < bufferBarrierCount; ++i) {
CC_ASSERT(buffers[i] && static_cast<const BufferValidator *>(buffers[i])->isInited());
}
/////////// execute ///////////
static ccstd::vector<Texture *> textureActors;
textureActors.resize(textureBarrierCount);
Texture **actorTextures = nullptr;
if (textureBarrierCount) {
actorTextures = textureActors.data();
for (uint32_t i = 0U; i < textureBarrierCount; ++i) {
actorTextures[i] = textures[i] ? static_cast<const TextureValidator *>(textures[i])->getActor() : nullptr;
}
}
static ccstd::vector<Buffer *> bufferActors;
bufferActors.resize(bufferBarrierCount);
Buffer **actorBuffers = nullptr;
if (bufferBarrierCount) {
actorBuffers = bufferActors.data();
for (uint32_t i = 0U; i < bufferBarrierCount; ++i) {
actorBuffers[i] = buffers[i] ? static_cast<const BufferValidator *>(buffers[i])->getActor() : nullptr;
}
}
_actor->pipelineBarrier(barrier, bufferBarriers, actorBuffers, bufferBarrierCount, textureBarriers, actorTextures, textureBarrierCount);
}
void CommandBufferValidator::beginQuery(QueryPool *queryPool, uint32_t id) {
CC_ASSERT(isInited());
CC_ASSERT(static_cast<QueryPoolValidator *>(queryPool)->isInited());
QueryPool *actorQueryPool = static_cast<QueryPoolValidator *>(queryPool)->getActor();
_actor->beginQuery(actorQueryPool, id);
}
void CommandBufferValidator::endQuery(QueryPool *queryPool, uint32_t id) {
CC_ASSERT(isInited());
CC_ASSERT(static_cast<QueryPoolValidator *>(queryPool)->isInited());
QueryPool *actorQueryPool = static_cast<QueryPoolValidator *>(queryPool)->getActor();
_actor->endQuery(actorQueryPool, id);
}
void CommandBufferValidator::resetQueryPool(QueryPool *queryPool) {
CC_ASSERT(isInited());
CC_ASSERT(static_cast<QueryPoolValidator *>(queryPool)->isInited());
QueryPool *actorQueryPool = static_cast<QueryPoolValidator *>(queryPool)->getActor();
_actor->resetQueryPool(actorQueryPool);
}
void CommandBufferValidator::completeQueryPool(QueryPool *queryPool) {
CC_ASSERT(isInited());
CC_ASSERT(static_cast<QueryPoolValidator *>(queryPool)->isInited());
QueryPool *actorQueryPool = static_cast<QueryPoolValidator *>(queryPool)->getActor();
_actor->completeQueryPool(actorQueryPool);
}
void CommandBufferValidator::customCommand(CustomCommand &&cmd) {
_actor->customCommand(std::move(cmd));
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,101 @@
/****************************************************************************
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"
#include "ValidationUtils.h"
namespace cc {
namespace gfx {
class CC_DLL CommandBufferValidator final : public Agent<CommandBuffer> {
public:
explicit CommandBufferValidator(CommandBuffer *actor);
~CommandBufferValidator() override;
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 bool isInited() const { return _inited; }
inline bool isCommandsFlushed() const { return _commandsFlushed; }
protected:
friend class DeviceValidator;
void initValidator();
void destroyValidator();
void doInit(const CommandBufferInfo &info) override;
void doDestroy() override;
CommandBufferStorage _curStates;
CommandRecorder _recorder;
bool _insideRenderPass{false};
bool _commandsFlushed{false};
uint32_t _curSubpass{0U};
bool _inited{false};
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,112 @@
/****************************************************************************
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 "gfx-base/GFXDef-common.h"
#include "math/Math.h"
#include "DescriptorSetLayoutValidator.h"
#include "DeviceValidator.h"
#include "ValidationUtils.h"
namespace cc {
namespace gfx {
DescriptorSetLayoutValidator::DescriptorSetLayoutValidator(DescriptorSetLayout *actor)
: Agent<DescriptorSetLayout>(actor) {
_typedID = actor->getTypedID();
}
DescriptorSetLayoutValidator::~DescriptorSetLayoutValidator() {
DeviceResourceTracker<DescriptorSetLayout>::erase(this);
CC_SAFE_DELETE(_actor);
}
void DescriptorSetLayoutValidator::doInit(const DescriptorSetLayoutInfo &info) {
// Initialize twice?
CC_ASSERT(!isInited());
_inited = true;
DescriptorSetLayoutBindingList bindings{info.bindings};
std::sort(bindings.begin(), bindings.end(), [&](const auto &a, const auto &b) {
return a.binding < b.binding;
});
static constexpr uint32_t DESCRIPTOR_TYPE_ORDERS[]{
INVALID_BINDING, // UNKNOWN
0, // UNIFORM_BUFFER
0, // DYNAMIC_UNIFORM_BUFFER
4, // STORAGE_BUFFER
4, // DYNAMIC_STORAGE_BUFFER
1, // SAMPLER_TEXTURE
2, // SAMPLER
3, // TEXTURE
5, // STORAGE_IMAGE
6, // INPUT_ATTACHMENT
};
_typeCounts.resize(DESCRIPTOR_TYPE_ORDERS[utils::getBitPosition(toNumber(DescriptorType::INPUT_ATTACHMENT))] + 1);
uint32_t lastType{0};
for (const auto &binding : bindings) {
CC_ASSERT(binding.binding != INVALID_BINDING);
CC_ASSERT_NE(binding.descriptorType, DescriptorType::UNKNOWN);
CC_ASSERT(math::isPowerOfTwo(toNumber(binding.descriptorType)));
CC_ASSERT(binding.count);
CC_ASSERT_NE(binding.stageFlags, ShaderStageFlagBit::NONE);
for (const Sampler *sampler : binding.immutableSamplers) {
CC_ASSERT(sampler);
}
/**
* Descriptors should be defined strictly in the following order,
* with consecutive bindings within each type:
* * Block
* * SamplerTexture
* * Sampler
* * Texture
* * Buffer
* * Image
* * SubpassInput
*/
uint32_t type{DESCRIPTOR_TYPE_ORDERS[utils::getBitPosition(toNumber(binding.descriptorType))]};
// deffered pipeline issue: https://github.com/cocos/cocos-engine/pull/10701
// CC_ASSERT_LE(lastType, type);
lastType = type;
++_typeCounts[type];
}
/////////// execute ///////////
_actor->initialize(info);
}
void DescriptorSetLayoutValidator::doDestroy() {
CC_ASSERT(isInited());
_inited = false;
/////////// execute ///////////
_actor->destroy();
}
} // namespace gfx
} // namespace cc

View File

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

View File

@@ -0,0 +1,191 @@
/****************************************************************************
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/Log.h"
#include "base/threading/MessageQueue.h"
#include "BufferValidator.h"
#include "DescriptorSetLayoutValidator.h"
#include "DescriptorSetValidator.h"
#include "DeviceValidator.h"
#include "TextureValidator.h"
#include "ValidationUtils.h"
namespace cc {
namespace gfx {
DescriptorSetValidator::DescriptorSetValidator(DescriptorSet *actor)
: Agent<DescriptorSet>(actor) {
_typedID = actor->getTypedID();
}
DescriptorSetValidator::~DescriptorSetValidator() {
DeviceResourceTracker<DescriptorSet>::erase(this);
CC_SAFE_DELETE(_actor);
}
void DescriptorSetValidator::doInit(const DescriptorSetInfo &info) {
CC_ASSERT(!isInited());
_inited = true;
CC_ASSERT(info.layout && static_cast<const DescriptorSetLayoutValidator *>(info.layout)->isInited());
/////////// execute ///////////
DescriptorSetInfo actorInfo;
actorInfo.layout = static_cast<const DescriptorSetLayoutValidator *>(info.layout)->getActor();
_actor->initialize(actorInfo);
}
void DescriptorSetValidator::doDestroy() {
// Destroy twice.
CC_ASSERT(isInited());
_inited = false;
/////////// execute ///////////
_actor->destroy();
}
void DescriptorSetValidator::update() {
CC_ASSERT(isInited());
const auto descriptorCount = _textures.size();
Texture *texture = nullptr;
Sampler *sampler = nullptr;
Format format = {};
for (size_t i = 0; i < descriptorCount; ++i) {
texture = _textures[i].ptr;
sampler = _samplers[i].ptr;
if (texture == nullptr || sampler == nullptr) continue;
format = texture->getInfo().format;
if (sampler->getInfo().magFilter == Filter::LINEAR ||
sampler->getInfo().mipFilter == Filter::LINEAR ||
sampler->getInfo().minFilter == Filter::LINEAR) {
if (!hasFlag(DeviceValidator::getInstance()->getFormatFeatures(format), FormatFeature::LINEAR_FILTER)) {
CC_LOG_WARNING("[WARNING]: Format doesn't support linear filter.");
}
}
}
// DescriptorSet can not be updated after bound to CommandBuffer.
CC_ASSERT(_referenceStamp < DeviceValidator::getInstance()->currentFrame());
/////////// execute ///////////
if (!_isDirty) return;
_actor->update();
_isDirty = false;
}
void DescriptorSetValidator::forceUpdate() {
_isDirty = true;
_actor->forceUpdate();
_isDirty = false;
}
void DescriptorSetValidator::updateReferenceStamp() {
_referenceStamp = DeviceValidator::getInstance()->currentFrame();
}
void DescriptorSetValidator::bindBuffer(uint32_t binding, Buffer *buffer, uint32_t index, AccessFlags flags) {
CC_ASSERT(isInited());
auto *vBuffer = static_cast<BufferValidator *>(buffer);
CC_ASSERT(buffer && vBuffer->isInited());
CC_ASSERT(vBuffer->isValid() && "Buffer View Expired");
const ccstd::vector<uint32_t> &bindingIndices = _layout->getBindingIndices();
const DescriptorSetLayoutBindingList &bindings = _layout->getBindings();
CC_ASSERT(binding < bindingIndices.size() && bindingIndices[binding] < bindings.size());
const DescriptorSetLayoutBinding &info = bindings[bindingIndices[binding]];
CC_ASSERT(hasAnyFlags(info.descriptorType, DESCRIPTOR_BUFFER_TYPE));
if (hasAnyFlags(info.descriptorType, DESCRIPTOR_DYNAMIC_TYPE)) {
// Should bind buffer views for dynamic descriptors.
CC_ASSERT(buffer->isBufferView());
}
if (hasAnyFlags(info.descriptorType, DescriptorType::UNIFORM_BUFFER | DescriptorType::DYNAMIC_UNIFORM_BUFFER)) {
CC_ASSERT(hasFlag(buffer->getUsage(), BufferUsageBit::UNIFORM));
} else if (hasAnyFlags(info.descriptorType, DescriptorType::STORAGE_BUFFER | DescriptorType::DYNAMIC_STORAGE_BUFFER)) {
CC_ASSERT(hasFlag(buffer->getUsage(), BufferUsageBit::STORAGE));
}
/////////// execute ///////////
DescriptorSet::bindBuffer(binding, buffer, index, flags);
_actor->bindBuffer(binding, vBuffer->getActor(), index, flags);
}
void DescriptorSetValidator::bindTexture(uint32_t binding, Texture *texture, uint32_t index, AccessFlags flags) {
CC_ASSERT(isInited());
CC_ASSERT(texture && static_cast<TextureValidator *>(texture)->isInited());
const ccstd::vector<uint32_t> &bindingIndices = _layout->getBindingIndices();
const DescriptorSetLayoutBindingList &bindings = _layout->getBindings();
CC_ASSERT(binding < bindingIndices.size() && bindingIndices[binding] < bindings.size());
const DescriptorSetLayoutBinding &info = bindings[bindingIndices[binding]];
CC_ASSERT(hasAnyFlags(info.descriptorType, DESCRIPTOR_TEXTURE_TYPE));
if (hasFlag(info.descriptorType, DescriptorType::INPUT_ATTACHMENT)) {
CC_ASSERT(hasFlag(texture->getInfo().usage, TextureUsageBit::INPUT_ATTACHMENT));
} else if (hasFlag(info.descriptorType, DescriptorType::STORAGE_IMAGE)) {
CC_ASSERT(hasFlag(texture->getInfo().usage, TextureUsageBit::STORAGE));
} else {
CC_ASSERT(hasFlag(texture->getInfo().usage, TextureUsageBit::SAMPLED));
}
/////////// execute ///////////
DescriptorSet::bindTexture(binding, texture, index, flags);
_actor->bindTexture(binding, static_cast<TextureValidator *>(texture)->getActor(), index, flags);
}
void DescriptorSetValidator::bindSampler(uint32_t binding, Sampler *sampler, uint32_t index) {
CC_ASSERT(isInited());
const ccstd::vector<uint32_t> &bindingIndices = _layout->getBindingIndices();
const DescriptorSetLayoutBindingList &bindings = _layout->getBindings();
CC_ASSERT(binding < bindingIndices.size() && bindingIndices[binding] < bindings.size());
const DescriptorSetLayoutBinding &info = bindings[bindingIndices[binding]];
CC_ASSERT(hasAnyFlags(info.descriptorType, DESCRIPTOR_TEXTURE_TYPE));
/////////// execute ///////////
DescriptorSet::bindSampler(binding, sampler, index);
_actor->bindSampler(binding, sampler, index);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,59 @@
/****************************************************************************
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 DescriptorSetValidator final : public Agent<DescriptorSet> {
public:
explicit DescriptorSetValidator(DescriptorSet *actor);
~DescriptorSetValidator() 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;
void updateReferenceStamp();
inline bool isInited() const { return _inited; }
protected:
void doInit(const DescriptorSetInfo &info) override;
void doDestroy() override;
uint64_t _referenceStamp{0U};
bool _inited{false};
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,360 @@
/****************************************************************************
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/Log.h"
#include "BufferValidator.h"
#include "CommandBufferValidator.h"
#include "DescriptorSetLayoutValidator.h"
#include "DescriptorSetValidator.h"
#include "DeviceValidator.h"
#include "FramebufferValidator.h"
#include "InputAssemblerValidator.h"
#include "PipelineLayoutValidator.h"
#include "PipelineStateValidator.h"
#include "QueryPoolValidator.h"
#include "QueueValidator.h"
#include "RenderPassValidator.h"
#include "ShaderValidator.h"
#include "SwapchainValidator.h"
#include "TextureValidator.h"
#include "ValidationUtils.h"
#include <algorithm>
#include <cstring>
namespace cc {
namespace gfx {
DeviceValidator *DeviceValidator::instance = nullptr;
bool DeviceValidator::allowStacktraceJS{true};
DeviceValidator *DeviceValidator::getInstance() {
return DeviceValidator::instance;
}
DeviceValidator::DeviceValidator(Device *device) : Agent(device) {
DeviceValidator::instance = this;
}
DeviceValidator::~DeviceValidator() {
CC_SAFE_DELETE(_actor);
DeviceValidator::instance = nullptr;
}
bool DeviceValidator::doInit(const DeviceInfo &info) {
uint32_t flexibleSet{info.bindingMappingInfo.setIndices.back()};
CC_ASSERT(!info.bindingMappingInfo.maxBlockCounts[flexibleSet]); // Flexible set limits should be zero.
CC_ASSERT(!info.bindingMappingInfo.maxSamplerTextureCounts[flexibleSet]); // Flexible set limits should be zero.
CC_ASSERT(!info.bindingMappingInfo.maxSamplerCounts[flexibleSet]); // Flexible set limits should be zero.
CC_ASSERT(!info.bindingMappingInfo.maxTextureCounts[flexibleSet]); // Flexible set limits should be zero.
CC_ASSERT(!info.bindingMappingInfo.maxBufferCounts[flexibleSet]); // Flexible set limits should be zero.
CC_ASSERT(!info.bindingMappingInfo.maxImageCounts[flexibleSet]); // Flexible set limits should be zero.
CC_ASSERT(!info.bindingMappingInfo.maxSubpassInputCounts[flexibleSet]); // Flexible set limits should be zero.
if (!_actor->initialize(info)) {
return false;
}
_api = _actor->getGfxAPI();
_deviceName = _actor->getDeviceName();
_queue = ccnew QueueValidator(_actor->getQueue());
_queryPool = ccnew QueryPoolValidator(_actor->getQueryPool());
_cmdBuff = ccnew CommandBufferValidator(_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));
static_cast<QueueValidator *>(_queue)->_inited = true;
static_cast<QueryPoolValidator *>(_queryPool)->_inited = true;
static_cast<CommandBufferValidator *>(_cmdBuff)->_queue = _queue;
static_cast<CommandBufferValidator *>(_cmdBuff)->initValidator();
DeviceResourceTracker<CommandBuffer>::push(_cmdBuff);
DeviceResourceTracker<QueryPool>::push(_queryPool);
DeviceResourceTracker<Queue>::push(_queue);
CC_LOG_INFO("Device validator enabled.");
return true;
}
void DeviceValidator::doDestroy() {
if (_cmdBuff) {
static_cast<CommandBufferValidator *>(_cmdBuff)->destroyValidator();
static_cast<CommandBufferValidator *>(_cmdBuff)->_actor = nullptr;
delete _cmdBuff;
_cmdBuff = nullptr;
}
if (_queryPool) {
static_cast<QueryPoolValidator *>(_queryPool)->_actor = nullptr;
delete _queryPool;
_queryPool = nullptr;
}
if (_queue) {
static_cast<QueueValidator *>(_queue)->_actor = nullptr;
delete _queue;
_queue = nullptr;
}
DeviceResourceTracker<CommandBuffer>::checkEmpty();
DeviceResourceTracker<QueryPool>::checkEmpty();
DeviceResourceTracker<Queue>::checkEmpty();
DeviceResourceTracker<Swapchain>::checkEmpty();
DeviceResourceTracker<Buffer>::checkEmpty();
DeviceResourceTracker<Texture>::checkEmpty();
DeviceResourceTracker<Sampler>::checkEmpty();
DeviceResourceTracker<Shader>::checkEmpty();
DeviceResourceTracker<InputAssembler>::checkEmpty();
DeviceResourceTracker<RenderPass>::checkEmpty();
DeviceResourceTracker<Framebuffer>::checkEmpty();
DeviceResourceTracker<DescriptorSet>::checkEmpty();
DeviceResourceTracker<DescriptorSetLayout>::checkEmpty();
DeviceResourceTracker<PipelineLayout>::checkEmpty();
DeviceResourceTracker<PipelineState>::checkEmpty();
_actor->destroy();
}
void DeviceValidator::acquire(Swapchain *const *swapchains, uint32_t count) {
static ccstd::vector<Swapchain *> swapchainActors;
swapchainActors.resize(count);
for (uint32_t i = 0U; i < count; ++i) {
auto *swapchain = static_cast<SwapchainValidator *>(swapchains[i]);
swapchainActors[i] = swapchain->getActor();
}
if (_onAcquire) _onAcquire->execute();
_actor->acquire(swapchainActors.data(), count);
}
void DeviceValidator::present() {
_actor->present();
++_currentFrame;
}
CommandBuffer *DeviceValidator::createCommandBuffer(const CommandBufferInfo &info, bool hasAgent) {
CommandBuffer *actor = _actor->createCommandBuffer(info, hasAgent);
CommandBuffer *result = ccnew CommandBufferValidator(actor);
DeviceResourceTracker<CommandBuffer>::push(result);
return result;
}
Queue *DeviceValidator::createQueue() {
Queue *actor = _actor->createQueue();
Queue *result = ccnew QueueValidator(actor);
DeviceResourceTracker<Queue>::push(result);
return result;
}
QueryPool *DeviceValidator::createQueryPool() {
QueryPool *actor = _actor->createQueryPool();
QueryPool *result = ccnew QueryPoolValidator(actor);
DeviceResourceTracker<QueryPool>::push(result);
return result;
}
Swapchain *DeviceValidator::createSwapchain() {
Swapchain *actor = _actor->createSwapchain();
Swapchain *result = ccnew SwapchainValidator(actor);
DeviceResourceTracker<Swapchain>::push(result);
return result;
}
Buffer *DeviceValidator::createBuffer() {
Buffer *actor = _actor->createBuffer();
Buffer *result = ccnew BufferValidator(actor);
DeviceResourceTracker<Buffer>::push(result);
return result;
}
Texture *DeviceValidator::createTexture() {
Texture *actor = _actor->createTexture();
Texture *result = ccnew TextureValidator(actor);
DeviceResourceTracker<Texture>::push(result);
return result;
}
Shader *DeviceValidator::createShader() {
Shader *actor = _actor->createShader();
Shader *result = ccnew ShaderValidator(actor);
DeviceResourceTracker<Shader>::push(result);
return result;
}
InputAssembler *DeviceValidator::createInputAssembler() {
InputAssembler *actor = _actor->createInputAssembler();
InputAssembler *result = ccnew InputAssemblerValidator(actor);
DeviceResourceTracker<InputAssembler>::push(result);
return result;
}
RenderPass *DeviceValidator::createRenderPass() {
RenderPass *actor = _actor->createRenderPass();
RenderPass *result = ccnew RenderPassValidator(actor);
DeviceResourceTracker<RenderPass>::push(result);
return result;
}
Framebuffer *DeviceValidator::createFramebuffer() {
Framebuffer *actor = _actor->createFramebuffer();
Framebuffer *result = ccnew FramebufferValidator(actor);
DeviceResourceTracker<Framebuffer>::push(result);
return result;
}
DescriptorSet *DeviceValidator::createDescriptorSet() {
DescriptorSet *actor = _actor->createDescriptorSet();
DescriptorSet *result = ccnew DescriptorSetValidator(actor);
DeviceResourceTracker<DescriptorSet>::push(result);
return result;
}
DescriptorSetLayout *DeviceValidator::createDescriptorSetLayout() {
DescriptorSetLayout *actor = _actor->createDescriptorSetLayout();
DescriptorSetLayout *result = ccnew DescriptorSetLayoutValidator(actor);
DeviceResourceTracker<DescriptorSetLayout>::push(result);
return result;
}
PipelineLayout *DeviceValidator::createPipelineLayout() {
PipelineLayout *actor = _actor->createPipelineLayout();
PipelineLayout *result = ccnew PipelineLayoutValidator(actor);
DeviceResourceTracker<PipelineLayout>::push(result);
return result;
}
PipelineState *DeviceValidator::createPipelineState() {
PipelineState *actor = _actor->createPipelineState();
PipelineState *result = ccnew PipelineStateValidator(actor);
DeviceResourceTracker<PipelineState>::push(result);
return result;
}
Sampler *DeviceValidator::getSampler(const SamplerInfo &info) {
if (info.addressU != info.addressV || info.addressV != info.addressW) {
CC_LOG_WARNING("Samplers with different wrapping modes may case reduced performance");
}
/////////// execute ///////////
return _actor->getSampler(info);
}
GeneralBarrier *DeviceValidator::getGeneralBarrier(const GeneralBarrierInfo &info) {
/////////// execute ///////////
return _actor->getGeneralBarrier(info);
}
TextureBarrier *DeviceValidator::getTextureBarrier(const TextureBarrierInfo &info) {
/////////// execute ///////////
return _actor->getTextureBarrier(info);
}
BufferBarrier *DeviceValidator::getBufferBarrier(const BufferBarrierInfo &info) {
return _actor->getBufferBarrier(info);
}
void DeviceValidator::copyBuffersToTexture(const uint8_t *const *buffers, Texture *dst, const BufferTextureCopy *regions, uint32_t count) {
auto *textureValidator = static_cast<TextureValidator *>(dst);
textureValidator->sanityCheck();
uint32_t blockWidth = formatAlignment(dst->getFormat()).first;
uint32_t blockHeight = formatAlignment(dst->getFormat()).second;
for (uint32_t i = 0; i < count; ++i) {
const auto region = regions[i];
uint32_t level = region.texSubres.mipLevel;
uint32_t offsetX = region.texOffset.x;
uint32_t offsetY = region.texOffset.y;
uint32_t extentX = region.texExtent.width;
uint32_t extentY = region.texExtent.height;
uint32_t imgWidth = dst->getWidth() >> level;
uint32_t imgHeight = dst->getHeight() >> level;
CC_ASSERT(offsetX % blockWidth == 0);
CC_ASSERT(offsetY % blockHeight == 0);
CC_ASSERT((extentX % blockWidth == 0) || (extentX % blockWidth != 0 && offsetX + extentX == imgWidth));
CC_ASSERT((extentY % blockHeight == 0) || (extentY % blockHeight != 0 && offsetY + extentY == imgHeight));
}
/////////// execute ///////////
_actor->copyBuffersToTexture(buffers, textureValidator->getActor(), regions, count);
}
void DeviceValidator::copyTextureToBuffers(Texture *src, uint8_t *const *buffers, const BufferTextureCopy *regions, uint32_t count) {
auto *textureValidator = static_cast<TextureValidator *>(src);
/////////// execute ///////////
_actor->copyTextureToBuffers(textureValidator->getActor(), buffers, regions, count);
}
void DeviceValidator::flushCommands(CommandBuffer *const *cmdBuffs, uint32_t count) {
if (!count) return;
/////////// execute ///////////
static ccstd::vector<CommandBuffer *> cmdBuffActors;
cmdBuffActors.resize(count);
for (uint32_t i = 0U; i < count; ++i) {
auto *cmdBuff = static_cast<CommandBufferValidator *>(cmdBuffs[i]);
cmdBuff->_commandsFlushed = true;
cmdBuffActors[i] = cmdBuff->getActor();
}
_actor->flushCommands(cmdBuffActors.data(), count);
}
void DeviceValidator::getQueryPoolResults(QueryPool *queryPool) {
auto *actorQueryPool = static_cast<QueryPoolValidator *>(queryPool)->getActor();
_actor->getQueryPoolResults(actorQueryPool);
auto *actorQueryPoolValidator = static_cast<QueryPoolValidator *>(actorQueryPool);
auto *queryPoolValidator = static_cast<QueryPoolValidator *>(queryPool);
std::lock_guard<std::mutex> lock(actorQueryPoolValidator->_mutex);
queryPoolValidator->_results = actorQueryPoolValidator->_results;
}
void DeviceValidator::enableAutoBarrier(bool en) {
_actor->enableAutoBarrier(en);
}
void DeviceValidator::frameSync() {
_actor->frameSync();
}
SampleCount DeviceValidator::getMaxSampleCount(Format format, TextureUsage usage, TextureFlags flags) const {
return _actor->getMaxSampleCount(format, usage, flags);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,116 @@
/****************************************************************************
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/GFXDevice.h"
namespace cc {
namespace gfx {
class CC_DLL DeviceValidator final : public Agent<Device> {
public:
static DeviceValidator *getInstance();
static bool allowStacktraceJS;
~DeviceValidator() override;
using Device::copyBuffersToTexture;
using Device::createBuffer;
using Device::createBufferBarrier;
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 getQueryPoolResults(QueryPool *queryPool) override;
void flushCommands(CommandBuffer *const *cmdBuffs, uint32_t count) 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(); }
inline void enableRecording(bool recording) { _recording = recording; }
inline bool isRecording() const { return _recording; }
inline uint64_t currentFrame() const { return _currentFrame; }
void enableAutoBarrier(bool enable) override;
SampleCount getMaxSampleCount(Format format, TextureUsage usage, TextureFlags flags) const override;
protected:
static DeviceValidator *instance;
friend class DeviceManager;
explicit DeviceValidator(Device *device);
bool doInit(const DeviceInfo &info) override;
void doDestroy() override;
void bindContext(bool bound) override { _actor->bindContext(bound); }
bool _recording{false};
uint64_t _currentFrame{1U};
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,109 @@
/****************************************************************************
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/Macros.h"
#include "base/threading/MessageQueue.h"
#include "DeviceValidator.h"
#include "FramebufferValidator.h"
#include "RenderPassValidator.h"
#include "TextureValidator.h"
#include "ValidationUtils.h"
namespace cc {
namespace gfx {
FramebufferValidator::FramebufferValidator(Framebuffer *actor)
: Agent<Framebuffer>(actor) {
_typedID = actor->getTypedID();
}
FramebufferValidator::~FramebufferValidator() {
DeviceResourceTracker<Framebuffer>::erase(this);
CC_SAFE_DELETE(_actor);
}
void FramebufferValidator::doInit(const FramebufferInfo &info) {
CC_ASSERT(!isInited());
_inited = true;
CC_ASSERT(info.renderPass && static_cast<RenderPassValidator *>(info.renderPass)->isInited());
CC_ASSERT(!info.colorTextures.empty() || info.depthStencilTexture);
CC_ASSERT(info.colorTextures.size() == info.renderPass->getColorAttachments().size());
if (info.renderPass->getDepthStencilAttachment().format != Format::UNKNOWN) {
CC_ASSERT(info.depthStencilTexture);
}
if (info.renderPass->getDepthStencilResolveAttachment().format != Format::UNKNOWN) {
CC_ASSERT(info.depthStencilResolveTexture);
}
for (uint32_t i = 0U; i < info.colorTextures.size(); ++i) {
const auto &desc = info.renderPass->getColorAttachments()[i];
const auto *tex = info.colorTextures[i];
CC_ASSERT(tex && static_cast<const TextureValidator *>(tex)->isInited());
CC_ASSERT(hasAnyFlags(tex->getInfo().usage, TextureUsageBit::COLOR_ATTACHMENT | TextureUsageBit::DEPTH_STENCIL_ATTACHMENT | TextureUsageBit::SHADING_RATE));
CC_ASSERT(tex->getFormat() == desc.format);
}
if (info.depthStencilTexture) {
CC_ASSERT(static_cast<TextureValidator *>(info.depthStencilTexture)->isInited());
CC_ASSERT(hasFlag(info.depthStencilTexture->getInfo().usage, TextureUsageBit::DEPTH_STENCIL_ATTACHMENT));
CC_ASSERT(info.depthStencilTexture->getFormat() == info.renderPass->getDepthStencilAttachment().format);
}
if (info.depthStencilResolveTexture) {
CC_ASSERT(static_cast<TextureValidator *>(info.depthStencilResolveTexture)->isInited());
CC_ASSERT(hasFlag(info.depthStencilResolveTexture->getInfo().usage, TextureUsageBit::DEPTH_STENCIL_ATTACHMENT));
CC_ASSERT(info.depthStencilResolveTexture->getFormat() == info.renderPass->getDepthStencilResolveAttachment().format);
}
/////////// execute ///////////
FramebufferInfo actorInfo = info;
for (uint32_t i = 0U; i < info.colorTextures.size(); ++i) {
if (info.colorTextures[i]) {
actorInfo.colorTextures[i] = static_cast<TextureValidator *>(info.colorTextures[i])->getActor();
}
}
if (info.depthStencilTexture) {
actorInfo.depthStencilTexture = static_cast<TextureValidator *>(info.depthStencilTexture)->getActor();
}
if (info.depthStencilResolveTexture) {
actorInfo.depthStencilResolveTexture = static_cast<TextureValidator *>(info.depthStencilResolveTexture)->getActor();
}
actorInfo.renderPass = static_cast<RenderPassValidator *>(info.renderPass)->getActor();
_actor->initialize(actorInfo);
}
void FramebufferValidator::doDestroy() {
// Destroy twice?
CC_ASSERT(isInited());
_inited = false;
/////////// execute ///////////
_actor->destroy();
}
} // 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/GFXFramebuffer.h"
namespace cc {
namespace gfx {
class CC_DLL FramebufferValidator final : public Agent<Framebuffer> {
public:
explicit FramebufferValidator(Framebuffer *actor);
~FramebufferValidator() override;
inline bool isInited() const { return _inited; }
protected:
void doInit(const FramebufferInfo &info) override;
void doDestroy() override;
bool _inited{false};
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,94 @@
/****************************************************************************
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 "BufferValidator.h"
#include "DeviceValidator.h"
#include "InputAssemblerValidator.h"
#include "ValidationUtils.h"
namespace cc {
namespace gfx {
InputAssemblerValidator::InputAssemblerValidator(InputAssembler *actor)
: Agent<InputAssembler>(actor) {
_typedID = actor->getTypedID();
}
InputAssemblerValidator::~InputAssemblerValidator() {
DeviceResourceTracker<InputAssembler>::erase(this);
CC_SAFE_DELETE(_actor);
}
void InputAssemblerValidator::doInit(const InputAssemblerInfo &info) {
CC_ASSERT(!isInited());
_inited = true;
// vertex attributes validations
for (auto const &attribute : info.attributes) {
// Format not supported for the specified features.
CC_ASSERT(hasFlag(DeviceValidator::getInstance()->getFormatFeatures(attribute.format), FormatFeature::VERTEX_ATTRIBUTE));
}
for (auto *vertexBuffer : info.vertexBuffers) {
CC_ASSERT(vertexBuffer && static_cast<BufferValidator *>(vertexBuffer)->isInited());
CC_ASSERT(hasFlag(vertexBuffer->getUsage(), BufferUsageBit::VERTEX));
}
if (info.indexBuffer) {
CC_ASSERT(static_cast<BufferValidator *>(info.indexBuffer)->isInited());
CC_ASSERT(hasFlag(info.indexBuffer->getUsage(), BufferUsageBit::INDEX));
}
if (info.indirectBuffer) {
CC_ASSERT(static_cast<BufferValidator *>(info.indirectBuffer)->isInited());
CC_ASSERT(hasFlag(info.indirectBuffer->getUsage(), BufferUsageBit::INDIRECT));
}
/////////// execute ///////////
InputAssemblerInfo actorInfo = info;
for (auto &vertexBuffer : actorInfo.vertexBuffers) {
vertexBuffer = static_cast<BufferValidator *>(vertexBuffer)->getActor();
}
if (actorInfo.indexBuffer) {
actorInfo.indexBuffer = static_cast<BufferValidator *>(actorInfo.indexBuffer)->getActor();
}
if (actorInfo.indirectBuffer) {
actorInfo.indirectBuffer = static_cast<BufferValidator *>(actorInfo.indirectBuffer)->getActor();
}
_actor->initialize(actorInfo);
}
void InputAssemblerValidator::doDestroy() {
CC_ASSERT(isInited());
_inited = false;
/////////// execute ///////////
_actor->destroy();
}
} // 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/GFXInputAssembler.h"
namespace cc {
namespace gfx {
class CC_DLL InputAssemblerValidator final : public Agent<InputAssembler> {
public:
explicit InputAssemblerValidator(InputAssembler *actor);
~InputAssemblerValidator() override;
inline bool isInited() const { return _inited; }
protected:
void doInit(const InputAssemblerInfo &info) override;
void doDestroy() override;
bool _inited{false};
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,87 @@
/****************************************************************************
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/Macros.h"
#include "base/threading/MessageQueue.h"
#include "DescriptorSetLayoutValidator.h"
#include "DeviceValidator.h"
#include "PipelineLayoutValidator.h"
#include "ValidationUtils.h"
namespace cc {
namespace gfx {
PipelineLayoutValidator::PipelineLayoutValidator(PipelineLayout *actor)
: Agent<PipelineLayout>(actor) {
_typedID = actor->getTypedID();
}
PipelineLayoutValidator::~PipelineLayoutValidator() {
DeviceResourceTracker<PipelineLayout>::erase(this);
CC_SAFE_DELETE(_actor);
}
void PipelineLayoutValidator::doInit(const PipelineLayoutInfo &info) {
CC_ASSERT(!isInited());
_inited = true;
const auto &bindingMappings{DeviceValidator::getInstance()->bindingMappingInfo()};
// deffered pipeline issue: https://github.com/cocos/cocos-engine/pull/10701
// for (uint32_t i = 0; i < info.setLayouts.size(); ++i) {
// auto *layout{static_cast<DescriptorSetLayoutValidator *>(info.setLayouts[i])};
// CC_ASSERT(layout && layout->isInited());
// // check against limits specified in BindingMappingInfo
// if (bindingMappings.setIndices.back() == i) continue; // flexible set
// CC_ASSERT(layout->_typeCounts[0] <= bindingMappings.maxBlockCounts[i]);
// CC_ASSERT(layout->_typeCounts[1] <= bindingMappings.maxSamplerTextureCounts[i]);
// CC_ASSERT(layout->_typeCounts[2] <= bindingMappings.maxSamplerCounts[i]);
// CC_ASSERT(layout->_typeCounts[3] <= bindingMappings.maxTextureCounts[i]);
// CC_ASSERT(layout->_typeCounts[4] <= bindingMappings.maxBufferCounts[i]);
// CC_ASSERT(layout->_typeCounts[5] <= bindingMappings.maxImageCounts[i]);
// CC_ASSERT(layout->_typeCounts[6] <= bindingMappings.maxSubpassInputCounts[i]);
// }
/////////// execute ///////////
PipelineLayoutInfo actorInfo;
actorInfo.setLayouts.resize(info.setLayouts.size());
for (uint32_t i = 0U; i < info.setLayouts.size(); i++) {
actorInfo.setLayouts[i] = static_cast<DescriptorSetLayoutValidator *>(info.setLayouts[i])->getActor();
}
_actor->initialize(actorInfo);
}
void PipelineLayoutValidator::doDestroy() {
CC_ASSERT(isInited());
_inited = false;
/////////// execute ///////////
_actor->destroy();
}
} // 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/GFXPipelineLayout.h"
namespace cc {
namespace gfx {
class CC_DLL PipelineLayoutValidator final : public Agent<PipelineLayout> {
public:
explicit PipelineLayoutValidator(PipelineLayout *actor);
~PipelineLayoutValidator() override;
inline bool isInited() const { return _inited; }
protected:
void doInit(const PipelineLayoutInfo &info) override;
void doDestroy() override;
bool _inited{false};
};
} // 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/threading/MessageQueue.h"
#include "DeviceValidator.h"
#include "PipelineLayoutValidator.h"
#include "PipelineStateValidator.h"
#include "RenderPassValidator.h"
#include "ShaderValidator.h"
#include "ValidationUtils.h"
namespace cc {
namespace gfx {
PipelineStateValidator::PipelineStateValidator(PipelineState *actor)
: Agent<PipelineState>(actor) {
_typedID = actor->getTypedID();
}
PipelineStateValidator::~PipelineStateValidator() {
DeviceResourceTracker<PipelineState>::erase(this);
CC_SAFE_DELETE(_actor);
}
void PipelineStateValidator::doInit(const PipelineStateInfo &info) {
CC_ASSERT(!isInited());
_inited = true;
CC_ASSERT(info.shader && static_cast<ShaderValidator *>(info.shader)->isInited());
CC_ASSERT(info.pipelineLayout && static_cast<PipelineLayoutValidator *>(info.pipelineLayout)->isInited());
CC_ASSERT(!info.renderPass || static_cast<RenderPassValidator *>(info.renderPass)->isInited());
/////////// execute ///////////
PipelineStateInfo actorInfo = info;
actorInfo.shader = static_cast<ShaderValidator *>(info.shader)->getActor();
actorInfo.pipelineLayout = static_cast<PipelineLayoutValidator *>(info.pipelineLayout)->getActor();
if (info.renderPass) actorInfo.renderPass = static_cast<RenderPassValidator *>(info.renderPass)->getActor();
_actor->initialize(actorInfo);
}
void PipelineStateValidator::doDestroy() {
CC_ASSERT(isInited());
_inited = false;
/////////// execute ///////////
_actor->destroy();
}
} // 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/GFXPipelineState.h"
namespace cc {
namespace gfx {
class CC_DLL PipelineStateValidator final : public Agent<PipelineState> {
public:
explicit PipelineStateValidator(PipelineState *actor);
~PipelineStateValidator() override;
inline bool isInited() const { return _inited; }
protected:
void doInit(const PipelineStateInfo &info) override;
void doDestroy() override;
bool _inited{false};
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,64 @@
/****************************************************************************
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 "QueryPoolValidator.h"
#include "CommandBufferValidator.h"
#include "DeviceValidator.h"
#include "ValidationUtils.h"
namespace cc {
namespace gfx {
QueryPoolValidator::QueryPoolValidator(QueryPool *actor)
: Agent<QueryPool>(actor) {
_typedID = actor->getTypedID();
_type = actor->getType();
_maxQueryObjects = actor->getMaxQueryObjects();
}
QueryPoolValidator::~QueryPoolValidator() {
DeviceResourceTracker<QueryPool>::erase(this);
CC_SAFE_DELETE(_actor);
}
void QueryPoolValidator::doInit(const QueryPoolInfo &info) {
CC_ASSERT(!isInited());
_inited = true;
/////////// execute ///////////
_actor->initialize(info);
}
void QueryPoolValidator::doDestroy() {
CC_ASSERT(isInited());
_inited = false;
/////////// execute ///////////
_actor->destroy();
}
} // 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/GFXQueryPool.h"
namespace cc {
namespace gfx {
class CC_DLL QueryPoolValidator final : public Agent<QueryPool> {
public:
explicit QueryPoolValidator(QueryPool *actor);
~QueryPoolValidator() override;
inline bool isInited() const { return _inited; }
protected:
friend class DeviceValidator;
void doInit(const QueryPoolInfo &info) override;
void doDestroy() override;
bool _inited{false};
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,85 @@
/****************************************************************************
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 "QueueValidator.h"
#include "CommandBufferValidator.h"
#include "DeviceValidator.h"
#include "ValidationUtils.h"
namespace cc {
namespace gfx {
QueueValidator::QueueValidator(Queue *actor)
: Agent<Queue>(actor) {
_typedID = actor->getTypedID();
}
QueueValidator::~QueueValidator() {
DeviceResourceTracker<Queue>::erase(this);
CC_SAFE_DELETE(_actor);
}
void QueueValidator::doInit(const QueueInfo &info) {
CC_ASSERT(!isInited());
_inited = true;
/////////// execute ///////////
_actor->initialize(info);
}
void QueueValidator::doDestroy() {
CC_ASSERT(isInited());
_inited = false;
/////////// execute ///////////
_actor->destroy();
}
void QueueValidator::submit(CommandBuffer *const *cmdBuffs, uint32_t count) {
CC_ASSERT(isInited());
if (!count) return;
for (uint32_t i = 0U; i < count; ++i) {
auto *cmdBuff = static_cast<CommandBufferValidator *>(cmdBuffs[i]);
CC_ASSERT(cmdBuff && cmdBuff->isInited());
// Command buffers must be flushed before submit.
CC_ASSERT(cmdBuff->isCommandsFlushed());
}
/////////// execute ///////////
static ccstd::vector<CommandBuffer *> cmdBuffActors;
cmdBuffActors.resize(count);
for (uint32_t i = 0U; i < count; ++i) {
cmdBuffActors[i] = static_cast<CommandBufferValidator *>(cmdBuffs[i])->getActor();
}
_actor->submit(cmdBuffActors.data(), count);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,54 @@
/****************************************************************************
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 QueueValidator final : public Agent<Queue> {
public:
using Queue::submit;
explicit QueueValidator(Queue *actor);
~QueueValidator() override;
void submit(CommandBuffer *const *cmdBuffs, uint32_t count) override;
inline bool isInited() const { return _inited; }
protected:
friend class DeviceValidator;
void doInit(const QueueInfo &info) override;
void doDestroy() override;
bool _inited{false};
};
} // 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 "DeviceValidator.h"
#include "RenderPassValidator.h"
#include "ValidationUtils.h"
namespace cc {
namespace gfx {
RenderPassValidator::RenderPassValidator(RenderPass *actor)
: Agent<RenderPass>(actor) {
_typedID = actor->getTypedID();
}
RenderPassValidator::~RenderPassValidator() {
DeviceResourceTracker<RenderPass>::erase(this);
CC_SAFE_DELETE(_actor);
}
void RenderPassValidator::doInit(const RenderPassInfo &info) {
CC_ASSERT(!isInited());
_inited = true;
bool hasDepth = info.depthStencilAttachment.format != Format::UNKNOWN;
if (!hasDepth) {
for (const auto &subpass : info.subpasses) {
CC_ASSERT(subpass.depthStencil == INVALID_BINDING || subpass.depthStencil < info.colorAttachments.size());
}
}
/////////// execute ///////////
_actor->initialize(info);
}
void RenderPassValidator::doDestroy() {
CC_ASSERT(isInited());
_inited = false;
/////////// execute ///////////
_actor->destroy();
}
} // 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/GFXRenderPass.h"
namespace cc {
namespace gfx {
class CC_DLL RenderPassValidator final : public Agent<RenderPass> {
public:
explicit RenderPassValidator(RenderPass *actor);
~RenderPassValidator() override;
inline bool isInited() const { return _inited; }
protected:
void doInit(const RenderPassInfo &info) override;
void doDestroy() override;
bool _inited{false};
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,63 @@
/****************************************************************************
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 "DeviceValidator.h"
#include "ShaderValidator.h"
#include "ValidationUtils.h"
namespace cc {
namespace gfx {
ShaderValidator::ShaderValidator(Shader *actor)
: Agent<Shader>(actor) {
_typedID = actor->getTypedID();
}
ShaderValidator::~ShaderValidator() {
DeviceResourceTracker<Shader>::erase(this);
CC_SAFE_DELETE(_actor);
}
void ShaderValidator::doInit(const ShaderInfo &info) {
CC_ASSERT(!isInited());
_inited = true;
/////////// execute ///////////
_actor->initialize(info);
}
void ShaderValidator::doDestroy() {
CC_ASSERT(isInited());
_inited = false;
/////////// execute ///////////
_actor->destroy();
}
} // 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/GFXShader.h"
namespace cc {
namespace gfx {
class CC_DLL ShaderValidator final : public Agent<Shader> {
public:
explicit ShaderValidator(Shader *actor);
~ShaderValidator() override;
inline bool isInited() const { return _inited; }
protected:
void doInit(const ShaderInfo &info) override;
void doDestroy() override;
bool _inited{false};
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,125 @@
/****************************************************************************
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 "SwapchainValidator.h"
#include "ValidationUtils.h"
#include "gfx-base/GFXDef.h"
#include "gfx-validator/DeviceValidator.h"
#include "gfx-validator/TextureValidator.h"
namespace cc {
namespace gfx {
SwapchainValidator::SwapchainValidator(Swapchain *actor)
: Agent<Swapchain>(actor) {
_typedID = actor->getTypedID();
_preRotationEnabled = static_cast<SwapchainValidator *>(actor)->_preRotationEnabled;
}
SwapchainValidator::~SwapchainValidator() {
DeviceResourceTracker<Swapchain>::erase(this);
CC_SAFE_DELETE(_actor);
}
void SwapchainValidator::doInit(const SwapchainInfo &info) {
CC_ASSERT(!isInited());
_inited = true;
/////////// execute ///////////
_actor->initialize(info);
auto *colorTexture = ccnew TextureValidator(_actor->getColorTexture());
colorTexture->renounceOwnership();
_colorTexture = colorTexture;
DeviceResourceTracker<Texture>::push(_colorTexture.get());
auto *depthStencilTexture = ccnew TextureValidator(_actor->getDepthStencilTexture());
depthStencilTexture->renounceOwnership();
_depthStencilTexture = depthStencilTexture;
DeviceResourceTracker<Texture>::push(_depthStencilTexture.get());
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 SwapchainValidator::doDestroy() {
CC_ASSERT(isInited());
_inited = false;
/////////// execute ///////////
_depthStencilTexture = nullptr;
_colorTexture = nullptr;
_actor->destroy();
}
void SwapchainValidator::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 SwapchainValidator::doResize(uint32_t width, uint32_t height, SurfaceTransform transform) {
CC_ASSERT(isInited());
_actor->resize(width, height, transform);
updateInfo();
}
void SwapchainValidator::doDestroySurface() {
CC_ASSERT(isInited());
_actor->destroySurface();
}
void SwapchainValidator::doCreateSurface(void *windowHandle) {
CC_ASSERT(isInited());
_actor->createSurface(windowHandle);
updateInfo();
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,53 @@
/****************************************************************************
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/GFXDef-common.h"
#include "gfx-base/GFXSwapchain.h"
namespace cc {
namespace gfx {
class CC_DLL SwapchainValidator final : public Agent<Swapchain> {
public:
explicit SwapchainValidator(Swapchain *actor);
~SwapchainValidator() override;
inline bool isInited() const { return _inited; }
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();
bool _inited{false};
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,177 @@
/****************************************************************************
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 "TextureValidator.h"
#include "DeviceValidator.h"
#include "SwapchainValidator.h"
#include "ValidationUtils.h"
#include "gfx-base/GFXDef-common.h"
namespace cc {
namespace gfx {
namespace {
struct EnumHasher final {
template <typename T, typename Enable = std::enable_if_t<std::is_enum<T>::value>>
size_t operator()(const T &v) const {
return static_cast<size_t>(v);
}
};
ccstd::unordered_map<Format, Feature, EnumHasher> featureCheckMap{};
} // namespace
TextureValidator::TextureValidator(Texture *actor)
: Agent<Texture>(actor) {
_typedID = actor->getTypedID();
}
TextureValidator::~TextureValidator() {
DeviceResourceTracker<Texture>::erase(this);
if (_ownTheActor) CC_SAFE_DELETE(_actor);
}
void TextureValidator::doInit(const TextureInfo &info) {
CC_ASSERT(!isInited());
_inited = true;
CC_ASSERT(info.width && info.height && info.depth);
FormatFeature ff = FormatFeature::NONE;
if (hasAnyFlags(info.usage, TextureUsageBit::COLOR_ATTACHMENT | TextureUsageBit::DEPTH_STENCIL_ATTACHMENT)) ff |= FormatFeature::RENDER_TARGET;
if (hasAnyFlags(info.usage, TextureUsageBit::SAMPLED)) ff |= FormatFeature::SAMPLED_TEXTURE;
if (hasAnyFlags(info.usage, TextureUsageBit::STORAGE)) ff |= FormatFeature::STORAGE_TEXTURE;
if (ff != FormatFeature::NONE) {
CC_ASSERT(hasAllFlags(DeviceValidator::getInstance()->getFormatFeatures(info.format), ff));
}
switch (info.type) {
case TextureType::TEX2D: {
if (std::max(info.width, info.height) > DeviceValidator::getInstance()->getCapabilities().maxTextureSize) {
CC_ABORT();
}
break;
}
case TextureType::TEX1D_ARRAY: {
if (std::min(info.width, info.height) > 1 || std::max(info.width, info.height) > DeviceValidator::getInstance()->getCapabilities().maxTextureSize || info.layerCount > DeviceValidator::getInstance()->getCapabilities().maxArrayTextureLayers) {
CC_ABORT();
}
break;
}
case TextureType::TEX2D_ARRAY: {
if (std::max(info.width, info.height) > DeviceValidator::getInstance()->getCapabilities().maxTextureSize || info.layerCount > DeviceValidator::getInstance()->getCapabilities().maxArrayTextureLayers) {
CC_ABORT();
}
break;
}
case TextureType::CUBE: {
if (std::max(info.width, info.height) > DeviceValidator::getInstance()->getCapabilities().maxCubeMapTextureSize || info.layerCount != 6) {
CC_ABORT();
}
break;
}
case TextureType::TEX3D: {
if (std::max(std::max(info.width, info.height), info.depth) > DeviceValidator::getInstance()->getCapabilities().maxCubeMapTextureSize) {
CC_ABORT();
}
break;
}
default: {
CC_ABORT();
break;
}
}
if (hasFlag(info.flags, TextureFlagBit::GEN_MIPMAP)) {
CC_ASSERT(info.levelCount > 1);
bool isCompressed = GFX_FORMAT_INFOS[static_cast<int>(info.format)].isCompressed;
CC_ASSERT(!isCompressed);
}
/////////// execute ///////////
_actor->initialize(info);
}
void TextureValidator::doInit(const TextureViewInfo &info) {
CC_ASSERT(!isInited());
_inited = true;
_isTextureView = true;
CC_ASSERT(info.texture && static_cast<TextureValidator *>(info.texture)->isInited());
/////////// execute ///////////
TextureViewInfo actorInfo = info;
actorInfo.texture = static_cast<TextureValidator *>(info.texture)->getActor();
_actor->initialize(actorInfo);
}
void TextureValidator::doInit(const SwapchainTextureInfo &info) {
CC_ASSERT(!isInited());
_inited = true;
CC_UNUSED_PARAM(info); // workaround tidy issue
CC_ASSERT(info.swapchain && static_cast<SwapchainValidator *>(info.swapchain)->isInited());
// the actor is already initialized
}
void TextureValidator::doDestroy() {
CC_ASSERT(isInited());
_inited = false;
/////////// execute ///////////
_actor->destroy();
}
void TextureValidator::doResize(uint32_t width, uint32_t height, uint32_t /*size*/) {
CC_ASSERT(isInited());
// Cannot resize texture views.
CC_ASSERT(!_isTextureView);
/////////// execute ///////////
_actor->resize(width, height);
}
void TextureValidator::sanityCheck() {
CC_ASSERT(isInited());
uint64_t cur = DeviceValidator::getInstance()->currentFrame();
// FIXME: minggo: as current implementation need to update some textures more than once, so disable it.
// Should enable it when it is fixed.
// if (cur == _lastUpdateFrame) {
// CC_LOG_WARNING(utils::getStacktraceJS().c_str());
// CC_LOG_WARNING("performance warning: texture updated more than once per frame");
// }
_lastUpdateFrame = cur;
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,62 @@
/****************************************************************************
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 TextureValidator final : public Agent<Texture> {
public:
explicit TextureValidator(Texture *actor);
~TextureValidator() override;
void sanityCheck();
inline void renounceOwnership() { _ownTheActor = false; }
inline bool isInited() const { return _inited; }
const Texture *getRaw() const override { return _actor->getRaw(); }
uint32_t getGLTextureHandle() const noexcept override { return _actor->getGLTextureHandle(); }
protected:
friend class SwapchainValidator;
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;
uint64_t _lastUpdateFrame{0U};
bool _ownTheActor{true};
bool _inited{false};
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,112 @@
/****************************************************************************
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 "ValidationUtils.h"
#include "DeviceValidator.h"
#ifndef CC_WGPU_WASM
#include "bindings/jswrapper/SeApi.h"
#endif
#include "gfx-base/GFXInputAssembler.h"
#include "gfx-base/GFXPipelineState.h"
#include "gfx-base/GFXRenderPass.h"
namespace cc {
namespace utils {
ccstd::string getStacktraceJS() {
#ifndef CC_WGPU_WASM
if (!gfx::DeviceValidator::allowStacktraceJS) return "";
return se::ScriptEngine::getInstance()->getCurrentStackTrace();
#else
return "";
#endif
}
} // namespace utils
namespace gfx {
void CommandRecorder::recordBeginRenderPass(const RenderPassSnapshot &renderPass) {
_renderPassCommands.emplace_back();
RenderPassCommand &command = _renderPassCommands.back();
command.renderArea = renderPass.renderArea;
command.clearColors = renderPass.clearColors;
command.clearDepth = renderPass.clearDepth;
command.clearStencil = renderPass.clearStencil;
command.colorAttachments = renderPass.renderPass->getColorAttachments();
command.depthStencilAttachment = renderPass.renderPass->getDepthStencilAttachment();
_commands.push_back(CommandType::BEGIN_RENDER_PASS);
}
void CommandRecorder::recordDrawcall(const DrawcallSnapshot &drawcall) {
_drawcallCommands.emplace_back();
DrawcallCommand &command = _drawcallCommands.back();
command.inputState = drawcall.pipelineState->getInputState();
command.rasterizerState = drawcall.pipelineState->getRasterizerState();
command.depthStencilState = drawcall.pipelineState->getDepthStencilState();
command.blendState = drawcall.pipelineState->getBlendState();
command.primitive = drawcall.pipelineState->getPrimitive();
command.dynamicStates = drawcall.pipelineState->getDynamicStates();
command.bindPoint = drawcall.pipelineState->getBindPoint();
command.drawInfo = drawcall.inputAssembler->getDrawInfo();
command.descriptorSets = drawcall.descriptorSets;
for (const auto &offsets : drawcall.dynamicOffsets) command.dynamicOffsets.insert(command.dynamicOffsets.end(), offsets.begin(), offsets.end());
_commands.push_back(CommandType::DRAW);
}
void CommandRecorder::recordEndRenderPass() {
_commands.push_back(CommandType::END_RENDER_PASS);
}
void CommandRecorder::clear() {
_commands.clear();
_renderPassCommands.clear();
_drawcallCommands.clear();
}
ccstd::vector<uint32_t> CommandRecorder::serialize(const CommandRecorder &recorder) {
ccstd::vector<uint32_t> bytes;
bytes.push_back(static_cast<uint32_t>(recorder._commands.size()));
return bytes;
}
CommandRecorder CommandRecorder::deserialize(const ccstd::vector<uint32_t> &bytes) {
CommandRecorder recorder;
recorder._commands.resize(bytes[0]);
return recorder;
}
bool CommandRecorder::compare(const CommandRecorder &test, const CommandRecorder &baseline) {
return test._commands.empty() && baseline._commands.empty();
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,190 @@
/****************************************************************************
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 <algorithm>
#include "base/Utils.h"
#include "base/std/container/array.h"
#include "gfx-base/GFXDef.h"
namespace cc {
namespace utils {
ccstd::string getStacktraceJS();
} // namespace utils
namespace gfx {
struct RenderPassSnapshot {
RenderPass *renderPass = nullptr;
Framebuffer *framebuffer = nullptr;
Rect renderArea;
ccstd::vector<Color> clearColors;
float clearDepth = 1.F;
uint32_t clearStencil = 0U;
};
struct DrawcallSnapshot {
PipelineState *pipelineState;
InputAssembler *inputAssembler;
ccstd::vector<DescriptorSet *> descriptorSets;
ccstd::vector<ccstd::vector<uint32_t>> dynamicOffsets;
};
struct CommandBufferStorage : public DynamicStates, RenderPassSnapshot, DrawcallSnapshot {};
class CommandRecorder {
public:
void recordBeginRenderPass(const RenderPassSnapshot &renderPass);
void recordDrawcall(const DrawcallSnapshot &drawcall);
void recordEndRenderPass();
void clear();
static ccstd::vector<uint32_t> serialize(const CommandRecorder &recorder);
static CommandRecorder deserialize(const ccstd::vector<uint32_t> &bytes);
static bool compare(const CommandRecorder &test, const CommandRecorder &baseline);
private:
enum class CommandType {
BEGIN_RENDER_PASS,
END_RENDER_PASS,
DRAW
};
struct RenderPassCommand {
ColorAttachmentList colorAttachments;
DepthStencilAttachment depthStencilAttachment;
Rect renderArea;
ccstd::vector<Color> clearColors;
float clearDepth = 1.F;
uint32_t clearStencil = 0U;
};
struct DrawcallCommand {
InputState inputState;
RasterizerState rasterizerState;
DepthStencilState depthStencilState;
BlendState blendState;
PrimitiveMode primitive = PrimitiveMode::TRIANGLE_LIST;
DynamicStateFlags dynamicStates = DynamicStateFlagBit::NONE;
PipelineBindPoint bindPoint = PipelineBindPoint::GRAPHICS;
DrawInfo drawInfo;
ccstd::vector<DescriptorSet *> descriptorSets;
ccstd::vector<uint32_t> dynamicOffsets;
};
ccstd::vector<CommandType> _commands;
ccstd::vector<RenderPassCommand> _renderPassCommands;
ccstd::vector<DrawcallCommand> _drawcallCommands;
struct BufferData {
BufferInfo info;
ccstd::vector<uint8_t> data;
};
ccstd::unordered_map<uint32_t, BufferData> _bufferMap;
};
//////////////////////////////////////////////////////////////////////////
template <typename T>
struct RecordStacktrace : std::false_type {};
template <typename Resource, typename Enable = std::enable_if_t<std::is_base_of<GFXObject, Resource>::value>>
class DeviceResourceTracker {
public:
template <typename T, typename = std::enable_if_t<std::is_same<Resource, T>::value>>
static std::enable_if_t<RecordStacktrace<T>::value, void> push(T *resource);
template <typename T, typename = std::enable_if_t<std::is_same<Resource, T>::value>>
static std::enable_if_t<!RecordStacktrace<T>::value, void> push(T *resource);
static void erase(Resource *resource);
static void checkEmpty();
private:
struct ResourceRecord {
Resource *resource = nullptr;
ccstd::string initStack;
};
static ccstd::vector<ResourceRecord> resources;
};
template <typename Resource, typename Enable>
ccstd::vector<typename DeviceResourceTracker<Resource, Enable>::ResourceRecord> DeviceResourceTracker<Resource, Enable>::resources;
template <typename Resource, typename Enable>
template <typename T, typename EnableFn>
std::enable_if_t<RecordStacktrace<T>::value, void>
DeviceResourceTracker<Resource, Enable>::push(T *resource) {
resources.emplace_back(ResourceRecord{resource, utils::getStacktrace(6, 10)});
}
template <typename Resource, typename Enable>
template <typename T, typename EnableFn>
std::enable_if_t<!RecordStacktrace<T>::value, void>
DeviceResourceTracker<Resource, Enable>::push(T *resource) {
resources.emplace_back(ResourceRecord{resource, {}});
}
template <typename Resource, typename Enable>
void DeviceResourceTracker<Resource, Enable>::erase(Resource *resource) {
CC_ASSERT(!resources.empty());
resources.erase(std::remove_if(resources.begin(), resources.end(),
[resource](const auto &record) { return record.resource == resource; }));
}
template <typename Resource, typename Enable>
void DeviceResourceTracker<Resource, Enable>::checkEmpty() {
// If this assertion is hit, it means you have leaked gfx resources.
// You can debug this by uncomment the `record_stacktrace` template specialization for the relevant type
// and look up the resource initialization stacktrace in `resources[i].initStack`.
// Note: capturing stacktrace is a painfully time-consuming process,
// so better to uncomment the exact type of resource that is leaking rather than toggle them all at once.
CC_ASSERT(resources.empty()); // Resource leaked.
}
//template <> struct RecordStacktrace<CommandBuffer> : std::true_type {};
//template <> struct RecordStacktrace<Queue> : std::true_type {};
//template <> struct RecordStacktrace<Buffer> : std::true_type {};
//template <> struct RecordStacktrace<Texture> : std::true_type {};
//template <> struct RecordStacktrace<Sampler> : std::true_type {};
//template <> struct RecordStacktrace<Shader> : std::true_type {};
//template <> struct RecordStacktrace<InputAssembler> : std::true_type {};
//template <> struct RecordStacktrace<RenderPass> : std::true_type {};
//template <> struct RecordStacktrace<Framebuffer> : std::true_type {};
//template <> struct RecordStacktrace<DescriptorSet> : std::true_type {};
//template <> struct RecordStacktrace<DescriptorSetLayout> : std::true_type {};
//template <> struct RecordStacktrace<PipelineLayout> : std::true_type {};
//template <> struct RecordStacktrace<PipelineState> : std::true_type {};
} // namespace gfx
} // namespace cc