Fix crashes in entity rendering on OSX

This commit is contained in:
Bradley Austin Davis 2017-09-07 14:32:50 -07:00
parent a0ae9ee747
commit 37b184d982
6 changed files with 70 additions and 55 deletions

View file

@ -91,20 +91,27 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi
qCWarning(entitiesrenderer) << "Bad particle properties"; qCWarning(entitiesrenderer) << "Bad particle properties";
} }
} }
if (_particleProperties != newParticleProperties) {
if (resultWithReadLock<bool>([&]{ return _particleProperties != newParticleProperties; })) {
_timeUntilNextEmit = 0; _timeUntilNextEmit = 0;
_particleProperties = newParticleProperties; withWriteLock([&]{
_particleProperties = newParticleProperties;
});
} }
_emitting = entity->getIsEmitting(); _emitting = entity->getIsEmitting();
if (_particleProperties.textures.isEmpty()) { bool hasTexture = resultWithReadLock<bool>([&]{ return _particleProperties.textures.isEmpty(); });
if (hasTexture) {
if (_networkTexture) { if (_networkTexture) {
withWriteLock([&] { withWriteLock([&] {
_networkTexture.reset(); _networkTexture.reset();
}); });
} }
} else { } else {
if (!_networkTexture || _networkTexture->getURL() != QUrl(_particleProperties.textures)) { bool textureNeedsUpdate = resultWithReadLock<bool>([&]{
return !_networkTexture || _networkTexture->getURL() != QUrl(_particleProperties.textures);
});
if (textureNeedsUpdate) {
withWriteLock([&] { withWriteLock([&] {
_networkTexture = DependencyManager::get<TextureCache>()->getTexture(_particleProperties.textures); _networkTexture = DependencyManager::get<TextureCache>()->getTexture(_particleProperties.textures);
}); });
@ -115,15 +122,17 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi
void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
// Fill in Uniforms structure // Fill in Uniforms structure
ParticleUniforms particleUniforms; ParticleUniforms particleUniforms;
particleUniforms.radius.start = _particleProperties.radius.range.start; withReadLock([&]{
particleUniforms.radius.middle = _particleProperties.radius.gradient.target; particleUniforms.radius.start = _particleProperties.radius.range.start;
particleUniforms.radius.finish = _particleProperties.radius.range.finish; particleUniforms.radius.middle = _particleProperties.radius.gradient.target;
particleUniforms.radius.spread = _particleProperties.radius.gradient.spread; particleUniforms.radius.finish = _particleProperties.radius.range.finish;
particleUniforms.color.start = _particleProperties.getColorStart(); particleUniforms.radius.spread = _particleProperties.radius.gradient.spread;
particleUniforms.color.middle = _particleProperties.getColorMiddle(); particleUniforms.color.start = _particleProperties.getColorStart();
particleUniforms.color.finish = _particleProperties.getColorFinish(); particleUniforms.color.middle = _particleProperties.getColorMiddle();
particleUniforms.color.spread = _particleProperties.getColorSpread(); particleUniforms.color.finish = _particleProperties.getColorFinish();
particleUniforms.lifespan = _particleProperties.lifespan; particleUniforms.color.spread = _particleProperties.getColorSpread();
particleUniforms.lifespan = _particleProperties.lifespan;
});
// Update particle uniforms // Update particle uniforms
memcpy(&_uniformBuffer.edit<ParticleUniforms>(), &particleUniforms, sizeof(ParticleUniforms)); memcpy(&_uniformBuffer.edit<ParticleUniforms>(), &particleUniforms, sizeof(ParticleUniforms));
} }
@ -146,35 +155,26 @@ Item::Bound ParticleEffectEntityRenderer::getBound() {
static const size_t VERTEX_PER_PARTICLE = 4; static const size_t VERTEX_PER_PARTICLE = 4;
bool ParticleEffectEntityRenderer::emitting() const { ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties) {
return (
_emitting &&
_particleProperties.emission.rate > 0.0f &&
_particleProperties.lifespan > 0.0f &&
_particleProperties.polar.start <= _particleProperties.polar.finish
);
}
void ParticleEffectEntityRenderer::createParticle(uint64_t now) {
CpuParticle particle; CpuParticle particle;
const auto& accelerationSpread = _particleProperties.emission.acceleration.spread; const auto& accelerationSpread = particleProperties.emission.acceleration.spread;
const auto& azimuthStart = _particleProperties.azimuth.start; const auto& azimuthStart = particleProperties.azimuth.start;
const auto& azimuthFinish = _particleProperties.azimuth.finish; const auto& azimuthFinish = particleProperties.azimuth.finish;
const auto& emitDimensions = _particleProperties.emission.dimensions; const auto& emitDimensions = particleProperties.emission.dimensions;
const auto& emitAcceleration = _particleProperties.emission.acceleration.target; const auto& emitAcceleration = particleProperties.emission.acceleration.target;
auto emitOrientation = _particleProperties.emission.orientation; auto emitOrientation = particleProperties.emission.orientation;
const auto& emitRadiusStart = glm::max(_particleProperties.radiusStart, EPSILON); // Avoid math complications at center const auto& emitRadiusStart = glm::max(particleProperties.radiusStart, EPSILON); // Avoid math complications at center
const auto& emitSpeed = _particleProperties.emission.speed.target; const auto& emitSpeed = particleProperties.emission.speed.target;
const auto& speedSpread = _particleProperties.emission.speed.spread; const auto& speedSpread = particleProperties.emission.speed.spread;
const auto& polarStart = _particleProperties.polar.start; const auto& polarStart = particleProperties.polar.start;
const auto& polarFinish = _particleProperties.polar.finish; const auto& polarFinish = particleProperties.polar.finish;
particle.seed = randFloatInRange(-1.0f, 1.0f); particle.seed = randFloatInRange(-1.0f, 1.0f);
particle.expiration = now + (uint64_t)(_particleProperties.lifespan * USECS_PER_SECOND); particle.expiration = now + (uint64_t)(particleProperties.lifespan * USECS_PER_SECOND);
if (_particleProperties.emission.shouldTrail) { if (particleProperties.emission.shouldTrail) {
particle.position = _modelTransform.getTranslation(); particle.position = baseTransform.getTranslation();
emitOrientation = _modelTransform.getRotation() * emitOrientation; emitOrientation = baseTransform.getRotation() * emitOrientation;
} }
// Position, velocity, and acceleration // Position, velocity, and acceleration
@ -232,7 +232,7 @@ void ParticleEffectEntityRenderer::createParticle(uint64_t now) {
particle.acceleration = emitAcceleration + randFloatInRange(-1.0f, 1.0f) * accelerationSpread; particle.acceleration = emitAcceleration + randFloatInRange(-1.0f, 1.0f) * accelerationSpread;
} }
_cpuParticles.push_back(particle); return particle;
} }
void ParticleEffectEntityRenderer::stepSimulation() { void ParticleEffectEntityRenderer::stepSimulation() {
@ -244,14 +244,19 @@ void ParticleEffectEntityRenderer::stepSimulation() {
const auto now = usecTimestampNow(); const auto now = usecTimestampNow();
const auto interval = std::min<uint64_t>(USECS_PER_SECOND / 60, now - _lastSimulated); const auto interval = std::min<uint64_t>(USECS_PER_SECOND / 60, now - _lastSimulated);
_lastSimulated = now; _lastSimulated = now;
particle::Properties particleProperties;
withReadLock([&]{
particleProperties = _particleProperties;
});
if (emitting()) { if (_emitting && particleProperties.emitting()) {
uint64_t emitInterval = (uint64_t)(USECS_PER_SECOND / _particleProperties.emission.rate); uint64_t emitInterval = particleProperties.emitIntervalUsecs();
if (interval >= _timeUntilNextEmit) { if (emitInterval > 0 && interval >= _timeUntilNextEmit) {
auto timeRemaining = interval; auto timeRemaining = interval;
while (timeRemaining > _timeUntilNextEmit) { while (timeRemaining > _timeUntilNextEmit) {
// emit particle // emit particle
createParticle(now); _cpuParticles.push_back(createParticle(now, _modelTransform, particleProperties));
_timeUntilNextEmit = emitInterval; _timeUntilNextEmit = emitInterval;
if (emitInterval < timeRemaining) { if (emitInterval < timeRemaining) {
timeRemaining -= emitInterval; timeRemaining -= emitInterval;
@ -263,7 +268,7 @@ void ParticleEffectEntityRenderer::stepSimulation() {
} }
// Kill any particles that have expired or are over the max size // Kill any particles that have expired or are over the max size
while (_cpuParticles.size() > _particleProperties.maxParticles || (!_cpuParticles.empty() && _cpuParticles.front().expiration <= now)) { while (_cpuParticles.size() > particleProperties.maxParticles || (!_cpuParticles.empty() && _cpuParticles.front().expiration <= now)) {
_cpuParticles.pop_front(); _cpuParticles.pop_front();
} }

View file

@ -93,9 +93,8 @@ private:
}; };
void createParticle(uint64_t now); static CpuParticle createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties);
void stepSimulation(); void stepSimulation();
bool emitting() const;
particle::Properties _particleProperties; particle::Properties _particleProperties;
CpuParticles _cpuParticles; CpuParticles _cpuParticles;

View file

@ -30,14 +30,11 @@ TextEntityRenderer::TextEntityRenderer(const EntityItemPointer& entity) :
} }
TextEntityRenderer::~TextEntityRenderer() {
void TextEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity) {
auto geometryCache = DependencyManager::get<GeometryCache>(); auto geometryCache = DependencyManager::get<GeometryCache>();
if (_geometryID && geometryCache) { if (_geometryID && geometryCache) {
geometryCache->releaseID(_geometryID); geometryCache->releaseID(_geometryID);
} }
delete _textRenderer;
_textRenderer = nullptr;
} }
bool TextEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { bool TextEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {

View file

@ -24,14 +24,13 @@ class TextEntityRenderer : public TypedEntityRenderer<TextEntityItem> {
using Pointer = std::shared_ptr<TextEntityRenderer>; using Pointer = std::shared_ptr<TextEntityRenderer>;
public: public:
TextEntityRenderer(const EntityItemPointer& entity); TextEntityRenderer(const EntityItemPointer& entity);
~TextEntityRenderer();
private: private:
virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override; virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override; virtual void doRender(RenderArgs* args) override;
int _geometryID{ 0 }; int _geometryID{ 0 };
TextRenderer3D* _textRenderer; std::shared_ptr<TextRenderer3D> _textRenderer;
bool _faceCamera; bool _faceCamera;
glm::vec3 _dimensions; glm::vec3 _dimensions;
glm::vec3 _textColor; glm::vec3 _textColor;

View file

@ -104,7 +104,7 @@ bool operator!=(const Properties& a, const Properties& b) {
return !(a == b); return !(a == b);
} }
bool particle::Properties::valid() const { bool Properties::valid() const {
if (glm::any(glm::isnan(emission.orientation))) { if (glm::any(glm::isnan(emission.orientation))) {
qCWarning(entities) << "Bad particle data"; qCWarning(entities) << "Bad particle data";
return false; return false;
@ -133,6 +133,19 @@ bool particle::Properties::valid() const {
(radius.gradient.spread == glm::clamp(radius.gradient.spread, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS)); (radius.gradient.spread == glm::clamp(radius.gradient.spread, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS));
} }
bool Properties::emitting() const {
return emission.rate > 0.0f && lifespan > 0.0f && polar.start <= polar.finish;
}
uint64_t Properties::emitIntervalUsecs() const {
if (emission.rate > 0.0f) {
return (uint64_t)(USECS_PER_SECOND / emission.rate);
}
return 0;
}
EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer entity { new ParticleEffectEntityItem(entityID) }; EntityItemPointer entity { new ParticleEffectEntityItem(entityID) };
entity->setProperties(properties); entity->setProperties(properties);

View file

@ -160,7 +160,9 @@ namespace particle {
Properties() {}; Properties() {};
Properties(const Properties& other) { *this = other; } Properties(const Properties& other) { *this = other; }
bool valid() const; bool valid() const;
bool emitting() const;
uint64_t emitIntervalUsecs() const;
Properties& operator =(const Properties& other) { Properties& operator =(const Properties& other) {
color = other.color; color = other.color;
alpha = other.alpha; alpha = other.alpha;