validate Engine in all Builder::build() methods

We now assert if the Engine given is invalid,
which would happen if it was used after being
destroyed.

Builder::build() is a reasonable place for this since it's generally
not in the critical path.
This commit is contained in:
Mathias Agopian
2019-10-03 16:09:57 -07:00
committed by Mathias Agopian
parent 2fa08123a0
commit 2548da9aed
12 changed files with 46 additions and 24 deletions

View File

@@ -94,29 +94,50 @@ FEngine* FEngine::create(Backend backend, Platform* platform, void* sharedGLCont
instance->mOwnPlatform = true;
}
instance->mDriver = platform->createDriver(sharedGLContext);
instance->init();
instance->execute();
return instance;
} else {
// start the driver thread
instance->mDriverThread = std::thread(&FEngine::loop, instance);
// wait for the driver to be ready
instance->mDriverBarrier.await();
if (UTILS_UNLIKELY(!instance->mDriver)) {
// something went horribly wrong during driver initialization
instance->mDriverThread.join();
return nullptr;
}
}
// start the driver thread
instance->mDriverThread = std::thread(&FEngine::loop, instance);
// wait for the driver to be ready
instance->mDriverBarrier.await();
if (UTILS_UNLIKELY(!instance->mDriver)) {
// something went horribly wrong during driver initialization
instance->mDriverThread.join();
return nullptr;
// Add this Engine to the list of active Engines
{ // scope for the lock
std::unique_ptr<FEngine> engine(instance);
std::lock_guard<std::mutex> guard(sEnginesLock);
Engine* handle = engine.get();
sEngines[handle] = std::move(engine);
}
// now we can initialize the largest part of the engine
instance->init();
if (!UTILS_HAS_THREADING) {
instance->execute();
}
return instance;
}
void FEngine::assertValid(Engine const& engine) {
bool valid;
{ // scope for the lock
std::lock_guard<std::mutex> guard(sEnginesLock);
auto const& engines = sEngines;
auto const& pos = engines.find(&engine);
valid = pos != engines.end();
}
ASSERT_POSTCONDITION(valid,
"Using an Engine instance (@ %p) after it's been destroyed", &engine);
}
// these must be static because only a pointer is copied to the render stream
// Note that these coordinates are specified in OpenGL clip space. Other backends can transform
@@ -748,16 +769,7 @@ bool FEngine::execute() {
using namespace details;
Engine* Engine::create(Backend backend, Platform* platform, void* sharedGLContext) {
std::unique_ptr<FEngine> engine(FEngine::create(backend, platform, sharedGLContext));
if (UTILS_UNLIKELY(!engine)) {
// something went wrong during the driver or engine initialization
return nullptr;
}
std::lock_guard<std::mutex> guard(sEnginesLock);
Engine* handle = engine.get();
sEngines[handle] = std::move(engine);
return handle;
return FEngine::create(backend, platform, sharedGLContext);
}
void Engine::destroy(Engine* engine) {

View File

@@ -48,6 +48,7 @@ IndexBuffer::Builder& IndexBuffer::Builder::bufferType(IndexType indexType) noex
}
IndexBuffer* IndexBuffer::Builder::build(Engine& engine) {
FEngine::assertValid(engine);
return upcast(engine).createIndexBuffer(*this);
}

View File

@@ -148,6 +148,7 @@ IndirectLight::Builder& IndirectLight::Builder::rotation(mat3f const& rotation)
}
IndirectLight* IndirectLight::Builder::build(Engine& engine) {
FEngine::assertValid(engine);
if (mImpl->mReflectionsMap) {
if (!ASSERT_POSTCONDITION_NON_FATAL(
mImpl->mReflectionsMap->getTarget() == Texture::Sampler::SAMPLER_CUBEMAP,

View File

@@ -73,6 +73,7 @@ Material::Builder& Material::Builder::package(const void* payload, size_t size)
}
Material* Material::Builder::build(Engine& engine) {
FEngine::assertValid(engine);
MaterialParser* materialParser = FMaterial::createParser(
upcast(engine).getBackend(), mImpl->mPayload, mImpl->mSize);

View File

@@ -61,6 +61,7 @@ RenderTarget::Builder& RenderTarget::Builder::layer(AttachmentPoint pt, uint32_t
}
RenderTarget* RenderTarget::Builder::build(Engine& engine) {
FEngine::assertValid(engine);
using backend::TextureUsage;
const FRenderTarget::Attachment& color = mImpl->mAttachments[COLOR];
const FRenderTarget::Attachment& depth = mImpl->mAttachments[DEPTH];

View File

@@ -69,6 +69,7 @@ Skybox::Builder& Skybox::Builder::showSun(bool show) noexcept {
}
Skybox* Skybox::Builder::build(Engine& engine) {
FEngine::assertValid(engine);
FTexture* cubemap = upcast(mImpl->mEnvironmentMap);
if (!ASSERT_PRECONDITION_NON_FATAL(cubemap, "environment texture not set")) {

View File

@@ -69,7 +69,7 @@ Stream::Builder& Stream::Builder::height(uint32_t height) noexcept {
}
Stream* Stream::Builder::build(Engine& engine) {
FEngine::assertValid(engine);
if (!ASSERT_PRECONDITION_NON_FATAL(!mImpl->mStream || !mImpl->mExternalTextureId,
"One and only one of the stream or external texture can be specified")) {
return nullptr;

View File

@@ -92,6 +92,7 @@ Texture::Builder& Texture::Builder::usage(Texture::Usage usage) noexcept {
}
Texture* Texture::Builder::build(Engine& engine) {
FEngine::assertValid(engine);
if (!ASSERT_POSTCONDITION_NON_FATAL(Texture::isTextureFormatSupported(engine, mImpl->mFormat),
"Texture format %u not supported on this platform", mImpl->mFormat)) {
return nullptr;

View File

@@ -110,10 +110,10 @@ VertexBuffer::Builder& VertexBuffer::Builder::normalized(VertexAttribute attribu
}
VertexBuffer* VertexBuffer::Builder::build(Engine& engine) {
FEngine::assertValid(engine);
if (!ASSERT_PRECONDITION_NON_FATAL(mImpl->mVertexCount > 0, "vertexCount cannot be 0")) {
return nullptr;
}
if (!ASSERT_PRECONDITION_NON_FATAL(mImpl->mBufferCount > 0, "bufferCount cannot be 0")) {
return nullptr;
}

View File

@@ -130,6 +130,7 @@ LightManager::Builder& LightManager::Builder::sunHaloFalloff(float haloFalloff)
}
LightManager::Builder::Result LightManager::Builder::build(Engine& engine, Entity entity) {
FEngine::assertValid(engine);
upcast(engine).createLight(*this, entity);
return Success;
}

View File

@@ -167,6 +167,7 @@ RenderableManager::Builder& RenderableManager::Builder::blendOrder(size_t index,
}
RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& engine, Entity entity) {
FEngine::assertValid(engine);
bool isEmpty = true;
if (!ASSERT_PRECONDITION_NON_FATAL(mImpl->mSkinningBoneCount <= CONFIG_MAX_BONE_COUNT,

View File

@@ -132,6 +132,8 @@ public:
static FEngine* create(Backend backend = Backend::DEFAULT,
Platform* platform = nullptr, void* sharedGLContext = nullptr);
static void assertValid(Engine const& engine);
~FEngine() noexcept;
backend::Driver& getDriver() const noexcept { return *mDriver; }