diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
index 4de09c1bf3..809f48361d 100644
--- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
+++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
@@ -571,6 +571,7 @@ Rectangle {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
+ hoverEnabled: true;
}
RalewayBold {
diff --git a/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml b/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml
index 145b78bdc4..8b0ec17232 100644
--- a/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml
+++ b/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml
@@ -45,6 +45,7 @@ Rectangle {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
+ hoverEnabled: true;
}
Rectangle {
diff --git a/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml b/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml
index 0d3f67ef7a..bcc641acd5 100644
--- a/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml
+++ b/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml
@@ -44,6 +44,7 @@ Rectangle {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
+ hoverEnabled: true;
}
Item {
diff --git a/interface/resources/qml/hifi/commerce/common/images/loader.gif b/interface/resources/qml/hifi/commerce/common/images/loader.gif
new file mode 100644
index 0000000000..0536bd1884
Binary files /dev/null and b/interface/resources/qml/hifi/commerce/common/images/loader.gif differ
diff --git a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml
index c331532f5e..421fa4b074 100644
--- a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml
+++ b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml
@@ -119,6 +119,7 @@ Rectangle {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
+ hoverEnabled: true;
}
Image {
diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
index f7913e5b1e..05e280b839 100644
--- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
+++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
@@ -316,6 +316,7 @@ Item {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
+ hoverEnabled: true;
}
RalewayBold {
diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml
index 87430246f3..c586af9e80 100644
--- a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml
@@ -66,6 +66,7 @@ Item {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
+ hoverEnabled: true;
}
// This will cause a bug -- if you bring up passphrase selection in HUD mode while
diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml
index 50e58f8cc4..50bea2a3cf 100644
--- a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml
@@ -34,6 +34,7 @@ Item {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
+ hoverEnabled: true;
}
Connections {
diff --git a/interface/resources/qml/hifi/commerce/wallet/Security.qml b/interface/resources/qml/hifi/commerce/wallet/Security.qml
index 634a68d117..224b743c06 100644
--- a/interface/resources/qml/hifi/commerce/wallet/Security.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/Security.qml
@@ -306,6 +306,7 @@ Item {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
+ hoverEnabled: true;
}
RalewayBold {
diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml
index fd74b07465..fab27a29bb 100644
--- a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml
@@ -394,6 +394,7 @@ Item {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
+ hoverEnabled: true;
}
Image {
diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
index f66781c919..ee1246c0c4 100644
--- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
+++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml
@@ -43,6 +43,7 @@ Item {
width: parent.width;
height: (root.shouldShowTopAndBottomOfWallet || root.shouldShowTopOfWallet) ? parent.height : parent.height - root.parentAppTitleBarHeight - root.parentAppNavBarHeight;
propagateComposedEvents: false;
+ hoverEnabled: true;
}
Connections {
@@ -57,6 +58,9 @@ Item {
if (result.status === 'success') {
root.nextActiveView = 'paymentSuccess';
+ if (sendPubliclyCheckbox.checked && sendMoneyStep.referrer === "nearby") {
+ sendSignalToWallet({method: 'sendMoney_sendPublicly', recipient: sendMoneyStep.selectedRecipientNodeID, amount: parseInt(amountTextField.text)});
+ }
} else {
root.nextActiveView = 'paymentFailure';
}
@@ -103,6 +107,12 @@ Item {
}
}
+ HifiCommerceCommon.CommerceLightbox {
+ id: lightboxPopup;
+ visible: false;
+ anchors.fill: parent;
+ }
+
// Send Money Home BEGIN
Item {
id: sendMoneyHome;
@@ -326,6 +336,7 @@ Item {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
+ hoverEnabled: true;
}
ListModel {
@@ -477,6 +488,7 @@ Item {
enabled: connectionsList.currentIndex !== index;
anchors.fill: parent;
propagateComposedEvents: false;
+ hoverEnabled: true;
onClicked: {
connectionsList.currentIndex = index;
}
@@ -505,6 +517,7 @@ Item {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
+ hoverEnabled: true;
}
Rectangle {
@@ -917,7 +930,7 @@ Item {
id: optionalMessage;
property int maximumLength: 72;
property string previousText: text;
- placeholderText: "Optional Message (" + maximumLength + " character limit)";
+ placeholderText: "Optional Public Message (" + maximumLength + " character limit)";
font.family: firaSansSemiBold.name;
font.pixelSize: 20;
// Anchors
@@ -967,16 +980,54 @@ Item {
HifiControlsUit.CheckBox {
id: sendPubliclyCheckbox;
- visible: false; // FIXME ONCE PARTICLE EFFECTS ARE IN
- text: "Send Publicly"
+ visible: sendMoneyStep.referrer === "nearby";
+ checked: Settings.getValue("sendMoneyNearbyPublicly", true);
+ text: "Show Effect"
// Anchors
anchors.top: messageContainer.bottom;
anchors.topMargin: 16;
anchors.left: parent.left;
anchors.leftMargin: 20;
- anchors.right: parent.right;
- anchors.rightMargin: 16;
- boxSize: 24;
+ width: 110;
+ boxSize: 28;
+ onCheckedChanged: {
+ Settings.setValue("sendMoneyNearbyPublicly", checked);
+ }
+ }
+ RalewaySemiBold {
+ id: sendPubliclyCheckboxHelp;
+ visible: sendPubliclyCheckbox.visible;
+ text: "[?]";
+ // Anchors
+ anchors.left: sendPubliclyCheckbox.right;
+ anchors.leftMargin: 8;
+ anchors.verticalCenter: sendPubliclyCheckbox.verticalCenter;
+ height: 30;
+ width: paintedWidth;
+ // Text size
+ size: 18;
+ // Style
+ color: hifi.colors.blueAccent;
+ MouseArea {
+ enabled: sendPubliclyCheckboxHelp.visible;
+ anchors.fill: parent;
+ hoverEnabled: true;
+ onEntered: {
+ parent.color = hifi.colors.blueHighlight;
+ }
+ onExited: {
+ parent.color = hifi.colors.blueAccent;
+ }
+ onClicked: {
+ lightboxPopup.titleText = "Send Money Effect";
+ lightboxPopup.bodyImageSource = "../wallet/sendMoney/images/send-money-effect-sm.jpg"; // Path relative to CommerceLightbox.qml
+ lightboxPopup.bodyText = "Enabling this option will create a particle effect between you and " +
+ "your recipient that is visible to everyone nearby.";
+ lightboxPopup.button1text = "CLOSE";
+ lightboxPopup.button1method = "root.visible = false;"
+ lightboxPopup.visible = true;
+ }
+ }
}
Item {
@@ -1059,6 +1110,7 @@ Item {
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
+ hoverEnabled: true;
}
AnimatedImage {
@@ -1533,6 +1585,8 @@ Item {
sendMoneyStep.selectedRecipientProfilePic = "";
amountTextField.text = "";
optionalMessage.text = "";
+ sendPubliclyCheckbox.checked = Settings.getValue("sendMoneyNearbyPublicly", true);
+ sendMoneyStep.referrer = "";
}
//
diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/send-money-effect-sm.jpg b/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/send-money-effect-sm.jpg
new file mode 100644
index 0000000000..7cabf9414a
Binary files /dev/null and b/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/send-money-effect-sm.jpg differ
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 99bd4d5758..1a54c94d53 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -2294,11 +2294,7 @@ void Application::initializeGL() {
#ifndef Q_OS_ANDROID
_renderEngine->addJob("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED);
#endif
- _renderEngine->addJob("RenderMainView", cullFunctor, !DISABLE_DEFERRED);
-
-#ifdef Q_OS_OSX
- DeadlockWatchdogThread::resume();
-#endif
+ _renderEngine->addJob("RenderMainView", cullFunctor, !DISABLE_DEFERRED, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0);
_renderEngine->load();
_renderEngine->registerScene(_main3DScene);
@@ -2306,6 +2302,10 @@ void Application::initializeGL() {
// Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success.
DependencyManager::get()->initializeShapePipelines();
+#ifdef Q_OS_OSX
+ DeadlockWatchdogThread::resume();
+#endif
+
_offscreenContext = new OffscreenGLCanvas();
_offscreenContext->setObjectName("MainThreadContext");
_offscreenContext->create(_glWidget->qglContext());
diff --git a/interface/src/Application_render.cpp b/interface/src/Application_render.cpp
index 1231e5834b..e1f198eed2 100644
--- a/interface/src/Application_render.cpp
+++ b/interface/src/Application_render.cpp
@@ -178,7 +178,7 @@ public:
render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID };
namespace render {
- template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape(); }
+ template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); }
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp
index 5db34c9441..6b8e370689 100644
--- a/interface/src/SecondaryCamera.cpp
+++ b/interface/src/SecondaryCamera.cpp
@@ -19,8 +19,9 @@
using RenderArgsPointer = std::shared_ptr;
void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
- task.addJob("RenderShadowTask", cullFunctor);
- const auto items = task.addJob("FetchCullSort", cullFunctor);
+
+ task.addJob("RenderShadowTask", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
+ const auto items = task.addJob("FetchCullSort", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
assert(items.canCast());
if (!isDeferred) {
task.addJob("Forward", items);
@@ -205,7 +206,7 @@ public:
void SecondaryCameraRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
const auto cachedArg = task.addJob("SecondaryCamera");
- const auto items = task.addJob("FetchCullSort", cullFunctor);
+ const auto items = task.addJob("FetchCullSort", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
assert(items.canCast());
if (!isDeferred) {
task.addJob("Forward", items);
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 4ab741e32c..d2a9e798f8 100755
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -48,6 +48,7 @@
#include
#include
#include
+#include
#include "MyHead.h"
#include "MySkeletonModel.h"
@@ -503,11 +504,42 @@ void MyAvatar::updateEyeContactTarget(float deltaTime) {
extern QByteArray avatarStateToFrame(const AvatarData* _avatar);
extern void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
+void MyAvatar::beParentOfChild(SpatiallyNestablePointer newChild) const {
+ _cauterizationNeedsUpdate = true;
+ SpatiallyNestable::beParentOfChild(newChild);
+}
+
+void MyAvatar::forgetChild(SpatiallyNestablePointer newChild) const {
+ _cauterizationNeedsUpdate = true;
+ SpatiallyNestable::forgetChild(newChild);
+}
+
+void MyAvatar::updateChildCauterization(SpatiallyNestablePointer object) {
+ if (object->getNestableType() == NestableType::Entity) {
+ EntityItemPointer entity = std::static_pointer_cast(object);
+ entity->setCauterized(!_prevShouldDrawHead);
+ }
+}
+
void MyAvatar::simulate(float deltaTime) {
PerformanceTimer perfTimer("simulate");
animateScaleChanges(deltaTime);
+ if (_cauterizationNeedsUpdate) {
+ const std::unordered_set& headBoneSet = _skeletonModel->getCauterizeBoneSet();
+ forEachChild([&](SpatiallyNestablePointer object) {
+ bool isChildOfHead = headBoneSet.find(object->getParentJointIndex()) != headBoneSet.end();
+ if (isChildOfHead) {
+ updateChildCauterization(object);
+ object->forEachDescendant([&](SpatiallyNestablePointer descendant) {
+ updateChildCauterization(descendant);
+ });
+ }
+ });
+ _cauterizationNeedsUpdate = false;
+ }
+
{
PerformanceTimer perfTimer("transform");
bool stepAction = false;
@@ -1067,7 +1099,7 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) {
}
void MyAvatar::setEnableMeshVisible(bool isEnabled) {
- _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene());
+ _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE);
}
void MyAvatar::setEnableInverseKinematics(bool isEnabled) {
@@ -1417,8 +1449,9 @@ void MyAvatar::clearJointsData() {
void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
Avatar::setSkeletonModelURL(skeletonModelURL);
- _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene());
+ _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE);
_headBoneSet.clear();
+ _cauterizationNeedsUpdate = true;
emit skeletonChanged();
}
@@ -1762,7 +1795,7 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName,
void MyAvatar::setVisibleInSceneIfReady(Model* model, const render::ScenePointer& scene, bool visible) {
if (model->isActive() && model->isRenderable()) {
- model->setVisibleInScene(visible, scene);
+ model->setVisibleInScene(visible, scene, render::ItemKey::TAG_BITS_NONE);
}
}
@@ -1790,6 +1823,8 @@ void MyAvatar::initHeadBones() {
}
q.pop();
}
+
+ _cauterizationNeedsUpdate = true;
}
QUrl MyAvatar::getAnimGraphOverrideUrl() const {
@@ -1860,6 +1895,7 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
_fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl();
initAnimGraph();
_isAnimatingScale = true;
+ _cauterizationNeedsUpdate = true;
}
if (_enableDebugDrawDefaultPose || _enableDebugDrawAnimPose) {
@@ -1948,6 +1984,7 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
// toggle using the cauterizedBones depending on where the camera is and the rendering pass type.
const bool shouldDrawHead = shouldRenderHead(renderArgs);
if (shouldDrawHead != _prevShouldDrawHead) {
+ _cauterizationNeedsUpdate = true;
_skeletonModel->setEnableCauterization(!shouldDrawHead);
for (int i = 0; i < _attachmentData.size(); i++) {
@@ -1957,7 +1994,8 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
_attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) {
- _attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene());
+ _attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene(),
+ render::ItemKey::TAG_BITS_NONE);
}
}
}
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index ed391f750a..97e82b87f5 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -633,6 +633,11 @@ signals:
private slots:
void leaveDomain();
+
+protected:
+ virtual void beParentOfChild(SpatiallyNestablePointer newChild) const override;
+ virtual void forgetChild(SpatiallyNestablePointer newChild) const override;
+
private:
bool requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& positionOut);
@@ -812,6 +817,8 @@ private:
bool _enableDebugDrawIKChains { false };
bool _enableDebugDrawDetailedCollision { false };
+ mutable bool _cauterizationNeedsUpdate; // do we need to scan children and update their "cauterized" state?
+
AudioListenerMode _audioListenerMode;
glm::vec3 _customListenPosition;
glm::quat _customListenOrientation;
@@ -849,6 +856,8 @@ private:
// height of user in sensor space, when standing erect.
ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT };
+ void updateChildCauterization(SpatiallyNestablePointer object);
+
// max unscaled forward movement speed
ThreadSafeValueCache _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED };
};
diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp
index 310dbf78d8..4847650163 100644
--- a/interface/src/ui/overlays/ModelOverlay.cpp
+++ b/interface/src/ui/overlays/ModelOverlay.cpp
@@ -86,7 +86,8 @@ void ModelOverlay::update(float deltatime) {
}
if (_visibleDirty) {
_visibleDirty = false;
- _model->setVisibleInScene(getVisible(), scene);
+ // don't show overlays in mirrors
+ _model->setVisibleInScene(getVisible(), scene, render::ItemKey::TAG_BITS_0);
}
if (_drawInFrontDirty) {
_drawInFrontDirty = false;
@@ -120,8 +121,10 @@ void ModelOverlay::removeFromScene(Overlay::Pointer overlay, const render::Scene
}
void ModelOverlay::setVisible(bool visible) {
- Overlay::setVisible(visible);
- _visibleDirty = true;
+ if (visible != getVisible()) {
+ Overlay::setVisible(visible);
+ _visibleDirty = true;
+ }
}
void ModelOverlay::setDrawInFront(bool drawInFront) {
diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h
index 60ba90e568..08c776c426 100644
--- a/interface/src/ui/overlays/ModelOverlay.h
+++ b/interface/src/ui/overlays/ModelOverlay.h
@@ -106,7 +106,7 @@ private:
bool _jointMappingCompleted { false };
QVector _jointMapping; // domain is index into model-joints, range is index into animation-joints
- bool _visibleDirty { false };
+ bool _visibleDirty { true };
bool _drawInFrontDirty { false };
bool _drawInHUDDirty { false };
diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp
index 449ac62998..f99ced0021 100644
--- a/interface/src/ui/overlays/OverlaysPayload.cpp
+++ b/interface/src/ui/overlays/OverlaysPayload.cpp
@@ -44,6 +44,13 @@ namespace render {
} else {
builder.withViewSpace();
}
+
+ if (!overlay->getVisible()) {
+ builder.withInvisible();
+ }
+
+ builder.withTagBits(render::ItemKey::TAG_BITS_0); // Only draw overlays in main view
+
return builder.build();
}
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {
diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
index 500a24763d..86635cd3bf 100644
--- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
+++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
@@ -50,7 +50,7 @@ const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
namespace render {
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
- return ItemKey::Builder::opaqueShape().withTypeMeta();
+ return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1);
}
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) {
return static_pointer_cast(avatar)->getBounds();
diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp
index 90bb83a663..d35d5c5317 100644
--- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp
@@ -398,7 +398,7 @@ void HmdDisplayPlugin::HUDRenderer::updatePipeline() {
auto vs = gpu::Shader::createVertex(std::string(hmd_ui_vert));
auto ps = gpu::Shader::createPixel(std::string(hmd_ui_frag));
auto program = gpu::Shader::createProgram(vs, ps);
- gpu::gl::GLBackend::makeProgram(*program, gpu::Shader::BindingSet());
+ gpu::Shader::makeProgram(*program, gpu::Shader::BindingSet());
uniformsLocation = program->getUniformBuffers().findLocation("hudBuffer");
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp
index fb9aba636b..aca2f4d35b 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp
@@ -159,10 +159,10 @@ Item::Bound EntityRenderer::getBound() {
ItemKey EntityRenderer::getKey() {
if (isTransparent()) {
- return ItemKey::Builder::transparentShape().withTypeMeta();
+ return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
}
- return ItemKey::Builder::opaqueShape().withTypeMeta();
+ return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
}
uint32_t EntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) {
@@ -185,7 +185,12 @@ void EntityRenderer::render(RenderArgs* args) {
emit requestRenderUpdate();
}
- if (_visible) {
+ auto& renderMode = args->_renderMode;
+ bool cauterized = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE &&
+ renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE &&
+ _cauterized);
+
+ if (_visible && !cauterized) {
doRender(args);
}
}
@@ -366,6 +371,7 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa
_moving = entity->isMovingRelativeToParent();
_visible = entity->getVisible();
+ _cauterized = entity->getCauterized();
_needsRenderUpdate = false;
});
}
diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h
index 8eb82e2c6e..f8685df5da 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableEntityItem.h
@@ -124,6 +124,7 @@ protected:
bool _isFading{ _entitiesShouldFadeFunction() };
bool _prevIsTransparent { false };
bool _visible { false };
+ bool _cauterized { false };
bool _moving { false };
bool _needsRenderUpdate { false };
// Only touched on the rendering thread
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index 9fcb7640ef..137203f475 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -1013,9 +1013,9 @@ ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Pare
void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) {
if (didVisualGeometryRequestSucceed) {
- _itemKey = ItemKey::Builder().withTypeMeta();
+ _itemKey = ItemKey::Builder().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
} else {
- _itemKey = ItemKey::Builder().withTypeMeta().withTypeShape();
+ _itemKey = ItemKey::Builder().withTypeMeta().withTypeShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
}
}
@@ -1334,11 +1334,16 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
entity->updateModelBounds();
entity->stopModelOverrideIfNoParent();
- if (model->isVisible() != _visible) {
+ // Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint)
+ uint32_t viewTaskBits = _cauterized ?
+ render::ItemKey::TAG_BITS_1 : // draw in every view except the main one (view zero)
+ render::ItemKey::TAG_BITS_ALL; // draw in all views
+
+ if (model->isVisible() != _visible || model->getViewTagBits() != viewTaskBits) {
// FIXME: this seems like it could be optimized if we tracked our last known visible state in
// the renderable item. As it stands now the model checks it's visible/invisible state
// so most of the time we don't do anything in this function.
- model->setVisibleInScene(_visible, scene);
+ model->setVisibleInScene(_visible, scene, viewTaskBits);
}
// TODO? early exit here when not visible?
diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
index 2059487426..af95878213 100644
--- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
@@ -147,9 +147,9 @@ void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEn
ItemKey ParticleEffectEntityRenderer::getKey() {
if (_visible) {
- return ItemKey::Builder::transparentShape();
+ return ItemKey::Builder::transparentShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
} else {
- return ItemKey::Builder().withInvisible().build();
+ return ItemKey::Builder().withInvisible().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).build();
}
}
diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
index 4d223669b4..42110170a0 100644
--- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
@@ -112,7 +112,7 @@ PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity)
}
ItemKey PolyLineEntityRenderer::getKey() {
- return ItemKey::Builder::transparentShape().withTypeMeta();
+ return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
}
ShapeKey PolyLineEntityRenderer::getShapeKey() {
diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
index ade3790df6..abd14d017e 100644
--- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
@@ -99,7 +99,7 @@ const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5;
In RenderablePolyVoxEntityItem::render, these flags are checked and changes are propagated along the chain.
decompressVolumeData() is called to decompress _voxelData into _volData. recomputeMesh() is called to invoke the
- polyVox surface extractor to create _mesh (as well as set Simulation _dirtyFlags). Because Simulation::DIRTY_SHAPE
+ polyVox surface extractor to create _mesh (as well as set Simulation _flags). Because Simulation::DIRTY_SHAPE
is set, isReadyToComputeShape() gets called and _shape is created either from _volData or _shape, depending on
the surface style.
@@ -1138,7 +1138,7 @@ void RenderablePolyVoxEntityItem::setMesh(graphics::MeshPointer mesh) {
bool neighborsNeedUpdate;
withWriteLock([&] {
if (!_collisionless) {
- _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
+ _flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
}
_mesh = mesh;
_meshDirty = true;
diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
index b43944f26a..04f07c5bd3 100644
--- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
@@ -269,7 +269,7 @@ void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe
ItemKey ZoneEntityRenderer::getKey() {
- return ItemKey::Builder().withTypeMeta().build();
+ return ItemKey::Builder().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).build();
}
bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index fe5213baa8..ed13a46414 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -933,7 +933,7 @@ void EntityItem::setDensity(float density) {
withWriteLock([&] {
if (_density != clampedDensity) {
_density = clampedDensity;
- _dirtyFlags |= Simulation::DIRTY_MASS;
+ _flags |= Simulation::DIRTY_MASS;
}
});
}
@@ -958,7 +958,7 @@ void EntityItem::setMass(float mass) {
withWriteLock([&] {
if (_density != newDensity) {
_density = newDensity;
- _dirtyFlags |= Simulation::DIRTY_MASS;
+ _flags |= Simulation::DIRTY_MASS;
}
});
}
@@ -1623,41 +1623,42 @@ void EntityItem::setParentID(const QUuid& value) {
if (!value.isNull() && tree) {
EntityItemPointer entity = tree->findEntityByEntityItemID(value);
if (entity) {
- newParentNoBootstrapping = entity->getDirtyFlags() & Simulation::NO_BOOTSTRAPPING;
+ newParentNoBootstrapping = entity->getSpecialFlags() & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
}
}
if (!oldParentID.isNull() && tree) {
EntityItemPointer entity = tree->findEntityByEntityItemID(oldParentID);
if (entity) {
- oldParentNoBootstrapping = entity->getDirtyFlags() & Simulation::NO_BOOTSTRAPPING;
+ oldParentNoBootstrapping = entity->getDirtyFlags() & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
}
}
if (!value.isNull() && (value == Physics::getSessionUUID() || value == AVATAR_SELF_ID)) {
- newParentNoBootstrapping |= Simulation::NO_BOOTSTRAPPING;
+ newParentNoBootstrapping |= Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
}
if (!oldParentID.isNull() && (oldParentID == Physics::getSessionUUID() || oldParentID == AVATAR_SELF_ID)) {
- oldParentNoBootstrapping |= Simulation::NO_BOOTSTRAPPING;
+ oldParentNoBootstrapping |= Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
}
if ((bool)(oldParentNoBootstrapping ^ newParentNoBootstrapping)) {
- if ((bool)(newParentNoBootstrapping & Simulation::NO_BOOTSTRAPPING)) {
- markDirtyFlags(Simulation::NO_BOOTSTRAPPING);
- forEachDescendant([&](SpatiallyNestablePointer object) {
- if (object->getNestableType() == NestableType::Entity) {
- EntityItemPointer entity = std::static_pointer_cast(object);
- entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP | Simulation::NO_BOOTSTRAPPING);
- }
- });
- } else {
- clearDirtyFlags(Simulation::NO_BOOTSTRAPPING);
+ if ((bool)(newParentNoBootstrapping & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING)) {
+ markSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
forEachDescendant([&](SpatiallyNestablePointer object) {
if (object->getNestableType() == NestableType::Entity) {
EntityItemPointer entity = std::static_pointer_cast(object);
entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP);
- entity->clearDirtyFlags(Simulation::NO_BOOTSTRAPPING);
+ entity->markSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
+ }
+ });
+ } else {
+ clearSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
+ forEachDescendant([&](SpatiallyNestablePointer object) {
+ if (object->getNestableType() == NestableType::Entity) {
+ EntityItemPointer entity = std::static_pointer_cast(object);
+ entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP);
+ entity->clearSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
}
});
}
@@ -1694,7 +1695,7 @@ void EntityItem::setUnscaledDimensions(const glm::vec3& value) {
locationChanged();
dimensionsChanged();
withWriteLock([&] {
- _dirtyFlags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
+ _flags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
_queryAACubeSet = false;
});
}
@@ -1703,7 +1704,7 @@ void EntityItem::setUnscaledDimensions(const glm::vec3& value) {
void EntityItem::setRotation(glm::quat rotation) {
if (getLocalOrientation() != rotation) {
setLocalOrientation(rotation);
- _dirtyFlags |= Simulation::DIRTY_ROTATION;
+ _flags |= Simulation::DIRTY_ROTATION;
forEachDescendant([&](SpatiallyNestablePointer object) {
if (object->getNestableType() == NestableType::Entity) {
EntityItemPointer entity = std::static_pointer_cast(object);
@@ -1733,7 +1734,7 @@ void EntityItem::setVelocity(const glm::vec3& value) {
velocity = value;
}
setLocalVelocity(velocity);
- _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY;
+ _flags |= Simulation::DIRTY_LINEAR_VELOCITY;
}
}
}
@@ -1744,7 +1745,7 @@ void EntityItem::setDamping(float value) {
withWriteLock([&] {
if (_damping != clampedDamping) {
_damping = clampedDamping;
- _dirtyFlags |= Simulation::DIRTY_MATERIAL;
+ _flags |= Simulation::DIRTY_MATERIAL;
}
});
}
@@ -1763,7 +1764,7 @@ void EntityItem::setGravity(const glm::vec3& value) {
} else {
_gravity = value;
}
- _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY;
+ _flags |= Simulation::DIRTY_LINEAR_VELOCITY;
}
}
}
@@ -1788,7 +1789,7 @@ void EntityItem::setAngularVelocity(const glm::vec3& value) {
angularVelocity = value;
}
setLocalAngularVelocity(angularVelocity);
- _dirtyFlags |= Simulation::DIRTY_ANGULAR_VELOCITY;
+ _flags |= Simulation::DIRTY_ANGULAR_VELOCITY;
}
}
}
@@ -1799,7 +1800,7 @@ void EntityItem::setAngularDamping(float value) {
withWriteLock([&] {
if (_angularDamping != clampedDamping) {
_angularDamping = clampedDamping;
- _dirtyFlags |= Simulation::DIRTY_MATERIAL;
+ _flags |= Simulation::DIRTY_MATERIAL;
}
});
}
@@ -1808,7 +1809,7 @@ void EntityItem::setCollisionless(bool value) {
withWriteLock([&] {
if (_collisionless != value) {
_collisionless = value;
- _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP;
+ _flags |= Simulation::DIRTY_COLLISION_GROUP;
}
});
}
@@ -1817,7 +1818,7 @@ void EntityItem::setCollisionMask(uint8_t value) {
withWriteLock([&] {
if ((_collisionMask & ENTITY_COLLISION_MASK_DEFAULT) != (value & ENTITY_COLLISION_MASK_DEFAULT)) {
_collisionMask = (value & ENTITY_COLLISION_MASK_DEFAULT);
- _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP;
+ _flags |= Simulation::DIRTY_COLLISION_GROUP;
}
});
}
@@ -1829,11 +1830,11 @@ void EntityItem::setDynamic(bool value) {
if (value && getShapeType() == SHAPE_TYPE_STATIC_MESH) {
if (_dynamic) {
_dynamic = false;
- _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
+ _flags |= Simulation::DIRTY_MOTION_TYPE;
}
} else {
_dynamic = value;
- _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
+ _flags |= Simulation::DIRTY_MOTION_TYPE;
}
});
}
@@ -1844,7 +1845,7 @@ void EntityItem::setRestitution(float value) {
withWriteLock([&] {
if (_restitution != clampedValue) {
_restitution = clampedValue;
- _dirtyFlags |= Simulation::DIRTY_MATERIAL;
+ _flags |= Simulation::DIRTY_MATERIAL;
}
});
@@ -1855,7 +1856,7 @@ void EntityItem::setFriction(float value) {
withWriteLock([&] {
if (_friction != clampedValue) {
_friction = clampedValue;
- _dirtyFlags |= Simulation::DIRTY_MATERIAL;
+ _flags |= Simulation::DIRTY_MATERIAL;
}
});
}
@@ -1864,7 +1865,7 @@ void EntityItem::setLifetime(float value) {
withWriteLock([&] {
if (_lifetime != value) {
_lifetime = value;
- _dirtyFlags |= Simulation::DIRTY_LIFETIME;
+ _flags |= Simulation::DIRTY_LIFETIME;
}
});
}
@@ -1873,7 +1874,7 @@ void EntityItem::setCreated(quint64 value) {
withWriteLock([&] {
if (_created != value) {
_created = value;
- _dirtyFlags |= Simulation::DIRTY_LIFETIME;
+ _flags |= Simulation::DIRTY_LIFETIME;
}
});
}
@@ -1902,7 +1903,7 @@ void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask
}
}
- if ((bool)(_dirtyFlags & Simulation::NO_BOOTSTRAPPING)) {
+ if ((bool)(_flags & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING)) {
userMask &= ~USER_COLLISION_GROUP_MY_AVATAR;
}
mask = Physics::getDefaultCollisionMask(group) & (int16_t)(userMask);
@@ -1997,17 +1998,18 @@ bool EntityItem::addActionInternal(EntitySimulationPointer simulation, EntityDyn
serializeActions(success, newDataCache);
if (success) {
_allActionsDataCache = newDataCache;
- _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
+ _flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
auto actionType = action->getType();
if (actionType == DYNAMIC_TYPE_HOLD || actionType == DYNAMIC_TYPE_FAR_GRAB) {
- if (!(bool)(_dirtyFlags & Simulation::NO_BOOTSTRAPPING)) {
- _dirtyFlags |= Simulation::NO_BOOTSTRAPPING;
- _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
+ if (!(bool)(_flags & Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING)) {
+ _flags |= Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
+ _flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
forEachDescendant([&](SpatiallyNestablePointer child) {
if (child->getNestableType() == NestableType::Entity) {
EntityItemPointer entity = std::static_pointer_cast(child);
- entity->markDirtyFlags(Simulation::NO_BOOTSTRAPPING | Simulation::DIRTY_COLLISION_GROUP);
+ entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP);
+ entity->markSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
}
});
}
@@ -2033,7 +2035,7 @@ bool EntityItem::updateAction(EntitySimulationPointer simulation, const QUuid& a
if (success) {
action->setIsMine(true);
serializeActions(success, _allActionsDataCache);
- _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
+ _flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
} else {
qCDebug(entities) << "EntityItem::updateAction failed";
}
@@ -2091,17 +2093,17 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi
_objectActions.remove(actionID);
if ((removedActionType == DYNAMIC_TYPE_HOLD || removedActionType == DYNAMIC_TYPE_FAR_GRAB) && !stillHasGrabActions()) {
- _dirtyFlags &= ~Simulation::NO_BOOTSTRAPPING;
- _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
+ _flags &= ~Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING;
+ _flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
forEachDescendant([&](SpatiallyNestablePointer child) {
if (child->getNestableType() == NestableType::Entity) {
EntityItemPointer entity = std::static_pointer_cast(child);
entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP);
- entity->clearDirtyFlags(Simulation::NO_BOOTSTRAPPING);
+ entity->clearSpecialFlags(Simulation::SPECIAL_FLAGS_NO_BOOTSTRAPPING);
}
});
} else {
- // NO-OP: we assume NO_BOOTSTRAPPING bits and collision group are correct
+ // NO-OP: we assume SPECIAL_FLAGS_NO_BOOTSTRAPPING bits and collision group are correct
// because they should have been set correctly when the action was added
// and/or when children were linked
}
@@ -2112,7 +2114,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi
bool success = true;
serializeActions(success, _allActionsDataCache);
- _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
+ _flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
setDynamicDataNeedsTransmit(true);
return success;
}
@@ -2132,8 +2134,8 @@ bool EntityItem::clearActions(EntitySimulationPointer simulation) {
// empty _serializedActions means no actions for the EntityItem
_actionsToRemove.clear();
_allActionsDataCache.clear();
- _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
- _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
+ _flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
+ _flags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
});
return true;
}
@@ -2364,7 +2366,7 @@ QList EntityItem::getActionsOfType(EntityDynamicType typeT
void EntityItem::locationChanged(bool tellPhysics) {
requiresRecalcBoxes();
if (tellPhysics) {
- _dirtyFlags |= Simulation::DIRTY_TRANSFORM;
+ _flags |= Simulation::DIRTY_TRANSFORM;
EntityTreePointer tree = getTree();
if (tree) {
tree->entityChanged(getThisPointer());
@@ -2832,7 +2834,7 @@ DEFINE_PROPERTY_ACCESSOR(quint32, StaticCertificateVersion, staticCertificateVer
uint32_t EntityItem::getDirtyFlags() const {
uint32_t result;
withReadLock([&] {
- result = _dirtyFlags;
+ result = _flags & Simulation::DIRTY_FLAGS;
});
return result;
}
@@ -2840,13 +2842,37 @@ uint32_t EntityItem::getDirtyFlags() const {
void EntityItem::markDirtyFlags(uint32_t mask) {
withWriteLock([&] {
- _dirtyFlags |= mask;
+ mask &= Simulation::DIRTY_FLAGS;
+ _flags |= mask;
});
}
void EntityItem::clearDirtyFlags(uint32_t mask) {
withWriteLock([&] {
- _dirtyFlags &= ~mask;
+ mask &= Simulation::DIRTY_FLAGS;
+ _flags &= ~mask;
+ });
+}
+
+uint32_t EntityItem::getSpecialFlags() const {
+ uint32_t result;
+ withReadLock([&] {
+ result = _flags & Simulation::SPECIAL_FLAGS;
+ });
+ return result;
+}
+
+void EntityItem::markSpecialFlags(uint32_t mask) {
+ withWriteLock([&] {
+ mask &= Simulation::SPECIAL_FLAGS;
+ _flags |= mask;
+ });
+}
+
+void EntityItem::clearSpecialFlags(uint32_t mask) {
+ withWriteLock([&] {
+ mask &= Simulation::SPECIAL_FLAGS;
+ _flags &= ~mask;
});
}
diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h
index 4c398b8a29..5f84bcc311 100644
--- a/libraries/entities/src/EntityItem.h
+++ b/libraries/entities/src/EntityItem.h
@@ -358,7 +358,11 @@ public:
uint32_t getDirtyFlags() const;
void markDirtyFlags(uint32_t mask);
- void clearDirtyFlags(uint32_t mask = 0xffffffff);
+ void clearDirtyFlags(uint32_t mask = 0x0000ffff);
+
+ uint32_t getSpecialFlags() const;
+ void markSpecialFlags(uint32_t mask);
+ void clearSpecialFlags(uint32_t mask = 0xffff0000);
bool isMoving() const;
bool isMovingRelativeToParent() const;
@@ -385,7 +389,7 @@ public:
void getAllTerseUpdateProperties(EntityItemProperties& properties) const;
void flagForOwnershipBid(uint8_t priority);
- void flagForMotionStateChange() { _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; }
+ void flagForMotionStateChange() { _flags |= Simulation::DIRTY_MOTION_TYPE; }
QString actionsToDebugString();
bool addAction(EntitySimulationPointer simulation, EntityDynamicPointer action);
@@ -470,6 +474,9 @@ public:
static QString _marketplacePublicKey;
static void retrieveMarketplacePublicKey();
+ void setCauterized(bool value) { _cauterized = value; }
+ bool getCauterized() const { return _cauterized; }
+
signals:
void requestRenderUpdate();
@@ -572,7 +579,7 @@ protected:
//
// DirtyFlags are set whenever a property changes that the EntitySimulation needs to know about.
- uint32_t _dirtyFlags { 0 }; // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation
+ uint32_t _flags { 0 }; // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation
// these backpointers are only ever set/cleared by friends:
EntityTreeElementPointer _element; // set by EntityTreeElement
@@ -623,6 +630,7 @@ protected:
quint64 _lastUpdatedAccelerationTimestamp { 0 };
quint64 _lastUpdatedQueryAACubeTimestamp { 0 };
+ bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera
};
#endif // hifi_EntityItem_h
diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp
index a615beefa9..5d33e4c047 100644
--- a/libraries/entities/src/ModelEntityItem.cpp
+++ b/libraries/entities/src/ModelEntityItem.cpp
@@ -85,7 +85,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) {
bool somethingChangedInAnimations = _animationProperties.setProperties(properties);
if (somethingChangedInAnimations) {
- _dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
+ _flags |= Simulation::DIRTY_UPDATEABLE;
}
somethingChanged = somethingChanged || somethingChangedInAnimations;
@@ -132,7 +132,7 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType);
if (animationPropertiesChanged) {
- _dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
+ _flags |= Simulation::DIRTY_UPDATEABLE;
somethingChanged = true;
}
@@ -305,10 +305,10 @@ void ModelEntityItem::setShapeType(ShapeType type) {
// dynamic and STATIC_MESH are incompatible
// since the shape is being set here we clear the dynamic bit
_dynamic = false;
- _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
+ _flags |= Simulation::DIRTY_MOTION_TYPE;
}
_shapeType = type;
- _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
+ _flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
}
});
}
@@ -336,7 +336,7 @@ void ModelEntityItem::setModelURL(const QString& url) {
if (_modelURL != url) {
_modelURL = url;
if (_shapeType == SHAPE_TYPE_STATIC_MESH) {
- _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
+ _flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
}
}
});
@@ -348,14 +348,14 @@ void ModelEntityItem::setCompoundShapeURL(const QString& url) {
ShapeType oldType = computeTrueShapeType();
_compoundShapeURL.set(url);
if (oldType != computeTrueShapeType()) {
- _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
+ _flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
}
}
});
}
void ModelEntityItem::setAnimationURL(const QString& url) {
- _dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
+ _flags |= Simulation::DIRTY_UPDATEABLE;
withWriteLock([&] {
_animationProperties.setURL(url);
});
@@ -422,16 +422,16 @@ void ModelEntityItem::setAnimationSettings(const QString& value) {
bool allowTranslation = settingsMap["allowTranslation"].toBool();
setAnimationAllowTranslation(allowTranslation);
}
- _dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
+ _flags |= Simulation::DIRTY_UPDATEABLE;
}
void ModelEntityItem::setAnimationIsPlaying(bool value) {
- _dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
+ _flags |= Simulation::DIRTY_UPDATEABLE;
_animationProperties.setRunning(value);
}
void ModelEntityItem::setAnimationFPS(float value) {
- _dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
+ _flags |= Simulation::DIRTY_UPDATEABLE;
_animationProperties.setFPS(value);
}
diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp
index c20572a491..7d27011c56 100644
--- a/libraries/entities/src/ParticleEffectEntityItem.cpp
+++ b/libraries/entities/src/ParticleEffectEntityItem.cpp
@@ -601,7 +601,7 @@ void ParticleEffectEntityItem::setShapeType(ShapeType type) {
withWriteLock([&] {
if (type != _shapeType) {
_shapeType = type;
- _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
+ _flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
}
});
}
diff --git a/libraries/entities/src/SimulationFlags.h b/libraries/entities/src/SimulationFlags.h
index aaa92000e7..c45b333b29 100644
--- a/libraries/entities/src/SimulationFlags.h
+++ b/libraries/entities/src/SimulationFlags.h
@@ -27,10 +27,28 @@ namespace Simulation {
const uint32_t DIRTY_PHYSICS_ACTIVATION = 0x0800; // should activate object in physics engine
const uint32_t DIRTY_SIMULATOR_ID = 0x1000; // the simulatorID has changed
const uint32_t DIRTY_SIMULATION_OWNERSHIP_PRIORITY = 0x2000; // our own bid priority has changed
- const uint32_t NO_BOOTSTRAPPING = 0x4000;
+
+ // bits 17-32 are reservied for special flags
+ const uint32_t SPECIAL_FLAGS_NO_BOOTSTRAPPING = 0x10000;
const uint32_t DIRTY_TRANSFORM = DIRTY_POSITION | DIRTY_ROTATION;
const uint32_t DIRTY_VELOCITIES = DIRTY_LINEAR_VELOCITY | DIRTY_ANGULAR_VELOCITY;
+ const uint32_t SPECIAL_FLAGS = SPECIAL_FLAGS_NO_BOOTSTRAPPING;
+
+ const uint32_t DIRTY_FLAGS = DIRTY_POSITION |
+ DIRTY_ROTATION |
+ DIRTY_LINEAR_VELOCITY |
+ DIRTY_ANGULAR_VELOCITY |
+ DIRTY_MASS |
+ DIRTY_COLLISION_GROUP |
+ DIRTY_MOTION_TYPE |
+ DIRTY_SHAPE |
+ DIRTY_LIFETIME |
+ DIRTY_UPDATEABLE |
+ DIRTY_MATERIAL |
+ DIRTY_PHYSICS_ACTIVATION |
+ DIRTY_SIMULATOR_ID |
+ DIRTY_SIMULATION_OWNERSHIP_PRIORITY;
};
#endif // hifi_SimulationFlags_h
diff --git a/libraries/gl/src/gl/GLShaders.cpp b/libraries/gl/src/gl/GLShaders.cpp
index 017c92b71c..ecd6fe3323 100644
--- a/libraries/gl/src/gl/GLShaders.cpp
+++ b/libraries/gl/src/gl/GLShaders.cpp
@@ -6,9 +6,9 @@ namespace gl {
#ifdef SEPARATE_PROGRAM
- bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& error) {
+ bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& message) {
#else
- bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& error) {
+ bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& message) {
#endif
if (shaderSource.empty()) {
qCDebug(glLogging) << "GLShader::compileShader - no GLSL shader source code ? so failed to create";
@@ -34,52 +34,57 @@ namespace gl {
GLint compiled = 0;
glGetShaderiv(glshader, GL_COMPILE_STATUS, &compiled);
- // if compilation fails
- if (!compiled) {
-
- // save the source code to a temp file so we can debug easily
- /*
- std::ofstream filestream;
- filestream.open("debugshader.glsl");
- if (filestream.is_open()) {
- filestream << srcstr[0];
- filestream << srcstr[1];
- filestream.close();
- }
- */
-
- GLint infoLength = 0;
- glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength);
+ GLint infoLength = 0;
+ glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength);
+ if ((infoLength > 0) || !compiled) {
char* temp = new char[infoLength];
glGetShaderInfoLog(glshader, infoLength, NULL, temp);
+ message = std::string(temp);
- /*
- filestream.open("debugshader.glsl.info.txt");
- if (filestream.is_open()) {
- filestream << std::string(temp);
- filestream.close();
- }
- */
-
- qCCritical(glLogging) << "GLShader::compileShader - failed to compile the gl shader object:";
- int lineNumber = 0;
- for (auto s : srcstr) {
- QString str(s);
- QStringList lines = str.split("\n");
- for (auto& line : lines) {
- qCCritical(glLogging).noquote() << QString("%1: %2").arg(lineNumber++, 5, 10, QChar('0')).arg(line);
+ // if compilation fails
+ if (!compiled) {
+ // save the source code to a temp file so we can debug easily
+ /*
+ std::ofstream filestream;
+ filestream.open("debugshader.glsl");
+ if (filestream.is_open()) {
+ filestream << srcstr[0];
+ filestream << srcstr[1];
+ filestream.close();
}
+ */
+
+ /*
+ filestream.open("debugshader.glsl.info.txt");
+ if (filestream.is_open()) {
+ filestream << std::string(temp);
+ filestream.close();
+ }
+ */
+
+ qCCritical(glLogging) << "GLShader::compileShader - failed to compile the gl shader object:";
+ int lineNumber = 0;
+ for (auto s : srcstr) {
+ QString str(s);
+ QStringList lines = str.split("\n");
+ for (auto& line : lines) {
+ qCCritical(glLogging).noquote() << QString("%1: %2").arg(lineNumber++, 5, 10, QChar('0')).arg(line);
+ }
+ }
+ qCCritical(glLogging) << "GLShader::compileShader - errors:";
+ qCCritical(glLogging) << temp;
+
+ delete[] temp;
+ glDeleteShader(glshader);
+ return false;
}
- qCCritical(glLogging) << "GLShader::compileShader - errors:";
- qCCritical(glLogging) << temp;
- error = std::string(temp);
+ // Compilation success
+ qCWarning(glLogging) << "GLShader::compileShader - Success:";
+ qCWarning(glLogging) << temp;
delete[] temp;
-
- glDeleteShader(glshader);
- return false;
}
#ifdef SEPARATE_PROGRAM
@@ -137,7 +142,7 @@ namespace gl {
return true;
}
-GLuint compileProgram(const std::vector& glshaders, std::string& error) {
+GLuint compileProgram(const std::vector& glshaders, std::string& message, std::vector& binary) {
// A brand new program:
GLuint glprogram = glCreateProgram();
if (!glprogram) {
@@ -157,39 +162,65 @@ GLuint compileProgram(const std::vector& glshaders, std::string& error)
GLint linked = 0;
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
- if (!linked) {
- /*
- // save the source code to a temp file so we can debug easily
- std::ofstream filestream;
- filestream.open("debugshader.glsl");
- if (filestream.is_open()) {
- filestream << shaderSource->source;
- filestream.close();
- }
- */
-
- GLint infoLength = 0;
- glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength);
+ GLint infoLength = 0;
+ glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength);
+ if ((infoLength > 0) || !linked) {
char* temp = new char[infoLength];
glGetProgramInfoLog(glprogram, infoLength, NULL, temp);
- qCDebug(glLogging) << "GLShader::compileProgram - failed to LINK the gl program object :";
- qCDebug(glLogging) << temp;
+ message = std::string(temp);
- error = std::string(temp);
- delete[] temp;
+ if (!linked) {
+ /*
+ // save the source code to a temp file so we can debug easily
+ std::ofstream filestream;
+ filestream.open("debugshader.glsl");
+ if (filestream.is_open()) {
+ filestream << shaderSource->source;
+ filestream.close();
+ }
+ */
- /*
- filestream.open("debugshader.glsl.info.txt");
- if (filestream.is_open()) {
- filestream << std::string(temp);
- filestream.close();
+ qCDebug(glLogging) << "GLShader::compileProgram - failed to LINK the gl program object :";
+ qCDebug(glLogging) << temp;
+
+ delete[] temp;
+
+ /*
+ filestream.open("debugshader.glsl.info.txt");
+ if (filestream.is_open()) {
+ filestream << std::string(temp);
+ filestream.close();
+ }
+ */
+
+ glDeleteProgram(glprogram);
+ return 0;
+ } else {
+ qCDebug(glLogging) << "GLShader::compileProgram - success:";
+ qCDebug(glLogging) << temp;
+ delete[] temp;
}
- */
+ }
- glDeleteProgram(glprogram);
- return 0;
+ // If linked get the binaries
+ if (linked) {
+ GLint binaryLength = 0;
+ glGetProgramiv(glprogram, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
+
+ if (binaryLength > 0) {
+ GLint numBinFormats = 0;
+ glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numBinFormats);
+ if (numBinFormats > 0) {
+ binary.resize(binaryLength);
+ std::vector binFormats(numBinFormats);
+ glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, binFormats.data());
+
+ GLenum programBinFormat;
+ glGetProgramBinary(glprogram, binaryLength, NULL, &programBinFormat, binary.data());
+ }
+ }
}
return glprogram;
diff --git a/libraries/gl/src/gl/GLShaders.h b/libraries/gl/src/gl/GLShaders.h
index a6213fd280..fc070d7659 100644
--- a/libraries/gl/src/gl/GLShaders.h
+++ b/libraries/gl/src/gl/GLShaders.h
@@ -17,12 +17,12 @@
namespace gl {
#ifdef SEPARATE_PROGRAM
- bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& error);
+ bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& message);
#else
- bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& error);
+ bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& message);
#endif
- GLuint compileProgram(const std::vector& glshaders, std::string& error);
+ GLuint compileProgram(const std::vector& glshaders, std::string& message, std::vector& binary);
}
diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp
index eb6de5df13..08bd20be66 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp
@@ -68,8 +68,8 @@ GLBackend& getBackend() {
return *INSTANCE;
}
-bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) {
- return GLShader::makeProgram(getBackend(), shader, slotBindings);
+bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
+ return GLShader::makeProgram(getBackend(), shader, slotBindings, handler);
}
GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h
index 5558d3ada1..18916ac18c 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h
+++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h
@@ -64,7 +64,7 @@ protected:
explicit GLBackend(bool syncCache);
GLBackend();
public:
- static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet());
+ static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler);
virtual ~GLBackend();
@@ -423,8 +423,8 @@ protected:
} _pipeline;
// Backend dependant compilation of the shader
- virtual GLShader* compileBackendProgram(const Shader& program);
- virtual GLShader* compileBackendShader(const Shader& shader);
+ virtual GLShader* compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler);
+ virtual GLShader* compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler);
virtual std::string getBackendShaderHeader() const;
virtual void makeProgramBindings(ShaderObject& shaderObject);
class ElementResource {
diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
index 9adfd550ef..93c9b0d2ff 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp
@@ -56,28 +56,47 @@ static const std::array VERSION_DEFINES { {
stereoVersion
} };
-GLShader* GLBackend::compileBackendShader(const Shader& shader) {
+GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler) {
// Any GLSLprogram ? normally yes...
const std::string& shaderSource = shader.getSource().getCode();
GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
GLShader::ShaderObjects shaderObjects;
+ Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
+ shader.incrementCompilationAttempt();
for (int version = 0; version < GLShader::NumVersions; version++) {
auto& shaderObject = shaderObjects[version];
std::string shaderDefines = getBackendShaderHeader() + "\n" + DOMAIN_DEFINES[shader.getType()] + "\n" + VERSION_DEFINES[version];
- std::string error;
+ if (handler) {
+ bool retest = true;
+ std::string currentSrc = shaderSource;
+ // When a Handler is specified, we can try multiple times to build the shader and let the handler change the source if the compilation fails.
+ // The retest bool is set to false as soon as the compilation succeed to wexit the while loop.
+ // The handler tells us if we should retry or not while returning a modified version of the source.
+ while (retest) {
+ bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
+ compilationLogs[version].compiled = result;
+ if (!result) {
+ std::string newSrc;
+ retest = handler(shader, currentSrc, compilationLogs[version], newSrc);
+ currentSrc = newSrc;
+ } else {
+ retest = false;
+ }
+ }
+ } else {
+ compilationLogs[version].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
+ }
-#ifdef SEPARATE_PROGRAM
- bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, shaderObject.glprogram, error);
-#else
- bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, error);
-#endif
- if (!result) {
- qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << error.c_str();
+ if (!compilationLogs[version].compiled) {
+ qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[version].message.c_str();
+ shader.setCompilationLogs(compilationLogs);
return nullptr;
}
}
+ // Compilation feedback
+ shader.setCompilationLogs(compilationLogs);
// So far so good, the shader is created successfully
GLShader* object = new GLShader(this->shared_from_this());
@@ -86,39 +105,47 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader) {
return object;
}
-GLShader* GLBackend::compileBackendProgram(const Shader& program) {
+GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler) {
if (!program.isProgram()) {
return nullptr;
}
GLShader::ShaderObjects programObjects;
+ program.incrementCompilationAttempt();
+ Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
+
for (int version = 0; version < GLShader::NumVersions; version++) {
auto& programObject = programObjects[version];
// Let's go through every shaders and make sure they are ready to go
std::vector< GLuint > shaderGLObjects;
for (auto subShader : program.getShaders()) {
- auto object = GLShader::sync((*this), *subShader);
+ auto object = GLShader::sync((*this), *subShader, handler);
if (object) {
shaderGLObjects.push_back(object->_shaderObjects[version].glshader);
} else {
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - One of the shaders of the program is not compiled?";
+ compilationLogs[version].compiled = false;
+ compilationLogs[version].message = std::string("Failed to compile, one of the shaders of the program is not compiled ?");
+ program.setCompilationLogs(compilationLogs);
return nullptr;
}
}
- std::string error;
- GLuint glprogram = ::gl::compileProgram(shaderGLObjects, error);
+ GLuint glprogram = ::gl::compileProgram(shaderGLObjects, compilationLogs[version].message, compilationLogs[version].binary);
if (glprogram == 0) {
- qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << error.c_str();
+ qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[version].message.c_str();
+ program.setCompilationLogs(compilationLogs);
return nullptr;
}
-
+ compilationLogs[version].compiled = true;
programObject.glprogram = glprogram;
makeProgramBindings(programObject);
}
+ // Compilation feedback
+ program.setCompilationLogs(compilationLogs);
// So far so good, the program versions have all been created successfully
GLShader* object = new GLShader(this->shared_from_this());
diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp
index 7ed9121978..010a7c479c 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp
@@ -30,7 +30,7 @@ GLShader::~GLShader() {
}
}
-GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
+GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler) {
GLShader* object = Backend::getGPUObject(shader);
// If GPU object already created then good
@@ -39,13 +39,13 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
}
// need to have a gpu object?
if (shader.isProgram()) {
- GLShader* tempObject = backend.compileBackendProgram(shader);
+ GLShader* tempObject = backend.compileBackendProgram(shader, handler);
if (tempObject) {
object = tempObject;
Backend::setGPUObject(shader, object);
}
} else if (shader.isDomain()) {
- GLShader* tempObject = backend.compileBackendShader(shader);
+ GLShader* tempObject = backend.compileBackendShader(shader, handler);
if (tempObject) {
object = tempObject;
Backend::setGPUObject(shader, object);
@@ -56,10 +56,10 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
return object;
}
-bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings) {
+bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
// First make sure the Shader has been compiled
- GLShader* object = sync(backend, shader);
+ GLShader* object = sync(backend, shader, handler);
if (!object) {
return false;
}
diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.h b/libraries/gpu-gl/src/gpu/gl/GLShader.h
index dcf2dc330d..3259982e93 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLShader.h
+++ b/libraries/gpu-gl/src/gpu/gl/GLShader.h
@@ -21,8 +21,8 @@ struct ShaderObject {
class GLShader : public GPUObject {
public:
- static GLShader* sync(GLBackend& backend, const Shader& shader);
- static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings);
+ static GLShader* sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler = nullptr);
+ static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler);
enum Version {
Mono = 0,
diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackend.cpp
index 6fd5df6f81..fc1bc39929 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLBackend.cpp
+++ b/libraries/gpu-gles/src/gpu/gl/GLBackend.cpp
@@ -61,8 +61,8 @@ GLBackend& getBackend() {
return *INSTANCE;
}
-bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) {
- return GLShader::makeProgram(getBackend(), shader, slotBindings);
+bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
+ return GLShader::makeProgram(getBackend(), shader, slotBindings, handler);
}
diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackend.h b/libraries/gpu-gles/src/gpu/gl/GLBackend.h
index ea06b6b672..3681fc0492 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLBackend.h
+++ b/libraries/gpu-gles/src/gpu/gl/GLBackend.h
@@ -61,7 +61,7 @@ protected:
explicit GLBackend(bool syncCache);
GLBackend();
public:
- static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet());
+ static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet(), const Shader::CompilationHandler& handler = nullptr);
virtual ~GLBackend();
@@ -420,8 +420,8 @@ protected:
} _pipeline;
// Backend dependant compilation of the shader
- virtual GLShader* compileBackendProgram(const Shader& program);
- virtual GLShader* compileBackendShader(const Shader& shader);
+ virtual GLShader* compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler);
+ virtual GLShader* compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler);
virtual std::string getBackendShaderHeader() const;
virtual void makeProgramBindings(ShaderObject& shaderObject);
class ElementResource {
diff --git a/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
index fd44ad462f..677bba97ca 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
+++ b/libraries/gpu-gles/src/gpu/gl/GLBackendShader.cpp
@@ -56,32 +56,50 @@ static const std::array VERSION_DEFINES { {
stereoVersion
} };
-GLShader* GLBackend::compileBackendShader(const Shader& shader) {
+GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler) {
// Any GLSLprogram ? normally yes...
const std::string& shaderSource = shader.getSource().getCode();
GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
GLShader::ShaderObjects shaderObjects;
+ Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
for (int version = 0; version < GLShader::NumVersions; version++) {
auto& shaderObject = shaderObjects[version];
std::string shaderDefines = getBackendShaderHeader() + "\n" + DOMAIN_DEFINES[shader.getType()] + "\n" + VERSION_DEFINES[version]
- + "\n#extension GL_EXT_texture_buffer : enable"
- + "\nprecision lowp float; // check precision 2"
- + "\nprecision lowp samplerBuffer;"
- + "\nprecision lowp sampler2DShadow;";
- std::string error;
+ + "\n#extension GL_EXT_texture_buffer : enable"
+ + "\nprecision lowp float; // check precision 2"
+ + "\nprecision lowp samplerBuffer;"
+ + "\nprecision lowp sampler2DShadow;";
+ if (handler) {
+ bool retest = true;
+ std::string currentSrc = shaderSource;
+ // When a Handler is specified, we can try multiple times to build the shader and let the handler change the source if the compilation fails.
+ // The retest bool is set to false as soon as the compilation succeed to wexit the while loop.
+ // The handler tells us if we should retry or not while returning a modified version of the source.
+ while (retest) {
+ bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
+ compilationLogs[version].compiled = result;
+ if (!result) {
+ std::string newSrc;
+ retest = handler(shader, currentSrc, compilationLogs[version], newSrc);
+ currentSrc = newSrc;
+ } else {
+ retest = false;
+ }
+ }
+ } else {
+ compilationLogs[version].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
+ }
-#ifdef SEPARATE_PROGRAM
- bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, shaderObject.glprogram, error);
-#else
- bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, error);
-#endif
- if (!result) {
- qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << error.c_str();
+ if (!compilationLogs[version].compiled) {
+ qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[version].message.c_str();
+ shader.setCompilationLogs(compilationLogs);
return nullptr;
}
}
+ // Compilation feedback
+ shader.setCompilationLogs(compilationLogs);
// So far so good, the shader is created successfully
GLShader* object = new GLShader(this->shared_from_this());
@@ -90,32 +108,35 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader) {
return object;
}
-GLShader* GLBackend::compileBackendProgram(const Shader& program) {
+GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler) {
if (!program.isProgram()) {
return nullptr;
}
GLShader::ShaderObjects programObjects;
+ Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
+
for (int version = 0; version < GLShader::NumVersions; version++) {
auto& programObject = programObjects[version];
// Let's go through every shaders and make sure they are ready to go
- std::vector shaderGLObjects;
+ std::vector< GLuint > shaderGLObjects;
for (auto subShader : program.getShaders()) {
- auto object = GLShader::sync((*this), *subShader);
+ auto object = GLShader::sync((*this), *subShader, handler);
if (object) {
shaderGLObjects.push_back(object->_shaderObjects[version].glshader);
} else {
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - One of the shaders of the program is not compiled?";
+ program.setCompilationLogs(compilationLogs);
return nullptr;
}
}
- std::string error;
- GLuint glprogram = ::gl::compileProgram(shaderGLObjects, error);
+ GLuint glprogram = ::gl::compileProgram(shaderGLObjects, compilationLogs[version].message, compilationLogs[version].binary);
if (glprogram == 0) {
- qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << error.c_str();
+ qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[version].message.c_str();
+ program.setCompilationLogs(compilationLogs);
return nullptr;
}
@@ -123,6 +144,8 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program) {
makeProgramBindings(programObject);
}
+ // Compilation feedback
+ program.setCompilationLogs(compilationLogs);
// So far so good, the program versions have all been created successfully
GLShader* object = new GLShader(this->shared_from_this());
diff --git a/libraries/gpu-gles/src/gpu/gl/GLShader.cpp b/libraries/gpu-gles/src/gpu/gl/GLShader.cpp
index 7ed9121978..010a7c479c 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLShader.cpp
+++ b/libraries/gpu-gles/src/gpu/gl/GLShader.cpp
@@ -30,7 +30,7 @@ GLShader::~GLShader() {
}
}
-GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
+GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler) {
GLShader* object = Backend::getGPUObject(shader);
// If GPU object already created then good
@@ -39,13 +39,13 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
}
// need to have a gpu object?
if (shader.isProgram()) {
- GLShader* tempObject = backend.compileBackendProgram(shader);
+ GLShader* tempObject = backend.compileBackendProgram(shader, handler);
if (tempObject) {
object = tempObject;
Backend::setGPUObject(shader, object);
}
} else if (shader.isDomain()) {
- GLShader* tempObject = backend.compileBackendShader(shader);
+ GLShader* tempObject = backend.compileBackendShader(shader, handler);
if (tempObject) {
object = tempObject;
Backend::setGPUObject(shader, object);
@@ -56,10 +56,10 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader) {
return object;
}
-bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings) {
+bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
// First make sure the Shader has been compiled
- GLShader* object = sync(backend, shader);
+ GLShader* object = sync(backend, shader, handler);
if (!object) {
return false;
}
diff --git a/libraries/gpu-gles/src/gpu/gl/GLShader.h b/libraries/gpu-gles/src/gpu/gl/GLShader.h
index dcf2dc330d..f2a144a81c 100644
--- a/libraries/gpu-gles/src/gpu/gl/GLShader.h
+++ b/libraries/gpu-gles/src/gpu/gl/GLShader.h
@@ -21,8 +21,8 @@ struct ShaderObject {
class GLShader : public GPUObject {
public:
- static GLShader* sync(GLBackend& backend, const Shader& shader);
- static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings);
+ static GLShader* sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler = nullptr);
+ static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler = nullptr);
enum Version {
Mono = 0,
diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp
index 24128524da..d7d86c3ef7 100644
--- a/libraries/gpu/src/gpu/Context.cpp
+++ b/libraries/gpu/src/gpu/Context.cpp
@@ -127,7 +127,7 @@ void Context::executeFrame(const FramePointer& frame) const {
_frameStats.evalDelta(beginStats, endStats);
}
-bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
+bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler) {
// If we're running in another DLL context, we need to fetch the program callback out of the application
// FIXME find a way to do this without reliance on Qt app properties
if (!_makeProgramCallback) {
@@ -135,7 +135,7 @@ bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
_makeProgramCallback = reinterpret_cast(rawCallback);
}
if (shader.isProgram() && _makeProgramCallback) {
- return _makeProgramCallback(shader, bindings);
+ return _makeProgramCallback(shader, bindings, handler);
}
return false;
}
diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h
index 7b7575e9ed..195565f438 100644
--- a/libraries/gpu/src/gpu/Context.h
+++ b/libraries/gpu/src/gpu/Context.h
@@ -143,7 +143,7 @@ class Context {
public:
using Size = Resource::Size;
typedef BackendPointer (*CreateBackend)();
- typedef bool (*MakeProgram)(Shader& shader, const Shader::BindingSet& bindings);
+ typedef bool (*MakeProgram)(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler);
// This one call must happen before any context is created or used (Shader::MakeProgram) in order to setup the Backend and any singleton data needed
@@ -262,7 +262,7 @@ protected:
// makeProgramShader(...) make a program shader ready to be used in a Batch.
// It compiles the sub shaders, link them and defines the Slots and their bindings.
// If the shader passed is not a program, nothing happens.
- static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings);
+ static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler);
static CreateBackend _createBackendCallback;
static MakeProgram _makeProgramCallback;
diff --git a/libraries/gpu/src/gpu/Shader.cpp b/libraries/gpu/src/gpu/Shader.cpp
index 398a269f3f..aa7898569b 100755
--- a/libraries/gpu/src/gpu/Shader.cpp
+++ b/libraries/gpu/src/gpu/Shader.cpp
@@ -17,59 +17,111 @@
using namespace gpu;
-Shader::Shader(Type type, const Source& source):
+std::atomic Shader::_nextShaderID( 1 );
+Shader::DomainShaderMaps Shader::_domainShaderMaps;
+Shader::ProgramMap Shader::_programMap;
+
+
+Shader::Shader(Type type, const Source& source) :
_source(source),
- _type(type)
+ _type(type),
+ _ID(_nextShaderID++)
{
}
-Shader::Shader(Type type, const Pointer& vertex, const Pointer& pixel):
- _type(type)
+Shader::Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel):
+ _type(type),
+ _ID(_nextShaderID++)
{
- _shaders.resize(2);
- _shaders[VERTEX] = vertex;
- _shaders[PIXEL] = pixel;
-}
-
-Shader::Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel) :
-_type(type) {
- _shaders.resize(3);
- _shaders[VERTEX] = vertex;
- _shaders[GEOMETRY] = geometry;
- _shaders[PIXEL] = pixel;
+ if (geometry) {
+ _shaders.resize(3);
+ _shaders[VERTEX] = vertex;
+ _shaders[GEOMETRY] = geometry;
+ _shaders[PIXEL] = pixel;
+ } else {
+ _shaders.resize(2);
+ _shaders[VERTEX] = vertex;
+ _shaders[PIXEL] = pixel;
+ }
}
Shader::~Shader()
{
}
+Shader::Pointer Shader::createOrReuseDomainShader(Type type, const Source& source) {
+ auto found = _domainShaderMaps[type].find(source);
+ if (found != _domainShaderMaps[type].end()) {
+ auto sharedShader = (*found).second.lock();
+ if (sharedShader) {
+ return sharedShader;
+ }
+ }
+ auto shader = Pointer(new Shader(type, source));
+ _domainShaderMaps[type].emplace(source, std::weak_ptr(shader));
+ return shader;
+}
+
Shader::Pointer Shader::createVertex(const Source& source) {
- return Pointer(new Shader(VERTEX, source));
+ return createOrReuseDomainShader(VERTEX, source);
}
Shader::Pointer Shader::createPixel(const Source& source) {
- return Pointer(new Shader(PIXEL, source));
+ return createOrReuseDomainShader(PIXEL, source);
}
Shader::Pointer Shader::createGeometry(const Source& source) {
- return Pointer(new Shader(GEOMETRY, source));
+ return createOrReuseDomainShader(GEOMETRY, source);
}
-Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) {
- if (vertexShader && vertexShader->getType() == VERTEX &&
- pixelShader && pixelShader->getType() == PIXEL) {
- return Pointer(new Shader(PROGRAM, vertexShader, pixelShader));
+ShaderPointer Shader::createOrReuseProgramShader(Type type, const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) {
+ ProgramMapKey key(0);
+
+ if (vertexShader && vertexShader->getType() == VERTEX) {
+ key.x = vertexShader->getID();
+ } else {
+ // Shader is not valid, exit
+ return Pointer();
}
- return Pointer();
+
+ if (pixelShader && pixelShader->getType() == PIXEL) {
+ key.y = pixelShader->getID();
+ } else {
+ // Shader is not valid, exit
+ return Pointer();
+ }
+
+ if (geometryShader) {
+ if (geometryShader->getType() == GEOMETRY) {
+ key.z = geometryShader->getID();
+ } else {
+ // Shader is not valid, exit
+ return Pointer();
+ }
+ }
+
+ // program key is defined, now try to reuse
+ auto found = _programMap.find(key);
+ if (found != _programMap.end()) {
+ auto sharedShader = (*found).second.lock();
+ if (sharedShader) {
+ return sharedShader;
+ }
+ }
+
+ // Program is a new one, let's create it
+ auto program = Pointer(new Shader(type, vertexShader, geometryShader, pixelShader));
+ _programMap.emplace(key, std::weak_ptr(program));
+ return program;
+}
+
+
+Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) {
+ return createOrReuseProgramShader(PROGRAM, vertexShader, nullptr, pixelShader);
}
Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) {
- if (vertexShader && vertexShader->getType() == VERTEX &&
- geometryShader && geometryShader->getType() == GEOMETRY &&
- pixelShader && pixelShader->getType() == PIXEL) {
- return Pointer(new Shader(PROGRAM, vertexShader, geometryShader, pixelShader));
- }
- return Pointer();
+ return createOrReuseProgramShader(PROGRAM, vertexShader, geometryShader, pixelShader);
}
void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& uniformBuffers, const SlotSet& resourceBuffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs) {
@@ -82,9 +134,21 @@ void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& uniformBuffers,
_outputs = outputs;
}
-bool Shader::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
+bool Shader::makeProgram(Shader& shader, const Shader::BindingSet& bindings, const CompilationHandler& handler) {
if (shader.isProgram()) {
- return Context::makeProgram(shader, bindings);
+ return Context::makeProgram(shader, bindings, handler);
}
return false;
}
+
+void Shader::setCompilationLogs(const CompilationLogs& logs) const {
+ _compilationLogs.clear();
+ for (const auto& log : logs) {
+ _compilationLogs.emplace_back(CompilationLog(log));
+ }
+}
+
+void Shader::incrementCompilationAttempt() const {
+ _numCompilationAttempts++;
+}
+
diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h
index 181c9b5e78..4504337789 100755
--- a/libraries/gpu/src/gpu/Shader.h
+++ b/libraries/gpu/src/gpu/Shader.h
@@ -15,6 +15,7 @@
#include
#include
#include
+#include