diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 0bf2b590c0..212baa6634 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -635,6 +635,7 @@ void EntityRenderer::updateShapeKeyBuilderFromMaterials(ShapeKey::Builder& build { std::lock_guard lock(_materialsLock); materials = _materials.find("0"); + if (materials != _materials.end()) { if (materials->second.shouldUpdate()) { RenderPipelines::updateMultiMaterial(materials->second); @@ -662,7 +663,6 @@ void EntityRenderer::updateShapeKeyBuilderFromMaterials(ShapeKey::Builder& build auto pipelineType = getPipelineType(materials->second); if (pipelineType == Pipeline::MATERIAL) { builder.withMaterial(); - if (drawMaterialKey.isNormalMap()) { builder.withTangents(); } diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp index 3fa2174114..9592a3e57f 100644 --- a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp @@ -198,10 +198,8 @@ void ImageEntityRenderer::doRender(RenderArgs* args) { procedural->prepare(*batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(transparent)); } else if (pipelineType == Pipeline::SIMPLE) { batch->setResourceTexture(0, _texture->getGPUTexture()); - } else { - if (RenderPipelines::bindMaterials(materials, *batch, args->_renderMode, args->_enableTexturing)) { - args->_details._materialSwitches++; - } + } else if (RenderPipelines::bindMaterials(materials, *batch, args->_renderMode, args->_enableTexturing)) { + args->_details._materialSwitches++; } DependencyManager::get()->renderQuad( diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index ed396f88c9..fe4c960bd6 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -954,7 +954,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * @property {string} materialURL="" - URL to a {@link Entities.MaterialResource|MaterialResource}. Alternatively, set the * property value to "materialData" to use the materialData property for the * {@link Entities.MaterialResource|MaterialResource} values. If you append "#name" to the URL, the material - * with that name will be applied to the entity. You can also use the ID of another material entity as the URL, in which + * with that name will be applied to the entity. You can also use the ID of another Material entity as the URL, in which * case this material will act as a copy of that material, with its own unique material transform, priority, etc. * @property {string} materialData="" - Used to store {@link Entities.MaterialResource|MaterialResource} data as a JSON string. * You can use JSON.parse() to parse the string into a JavaScript object which you can manipulate the @@ -1380,7 +1380,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { /*@jsdoc * The "Web" {@link Entities.EntityType|EntityType} displays a browsable web page. Each user views their own copy * of the web page: if one user navigates to another page on the entity, other users do not see the change; if a video is being - * played, users don't see it in sync. It has properties in addition to the common + * played, users don't see it in sync. Internally, a Web Entity is rendered as a non-repeating, upside down texture, so additional + * transformations may be necessary if you reference a web entity texture by UUID. It has properties in addition to the common * {@link Entities.EntityProperties|EntityProperties}. * * @typedef {object} Entities.EntityProperties-Web diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 099d6dc0d8..48159c5da5 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -898,8 +898,11 @@ void SphericalHarmonics::evalFromTexture(const Texture& texture, gpu::BackendTar // TextureSource const gpu::TexturePointer TextureSource::getGPUTexture() const { - if (_gpuTextureOperator) { - return _gpuTextureOperator(); + if (_gpuTextureOperator && !_locked) { + _locked = true; + auto gpuTexture = _gpuTextureOperator(); + _locked = false; + return gpuTexture; } return _gpuTexture; } @@ -915,8 +918,10 @@ void TextureSource::resetTextureOperator(const std::functionisDefined(); } return _gpuTexture && _gpuTexture->isDefined(); diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 12896aca7b..a0cfc60b6e 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -727,6 +727,7 @@ public: protected: gpu::TexturePointer _gpuTexture; std::function _gpuTextureOperator { nullptr }; + mutable bool _locked { false }; QUrl _imageUrl; int _type { 0 }; }; diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index 3abcb8b4c0..2eb4e0cbe1 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -341,7 +341,7 @@ public: virtual ~Material() = default; Material& operator= (const Material& material); - virtual const MaterialKey& getKey() const { return _key; } + virtual MaterialKey getKey() const { return _key; } static const float DEFAULT_EMISSIVE; void setEmissive(const glm::vec3& emissive, bool isSRGB = true); @@ -385,7 +385,7 @@ public: // The texture map to channel association static const int NUM_TEXCOORD_TRANSFORMS { 2 }; void setTextureMap(MapChannel channel, const TextureMapPointer& textureMap); - virtual const TextureMaps& getTextureMaps() const { return _textureMaps; } // FIXME - not thread safe... + virtual TextureMaps getTextureMaps() const { return _textureMaps; } // FIXME - not thread safe... const TextureMapPointer getTextureMap(MapChannel channel) const; // Albedo maps cannot have opacity detected until they are loaded diff --git a/libraries/material-networking/src/material-networking/TextureCache.cpp b/libraries/material-networking/src/material-networking/TextureCache.cpp index 8c44379dd5..489692e3e2 100644 --- a/libraries/material-networking/src/material-networking/TextureCache.cpp +++ b/libraries/material-networking/src/material-networking/TextureCache.cpp @@ -1402,4 +1402,9 @@ std::function Texture::getTextureForUUIDOperator(const QU return std::bind(_unboundTextureForUUIDOperator, uuid); } return nullptr; -} \ No newline at end of file +} + + +void Texture::setUnboundTextureForUUIDOperator(std::function textureForUUIDOperator) { + _unboundTextureForUUIDOperator = textureForUUIDOperator; +} diff --git a/libraries/material-networking/src/material-networking/TextureCache.h b/libraries/material-networking/src/material-networking/TextureCache.h index 069c5d15f5..c0633c2f9b 100644 --- a/libraries/material-networking/src/material-networking/TextureCache.h +++ b/libraries/material-networking/src/material-networking/TextureCache.h @@ -41,7 +41,7 @@ public: gpu::TextureSourcePointer _textureSource; static std::function getTextureForUUIDOperator(const QUuid& uuid); - static void setUnboundTextureForUUIDOperator(std::function textureForUUIDOperator) { _unboundTextureForUUIDOperator = textureForUUIDOperator; } + static void setUnboundTextureForUUIDOperator(std::function textureForUUIDOperator); private: static std::function _unboundTextureForUUIDOperator; diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index 3b50a34fa0..d6971e3cdf 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -40,7 +40,7 @@ const size_t MAX_PROCEDURAL_TEXTURE_CHANNELS{ 4 }; * If a procedural material contains a vertex shader, the bounding box of the material entity is used to cull the object to which the material is applied. * @property {string} fragmentShaderURL - A link to a fragment shader. Currently, only GLSL shaders are supported. The shader must implement a different method depending on the version. * shaderUrl is an alias. - * @property {string[]} channels=[] - An array of input texture URLs or entity IDs. Currently, up to 4 are supported. + * @property {string[]} channels=[] - An array of input texture URLs or entity IDs. Currently, up to 4 are supported. An entity ID may be that of an Image or a Web entity. * @property {ProceduralUniforms} uniforms={} - A {@link ProceduralUniforms} object containing all the custom uniforms to be passed to the shader. */ diff --git a/libraries/procedural/src/procedural/ReferenceMaterial.cpp b/libraries/procedural/src/procedural/ReferenceMaterial.cpp index a926c1f5ce..97211eb737 100644 --- a/libraries/procedural/src/procedural/ReferenceMaterial.cpp +++ b/libraries/procedural/src/procedural/ReferenceMaterial.cpp @@ -18,157 +18,216 @@ ReferenceMaterial::ReferenceMaterial(QUuid uuid) : } // Material -const graphics::MaterialKey& ReferenceMaterial::getKey() const { - auto material = getMaterial(); - return material ? material->getKey() : Parent::getKey(); +graphics::MaterialKey ReferenceMaterial::getKey() const { + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->getKey() : Parent::getKey(); + }); } glm::vec3 ReferenceMaterial::getEmissive(bool SRGB) const { - auto material = getMaterial(); - return material ? material->getEmissive(SRGB) : glm::vec3(DEFAULT_EMISSIVE); + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->getEmissive(SRGB) : glm::vec3(DEFAULT_EMISSIVE); + }); } float ReferenceMaterial::getOpacity() const { - auto material = getMaterial(); - return material ? material->getOpacity() : DEFAULT_OPACITY; + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->getOpacity() : DEFAULT_OPACITY; + }); } graphics::MaterialKey::OpacityMapMode ReferenceMaterial::getOpacityMapMode() const { - auto material = getMaterial(); - return material ? material->getOpacityMapMode() : DEFAULT_OPACITY_MAP_MODE; + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->getOpacityMapMode() : DEFAULT_OPACITY_MAP_MODE; + }); } float ReferenceMaterial::getOpacityCutoff() const { - auto material = getMaterial(); - return material ? material->getOpacityCutoff() : DEFAULT_OPACITY_CUTOFF; + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->getOpacityCutoff() : DEFAULT_OPACITY_CUTOFF; + }); } graphics::MaterialKey::CullFaceMode ReferenceMaterial::getCullFaceMode() const { - auto material = getMaterial(); - return material ? material->getCullFaceMode() : DEFAULT_CULL_FACE_MODE; + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->getCullFaceMode() : DEFAULT_CULL_FACE_MODE; + }); } bool ReferenceMaterial::isUnlit() const { - auto material = getMaterial(); - return material ? material->isUnlit() : false; + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->isUnlit() : false; + }); } glm::vec3 ReferenceMaterial::getAlbedo(bool SRGB) const { - auto material = getMaterial(); - return material ? material->getAlbedo(SRGB) : glm::vec3(DEFAULT_ALBEDO); + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->getAlbedo(SRGB) : glm::vec3(DEFAULT_ALBEDO); + }); } float ReferenceMaterial::getMetallic() const { - auto material = getMaterial(); - return material ? material->getMetallic() : DEFAULT_METALLIC; + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->getMetallic() : DEFAULT_METALLIC; + }); } float ReferenceMaterial::getRoughness() const { - auto material = getMaterial(); - return material ? material->getRoughness() : DEFAULT_ROUGHNESS; + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->getRoughness() : DEFAULT_ROUGHNESS; + }); } float ReferenceMaterial::getScattering() const { - auto material = getMaterial(); - return material ? material->getScattering() : DEFAULT_SCATTERING; + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->getScattering() : DEFAULT_SCATTERING; + }); } bool ReferenceMaterial::resetOpacityMap() const { - auto material = getMaterial(); - return material ? material->resetOpacityMap() : false; + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->resetOpacityMap() : false; + }); } -const graphics::Material::TextureMaps& ReferenceMaterial::getTextureMaps() const { - auto material = getMaterial(); - return material ? material->getTextureMaps() : Parent::getTextureMaps(); -} +graphics::Material::TextureMaps ReferenceMaterial::getTextureMaps() const { + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->getTextureMaps() : Parent::getTextureMaps(); + }); +} glm::vec2 ReferenceMaterial::getLightmapParams() const { - auto material = getMaterial(); - return material ? material->getLightmapParams() : glm::vec2(0.0f, 1.0f); + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->getLightmapParams() : glm::vec2(0.0f, 1.0f); + }); } bool ReferenceMaterial::getDefaultFallthrough() const { - auto material = getMaterial(); - return material ? material->getDefaultFallthrough() : false; + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->getDefaultFallthrough() : false; + }); } // NetworkMaterial bool ReferenceMaterial::isMissingTexture() { - auto material = getNetworkMaterial(); - return material ? material->isMissingTexture() : false; + return resultWithLock([&] { + auto material = getNetworkMaterial(); + return material ? material->isMissingTexture() : false; + }); } bool ReferenceMaterial::checkResetOpacityMap() { - auto material = getNetworkMaterial(); - return material ? material->checkResetOpacityMap() : false; + return resultWithLock([&] { + auto material = getNetworkMaterial(); + return material ? material->checkResetOpacityMap() : false; + }); } // ProceduralMaterial bool ReferenceMaterial::isProcedural() const { - auto material = getMaterial(); - return material ? material->isProcedural() : false; + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->isProcedural() : false; + }); } bool ReferenceMaterial::isEnabled() const { - auto material = getMaterial(); - return material ? material->isEnabled() : false; + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->isEnabled() : false; + }); } bool ReferenceMaterial::isReady() const { - auto material = getMaterial(); - return material ? material->isReady() : false; + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->isReady() : false; + }); } QString ReferenceMaterial::getProceduralString() const { - auto material = getMaterial(); - return material ? material->getProceduralString() : QString(); + return resultWithLock([&] { + auto material = getMaterial(); + return material ? material->getProceduralString() : QString(); + }); } glm::vec4 ReferenceMaterial::getColor(const glm::vec4& color) const { - auto material = getProceduralMaterial(); - return material ? material->getColor(color) : glm::vec4(); + return resultWithLock([&] { + auto material = getProceduralMaterial(); + return material ? material->getColor(color) : glm::vec4(); + }); } bool ReferenceMaterial::isFading() const { - auto material = getProceduralMaterial(); - return material ? material->isFading() : false; + return resultWithLock([&] { + auto material = getProceduralMaterial(); + return material ? material->isFading() : false; + }); } uint64_t ReferenceMaterial::getFadeStartTime() const { - auto material = getProceduralMaterial(); - return material ? material->getFadeStartTime() : 0; + return resultWithLock([&] { + auto material = getProceduralMaterial(); + return material ? material->getFadeStartTime() : 0; + }); } bool ReferenceMaterial::hasVertexShader() const { - auto material = getProceduralMaterial(); - return material ? material->hasVertexShader() : false; + return resultWithLock([&] { + auto material = getProceduralMaterial(); + return material ? material->hasVertexShader() : false; + }); } void ReferenceMaterial::prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation, - const uint64_t& created, const ProceduralProgramKey key) { - if (auto material = getProceduralMaterial()) { - material->prepare(batch, position, size, orientation, created, key); - } + const uint64_t& created, const ProceduralProgramKey key) { + withLock([&] { + if (auto material = getProceduralMaterial()) { + material->prepare(batch, position, size, orientation, created, key); + } + }); } void ReferenceMaterial::initializeProcedural() { - if (auto material = getProceduralMaterial()) { - material->initializeProcedural(); - } + withLock([&] { + if (auto material = getProceduralMaterial()) { + material->initializeProcedural(); + } + }); +} + +void ReferenceMaterial::setMaterialForUUIDOperator(std::function materialForUUIDOperator) { + _unboundMaterialForUUIDOperator = materialForUUIDOperator; } graphics::MaterialPointer ReferenceMaterial::getMaterial() const { if (_materialForUUIDOperator) { - return _materialForUUIDOperator(); + auto material = _materialForUUIDOperator(); + return material; } return nullptr; } std::shared_ptr ReferenceMaterial::getNetworkMaterial() const { if (_materialForUUIDOperator) { - auto material = _materialForUUIDOperator(); - if (material && material->isProcedural()) { + std::shared_ptr result = nullptr; + if (auto material = _materialForUUIDOperator()) { return std::static_pointer_cast(material); } } @@ -184,3 +243,24 @@ graphics::ProceduralMaterialPointer ReferenceMaterial::getProceduralMaterial() c } return nullptr; } + +template +inline T ReferenceMaterial::resultWithLock(F&& f) const { + if (_locked) { + return T(); + } else { + _locked = true; + T result = f(); + _locked = false; + return result; + } +} + +template +inline void ReferenceMaterial::withLock(F&& f) const { + if (!_locked) { + _locked = true; + f(); + _locked = false; + } +} diff --git a/libraries/procedural/src/procedural/ReferenceMaterial.h b/libraries/procedural/src/procedural/ReferenceMaterial.h index 393ef10816..ac778f94b1 100644 --- a/libraries/procedural/src/procedural/ReferenceMaterial.h +++ b/libraries/procedural/src/procedural/ReferenceMaterial.h @@ -18,7 +18,7 @@ public: ReferenceMaterial(QUuid uuid); // Material - const graphics::MaterialKey& getKey() const override; + graphics::MaterialKey getKey() const override; glm::vec3 getEmissive(bool SRGB = true) const override; float getOpacity() const override; graphics::MaterialKey::OpacityMapMode getOpacityMapMode() const override; @@ -30,10 +30,8 @@ public: float getRoughness() const override; float getScattering() const override; bool resetOpacityMap() const override; - const graphics::Material::TextureMaps& getTextureMaps() const override; - //glm::mat4 getTexCoordTransform(uint i) const override; // use my actual transform, instead of the original + graphics::Material::TextureMaps getTextureMaps() const override; glm::vec2 getLightmapParams() const override; - //glm::vec2 getMaterialParams() const override; // use my actual params, instead of the original bool getDefaultFallthrough() const override; // NetworkMaterial @@ -57,13 +55,20 @@ public: bool isReference() const override { return true; } std::function getReferenceOperator() const { return _materialForUUIDOperator; } - static void setMaterialForUUIDOperator(std::function materialForUUIDOperator) { _unboundMaterialForUUIDOperator = materialForUUIDOperator; } + static void setMaterialForUUIDOperator(std::function materialForUUIDOperator); private: static std::function _unboundMaterialForUUIDOperator; std::function _materialForUUIDOperator; + mutable bool _locked { false }; graphics::MaterialPointer getMaterial() const; std::shared_ptr getNetworkMaterial() const; graphics::ProceduralMaterialPointer getProceduralMaterial() const; + + template + T resultWithLock(F&& f) const; + + template + void withLock(F&& f) const; }; diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 3e760b2110..ed9fb326c4 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -415,8 +415,8 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial } bool defaultFallthrough = material->getDefaultFallthrough(); - const auto& materialKey = material->getKey(); - const auto& textureMaps = material->getTextureMaps(); + const auto materialKey = material->getKey(); + const auto textureMaps = material->getTextureMaps(); auto it = flagsToCheck.begin(); while (it != flagsToCheck.end()) {