mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 01:27:37 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into fixLoopingConnectionMonitor
This commit is contained in:
commit
bcd014ddc8
33 changed files with 460 additions and 346 deletions
|
@ -346,7 +346,15 @@ Item {
|
||||||
target: loginDialog
|
target: loginDialog
|
||||||
onHandleLoginCompleted: {
|
onHandleLoginCompleted: {
|
||||||
console.log("Login Succeeded, linking steam account")
|
console.log("Login Succeeded, linking steam account")
|
||||||
|
var poppedUp = Settings.getValue("loginDialogPoppedUp", false);
|
||||||
|
if (poppedUp) {
|
||||||
|
console.log("[ENCOURAGELOGINDIALOG]: logging in")
|
||||||
|
var data = {
|
||||||
|
"action": "user logged in"
|
||||||
|
};
|
||||||
|
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||||
|
Settings.setValue("loginDialogPoppedUp", false);
|
||||||
|
}
|
||||||
if (loginDialog.isSteamRunning()) {
|
if (loginDialog.isSteamRunning()) {
|
||||||
loginDialog.linkSteam()
|
loginDialog.linkSteam()
|
||||||
} else {
|
} else {
|
||||||
|
@ -354,23 +362,20 @@ Item {
|
||||||
bodyLoader.item.width = root.pane.width
|
bodyLoader.item.width = root.pane.width
|
||||||
bodyLoader.item.height = root.pane.height
|
bodyLoader.item.height = root.pane.height
|
||||||
}
|
}
|
||||||
if (Settings.getValue("loginDialogPoppedUp", false)) {
|
|
||||||
var data = {
|
|
||||||
"action": "user logged in"
|
|
||||||
};
|
|
||||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
onHandleLoginFailed: {
|
onHandleLoginFailed: {
|
||||||
console.log("Login Failed")
|
console.log("Login Failed")
|
||||||
mainTextContainer.visible = true
|
var poppedUp = Settings.getValue("loginDialogPoppedUp", false);
|
||||||
toggleLoading(false)
|
if (poppedUp) {
|
||||||
if (Settings.getValue("loginDialogPoppedUp", false)) {
|
console.log("[ENCOURAGELOGINDIALOG]: failed logging in")
|
||||||
var data = {
|
var data = {
|
||||||
"action": "user failed logging in"
|
"action": "user failed logging in"
|
||||||
};
|
};
|
||||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||||
|
Settings.setValue("loginDialogPoppedUp", false);
|
||||||
}
|
}
|
||||||
|
mainTextContainer.visible = true
|
||||||
|
toggleLoading(false)
|
||||||
}
|
}
|
||||||
onHandleLinkCompleted: {
|
onHandleLinkCompleted: {
|
||||||
console.log("Link Succeeded")
|
console.log("Link Succeeded")
|
||||||
|
|
|
@ -443,6 +443,11 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar
|
||||||
avatar->die();
|
avatar->die();
|
||||||
queuePhysicsChange(avatar);
|
queuePhysicsChange(avatar);
|
||||||
|
|
||||||
|
// remove this avatar's entities from the tree now, if we wait (as we did previously) for this Avatar's destructor
|
||||||
|
// it might not fire until after we create a new instance for the same remote avatar, which creates a race
|
||||||
|
// on the creation of entities for that avatar instance and the deletion of entities for this instance
|
||||||
|
avatar->removeAvatarEntitiesFromTree();
|
||||||
|
|
||||||
if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble) {
|
if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble) {
|
||||||
emit DependencyManager::get<UsersScriptingInterface>()->enteredIgnoreRadius();
|
emit DependencyManager::get<UsersScriptingInterface>()->enteredIgnoreRadius();
|
||||||
} else if (removalReason == KillAvatarReason::AvatarDisconnected) {
|
} else if (removalReason == KillAvatarReason::AvatarDisconnected) {
|
||||||
|
|
|
@ -131,16 +131,6 @@ Avatar::Avatar(QThread* thread) :
|
||||||
}
|
}
|
||||||
|
|
||||||
Avatar::~Avatar() {
|
Avatar::~Avatar() {
|
||||||
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
|
|
||||||
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
|
|
||||||
if (entityTree) {
|
|
||||||
entityTree->withWriteLock([&] {
|
|
||||||
AvatarEntityMap avatarEntities = getAvatarEntityData();
|
|
||||||
for (auto entityID : avatarEntities.keys()) {
|
|
||||||
entityTree->deleteEntity(entityID, true, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
if (geometryCache) {
|
if (geometryCache) {
|
||||||
geometryCache->releaseID(_nameRectGeometryID);
|
geometryCache->releaseID(_nameRectGeometryID);
|
||||||
|
@ -385,6 +375,19 @@ void Avatar::updateAvatarEntities() {
|
||||||
setAvatarEntityDataChanged(false);
|
setAvatarEntityDataChanged(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Avatar::removeAvatarEntitiesFromTree() {
|
||||||
|
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
|
||||||
|
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
|
||||||
|
if (entityTree) {
|
||||||
|
entityTree->withWriteLock([&] {
|
||||||
|
AvatarEntityMap avatarEntities = getAvatarEntityData();
|
||||||
|
for (auto entityID : avatarEntities.keys()) {
|
||||||
|
entityTree->deleteEntity(entityID, true, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Avatar::relayJointDataToChildren() {
|
void Avatar::relayJointDataToChildren() {
|
||||||
forEachChild([&](SpatiallyNestablePointer child) {
|
forEachChild([&](SpatiallyNestablePointer child) {
|
||||||
if (child->getNestableType() == NestableType::Entity) {
|
if (child->getNestableType() == NestableType::Entity) {
|
||||||
|
|
|
@ -73,6 +73,7 @@ public:
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void updateAvatarEntities();
|
void updateAvatarEntities();
|
||||||
|
void removeAvatarEntitiesFromTree();
|
||||||
void simulate(float deltaTime, bool inView);
|
void simulate(float deltaTime, bool inView);
|
||||||
virtual void simulateAttachments(float deltaTime);
|
virtual void simulateAttachments(float deltaTime);
|
||||||
|
|
||||||
|
|
|
@ -1861,9 +1861,7 @@ qint64 AvatarData::packTrait(AvatarTraits::TraitType traitType, ExtendedIODevice
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 AvatarData::packTraitInstance(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID traitInstanceID,
|
qint64 AvatarData::packTraitInstance(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID traitInstanceID,
|
||||||
ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion,
|
ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion) {
|
||||||
AvatarTraits::TraitInstanceID wireInstanceID) {
|
|
||||||
|
|
||||||
qint64 bytesWritten = 0;
|
qint64 bytesWritten = 0;
|
||||||
|
|
||||||
bytesWritten += destination.writePrimitive(traitType);
|
bytesWritten += destination.writePrimitive(traitType);
|
||||||
|
@ -1872,11 +1870,7 @@ qint64 AvatarData::packTraitInstance(AvatarTraits::TraitType traitType, AvatarTr
|
||||||
bytesWritten += destination.writePrimitive(traitVersion);
|
bytesWritten += destination.writePrimitive(traitVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wireInstanceID.isNull()) {
|
bytesWritten += destination.write(traitInstanceID.toRfc4122());
|
||||||
bytesWritten += destination.write(wireInstanceID.toRfc4122());
|
|
||||||
} else {
|
|
||||||
bytesWritten += destination.write(traitInstanceID.toRfc4122());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (traitType == AvatarTraits::AvatarEntity) {
|
if (traitType == AvatarTraits::AvatarEntity) {
|
||||||
// grab a read lock on the avatar entities and check for entity data for the given ID
|
// grab a read lock on the avatar entities and check for entity data for the given ID
|
||||||
|
|
|
@ -962,8 +962,7 @@ public:
|
||||||
qint64 packTrait(AvatarTraits::TraitType traitType, ExtendedIODevice& destination,
|
qint64 packTrait(AvatarTraits::TraitType traitType, ExtendedIODevice& destination,
|
||||||
AvatarTraits::TraitVersion traitVersion = AvatarTraits::NULL_TRAIT_VERSION);
|
AvatarTraits::TraitVersion traitVersion = AvatarTraits::NULL_TRAIT_VERSION);
|
||||||
qint64 packTraitInstance(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID,
|
qint64 packTraitInstance(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID,
|
||||||
ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion = AvatarTraits::NULL_TRAIT_VERSION,
|
ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion = AvatarTraits::NULL_TRAIT_VERSION);
|
||||||
AvatarTraits::TraitInstanceID wireInstanceID = AvatarTraits::TraitInstanceID());
|
|
||||||
|
|
||||||
void prepareResetTraitInstances();
|
void prepareResetTraitInstances();
|
||||||
|
|
||||||
|
@ -1193,9 +1192,6 @@ public:
|
||||||
void setReplicaIndex(int replicaIndex) { _replicaIndex = replicaIndex; }
|
void setReplicaIndex(int replicaIndex) { _replicaIndex = replicaIndex; }
|
||||||
int getReplicaIndex() { return _replicaIndex; }
|
int getReplicaIndex() { return _replicaIndex; }
|
||||||
|
|
||||||
const AvatarTraits::TraitInstanceID getTraitInstanceXORID() const { return _traitInstanceXORID; }
|
|
||||||
void cycleTraitInstanceXORID() { _traitInstanceXORID = QUuid::createUuid(); }
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
@ -1502,8 +1498,6 @@ private:
|
||||||
// privatize the copy constructor and assignment operator so they cannot be called
|
// privatize the copy constructor and assignment operator so they cannot be called
|
||||||
AvatarData(const AvatarData&);
|
AvatarData(const AvatarData&);
|
||||||
AvatarData& operator= (const AvatarData&);
|
AvatarData& operator= (const AvatarData&);
|
||||||
|
|
||||||
AvatarTraits::TraitInstanceID _traitInstanceXORID { QUuid::createUuid() };
|
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(AvatarData*)
|
Q_DECLARE_METATYPE(AvatarData*)
|
||||||
|
|
||||||
|
|
|
@ -86,8 +86,7 @@ void AvatarReplicas::processDeletedTraitInstance(const QUuid& parentID, AvatarTr
|
||||||
if (_replicasMap.find(parentID) != _replicasMap.end()) {
|
if (_replicasMap.find(parentID) != _replicasMap.end()) {
|
||||||
auto &replicas = _replicasMap[parentID];
|
auto &replicas = _replicasMap[parentID];
|
||||||
for (auto avatar : replicas) {
|
for (auto avatar : replicas) {
|
||||||
avatar->processDeletedTraitInstance(traitType,
|
avatar->processDeletedTraitInstance(traitType, instanceID);
|
||||||
AvatarTraits::xoredInstanceID(instanceID, avatar->getTraitInstanceXORID()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,9 +95,7 @@ void AvatarReplicas::processTraitInstance(const QUuid& parentID, AvatarTraits::T
|
||||||
if (_replicasMap.find(parentID) != _replicasMap.end()) {
|
if (_replicasMap.find(parentID) != _replicasMap.end()) {
|
||||||
auto &replicas = _replicasMap[parentID];
|
auto &replicas = _replicasMap[parentID];
|
||||||
for (auto avatar : replicas) {
|
for (auto avatar : replicas) {
|
||||||
avatar->processTraitInstance(traitType,
|
avatar->processTraitInstance(traitType, instanceID, traitBinaryData);
|
||||||
AvatarTraits::xoredInstanceID(instanceID, avatar->getTraitInstanceXORID()),
|
|
||||||
traitBinaryData);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -346,28 +343,16 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer<ReceivedMessage> mess
|
||||||
AvatarTraits::TraitInstanceID traitInstanceID =
|
AvatarTraits::TraitInstanceID traitInstanceID =
|
||||||
QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
||||||
|
|
||||||
// XOR the incoming trait instance ID with this avatar object's personal XOR ID
|
|
||||||
|
|
||||||
// this ensures that we have separate entity instances in the local tree
|
|
||||||
// if we briefly end up with two Avatar objects for this node
|
|
||||||
|
|
||||||
// (which can occur if the shared pointer for the
|
|
||||||
// previous instance of an avatar hasn't yet gone out of scope before the
|
|
||||||
// new instance is created)
|
|
||||||
|
|
||||||
auto xoredInstanceID = AvatarTraits::xoredInstanceID(traitInstanceID, avatar->getTraitInstanceXORID());
|
|
||||||
|
|
||||||
message->readPrimitive(&traitBinarySize);
|
message->readPrimitive(&traitBinarySize);
|
||||||
|
|
||||||
auto& processedInstanceVersion = lastProcessedVersions.getInstanceValueRef(traitType, traitInstanceID);
|
auto& processedInstanceVersion = lastProcessedVersions.getInstanceValueRef(traitType, traitInstanceID);
|
||||||
if (packetTraitVersion > processedInstanceVersion) {
|
if (packetTraitVersion > processedInstanceVersion) {
|
||||||
// in order to handle re-connections to the avatar mixer when the other
|
|
||||||
if (traitBinarySize == AvatarTraits::DELETED_TRAIT_SIZE) {
|
if (traitBinarySize == AvatarTraits::DELETED_TRAIT_SIZE) {
|
||||||
avatar->processDeletedTraitInstance(traitType, xoredInstanceID);
|
avatar->processDeletedTraitInstance(traitType, traitInstanceID);
|
||||||
_replicas.processDeletedTraitInstance(avatarID, traitType, traitInstanceID);
|
_replicas.processDeletedTraitInstance(avatarID, traitType, traitInstanceID);
|
||||||
} else {
|
} else {
|
||||||
auto traitData = message->read(traitBinarySize);
|
auto traitData = message->read(traitBinarySize);
|
||||||
avatar->processTraitInstance(traitType, xoredInstanceID, traitData);
|
avatar->processTraitInstance(traitType, traitInstanceID, traitData);
|
||||||
_replicas.processTraitInstance(avatarID, traitType, traitInstanceID, traitData);
|
_replicas.processTraitInstance(avatarID, traitType, traitInstanceID, traitData);
|
||||||
}
|
}
|
||||||
processedInstanceVersion = packetTraitVersion;
|
processedInstanceVersion = packetTraitVersion;
|
||||||
|
|
|
@ -41,8 +41,7 @@ namespace AvatarTraits {
|
||||||
const TraitWireSize DELETED_TRAIT_SIZE = -1;
|
const TraitWireSize DELETED_TRAIT_SIZE = -1;
|
||||||
|
|
||||||
inline qint64 packInstancedTraitDelete(TraitType traitType, TraitInstanceID instanceID, ExtendedIODevice& destination,
|
inline qint64 packInstancedTraitDelete(TraitType traitType, TraitInstanceID instanceID, ExtendedIODevice& destination,
|
||||||
TraitVersion traitVersion = NULL_TRAIT_VERSION,
|
TraitVersion traitVersion = NULL_TRAIT_VERSION) {
|
||||||
TraitInstanceID xoredInstanceID = TraitInstanceID()) {
|
|
||||||
qint64 bytesWritten = 0;
|
qint64 bytesWritten = 0;
|
||||||
|
|
||||||
bytesWritten += destination.writePrimitive(traitType);
|
bytesWritten += destination.writePrimitive(traitType);
|
||||||
|
@ -51,28 +50,12 @@ namespace AvatarTraits {
|
||||||
bytesWritten += destination.writePrimitive(traitVersion);
|
bytesWritten += destination.writePrimitive(traitVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xoredInstanceID.isNull()) {
|
bytesWritten += destination.write(instanceID.toRfc4122());
|
||||||
bytesWritten += destination.write(instanceID.toRfc4122());
|
|
||||||
} else {
|
|
||||||
bytesWritten += destination.write(xoredInstanceID.toRfc4122());
|
|
||||||
}
|
|
||||||
|
|
||||||
bytesWritten += destination.writePrimitive(DELETED_TRAIT_SIZE);
|
bytesWritten += destination.writePrimitive(DELETED_TRAIT_SIZE);
|
||||||
|
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline TraitInstanceID xoredInstanceID(TraitInstanceID localInstanceID, TraitInstanceID xorKeyID) {
|
|
||||||
QByteArray xoredInstanceID { NUM_BYTES_RFC4122_UUID, 0 };
|
|
||||||
auto xorKeyIDBytes = xorKeyID.toRfc4122();
|
|
||||||
auto localInstanceIDBytes = localInstanceID.toRfc4122();
|
|
||||||
|
|
||||||
for (auto i = 0; i < localInstanceIDBytes.size(); ++i) {
|
|
||||||
xoredInstanceID[i] = localInstanceIDBytes[i] ^ xorKeyIDBytes[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return QUuid::fromRfc4122(xoredInstanceID);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AvatarTraits_h
|
#endif // hifi_AvatarTraits_h
|
||||||
|
|
|
@ -43,9 +43,6 @@ void ClientTraitsHandler::resetForNewMixer() {
|
||||||
|
|
||||||
// pre-fill the instanced statuses that we will need to send next frame
|
// pre-fill the instanced statuses that we will need to send next frame
|
||||||
_owningAvatar->prepareResetTraitInstances();
|
_owningAvatar->prepareResetTraitInstances();
|
||||||
|
|
||||||
// reset the trait XOR ID since we're resetting for a new avatar mixer
|
|
||||||
_owningAvatar->cycleTraitInstanceXORID();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientTraitsHandler::sendChangedTraitsToMixer() {
|
void ClientTraitsHandler::sendChangedTraitsToMixer() {
|
||||||
|
@ -96,19 +93,11 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() {
|
||||||
|| instanceIDValuePair.value == Updated) {
|
|| instanceIDValuePair.value == Updated) {
|
||||||
// this is a changed trait we need to send or we haven't send out trait information yet
|
// this is a changed trait we need to send or we haven't send out trait information yet
|
||||||
// ask the owning avatar to pack it
|
// ask the owning avatar to pack it
|
||||||
|
_owningAvatar->packTraitInstance(instancedIt->traitType, instanceIDValuePair.id, *traitsPacketList);
|
||||||
// since this is going to the mixer, use the XORed instance ID (to anonymize trait instance IDs
|
|
||||||
// that would typically persist across sessions)
|
|
||||||
_owningAvatar->packTraitInstance(instancedIt->traitType, instanceIDValuePair.id, *traitsPacketList,
|
|
||||||
AvatarTraits::NULL_TRAIT_VERSION,
|
|
||||||
AvatarTraits::xoredInstanceID(instanceIDValuePair.id,
|
|
||||||
_owningAvatar->getTraitInstanceXORID()));
|
|
||||||
} else if (!_shouldPerformInitialSend && instanceIDValuePair.value == Deleted) {
|
} else if (!_shouldPerformInitialSend && instanceIDValuePair.value == Deleted) {
|
||||||
// pack delete for this trait instance
|
// pack delete for this trait instance
|
||||||
AvatarTraits::packInstancedTraitDelete(instancedIt->traitType, instanceIDValuePair.id,
|
AvatarTraits::packInstancedTraitDelete(instancedIt->traitType, instanceIDValuePair.id,
|
||||||
*traitsPacketList, AvatarTraits::NULL_TRAIT_VERSION,
|
*traitsPacketList);
|
||||||
AvatarTraits::xoredInstanceID(instanceIDValuePair.id,
|
|
||||||
_owningAvatar->getTraitInstanceXORID()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,9 +30,9 @@ public:
|
||||||
|
|
||||||
void markTraitUpdated(AvatarTraits::TraitType updatedTrait)
|
void markTraitUpdated(AvatarTraits::TraitType updatedTrait)
|
||||||
{ _traitStatuses[updatedTrait] = Updated; _hasChangedTraits = true; }
|
{ _traitStatuses[updatedTrait] = Updated; _hasChangedTraits = true; }
|
||||||
void markInstancedTraitUpdated(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID updatedInstanceID)
|
void markInstancedTraitUpdated(AvatarTraits::TraitType traitType, QUuid updatedInstanceID)
|
||||||
{ _traitStatuses.instanceInsert(traitType, updatedInstanceID, Updated); _hasChangedTraits = true; }
|
{ _traitStatuses.instanceInsert(traitType, updatedInstanceID, Updated); _hasChangedTraits = true; }
|
||||||
void markInstancedTraitDeleted(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID deleteInstanceID)
|
void markInstancedTraitDeleted(AvatarTraits::TraitType traitType, QUuid deleteInstanceID)
|
||||||
{ _traitStatuses.instanceInsert(traitType, deleteInstanceID, Deleted); _hasChangedTraits = true; }
|
{ _traitStatuses.instanceInsert(traitType, deleteInstanceID, Deleted); _hasChangedTraits = true; }
|
||||||
|
|
||||||
void resetForNewMixer();
|
void resetForNewMixer();
|
||||||
|
|
|
@ -240,7 +240,6 @@ public:
|
||||||
QVector<glm::vec3> vertices;
|
QVector<glm::vec3> vertices;
|
||||||
QVector<glm::vec3> normals;
|
QVector<glm::vec3> normals;
|
||||||
QVector<glm::vec3> tangents;
|
QVector<glm::vec3> tangents;
|
||||||
mutable QVector<NormalType> normalsAndTangents; // Populated later if needed for blendshapes
|
|
||||||
QVector<glm::vec3> colors;
|
QVector<glm::vec3> colors;
|
||||||
QVector<glm::vec2> texCoords;
|
QVector<glm::vec2> texCoords;
|
||||||
QVector<glm::vec2> texCoords1;
|
QVector<glm::vec2> texCoords1;
|
||||||
|
|
|
@ -201,9 +201,10 @@ void GLBackend::renderPassTransfer(const Batch& batch) {
|
||||||
{
|
{
|
||||||
Vec2u outputSize{ 1,1 };
|
Vec2u outputSize{ 1,1 };
|
||||||
|
|
||||||
if (_output._framebuffer) {
|
auto framebuffer = acquire(_output._framebuffer);
|
||||||
outputSize.x = _output._framebuffer->getWidth();
|
if (framebuffer) {
|
||||||
outputSize.y = _output._framebuffer->getHeight();
|
outputSize.x = framebuffer->getWidth();
|
||||||
|
outputSize.y = framebuffer->getHeight();
|
||||||
} else if (glm::dot(_transform._projectionJitter, _transform._projectionJitter)>0.0f) {
|
} else if (glm::dot(_transform._projectionJitter, _transform._projectionJitter)>0.0f) {
|
||||||
qCWarning(gpugllogging) << "Jittering needs to have a frame buffer to be set";
|
qCWarning(gpugllogging) << "Jittering needs to have a frame buffer to be set";
|
||||||
}
|
}
|
||||||
|
@ -220,6 +221,7 @@ void GLBackend::renderPassTransfer(const Batch& batch) {
|
||||||
_stereo._contextDisable = false;
|
_stereo._contextDisable = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Batch::COMMAND_setFramebuffer:
|
||||||
case Batch::COMMAND_setViewportTransform:
|
case Batch::COMMAND_setViewportTransform:
|
||||||
case Batch::COMMAND_setViewTransform:
|
case Batch::COMMAND_setViewTransform:
|
||||||
case Batch::COMMAND_setProjectionTransform:
|
case Batch::COMMAND_setProjectionTransform:
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
|
|
||||||
#include "GLShared.h"
|
#include "GLShared.h"
|
||||||
|
|
||||||
|
|
||||||
// Different versions for the stereo drawcall
|
// Different versions for the stereo drawcall
|
||||||
// Current preferred is "instanced" which draw the shape twice but instanced and rely on clipping plane to draw left/right side only
|
// Current preferred is "instanced" which draw the shape twice but instanced and rely on clipping plane to draw left/right side only
|
||||||
#if defined(USE_GLES)
|
#if defined(USE_GLES)
|
||||||
|
@ -40,7 +39,6 @@
|
||||||
#define GPU_STEREO_TECHNIQUE_INSTANCED
|
#define GPU_STEREO_TECHNIQUE_INSTANCED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Let these be configured by the one define picked above
|
// Let these be configured by the one define picked above
|
||||||
#ifdef GPU_STEREO_TECHNIQUE_DOUBLED_SIMPLE
|
#ifdef GPU_STEREO_TECHNIQUE_DOUBLED_SIMPLE
|
||||||
#define GPU_STEREO_DRAWCALL_DOUBLED
|
#define GPU_STEREO_DRAWCALL_DOUBLED
|
||||||
|
@ -56,8 +54,153 @@
|
||||||
#define GPU_STEREO_CAMERA_BUFFER
|
#define GPU_STEREO_CAMERA_BUFFER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// GL Backend pointer storage mechanism
|
||||||
|
// One of the following three defines must be defined.
|
||||||
|
// GPU_POINTER_STORAGE_SHARED
|
||||||
|
|
||||||
|
// The platonic ideal, use references to smart pointers.
|
||||||
|
// However, this produces artifacts because there are too many places in the code right now that
|
||||||
|
// create temporary values (undesirable smart pointer duplications) and then those temp variables
|
||||||
|
// get passed on and have their reference taken, and then invalidated
|
||||||
|
// GPU_POINTER_STORAGE_REF
|
||||||
|
|
||||||
|
// Raw pointer manipulation. Seems more dangerous than the reference wrappers,
|
||||||
|
// but in practice, the danger of grabbing a reference to a temporary variable
|
||||||
|
// is causing issues
|
||||||
|
// GPU_POINTER_STORAGE_RAW
|
||||||
|
|
||||||
|
#if defined(USE_GLES)
|
||||||
|
#define GPU_POINTER_STORAGE_SHARED
|
||||||
|
#else
|
||||||
|
#define GPU_POINTER_STORAGE_RAW
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace gpu { namespace gl {
|
namespace gpu { namespace gl {
|
||||||
|
|
||||||
|
#if defined(GPU_POINTER_STORAGE_SHARED)
|
||||||
|
template <typename T>
|
||||||
|
static inline bool compare(const std::shared_ptr<T>& a, const std::shared_ptr<T>& b) {
|
||||||
|
return a == b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline T* acquire(const std::shared_ptr<T>& pointer) {
|
||||||
|
return pointer.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline void reset(std::shared_ptr<T>& pointer) {
|
||||||
|
return pointer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline bool valid(const std::shared_ptr<T>& pointer) {
|
||||||
|
return pointer.operator bool();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline void assign(std::shared_ptr<T>& pointer, const std::shared_ptr<T>& source) {
|
||||||
|
pointer = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
using BufferReference = BufferPointer;
|
||||||
|
using TextureReference = TexturePointer;
|
||||||
|
using FramebufferReference = FramebufferPointer;
|
||||||
|
using FormatReference = Stream::FormatPointer;
|
||||||
|
using PipelineReference = PipelinePointer;
|
||||||
|
|
||||||
|
#define GPU_REFERENCE_INIT_VALUE nullptr
|
||||||
|
|
||||||
|
#elif defined(GPU_POINTER_STORAGE_REF)
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class PointerReferenceWrapper : public std::reference_wrapper<const std::shared_ptr<T>> {
|
||||||
|
using Parent = std::reference_wrapper<const std::shared_ptr<T>>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Pointer = std::shared_ptr<T>;
|
||||||
|
PointerReferenceWrapper() : Parent(EMPTY()) {}
|
||||||
|
PointerReferenceWrapper(const Pointer& pointer) : Parent(pointer) {}
|
||||||
|
void clear() { *this = EMPTY(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const Pointer& EMPTY() {
|
||||||
|
static const Pointer EMPTY_VALUE;
|
||||||
|
return EMPTY_VALUE;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static bool compare(const PointerReferenceWrapper<T>& reference, const std::shared_ptr<T>& pointer) {
|
||||||
|
return reference.get() == pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline T* acquire(const PointerReferenceWrapper<T>& reference) {
|
||||||
|
return reference.get().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static void assign(PointerReferenceWrapper<T>& reference, const std::shared_ptr<T>& pointer) {
|
||||||
|
reference = pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static bool valid(const PointerReferenceWrapper<T>& reference) {
|
||||||
|
return reference.get().operator bool();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline void reset(PointerReferenceWrapper<T>& reference) {
|
||||||
|
return reference.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
using BufferReference = PointerReferenceWrapper<Buffer>;
|
||||||
|
using TextureReference = PointerReferenceWrapper<Texture>;
|
||||||
|
using FramebufferReference = PointerReferenceWrapper<Framebuffer>;
|
||||||
|
using FormatReference = PointerReferenceWrapper<Stream::Format>;
|
||||||
|
using PipelineReference = PointerReferenceWrapper<Pipeline>;
|
||||||
|
|
||||||
|
#define GPU_REFERENCE_INIT_VALUE
|
||||||
|
|
||||||
|
#elif defined(GPU_POINTER_STORAGE_RAW)
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static bool compare(const T* const& rawPointer, const std::shared_ptr<T>& pointer) {
|
||||||
|
return rawPointer == pointer.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline T* acquire(T*& rawPointer) {
|
||||||
|
return rawPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline bool valid(const T* const& rawPointer) {
|
||||||
|
return rawPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline void reset(T*& rawPointer) {
|
||||||
|
rawPointer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline void assign(T*& rawPointer, const std::shared_ptr<T>& pointer) {
|
||||||
|
rawPointer = pointer.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
using BufferReference = Buffer*;
|
||||||
|
using TextureReference = Texture*;
|
||||||
|
using FramebufferReference = Framebuffer*;
|
||||||
|
using FormatReference = Stream::Format*;
|
||||||
|
using PipelineReference = Pipeline*;
|
||||||
|
|
||||||
|
#define GPU_REFERENCE_INIT_VALUE nullptr
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
class GLBackend : public Backend, public std::enable_shared_from_this<GLBackend> {
|
class GLBackend : public Backend, public std::enable_shared_from_this<GLBackend> {
|
||||||
// Context Backend static interface required
|
// Context Backend static interface required
|
||||||
friend class gpu::Context;
|
friend class gpu::Context;
|
||||||
|
@ -67,8 +210,8 @@ class GLBackend : public Backend, public std::enable_shared_from_this<GLBackend>
|
||||||
protected:
|
protected:
|
||||||
explicit GLBackend(bool syncCache);
|
explicit GLBackend(bool syncCache);
|
||||||
GLBackend();
|
GLBackend();
|
||||||
public:
|
|
||||||
|
|
||||||
|
public:
|
||||||
#if defined(USE_GLES)
|
#if defined(USE_GLES)
|
||||||
// https://www.khronos.org/registry/OpenGL-Refpages/es3/html/glGet.xhtml
|
// https://www.khronos.org/registry/OpenGL-Refpages/es3/html/glGet.xhtml
|
||||||
static const GLint MIN_REQUIRED_TEXTURE_IMAGE_UNITS = 16;
|
static const GLint MIN_REQUIRED_TEXTURE_IMAGE_UNITS = 16;
|
||||||
|
@ -109,8 +252,8 @@ public:
|
||||||
// This is the ugly "download the pixels to sysmem for taking a snapshot"
|
// This is the ugly "download the pixels to sysmem for taking a snapshot"
|
||||||
// Just avoid using it, it's ugly and will break performances
|
// Just avoid using it, it's ugly and will break performances
|
||||||
virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer,
|
virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer,
|
||||||
const Vec4i& region, QImage& destImage) final override;
|
const Vec4i& region,
|
||||||
|
QImage& destImage) final override;
|
||||||
|
|
||||||
// this is the maximum numeber of available input buffers
|
// this is the maximum numeber of available input buffers
|
||||||
size_t getNumInputBuffers() const { return _input._invalidBuffers.size(); }
|
size_t getNumInputBuffers() const { return _input._invalidBuffers.size(); }
|
||||||
|
@ -131,7 +274,6 @@ public:
|
||||||
static const int MAX_NUM_RESOURCE_TABLE_TEXTURES = 2;
|
static const int MAX_NUM_RESOURCE_TABLE_TEXTURES = 2;
|
||||||
size_t getMaxNumResourceTextureTables() const { return MAX_NUM_RESOURCE_TABLE_TEXTURES; }
|
size_t getMaxNumResourceTextureTables() const { return MAX_NUM_RESOURCE_TABLE_TEXTURES; }
|
||||||
|
|
||||||
|
|
||||||
// Draw Stage
|
// Draw Stage
|
||||||
virtual void do_draw(const Batch& batch, size_t paramOffset) = 0;
|
virtual void do_draw(const Batch& batch, size_t paramOffset) = 0;
|
||||||
virtual void do_drawIndexed(const Batch& batch, size_t paramOffset) = 0;
|
virtual void do_drawIndexed(const Batch& batch, size_t paramOffset) = 0;
|
||||||
|
@ -183,7 +325,6 @@ public:
|
||||||
// Reset stages
|
// Reset stages
|
||||||
virtual void do_resetStages(const Batch& batch, size_t paramOffset) final;
|
virtual void do_resetStages(const Batch& batch, size_t paramOffset) final;
|
||||||
|
|
||||||
|
|
||||||
virtual void do_disableContextViewCorrection(const Batch& batch, size_t paramOffset) final;
|
virtual void do_disableContextViewCorrection(const Batch& batch, size_t paramOffset) final;
|
||||||
virtual void do_restoreContextViewCorrection(const Batch& batch, size_t paramOffset) final;
|
virtual void do_restoreContextViewCorrection(const Batch& batch, size_t paramOffset) final;
|
||||||
|
|
||||||
|
@ -203,7 +344,7 @@ public:
|
||||||
virtual void do_popProfileRange(const Batch& batch, size_t paramOffset) final;
|
virtual void do_popProfileRange(const Batch& batch, size_t paramOffset) final;
|
||||||
|
|
||||||
// TODO: As long as we have gl calls explicitely issued from interface
|
// TODO: As long as we have gl calls explicitely issued from interface
|
||||||
// code, we need to be able to record and batch these calls. THe long
|
// code, we need to be able to record and batch these calls. THe long
|
||||||
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
|
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
|
||||||
virtual void do_glUniform1i(const Batch& batch, size_t paramOffset) final;
|
virtual void do_glUniform1i(const Batch& batch, size_t paramOffset) final;
|
||||||
virtual void do_glUniform1f(const Batch& batch, size_t paramOffset) final;
|
virtual void do_glUniform1f(const Batch& batch, size_t paramOffset) final;
|
||||||
|
@ -228,7 +369,9 @@ public:
|
||||||
virtual void do_setStateAntialiasedLineEnable(bool enable) final;
|
virtual void do_setStateAntialiasedLineEnable(bool enable) final;
|
||||||
virtual void do_setStateDepthBias(Vec2 bias) final;
|
virtual void do_setStateDepthBias(Vec2 bias) final;
|
||||||
virtual void do_setStateDepthTest(State::DepthTest test) final;
|
virtual void do_setStateDepthTest(State::DepthTest test) final;
|
||||||
virtual void do_setStateStencil(State::StencilActivation activation, State::StencilTest frontTest, State::StencilTest backTest) final;
|
virtual void do_setStateStencil(State::StencilActivation activation,
|
||||||
|
State::StencilTest frontTest,
|
||||||
|
State::StencilTest backTest) final;
|
||||||
virtual void do_setStateAlphaToCoverageEnable(bool enable) final;
|
virtual void do_setStateAlphaToCoverageEnable(bool enable) final;
|
||||||
virtual void do_setStateSampleMask(uint32 mask) final;
|
virtual void do_setStateSampleMask(uint32 mask) final;
|
||||||
virtual void do_setStateBlend(State::BlendFunction blendFunction) final;
|
virtual void do_setStateBlend(State::BlendFunction blendFunction) final;
|
||||||
|
@ -257,7 +400,9 @@ public:
|
||||||
virtual void releaseQuery(GLuint id) const;
|
virtual void releaseQuery(GLuint id) const;
|
||||||
virtual void queueLambda(const std::function<void()> lambda) const;
|
virtual void queueLambda(const std::function<void()> lambda) const;
|
||||||
|
|
||||||
bool isTextureManagementSparseEnabled() const override { return (_textureManagement._sparseCapable && Texture::getEnableSparseTextures()); }
|
bool isTextureManagementSparseEnabled() const override {
|
||||||
|
return (_textureManagement._sparseCapable && Texture::getEnableSparseTextures());
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual GLint getRealUniformLocation(GLint location) const;
|
virtual GLint getRealUniformLocation(GLint location) const;
|
||||||
|
@ -266,11 +411,11 @@ protected:
|
||||||
|
|
||||||
// FIXME instead of a single flag, create a features struct similar to
|
// FIXME instead of a single flag, create a features struct similar to
|
||||||
// https://www.khronos.org/registry/vulkan/specs/1.0/man/html/VkPhysicalDeviceFeatures.html
|
// https://www.khronos.org/registry/vulkan/specs/1.0/man/html/VkPhysicalDeviceFeatures.html
|
||||||
virtual bool supportsBindless() const { return false; }
|
virtual bool supportsBindless() const { return false; }
|
||||||
|
|
||||||
static const size_t INVALID_OFFSET = (size_t)-1;
|
static const size_t INVALID_OFFSET = (size_t)-1;
|
||||||
bool _inRenderTransferPass { false };
|
bool _inRenderTransferPass{ false };
|
||||||
int _currentDraw { -1 };
|
int _currentDraw{ -1 };
|
||||||
|
|
||||||
std::list<std::string> profileRanges;
|
std::list<std::string> profileRanges;
|
||||||
mutable Mutex _trashMutex;
|
mutable Mutex _trashMutex;
|
||||||
|
@ -299,46 +444,36 @@ protected:
|
||||||
virtual void updateInput() = 0;
|
virtual void updateInput() = 0;
|
||||||
|
|
||||||
struct InputStageState {
|
struct InputStageState {
|
||||||
bool _invalidFormat { true };
|
bool _invalidFormat{ true };
|
||||||
bool _lastUpdateStereoState{ false };
|
bool _lastUpdateStereoState{ false };
|
||||||
bool _hadColorAttribute{ true };
|
bool _hadColorAttribute{ true };
|
||||||
Stream::FormatPointer _format;
|
FormatReference _format{ GPU_REFERENCE_INIT_VALUE };
|
||||||
std::string _formatKey;
|
std::string _formatKey;
|
||||||
|
|
||||||
typedef std::bitset<MAX_NUM_ATTRIBUTES> ActivationCache;
|
typedef std::bitset<MAX_NUM_ATTRIBUTES> ActivationCache;
|
||||||
ActivationCache _attributeActivation { 0 };
|
ActivationCache _attributeActivation{ 0 };
|
||||||
|
|
||||||
typedef std::bitset<MAX_NUM_INPUT_BUFFERS> BuffersState;
|
typedef std::bitset<MAX_NUM_INPUT_BUFFERS> BuffersState;
|
||||||
|
|
||||||
BuffersState _invalidBuffers{ 0 };
|
BuffersState _invalidBuffers{ 0 };
|
||||||
BuffersState _attribBindingBuffers{ 0 };
|
BuffersState _attribBindingBuffers{ 0 };
|
||||||
|
|
||||||
Buffers _buffers;
|
std::array<BufferReference, MAX_NUM_INPUT_BUFFERS> _buffers{};
|
||||||
Offsets _bufferOffsets;
|
std::array<Offset, MAX_NUM_INPUT_BUFFERS> _bufferOffsets{};
|
||||||
Offsets _bufferStrides;
|
std::array<Offset, MAX_NUM_INPUT_BUFFERS> _bufferStrides{};
|
||||||
std::vector<GLuint> _bufferVBOs;
|
std::array<GLuint, MAX_NUM_INPUT_BUFFERS> _bufferVBOs{};
|
||||||
|
|
||||||
glm::vec4 _colorAttribute{ 0.0f };
|
glm::vec4 _colorAttribute{ 0.0f };
|
||||||
|
|
||||||
BufferPointer _indexBuffer;
|
BufferReference _indexBuffer{};
|
||||||
Offset _indexBufferOffset { 0 };
|
Offset _indexBufferOffset{ 0 };
|
||||||
Type _indexBufferType { UINT32 };
|
Type _indexBufferType{ UINT32 };
|
||||||
|
|
||||||
BufferPointer _indirectBuffer;
|
BufferReference _indirectBuffer{};
|
||||||
Offset _indirectBufferOffset{ 0 };
|
Offset _indirectBufferOffset{ 0 };
|
||||||
Offset _indirectBufferStride{ 0 };
|
Offset _indirectBufferStride{ 0 };
|
||||||
|
|
||||||
GLuint _defaultVAO { 0 };
|
GLuint _defaultVAO{ 0 };
|
||||||
|
|
||||||
InputStageState() :
|
|
||||||
_invalidFormat(true),
|
|
||||||
_format(0),
|
|
||||||
_formatKey(),
|
|
||||||
_attributeActivation(0),
|
|
||||||
_buffers(_invalidBuffers.size(), BufferPointer(0)),
|
|
||||||
_bufferOffsets(_invalidBuffers.size(), 0),
|
|
||||||
_bufferStrides(_invalidBuffers.size(), 0),
|
|
||||||
_bufferVBOs(_invalidBuffers.size(), 0) {}
|
|
||||||
} _input;
|
} _input;
|
||||||
|
|
||||||
virtual void initTransform() = 0;
|
virtual void initTransform() = 0;
|
||||||
|
@ -349,7 +484,7 @@ protected:
|
||||||
virtual void resetTransformStage();
|
virtual void resetTransformStage();
|
||||||
|
|
||||||
// Allows for correction of the camera pose to account for changes
|
// Allows for correction of the camera pose to account for changes
|
||||||
// between the time when a was recorded and the time(s) when it is
|
// between the time when a was recorded and the time(s) when it is
|
||||||
// executed
|
// executed
|
||||||
// Prev is the previous correction used at previous frame
|
// Prev is the previous correction used at previous frame
|
||||||
struct CameraCorrection {
|
struct CameraCorrection {
|
||||||
|
@ -364,9 +499,12 @@ protected:
|
||||||
struct Cameras {
|
struct Cameras {
|
||||||
TransformCamera _cams[2];
|
TransformCamera _cams[2];
|
||||||
|
|
||||||
Cameras() {};
|
Cameras(){};
|
||||||
Cameras(const TransformCamera& cam) { memcpy(_cams, &cam, sizeof(TransformCamera)); };
|
Cameras(const TransformCamera& cam) { memcpy(_cams, &cam, sizeof(TransformCamera)); };
|
||||||
Cameras(const TransformCamera& camL, const TransformCamera& camR) { memcpy(_cams, &camL, sizeof(TransformCamera)); memcpy(_cams + 1, &camR, sizeof(TransformCamera)); };
|
Cameras(const TransformCamera& camL, const TransformCamera& camR) {
|
||||||
|
memcpy(_cams, &camL, sizeof(TransformCamera));
|
||||||
|
memcpy(_cams + 1, &camR, sizeof(TransformCamera));
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
using CameraBufferElement = Cameras;
|
using CameraBufferElement = Cameras;
|
||||||
|
@ -380,25 +518,24 @@ protected:
|
||||||
|
|
||||||
mutable std::map<std::string, GLvoid*> _drawCallInfoOffsets;
|
mutable std::map<std::string, GLvoid*> _drawCallInfoOffsets;
|
||||||
|
|
||||||
GLuint _objectBuffer { 0 };
|
GLuint _objectBuffer{ 0 };
|
||||||
GLuint _cameraBuffer { 0 };
|
GLuint _cameraBuffer{ 0 };
|
||||||
GLuint _drawCallInfoBuffer { 0 };
|
GLuint _drawCallInfoBuffer{ 0 };
|
||||||
GLuint _objectBufferTexture { 0 };
|
GLuint _objectBufferTexture{ 0 };
|
||||||
size_t _cameraUboSize { 0 };
|
size_t _cameraUboSize{ 0 };
|
||||||
bool _viewIsCamera{ false };
|
bool _viewIsCamera{ false };
|
||||||
bool _skybox { false };
|
bool _skybox{ false };
|
||||||
Transform _view;
|
Transform _view;
|
||||||
CameraCorrection _correction;
|
CameraCorrection _correction;
|
||||||
bool _viewCorrectionEnabled{ true };
|
bool _viewCorrectionEnabled{ true };
|
||||||
|
|
||||||
|
|
||||||
Mat4 _projection;
|
Mat4 _projection;
|
||||||
Vec4i _viewport { 0, 0, 1, 1 };
|
Vec4i _viewport{ 0, 0, 1, 1 };
|
||||||
Vec2 _depthRange { 0.0f, 1.0f };
|
Vec2 _depthRange{ 0.0f, 1.0f };
|
||||||
Vec2 _projectionJitter{ 0.0f, 0.0f };
|
Vec2 _projectionJitter{ 0.0f, 0.0f };
|
||||||
bool _invalidView { false };
|
bool _invalidView{ false };
|
||||||
bool _invalidProj { false };
|
bool _invalidProj{ false };
|
||||||
bool _invalidViewport { false };
|
bool _invalidViewport{ false };
|
||||||
|
|
||||||
bool _enabledDrawcallInfoBuffer{ false };
|
bool _enabledDrawcallInfoBuffer{ false };
|
||||||
|
|
||||||
|
@ -417,45 +554,54 @@ protected:
|
||||||
|
|
||||||
struct UniformStageState {
|
struct UniformStageState {
|
||||||
struct BufferState {
|
struct BufferState {
|
||||||
BufferPointer buffer;
|
BufferReference buffer{};
|
||||||
GLintptr offset{ 0 };
|
GLintptr offset{ 0 };
|
||||||
GLsizeiptr size{ 0 };
|
GLsizeiptr size{ 0 };
|
||||||
BufferState(const BufferPointer& buffer = nullptr, GLintptr offset = 0, GLsizeiptr size = 0);
|
|
||||||
bool operator ==(BufferState& other) const {
|
BufferState& operator=(const BufferState& other) = delete;
|
||||||
return offset == other.offset && size == other.size && buffer == other.buffer;
|
void reset() {
|
||||||
|
gpu::gl::reset(buffer);
|
||||||
|
offset = 0;
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
bool compare(const BufferPointer& buffer, GLintptr offset, GLsizeiptr size) {
|
||||||
|
const auto& self = *this;
|
||||||
|
return (self.offset == offset && self.size == size && gpu::gl::compare(self.buffer, buffer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// MAX_NUM_UNIFORM_BUFFERS-1 is the max uniform index BATCHES are allowed to set, but
|
// MAX_NUM_UNIFORM_BUFFERS-1 is the max uniform index BATCHES are allowed to set, but
|
||||||
// MIN_REQUIRED_UNIFORM_BUFFER_BINDINGS is used here because the backend sets some
|
// MIN_REQUIRED_UNIFORM_BUFFER_BINDINGS is used here because the backend sets some
|
||||||
// internal UBOs for things like camera correction
|
// internal UBOs for things like camera correction
|
||||||
std::array<BufferState, MIN_REQUIRED_UNIFORM_BUFFER_BINDINGS> _buffers;
|
std::array<BufferState, MIN_REQUIRED_UNIFORM_BUFFER_BINDINGS> _buffers;
|
||||||
} _uniform;
|
} _uniform;
|
||||||
|
|
||||||
// Helper function that provides common code
|
// Helper function that provides common code
|
||||||
void bindUniformBuffer(uint32_t slot, const BufferPointer& buffer, GLintptr offset = 0, GLsizeiptr size = 0);
|
void bindUniformBuffer(uint32_t slot, const BufferPointer& buffer, GLintptr offset = 0, GLsizeiptr size = 0);
|
||||||
void releaseUniformBuffer(uint32_t slot);
|
void releaseUniformBuffer(uint32_t slot);
|
||||||
void resetUniformStage();
|
void resetUniformStage();
|
||||||
|
|
||||||
// update resource cache and do the gl bind/unbind call with the current gpu::Buffer cached at slot s
|
// update resource cache and do the gl bind/unbind call with the current gpu::Buffer cached at slot s
|
||||||
// This is using different gl object depending on the gl version
|
// This is using different gl object depending on the gl version
|
||||||
virtual bool bindResourceBuffer(uint32_t slot, BufferPointer& buffer) = 0;
|
virtual bool bindResourceBuffer(uint32_t slot, const BufferPointer& buffer) = 0;
|
||||||
virtual void releaseResourceBuffer(uint32_t slot) = 0;
|
virtual void releaseResourceBuffer(uint32_t slot) = 0;
|
||||||
|
|
||||||
// Helper function that provides common code used by do_setResourceTexture and
|
// Helper function that provides common code used by do_setResourceTexture and
|
||||||
// do_setResourceTextureTable (in non-bindless mode)
|
// do_setResourceTextureTable (in non-bindless mode)
|
||||||
void bindResourceTexture(uint32_t slot, const TexturePointer& texture);
|
void bindResourceTexture(uint32_t slot, const TexturePointer& texture);
|
||||||
|
|
||||||
|
|
||||||
// update resource cache and do the gl unbind call with the current gpu::Texture cached at slot s
|
// update resource cache and do the gl unbind call with the current gpu::Texture cached at slot s
|
||||||
void releaseResourceTexture(uint32_t slot);
|
void releaseResourceTexture(uint32_t slot);
|
||||||
|
|
||||||
void resetResourceStage();
|
void resetResourceStage();
|
||||||
|
|
||||||
struct ResourceStageState {
|
struct ResourceStageState {
|
||||||
std::array<BufferPointer, MAX_NUM_RESOURCE_BUFFERS> _buffers;
|
struct TextureState {
|
||||||
std::array<TexturePointer, MAX_NUM_RESOURCE_TEXTURES> _textures;
|
TextureReference _texture{};
|
||||||
//Textures _textures { { MAX_NUM_RESOURCE_TEXTURES } };
|
GLenum _target;
|
||||||
|
};
|
||||||
|
std::array<BufferReference, MAX_NUM_RESOURCE_BUFFERS> _buffers{};
|
||||||
|
std::array<TextureState, MAX_NUM_RESOURCE_TEXTURES> _textures{};
|
||||||
int findEmptyTextureSlot() const;
|
int findEmptyTextureSlot() const;
|
||||||
} _resource;
|
} _resource;
|
||||||
|
|
||||||
|
@ -470,21 +616,22 @@ protected:
|
||||||
void resetPipelineStage();
|
void resetPipelineStage();
|
||||||
|
|
||||||
struct PipelineStageState {
|
struct PipelineStageState {
|
||||||
PipelinePointer _pipeline;
|
PipelineReference _pipeline{};
|
||||||
|
|
||||||
GLuint _program { 0 };
|
GLuint _program{ 0 };
|
||||||
bool _cameraCorrection { false };
|
bool _cameraCorrection{ false };
|
||||||
GLShader* _programShader { nullptr };
|
GLShader* _programShader{ nullptr };
|
||||||
bool _invalidProgram { false };
|
bool _invalidProgram{ false };
|
||||||
|
|
||||||
BufferView _cameraCorrectionBuffer { gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(CameraCorrection), nullptr )) };
|
BufferView _cameraCorrectionBuffer{ gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(CameraCorrection), nullptr)) };
|
||||||
BufferView _cameraCorrectionBufferIdentity { gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(CameraCorrection), nullptr )) };
|
BufferView _cameraCorrectionBufferIdentity{ gpu::BufferView(
|
||||||
|
std::make_shared<gpu::Buffer>(sizeof(CameraCorrection), nullptr)) };
|
||||||
|
|
||||||
State::Data _stateCache{ State::DEFAULT };
|
State::Data _stateCache{ State::DEFAULT };
|
||||||
State::Signature _stateSignatureCache { 0 };
|
State::Signature _stateSignatureCache{ 0 };
|
||||||
|
|
||||||
GLState* _state { nullptr };
|
GLState* _state{ nullptr };
|
||||||
bool _invalidState { false };
|
bool _invalidState{ false };
|
||||||
|
|
||||||
PipelineStageState() {
|
PipelineStageState() {
|
||||||
_cameraCorrectionBuffer.edit<CameraCorrection>() = CameraCorrection();
|
_cameraCorrectionBuffer.edit<CameraCorrection>() = CameraCorrection();
|
||||||
|
@ -498,9 +645,9 @@ protected:
|
||||||
virtual GLShader* compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler);
|
virtual GLShader* compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler);
|
||||||
virtual GLShader* compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler);
|
virtual GLShader* compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler);
|
||||||
virtual std::string getBackendShaderHeader() const = 0;
|
virtual std::string getBackendShaderHeader() const = 0;
|
||||||
// For a program, this will return a string containing all the source files (without any
|
// For a program, this will return a string containing all the source files (without any
|
||||||
// backend headers or defines). For a vertex, fragment or geometry shader, this will
|
// backend headers or defines). For a vertex, fragment or geometry shader, this will
|
||||||
// return the fully customized shader with all the version and backend specific
|
// return the fully customized shader with all the version and backend specific
|
||||||
// preprocessor directives
|
// preprocessor directives
|
||||||
// The program string returned can be used as a key for a cache of shader binaries
|
// The program string returned can be used as a key for a cache of shader binaries
|
||||||
// The shader strings can be reliably sent to the low level `compileShader` functions
|
// The shader strings can be reliably sent to the low level `compileShader` functions
|
||||||
|
@ -516,22 +663,22 @@ protected:
|
||||||
// Synchronize the state cache of this Backend with the actual real state of the GL Context
|
// Synchronize the state cache of this Backend with the actual real state of the GL Context
|
||||||
void syncOutputStateCache();
|
void syncOutputStateCache();
|
||||||
void resetOutputStage();
|
void resetOutputStage();
|
||||||
|
|
||||||
struct OutputStageState {
|
struct OutputStageState {
|
||||||
FramebufferPointer _framebuffer { nullptr };
|
FramebufferReference _framebuffer{};
|
||||||
GLuint _drawFBO { 0 };
|
GLuint _drawFBO{ 0 };
|
||||||
} _output;
|
} _output;
|
||||||
|
|
||||||
void resetQueryStage();
|
void resetQueryStage();
|
||||||
struct QueryStageState {
|
struct QueryStageState {
|
||||||
uint32_t _rangeQueryDepth { 0 };
|
uint32_t _rangeQueryDepth{ 0 };
|
||||||
} _queryStage;
|
} _queryStage;
|
||||||
|
|
||||||
void resetStages();
|
void resetStages();
|
||||||
|
|
||||||
// Stores cached binary versions of the shaders for quicker startup on subsequent runs
|
// Stores cached binary versions of the shaders for quicker startup on subsequent runs
|
||||||
// Note that shaders in the cache can still fail to load due to hardware or driver
|
// Note that shaders in the cache can still fail to load due to hardware or driver
|
||||||
// changes that invalidate the cached binary, in which case we fall back on compiling
|
// changes that invalidate the cached binary, in which case we fall back on compiling
|
||||||
// the source again
|
// the source again
|
||||||
struct ShaderBinaryCache {
|
struct ShaderBinaryCache {
|
||||||
std::mutex _mutex;
|
std::mutex _mutex;
|
||||||
|
@ -543,7 +690,7 @@ protected:
|
||||||
virtual void killShaderBinaryCache();
|
virtual void killShaderBinaryCache();
|
||||||
|
|
||||||
struct TextureManagementStageState {
|
struct TextureManagementStageState {
|
||||||
bool _sparseCapable { false };
|
bool _sparseCapable{ false };
|
||||||
GLTextureTransferEnginePointer _transferEngine;
|
GLTextureTransferEnginePointer _transferEngine;
|
||||||
} _textureManagement;
|
} _textureManagement;
|
||||||
virtual void initTextureManagementStage();
|
virtual void initTextureManagementStage();
|
||||||
|
@ -556,6 +703,6 @@ protected:
|
||||||
friend class GLShader;
|
friend class GLShader;
|
||||||
};
|
};
|
||||||
|
|
||||||
} }
|
}} // namespace gpu::gl
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -17,10 +17,10 @@ using namespace gpu;
|
||||||
using namespace gpu::gl;
|
using namespace gpu::gl;
|
||||||
|
|
||||||
void GLBackend::do_setInputFormat(const Batch& batch, size_t paramOffset) {
|
void GLBackend::do_setInputFormat(const Batch& batch, size_t paramOffset) {
|
||||||
Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint);
|
const auto& format = batch._streamFormats.get(batch._params[paramOffset]._uint);
|
||||||
if (format != _input._format) {
|
if (!compare(_input._format, format)) {
|
||||||
_input._format = format;
|
|
||||||
if (format) {
|
if (format) {
|
||||||
|
assign(_input._format, format);
|
||||||
auto inputFormat = GLInputFormat::sync((*format));
|
auto inputFormat = GLInputFormat::sync((*format));
|
||||||
assert(inputFormat);
|
assert(inputFormat);
|
||||||
if (_input._formatKey != inputFormat->key) {
|
if (_input._formatKey != inputFormat->key) {
|
||||||
|
@ -28,6 +28,7 @@ void GLBackend::do_setInputFormat(const Batch& batch, size_t paramOffset) {
|
||||||
_input._invalidFormat = true;
|
_input._invalidFormat = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
reset(_input._format);
|
||||||
_input._formatKey.clear();
|
_input._formatKey.clear();
|
||||||
_input._invalidFormat = true;
|
_input._invalidFormat = true;
|
||||||
}
|
}
|
||||||
|
@ -37,13 +38,13 @@ void GLBackend::do_setInputFormat(const Batch& batch, size_t paramOffset) {
|
||||||
void GLBackend::do_setInputBuffer(const Batch& batch, size_t paramOffset) {
|
void GLBackend::do_setInputBuffer(const Batch& batch, size_t paramOffset) {
|
||||||
Offset stride = batch._params[paramOffset + 0]._uint;
|
Offset stride = batch._params[paramOffset + 0]._uint;
|
||||||
Offset offset = batch._params[paramOffset + 1]._uint;
|
Offset offset = batch._params[paramOffset + 1]._uint;
|
||||||
BufferPointer buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
const auto& buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
||||||
uint32 channel = batch._params[paramOffset + 3]._uint;
|
uint32 channel = batch._params[paramOffset + 3]._uint;
|
||||||
|
|
||||||
if (channel < getNumInputBuffers()) {
|
if (channel < getNumInputBuffers()) {
|
||||||
bool isModified = false;
|
bool isModified = false;
|
||||||
if (_input._buffers[channel] != buffer) {
|
if (!compare(_input._buffers[channel], buffer)) {
|
||||||
_input._buffers[channel] = buffer;
|
assign(_input._buffers[channel], buffer);
|
||||||
_input._bufferVBOs[channel] = getBufferIDUnsynced((*buffer));
|
_input._bufferVBOs[channel] = getBufferIDUnsynced((*buffer));
|
||||||
isModified = true;
|
isModified = true;
|
||||||
}
|
}
|
||||||
|
@ -94,18 +95,18 @@ void GLBackend::resetInputStage() {
|
||||||
// Reset index buffer
|
// Reset index buffer
|
||||||
_input._indexBufferType = UINT32;
|
_input._indexBufferType = UINT32;
|
||||||
_input._indexBufferOffset = 0;
|
_input._indexBufferOffset = 0;
|
||||||
_input._indexBuffer.reset();
|
reset(_input._indexBuffer);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
(void) CHECK_GL_ERROR();
|
(void) CHECK_GL_ERROR();
|
||||||
|
|
||||||
// Reset vertex buffer and format
|
// Reset vertex buffer and format
|
||||||
_input._format.reset();
|
reset(_input._format);
|
||||||
_input._formatKey.clear();
|
_input._formatKey.clear();
|
||||||
_input._invalidFormat = false;
|
_input._invalidFormat = false;
|
||||||
_input._attributeActivation.reset();
|
_input._attributeActivation.reset();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < _input._buffers.size(); i++) {
|
for (uint32_t i = 0; i < _input._buffers.size(); i++) {
|
||||||
_input._buffers[i].reset();
|
reset(_input._buffers[i]);
|
||||||
_input._bufferOffsets[i] = 0;
|
_input._bufferOffsets[i] = 0;
|
||||||
_input._bufferStrides[i] = 0;
|
_input._bufferStrides[i] = 0;
|
||||||
_input._bufferVBOs[i] = 0;
|
_input._bufferVBOs[i] = 0;
|
||||||
|
@ -119,9 +120,9 @@ void GLBackend::do_setIndexBuffer(const Batch& batch, size_t paramOffset) {
|
||||||
_input._indexBufferType = (Type)batch._params[paramOffset + 2]._uint;
|
_input._indexBufferType = (Type)batch._params[paramOffset + 2]._uint;
|
||||||
_input._indexBufferOffset = batch._params[paramOffset + 0]._uint;
|
_input._indexBufferOffset = batch._params[paramOffset + 0]._uint;
|
||||||
|
|
||||||
BufferPointer indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint);
|
const auto& indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint);
|
||||||
if (indexBuffer != _input._indexBuffer) {
|
if (!compare(_input._indexBuffer, indexBuffer)) {
|
||||||
_input._indexBuffer = indexBuffer;
|
assign(_input._indexBuffer, indexBuffer);
|
||||||
if (indexBuffer) {
|
if (indexBuffer) {
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferIDUnsynced(*indexBuffer));
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferIDUnsynced(*indexBuffer));
|
||||||
} else {
|
} else {
|
||||||
|
@ -136,9 +137,9 @@ void GLBackend::do_setIndirectBuffer(const Batch& batch, size_t paramOffset) {
|
||||||
_input._indirectBufferOffset = batch._params[paramOffset + 1]._uint;
|
_input._indirectBufferOffset = batch._params[paramOffset + 1]._uint;
|
||||||
_input._indirectBufferStride = batch._params[paramOffset + 2]._uint;
|
_input._indirectBufferStride = batch._params[paramOffset + 2]._uint;
|
||||||
|
|
||||||
BufferPointer buffer = batch._buffers.get(batch._params[paramOffset]._uint);
|
const auto& buffer = batch._buffers.get(batch._params[paramOffset]._uint);
|
||||||
if (buffer != _input._indirectBuffer) {
|
if (!compare(_input._indirectBuffer, buffer)) {
|
||||||
_input._indirectBuffer = buffer;
|
assign(_input._indirectBuffer, buffer);
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, getBufferIDUnsynced(*buffer));
|
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, getBufferIDUnsynced(*buffer));
|
||||||
} else {
|
} else {
|
||||||
|
@ -152,7 +153,7 @@ void GLBackend::do_setIndirectBuffer(const Batch& batch, size_t paramOffset) {
|
||||||
|
|
||||||
void GLBackend::updateInput() {
|
void GLBackend::updateInput() {
|
||||||
bool isStereoNow = isStereo();
|
bool isStereoNow = isStereo();
|
||||||
// track stereo state change potentially happening wihtout changing the input format
|
// track stereo state change potentially happening without changing the input format
|
||||||
// this is a rare case requesting to invalid the format
|
// this is a rare case requesting to invalid the format
|
||||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
||||||
_input._invalidFormat |= (isStereoNow != _input._lastUpdateStereoState);
|
_input._invalidFormat |= (isStereoNow != _input._lastUpdateStereoState);
|
||||||
|
@ -163,13 +164,14 @@ void GLBackend::updateInput() {
|
||||||
InputStageState::ActivationCache newActivation;
|
InputStageState::ActivationCache newActivation;
|
||||||
|
|
||||||
// Assign the vertex format required
|
// Assign the vertex format required
|
||||||
if (_input._format) {
|
auto format = acquire(_input._format);
|
||||||
|
if (format) {
|
||||||
bool hasColorAttribute{ false };
|
bool hasColorAttribute{ false };
|
||||||
|
|
||||||
_input._attribBindingBuffers.reset();
|
_input._attribBindingBuffers.reset();
|
||||||
|
|
||||||
const Stream::Format::AttributeMap& attributes = _input._format->getAttributes();
|
const auto& attributes = format->getAttributes();
|
||||||
auto& inputChannels = _input._format->getChannels();
|
const auto& inputChannels = format->getChannels();
|
||||||
for (auto& channelIt : inputChannels) {
|
for (auto& channelIt : inputChannels) {
|
||||||
auto bufferChannelNum = (channelIt).first;
|
auto bufferChannelNum = (channelIt).first;
|
||||||
const Stream::Format::ChannelMap::value_type::second_type& channel = (channelIt).second;
|
const Stream::Format::ChannelMap::value_type::second_type& channel = (channelIt).second;
|
||||||
|
|
|
@ -27,12 +27,12 @@ void GLBackend::syncOutputStateCache() {
|
||||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤tFBO);
|
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤tFBO);
|
||||||
|
|
||||||
_output._drawFBO = currentFBO;
|
_output._drawFBO = currentFBO;
|
||||||
_output._framebuffer.reset();
|
reset(_output._framebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLBackend::resetOutputStage() {
|
void GLBackend::resetOutputStage() {
|
||||||
if (_output._framebuffer) {
|
if (valid(_output._framebuffer)) {
|
||||||
_output._framebuffer.reset();
|
reset(_output._framebuffer);
|
||||||
_output._drawFBO = 0;
|
_output._drawFBO = 0;
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ void GLBackend::resetOutputStage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLBackend::do_setFramebuffer(const Batch& batch, size_t paramOffset) {
|
void GLBackend::do_setFramebuffer(const Batch& batch, size_t paramOffset) {
|
||||||
auto framebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint);
|
const auto& framebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint);
|
||||||
setFramebuffer(framebuffer);
|
setFramebuffer(framebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,13 +55,13 @@ void GLBackend::do_setFramebufferSwapChain(const Batch& batch, size_t paramOffse
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLBackend::setFramebuffer(const FramebufferPointer& framebuffer) {
|
void GLBackend::setFramebuffer(const FramebufferPointer& framebuffer) {
|
||||||
if (_output._framebuffer != framebuffer) {
|
if (!compare(_output._framebuffer, framebuffer)) {
|
||||||
auto newFBO = getFramebufferID(framebuffer);
|
auto newFBO = getFramebufferID(framebuffer);
|
||||||
if (_output._drawFBO != newFBO) {
|
if (_output._drawFBO != newFBO) {
|
||||||
_output._drawFBO = newFBO;
|
_output._drawFBO = newFBO;
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, newFBO);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, newFBO);
|
||||||
}
|
}
|
||||||
_output._framebuffer = framebuffer;
|
assign(_output._framebuffer, framebuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,8 +114,9 @@ void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<GLenum> drawBuffers;
|
std::vector<GLenum> drawBuffers;
|
||||||
|
auto framebuffer = acquire(_output._framebuffer);
|
||||||
if (masks & Framebuffer::BUFFER_COLORS) {
|
if (masks & Framebuffer::BUFFER_COLORS) {
|
||||||
if (_output._framebuffer) {
|
if (framebuffer) {
|
||||||
for (unsigned int i = 0; i < Framebuffer::MAX_NUM_RENDER_BUFFERS; i++) {
|
for (unsigned int i = 0; i < Framebuffer::MAX_NUM_RENDER_BUFFERS; i++) {
|
||||||
if (masks & (1 << i)) {
|
if (masks & (1 << i)) {
|
||||||
drawBuffers.push_back(GL_COLOR_ATTACHMENT0 + i);
|
drawBuffers.push_back(GL_COLOR_ATTACHMENT0 + i);
|
||||||
|
@ -163,8 +164,8 @@ void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore the color draw buffers only if a frmaebuffer is bound
|
// Restore the color draw buffers only if a frmaebuffer is bound
|
||||||
if (_output._framebuffer && !drawBuffers.empty()) {
|
if (framebuffer && !drawBuffers.empty()) {
|
||||||
auto glFramebuffer = syncGPUObject(*_output._framebuffer);
|
auto glFramebuffer = syncGPUObject(*framebuffer);
|
||||||
if (glFramebuffer) {
|
if (glFramebuffer) {
|
||||||
glDrawBuffers((GLsizei)glFramebuffer->_colorBuffers.size(), glFramebuffer->_colorBuffers.data());
|
glDrawBuffers((GLsizei)glFramebuffer->_colorBuffers.size(), glFramebuffer->_colorBuffers.data());
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,9 @@ using namespace gpu;
|
||||||
using namespace gpu::gl;
|
using namespace gpu::gl;
|
||||||
|
|
||||||
void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {
|
void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {
|
||||||
PipelinePointer pipeline = batch._pipelines.get(batch._params[paramOffset + 0]._uint);
|
const auto& pipeline = batch._pipelines.get(batch._params[paramOffset + 0]._uint);
|
||||||
|
|
||||||
if (_pipeline._pipeline == pipeline) {
|
if (compare(_pipeline._pipeline, pipeline)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {
|
||||||
|
|
||||||
// null pipeline == reset
|
// null pipeline == reset
|
||||||
if (!pipeline) {
|
if (!pipeline) {
|
||||||
_pipeline._pipeline.reset();
|
reset(_pipeline._pipeline);
|
||||||
|
|
||||||
_pipeline._program = 0;
|
_pipeline._program = 0;
|
||||||
_pipeline._cameraCorrection = false;
|
_pipeline._cameraCorrection = false;
|
||||||
|
@ -73,7 +73,7 @@ void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remember the new pipeline
|
// Remember the new pipeline
|
||||||
_pipeline._pipeline = pipeline;
|
assign(_pipeline._pipeline, pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
// THis should be done on Pipeline::update...
|
// THis should be done on Pipeline::update...
|
||||||
|
@ -81,7 +81,7 @@ void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {
|
||||||
glUseProgram(_pipeline._program);
|
glUseProgram(_pipeline._program);
|
||||||
if (_pipeline._cameraCorrection) {
|
if (_pipeline._cameraCorrection) {
|
||||||
// Invalidate uniform buffer cache slot
|
// Invalidate uniform buffer cache slot
|
||||||
_uniform._buffers[gpu::slot::buffer::CameraCorrection] = {};
|
_uniform._buffers[gpu::slot::buffer::CameraCorrection].reset();
|
||||||
auto& cameraCorrectionBuffer = _transform._viewCorrectionEnabled ?
|
auto& cameraCorrectionBuffer = _transform._viewCorrectionEnabled ?
|
||||||
_pipeline._cameraCorrectionBuffer._buffer :
|
_pipeline._cameraCorrectionBuffer._buffer :
|
||||||
_pipeline._cameraCorrectionBufferIdentity._buffer;
|
_pipeline._cameraCorrectionBufferIdentity._buffer;
|
||||||
|
@ -112,7 +112,7 @@ void GLBackend::updatePipeline() {
|
||||||
_pipeline._stateSignatureCache |= _pipeline._state->_signature;
|
_pipeline._stateSignatureCache |= _pipeline._state->_signature;
|
||||||
|
|
||||||
// And perform
|
// And perform
|
||||||
for (auto command : _pipeline._state->_commands) {
|
for (const auto& command : _pipeline._state->_commands) {
|
||||||
command->run(this);
|
command->run(this);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -134,23 +134,17 @@ void GLBackend::resetPipelineStage() {
|
||||||
_pipeline._invalidProgram = false;
|
_pipeline._invalidProgram = false;
|
||||||
_pipeline._program = 0;
|
_pipeline._program = 0;
|
||||||
_pipeline._programShader = nullptr;
|
_pipeline._programShader = nullptr;
|
||||||
_pipeline._pipeline.reset();
|
reset(_pipeline._pipeline);
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLBackend::UniformStageState::BufferState::BufferState(const BufferPointer& buffer, GLintptr offset, GLsizeiptr size)
|
|
||||||
: buffer(buffer), offset(offset), size(size) {}
|
|
||||||
|
|
||||||
void GLBackend::releaseUniformBuffer(uint32_t slot) {
|
void GLBackend::releaseUniformBuffer(uint32_t slot) {
|
||||||
auto& buf = _uniform._buffers[slot];
|
auto& bufferState = _uniform._buffers[slot];
|
||||||
if (buf.buffer) {
|
if (valid(bufferState.buffer)) {
|
||||||
auto* object = Backend::getGPUObject<GLBuffer>(*buf.buffer);
|
glBindBufferBase(GL_UNIFORM_BUFFER, slot, 0); // RELEASE
|
||||||
if (object) {
|
(void)CHECK_GL_ERROR();
|
||||||
glBindBufferBase(GL_UNIFORM_BUFFER, slot, 0); // RELEASE
|
|
||||||
(void)CHECK_GL_ERROR();
|
|
||||||
}
|
|
||||||
buf = UniformStageState::BufferState();
|
|
||||||
}
|
}
|
||||||
|
bufferState.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLBackend::resetUniformStage() {
|
void GLBackend::resetUniformStage() {
|
||||||
|
@ -165,18 +159,20 @@ void GLBackend::bindUniformBuffer(uint32_t slot, const BufferPointer& buffer, GL
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UniformStageState::BufferState bufferState{ buffer, offset, size };
|
|
||||||
|
|
||||||
|
auto& currentBufferState = _uniform._buffers[slot];
|
||||||
// check cache before thinking
|
// check cache before thinking
|
||||||
if (_uniform._buffers[slot] == bufferState) {
|
if (currentBufferState.compare(buffer, offset, size)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab the true gl Buffer object
|
// Grab the true gl Buffer object
|
||||||
auto glBO = getBufferIDUnsynced(*buffer);
|
auto glBO = getBufferIDUnsynced(*buffer);
|
||||||
if (glBO) {
|
if (glBO) {
|
||||||
glBindBufferRange(GL_UNIFORM_BUFFER, slot, glBO, bufferState.offset, bufferState.size);
|
glBindBufferRange(GL_UNIFORM_BUFFER, slot, glBO, offset, size);
|
||||||
_uniform._buffers[slot] = bufferState;
|
assign(currentBufferState.buffer, buffer);
|
||||||
|
currentBufferState.offset = offset;
|
||||||
|
currentBufferState.size = size;
|
||||||
(void)CHECK_GL_ERROR();
|
(void)CHECK_GL_ERROR();
|
||||||
} else {
|
} else {
|
||||||
releaseUniformBuffer(slot);
|
releaseUniformBuffer(slot);
|
||||||
|
@ -193,7 +189,7 @@ void GLBackend::do_setUniformBuffer(const Batch& batch, size_t paramOffset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
const auto& uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
||||||
GLintptr rangeStart = batch._params[paramOffset + 1]._uint;
|
GLintptr rangeStart = batch._params[paramOffset + 1]._uint;
|
||||||
GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint;
|
GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint;
|
||||||
|
|
||||||
|
@ -201,16 +197,12 @@ void GLBackend::do_setUniformBuffer(const Batch& batch, size_t paramOffset) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLBackend::releaseResourceTexture(uint32_t slot) {
|
void GLBackend::releaseResourceTexture(uint32_t slot) {
|
||||||
auto& tex = _resource._textures[slot];
|
auto& textureState = _resource._textures[slot];
|
||||||
if (tex) {
|
if (valid(textureState._texture)) {
|
||||||
auto* object = Backend::getGPUObject<GLTexture>(*tex);
|
glActiveTexture(GL_TEXTURE0 + slot);
|
||||||
if (object) {
|
glBindTexture(textureState._target, 0); // RELEASE
|
||||||
GLuint target = object->_target;
|
(void)CHECK_GL_ERROR();
|
||||||
glActiveTexture(GL_TEXTURE0 + slot);
|
reset(textureState._texture);
|
||||||
glBindTexture(target, 0); // RELEASE
|
|
||||||
(void)CHECK_GL_ERROR();
|
|
||||||
}
|
|
||||||
tex.reset();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,14 +224,14 @@ void GLBackend::do_setResourceBuffer(const Batch& batch, size_t paramOffset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto resourceBuffer = batch._buffers.get(batch._params[paramOffset + 0]._uint);
|
const auto& resourceBuffer = batch._buffers.get(batch._params[paramOffset + 0]._uint);
|
||||||
|
|
||||||
if (!resourceBuffer) {
|
if (!resourceBuffer) {
|
||||||
releaseResourceBuffer(slot);
|
releaseResourceBuffer(slot);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// check cache before thinking
|
// check cache before thinking
|
||||||
if (_resource._buffers[slot] == resourceBuffer) {
|
if (compare(_resource._buffers[slot], resourceBuffer)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +240,7 @@ void GLBackend::do_setResourceBuffer(const Batch& batch, size_t paramOffset) {
|
||||||
|
|
||||||
// If successful bind then cache it
|
// If successful bind then cache it
|
||||||
if (bindResourceBuffer(slot, resourceBuffer)) {
|
if (bindResourceBuffer(slot, resourceBuffer)) {
|
||||||
_resource._buffers[slot] = resourceBuffer;
|
assign(_resource._buffers[slot], resourceBuffer);
|
||||||
} else { // else clear slot and cache
|
} else { // else clear slot and cache
|
||||||
releaseResourceBuffer(slot);
|
releaseResourceBuffer(slot);
|
||||||
return;
|
return;
|
||||||
|
@ -293,14 +285,15 @@ void GLBackend::do_setResourceFramebufferSwapChainTexture(const Batch& batch, si
|
||||||
}
|
}
|
||||||
auto index = batch._params[paramOffset + 2]._uint;
|
auto index = batch._params[paramOffset + 2]._uint;
|
||||||
auto renderBufferSlot = batch._params[paramOffset + 3]._uint;
|
auto renderBufferSlot = batch._params[paramOffset + 3]._uint;
|
||||||
auto resourceFramebuffer = swapChain->get(index);
|
const auto& resourceFramebuffer = swapChain->get(index);
|
||||||
auto resourceTexture = resourceFramebuffer->getRenderBuffer(renderBufferSlot);
|
const auto& resourceTexture = resourceFramebuffer->getRenderBuffer(renderBufferSlot);
|
||||||
setResourceTexture(slot, resourceTexture);
|
setResourceTexture(slot, resourceTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLBackend::setResourceTexture(unsigned int slot, const TexturePointer& resourceTexture) {
|
void GLBackend::setResourceTexture(unsigned int slot, const TexturePointer& resourceTexture) {
|
||||||
|
auto& textureState = _resource._textures[slot];
|
||||||
// check cache before thinking
|
// check cache before thinking
|
||||||
if (_resource._textures[slot] == resourceTexture) {
|
if (compare(textureState._texture, resourceTexture)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,15 +303,12 @@ void GLBackend::setResourceTexture(unsigned int slot, const TexturePointer& reso
|
||||||
// Always make sure the GLObject is in sync
|
// Always make sure the GLObject is in sync
|
||||||
GLTexture* object = syncGPUObject(resourceTexture);
|
GLTexture* object = syncGPUObject(resourceTexture);
|
||||||
if (object) {
|
if (object) {
|
||||||
|
assign(textureState._texture, resourceTexture);
|
||||||
GLuint to = object->_texture;
|
GLuint to = object->_texture;
|
||||||
GLuint target = object->_target;
|
textureState._target = object->_target;
|
||||||
glActiveTexture(GL_TEXTURE0 + slot);
|
glActiveTexture(GL_TEXTURE0 + slot);
|
||||||
glBindTexture(target, to);
|
glBindTexture(textureState._target, to);
|
||||||
|
|
||||||
(void)CHECK_GL_ERROR();
|
(void)CHECK_GL_ERROR();
|
||||||
|
|
||||||
_resource._textures[slot] = resourceTexture;
|
|
||||||
|
|
||||||
_stats._RSAmountTextureMemoryBounded += (int)object->size();
|
_stats._RSAmountTextureMemoryBounded += (int)object->size();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -343,7 +333,7 @@ void GLBackend::do_setResourceTextureTable(const Batch& batch, size_t paramOffse
|
||||||
int GLBackend::ResourceStageState::findEmptyTextureSlot() const {
|
int GLBackend::ResourceStageState::findEmptyTextureSlot() const {
|
||||||
// start from the end of the slots, try to find an empty one that can be used
|
// start from the end of the slots, try to find an empty one that can be used
|
||||||
for (auto i = MAX_NUM_RESOURCE_TEXTURES - 1; i > 0; i--) {
|
for (auto i = MAX_NUM_RESOURCE_TEXTURES - 1; i > 0; i--) {
|
||||||
if (!_textures[i]) {
|
if (!valid(_textures[i]._texture)) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLBackend::do_generateTextureMips(const Batch& batch, size_t paramOffset) {
|
void GLBackend::do_generateTextureMips(const Batch& batch, size_t paramOffset) {
|
||||||
TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);
|
const auto& resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);
|
||||||
if (!resourceTexture) {
|
if (!resourceTexture) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ GLPipeline* GLPipeline::sync(GLBackend& backend, const Pipeline& pipeline) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// No object allocated yet, let's see if it's worth it...
|
// No object allocated yet, let's see if it's worth it...
|
||||||
ShaderPointer shader = pipeline.getProgram();
|
const auto& shader = pipeline.getProgram();
|
||||||
|
|
||||||
// If this pipeline's shader has already failed to compile, don't try again
|
// If this pipeline's shader has already failed to compile, don't try again
|
||||||
if (shader->compilationHasFailed()) {
|
if (shader->compilationHasFailed()) {
|
||||||
|
@ -37,7 +37,7 @@ GLPipeline* GLPipeline::sync(GLBackend& backend, const Pipeline& pipeline) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
StatePointer state = pipeline.getState();
|
const auto& state = pipeline.getState();
|
||||||
GLState* stateObject = GLState::sync(*state);
|
GLState* stateObject = GLState::sync(*state);
|
||||||
if (stateObject == nullptr) {
|
if (stateObject == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -161,7 +161,7 @@ protected:
|
||||||
void updateTransform(const Batch& batch) override;
|
void updateTransform(const Batch& batch) override;
|
||||||
|
|
||||||
// Resource Stage
|
// Resource Stage
|
||||||
bool bindResourceBuffer(uint32_t slot, BufferPointer& buffer) override;
|
bool bindResourceBuffer(uint32_t slot, const BufferPointer& buffer) override;
|
||||||
void releaseResourceBuffer(uint32_t slot) override;
|
void releaseResourceBuffer(uint32_t slot) override;
|
||||||
|
|
||||||
// Output stage
|
// Output stage
|
||||||
|
|
|
@ -100,7 +100,7 @@ GLBuffer* GL41Backend::syncGPUObject(const Buffer& buffer) {
|
||||||
return GL41Buffer::sync<GL41Buffer>(*this, buffer);
|
return GL41Buffer::sync<GL41Buffer>(*this, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GL41Backend::bindResourceBuffer(uint32_t slot, BufferPointer& buffer) {
|
bool GL41Backend::bindResourceBuffer(uint32_t slot, const BufferPointer& buffer) {
|
||||||
GLuint texBuffer = GL41Backend::getResourceBufferID((*buffer));
|
GLuint texBuffer = GL41Backend::getResourceBufferID((*buffer));
|
||||||
if (texBuffer) {
|
if (texBuffer) {
|
||||||
glActiveTexture(GL_TEXTURE0 + GL41Backend::RESOURCE_BUFFER_SLOT0_TEX_UNIT + slot);
|
glActiveTexture(GL_TEXTURE0 + GL41Backend::RESOURCE_BUFFER_SLOT0_TEX_UNIT + slot);
|
||||||
|
@ -108,7 +108,7 @@ bool GL41Backend::bindResourceBuffer(uint32_t slot, BufferPointer& buffer) {
|
||||||
|
|
||||||
(void)CHECK_GL_ERROR();
|
(void)CHECK_GL_ERROR();
|
||||||
|
|
||||||
_resource._buffers[slot] = buffer;
|
assign(_resource._buffers[slot], buffer);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -117,10 +117,11 @@ bool GL41Backend::bindResourceBuffer(uint32_t slot, BufferPointer& buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GL41Backend::releaseResourceBuffer(uint32_t slot) {
|
void GL41Backend::releaseResourceBuffer(uint32_t slot) {
|
||||||
auto& buf = _resource._buffers[slot];
|
auto& bufferReference = _resource._buffers[slot];
|
||||||
if (buf) {
|
auto buffer = acquire(bufferReference);
|
||||||
|
if (buffer) {
|
||||||
glActiveTexture(GL_TEXTURE0 + GL41Backend::RESOURCE_BUFFER_SLOT0_TEX_UNIT + slot);
|
glActiveTexture(GL_TEXTURE0 + GL41Backend::RESOURCE_BUFFER_SLOT0_TEX_UNIT + slot);
|
||||||
glBindTexture(GL_TEXTURE_BUFFER, 0);
|
glBindTexture(GL_TEXTURE_BUFFER, 0);
|
||||||
buf.reset();
|
reset(bufferReference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,14 +35,15 @@ void GL41Backend::updateInput() {
|
||||||
|
|
||||||
if (_input._invalidFormat || _input._invalidBuffers.any()) {
|
if (_input._invalidFormat || _input._invalidBuffers.any()) {
|
||||||
|
|
||||||
|
auto format = acquire(_input._format);
|
||||||
if (_input._invalidFormat) {
|
if (_input._invalidFormat) {
|
||||||
InputStageState::ActivationCache newActivation;
|
InputStageState::ActivationCache newActivation;
|
||||||
|
|
||||||
_stats._ISNumFormatChanges++;
|
_stats._ISNumFormatChanges++;
|
||||||
|
|
||||||
// Check expected activation
|
// Check expected activation
|
||||||
if (_input._format) {
|
if (format) {
|
||||||
for (auto& it : _input._format->getAttributes()) {
|
for (auto& it : format->getAttributes()) {
|
||||||
const Stream::Attribute& attrib = (it).second;
|
const Stream::Attribute& attrib = (it).second;
|
||||||
uint8_t locationCount = attrib._element.getLocationCount();
|
uint8_t locationCount = attrib._element.getLocationCount();
|
||||||
for (int i = 0; i < locationCount; ++i) {
|
for (int i = 0; i < locationCount; ++i) {
|
||||||
|
@ -69,15 +70,15 @@ void GL41Backend::updateInput() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// now we need to bind the buffers and assign the attrib pointers
|
// now we need to bind the buffers and assign the attrib pointers
|
||||||
if (_input._format) {
|
if (format) {
|
||||||
bool hasColorAttribute{ false };
|
bool hasColorAttribute{ false };
|
||||||
|
|
||||||
const Buffers& buffers = _input._buffers;
|
const auto& buffers = _input._buffers;
|
||||||
const Offsets& offsets = _input._bufferOffsets;
|
const auto& offsets = _input._bufferOffsets;
|
||||||
const Offsets& strides = _input._bufferStrides;
|
const auto& strides = _input._bufferStrides;
|
||||||
|
|
||||||
const Stream::Format::AttributeMap& attributes = _input._format->getAttributes();
|
const auto& attributes = format->getAttributes();
|
||||||
auto& inputChannels = _input._format->getChannels();
|
const auto& inputChannels = format->getChannels();
|
||||||
int numInvalids = (int)_input._invalidBuffers.count();
|
int numInvalids = (int)_input._invalidBuffers.count();
|
||||||
_stats._ISNumInputBufferChanges += numInvalids;
|
_stats._ISNumInputBufferChanges += numInvalids;
|
||||||
|
|
||||||
|
|
|
@ -262,7 +262,7 @@ protected:
|
||||||
void updateTransform(const Batch& batch) override;
|
void updateTransform(const Batch& batch) override;
|
||||||
|
|
||||||
// Resource Stage
|
// Resource Stage
|
||||||
bool bindResourceBuffer(uint32_t slot, BufferPointer& buffer) override;
|
bool bindResourceBuffer(uint32_t slot, const BufferPointer& buffer) override;
|
||||||
void releaseResourceBuffer(uint32_t slot) override;
|
void releaseResourceBuffer(uint32_t slot) override;
|
||||||
|
|
||||||
// Output stage
|
// Output stage
|
||||||
|
|
|
@ -60,14 +60,14 @@ GLBuffer* GL45Backend::syncGPUObject(const Buffer& buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool GL45Backend::bindResourceBuffer(uint32_t slot, BufferPointer& buffer) {
|
bool GL45Backend::bindResourceBuffer(uint32_t slot, const BufferPointer& buffer) {
|
||||||
GLBuffer* object = syncGPUObject((*buffer));
|
GLBuffer* object = syncGPUObject((*buffer));
|
||||||
if (object) {
|
if (object) {
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot, object->_id);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot, object->_id);
|
||||||
|
|
||||||
(void)CHECK_GL_ERROR();
|
(void)CHECK_GL_ERROR();
|
||||||
|
|
||||||
_resource._buffers[slot] = buffer;
|
assign(_resource._buffers[slot], buffer);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -76,11 +76,10 @@ bool GL45Backend::bindResourceBuffer(uint32_t slot, BufferPointer& buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GL45Backend::releaseResourceBuffer(uint32_t slot) {
|
void GL45Backend::releaseResourceBuffer(uint32_t slot) {
|
||||||
auto& buf = _resource._buffers[slot];
|
auto& bufferReference = _resource._buffers[slot];
|
||||||
if (buf) {
|
auto buffer = acquire(bufferReference);
|
||||||
|
if (buffer) {
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot, 0);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot, 0);
|
||||||
buf.reset();
|
reset(bufferReference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ void GL45Backend::resetInputStage() {
|
||||||
|
|
||||||
void GL45Backend::updateInput() {
|
void GL45Backend::updateInput() {
|
||||||
bool isStereoNow = isStereo();
|
bool isStereoNow = isStereo();
|
||||||
// track stereo state change potentially happening wihtout changing the input format
|
// track stereo state change potentially happening without changing the input format
|
||||||
// this is a rare case requesting to invalid the format
|
// this is a rare case requesting to invalid the format
|
||||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
||||||
_input._invalidFormat |= (isStereoNow != _input._lastUpdateStereoState);
|
_input._invalidFormat |= (isStereoNow != _input._lastUpdateStereoState);
|
||||||
|
@ -39,13 +39,14 @@ void GL45Backend::updateInput() {
|
||||||
InputStageState::ActivationCache newActivation;
|
InputStageState::ActivationCache newActivation;
|
||||||
|
|
||||||
// Assign the vertex format required
|
// Assign the vertex format required
|
||||||
if (_input._format) {
|
auto format = acquire(_input._format);
|
||||||
|
if (format) {
|
||||||
bool hasColorAttribute{ false };
|
bool hasColorAttribute{ false };
|
||||||
|
|
||||||
_input._attribBindingBuffers.reset();
|
_input._attribBindingBuffers.reset();
|
||||||
|
|
||||||
const Stream::Format::AttributeMap& attributes = _input._format->getAttributes();
|
const auto& attributes = format->getAttributes();
|
||||||
auto& inputChannels = _input._format->getChannels();
|
const auto& inputChannels = format->getChannels();
|
||||||
for (auto& channelIt : inputChannels) {
|
for (auto& channelIt : inputChannels) {
|
||||||
auto bufferChannelNum = (channelIt).first;
|
auto bufferChannelNum = (channelIt).first;
|
||||||
const Stream::Format::ChannelMap::value_type::second_type& channel = (channelIt).second;
|
const Stream::Format::ChannelMap::value_type::second_type& channel = (channelIt).second;
|
||||||
|
|
|
@ -157,7 +157,7 @@ protected:
|
||||||
void updateTransform(const Batch& batch) override;
|
void updateTransform(const Batch& batch) override;
|
||||||
|
|
||||||
// Resource Stage
|
// Resource Stage
|
||||||
bool bindResourceBuffer(uint32_t slot, BufferPointer& buffer) override;
|
bool bindResourceBuffer(uint32_t slot, const BufferPointer& buffer) override;
|
||||||
void releaseResourceBuffer(uint32_t slot) override;
|
void releaseResourceBuffer(uint32_t slot) override;
|
||||||
|
|
||||||
// Output stage
|
// Output stage
|
||||||
|
|
|
@ -72,14 +72,14 @@ GLBuffer* GLESBackend::syncGPUObject(const Buffer& buffer) {
|
||||||
return GLESBuffer::sync<GLESBuffer>(*this, buffer);
|
return GLESBuffer::sync<GLESBuffer>(*this, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLESBackend::bindResourceBuffer(uint32_t slot, BufferPointer& buffer) {
|
bool GLESBackend::bindResourceBuffer(uint32_t slot, const BufferPointer& buffer) {
|
||||||
GLBuffer* object = syncGPUObject((*buffer));
|
GLBuffer* object = syncGPUObject((*buffer));
|
||||||
if (object) {
|
if (object) {
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot, object->_id);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot, object->_id);
|
||||||
|
|
||||||
(void)CHECK_GL_ERROR();
|
(void)CHECK_GL_ERROR();
|
||||||
|
|
||||||
_resource._buffers[slot] = buffer;
|
assign(_resource._buffers[slot], buffer);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -88,10 +88,10 @@ bool GLESBackend::bindResourceBuffer(uint32_t slot, BufferPointer& buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLESBackend::releaseResourceBuffer(uint32_t slot) {
|
void GLESBackend::releaseResourceBuffer(uint32_t slot) {
|
||||||
auto& buf = _resource._buffers[slot];
|
auto& bufferReference = _resource._buffers[slot];
|
||||||
if (buf) {
|
if (valid(bufferReference)) {
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot, 0);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot, 0);
|
||||||
buf.reset();
|
reset(bufferReference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -498,7 +498,7 @@ void Batch::setupNamedCalls(const std::string& instanceName, NamedBatchData::Fun
|
||||||
captureNamedDrawCallInfo(instanceName);
|
captureNamedDrawCallInfo(instanceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferPointer Batch::getNamedBuffer(const std::string& instanceName, uint8_t index) {
|
const BufferPointer& Batch::getNamedBuffer(const std::string& instanceName, uint8_t index) {
|
||||||
NamedBatchData& instance = _namedData[instanceName];
|
NamedBatchData& instance = _namedData[instanceName];
|
||||||
if (instance.buffers.size() <= index) {
|
if (instance.buffers.size() <= index) {
|
||||||
instance.buffers.resize(index + 1);
|
instance.buffers.resize(index + 1);
|
||||||
|
|
|
@ -119,7 +119,7 @@ public:
|
||||||
void multiDrawIndexedIndirect(uint32 numCommands, Primitive primitiveType);
|
void multiDrawIndexedIndirect(uint32 numCommands, Primitive primitiveType);
|
||||||
|
|
||||||
void setupNamedCalls(const std::string& instanceName, NamedBatchData::Function function);
|
void setupNamedCalls(const std::string& instanceName, NamedBatchData::Function function);
|
||||||
BufferPointer getNamedBuffer(const std::string& instanceName, uint8_t index = 0);
|
const BufferPointer& getNamedBuffer(const std::string& instanceName, uint8_t index = 0);
|
||||||
|
|
||||||
// Input Stage
|
// Input Stage
|
||||||
// InputFormat
|
// InputFormat
|
||||||
|
|
|
@ -203,11 +203,12 @@ uint32 Framebuffer::getNumRenderBuffers() const {
|
||||||
return nb;
|
return nb;
|
||||||
}
|
}
|
||||||
|
|
||||||
TexturePointer Framebuffer::getRenderBuffer(uint32 slot) const {
|
const TexturePointer& Framebuffer::getRenderBuffer(uint32 slot) const {
|
||||||
|
static const TexturePointer EMPTY;
|
||||||
if (!isSwapchain() && (slot < getMaxNumRenderBuffers())) {
|
if (!isSwapchain() && (slot < getMaxNumRenderBuffers())) {
|
||||||
return _renderBuffers[slot]._texture;
|
return _renderBuffers[slot]._texture;
|
||||||
} else {
|
} else {
|
||||||
return TexturePointer();
|
return EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -297,9 +298,10 @@ bool Framebuffer::setDepthStencilBuffer(const TexturePointer& texture, const For
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TexturePointer Framebuffer::getDepthStencilBuffer() const {
|
const TexturePointer& Framebuffer::getDepthStencilBuffer() const {
|
||||||
|
static const TexturePointer EMPTY;
|
||||||
if (isSwapchain()) {
|
if (isSwapchain()) {
|
||||||
return TexturePointer();
|
return EMPTY;
|
||||||
} else {
|
} else {
|
||||||
return _depthStencilBuffer._texture;
|
return _depthStencilBuffer._texture;
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ public:
|
||||||
static Framebuffer* createShadowmap(uint16 width);
|
static Framebuffer* createShadowmap(uint16 width);
|
||||||
|
|
||||||
bool isSwapchain() const;
|
bool isSwapchain() const;
|
||||||
SwapchainPointer getSwapchain() const { return _swapchain; }
|
const SwapchainPointer& getSwapchain() const { return _swapchain; }
|
||||||
|
|
||||||
uint32 getFrameCount() const;
|
uint32 getFrameCount() const;
|
||||||
|
|
||||||
|
@ -105,13 +105,13 @@ public:
|
||||||
const TextureViews& getRenderBuffers() const { return _renderBuffers; }
|
const TextureViews& getRenderBuffers() const { return _renderBuffers; }
|
||||||
|
|
||||||
int32 setRenderBuffer(uint32 slot, const TexturePointer& texture, uint32 subresource = 0);
|
int32 setRenderBuffer(uint32 slot, const TexturePointer& texture, uint32 subresource = 0);
|
||||||
TexturePointer getRenderBuffer(uint32 slot) const;
|
const TexturePointer& getRenderBuffer(uint32 slot) const;
|
||||||
uint32 getRenderBufferSubresource(uint32 slot) const;
|
uint32 getRenderBufferSubresource(uint32 slot) const;
|
||||||
|
|
||||||
bool setDepthBuffer(const TexturePointer& texture, const Format& format, uint32 subresource = 0);
|
bool setDepthBuffer(const TexturePointer& texture, const Format& format, uint32 subresource = 0);
|
||||||
bool setStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource = 0);
|
bool setStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource = 0);
|
||||||
bool setDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource = 0);
|
bool setDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource = 0);
|
||||||
TexturePointer getDepthStencilBuffer() const;
|
const TexturePointer& getDepthStencilBuffer() const;
|
||||||
uint32 getDepthStencilBufferSubresource() const;
|
uint32 getDepthStencilBufferSubresource() const;
|
||||||
Format getDepthStencilBufferFormat() const;
|
Format getDepthStencilBufferFormat() const;
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ void CauterizedModel::createRenderItemSet() {
|
||||||
// Create the render payloads
|
// Create the render payloads
|
||||||
int numParts = (int)mesh->getNumParts();
|
int numParts = (int)mesh->getNumParts();
|
||||||
for (int partIndex = 0; partIndex < numParts; partIndex++) {
|
for (int partIndex = 0; partIndex < numParts; partIndex++) {
|
||||||
if (!fbxGeometry.meshes[i].blendshapes.empty()) {
|
if (!fbxGeometry.meshes[i].blendshapes.empty() && _blendedVertexBuffers.find(i) == _blendedVertexBuffers.end()) {
|
||||||
initializeBlendshapes(fbxGeometry.meshes[i], i);
|
initializeBlendshapes(fbxGeometry.meshes[i], i);
|
||||||
}
|
}
|
||||||
auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
|
auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
|
||||||
|
@ -97,6 +97,7 @@ void CauterizedModel::createRenderItemSet() {
|
||||||
shapeID++;
|
shapeID++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_blendedVertexBuffersInitialized = true;
|
||||||
} else {
|
} else {
|
||||||
Model::createRenderItemSet();
|
Model::createRenderItemSet();
|
||||||
}
|
}
|
||||||
|
|
|
@ -302,15 +302,22 @@ bool Model::updateGeometry() {
|
||||||
assert(_meshStates.empty());
|
assert(_meshStates.empty());
|
||||||
|
|
||||||
const FBXGeometry& fbxGeometry = getFBXGeometry();
|
const FBXGeometry& fbxGeometry = getFBXGeometry();
|
||||||
|
int i = 0;
|
||||||
foreach (const FBXMesh& mesh, fbxGeometry.meshes) {
|
foreach (const FBXMesh& mesh, fbxGeometry.meshes) {
|
||||||
MeshState state;
|
MeshState state;
|
||||||
state.clusterDualQuaternions.resize(mesh.clusters.size());
|
state.clusterDualQuaternions.resize(mesh.clusters.size());
|
||||||
state.clusterMatrices.resize(mesh.clusters.size());
|
state.clusterMatrices.resize(mesh.clusters.size());
|
||||||
_meshStates.push_back(state);
|
_meshStates.push_back(state);
|
||||||
|
if (!mesh.blendshapes.empty() && _blendedVertexBuffers.find(i) == _blendedVertexBuffers.end()) {
|
||||||
|
initializeBlendshapes(mesh, i);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
_blendedVertexBuffersInitialized = true;
|
||||||
needFullUpdate = true;
|
needFullUpdate = true;
|
||||||
emit rigReady();
|
emit rigReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
return needFullUpdate;
|
return needFullUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1027,6 +1034,10 @@ void Model::removeFromScene(const render::ScenePointer& scene, render::Transacti
|
||||||
_modelMeshMaterialNames.clear();
|
_modelMeshMaterialNames.clear();
|
||||||
_modelMeshRenderItemShapes.clear();
|
_modelMeshRenderItemShapes.clear();
|
||||||
|
|
||||||
|
_blendedVertexBuffers.clear();
|
||||||
|
_normalsAndTangents.clear();
|
||||||
|
_blendedVertexBuffersInitialized = false;
|
||||||
|
|
||||||
_addedToScene = false;
|
_addedToScene = false;
|
||||||
|
|
||||||
_renderInfoVertexCount = 0;
|
_renderInfoVertexCount = 0;
|
||||||
|
@ -1273,8 +1284,7 @@ QStringList Model::getJointNames() const {
|
||||||
class Blender : public QRunnable {
|
class Blender : public QRunnable {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry,
|
Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry, const QVector<float>& blendshapeCoefficients);
|
||||||
const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients);
|
|
||||||
|
|
||||||
virtual void run() override;
|
virtual void run() override;
|
||||||
|
|
||||||
|
@ -1283,37 +1293,37 @@ private:
|
||||||
ModelPointer _model;
|
ModelPointer _model;
|
||||||
int _blendNumber;
|
int _blendNumber;
|
||||||
Geometry::WeakPointer _geometry;
|
Geometry::WeakPointer _geometry;
|
||||||
QVector<FBXMesh> _meshes;
|
|
||||||
QVector<float> _blendshapeCoefficients;
|
QVector<float> _blendshapeCoefficients;
|
||||||
};
|
};
|
||||||
|
|
||||||
Blender::Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry,
|
Blender::Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry, const QVector<float>& blendshapeCoefficients) :
|
||||||
const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients) :
|
|
||||||
_model(model),
|
_model(model),
|
||||||
_blendNumber(blendNumber),
|
_blendNumber(blendNumber),
|
||||||
_geometry(geometry),
|
_geometry(geometry),
|
||||||
_meshes(meshes),
|
|
||||||
_blendshapeCoefficients(blendshapeCoefficients) {
|
_blendshapeCoefficients(blendshapeCoefficients) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Blender::run() {
|
void Blender::run() {
|
||||||
DETAILED_PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xFFFF0000, 0, { { "url", _model->getURL().toString() } });
|
|
||||||
QVector<glm::vec3> vertices;
|
QVector<glm::vec3> vertices;
|
||||||
QVector<NormalType> normalsAndTangents;
|
QVector<NormalType> normalsAndTangents;
|
||||||
if (_model) {
|
if (_model && _model->isLoaded()) {
|
||||||
|
DETAILED_PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xFFFF0000, 0, { { "url", _model->getURL().toString() } });
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int normalsAndTangentsOffset = 0;
|
int normalsAndTangentsOffset = 0;
|
||||||
foreach (const FBXMesh& mesh, _meshes) {
|
auto meshes = _model->getFBXGeometry().meshes;
|
||||||
if (mesh.blendshapes.isEmpty()) {
|
int meshIndex = 0;
|
||||||
|
foreach (const FBXMesh& mesh, meshes) {
|
||||||
|
auto modelMeshNormalsAndTangents = _model->_normalsAndTangents.find(meshIndex++);
|
||||||
|
if (mesh.blendshapes.isEmpty() || modelMeshNormalsAndTangents == _model->_normalsAndTangents.end()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
vertices += mesh.vertices;
|
vertices += mesh.vertices;
|
||||||
normalsAndTangents += mesh.normalsAndTangents;
|
normalsAndTangents += modelMeshNormalsAndTangents->second;
|
||||||
glm::vec3* meshVertices = vertices.data() + offset;
|
glm::vec3* meshVertices = vertices.data() + offset;
|
||||||
NormalType* meshNormalsAndTangents = normalsAndTangents.data() + normalsAndTangentsOffset;
|
NormalType* meshNormalsAndTangents = normalsAndTangents.data() + normalsAndTangentsOffset;
|
||||||
offset += mesh.vertices.size();
|
offset += mesh.vertices.size();
|
||||||
normalsAndTangentsOffset += mesh.normalsAndTangents.size();
|
normalsAndTangentsOffset += modelMeshNormalsAndTangents->second.size();
|
||||||
const float NORMAL_COEFFICIENT_SCALE = 0.01f;
|
const float NORMAL_COEFFICIENT_SCALE = 0.01f;
|
||||||
for (int i = 0, n = qMin(_blendshapeCoefficients.size(), mesh.blendshapes.size()); i < n; i++) {
|
for (int i = 0, n = qMin(_blendshapeCoefficients.size(), mesh.blendshapes.size()); i < n; i++) {
|
||||||
float vertexCoefficient = _blendshapeCoefficients.at(i);
|
float vertexCoefficient = _blendshapeCoefficients.at(i);
|
||||||
|
@ -1353,9 +1363,8 @@ void Blender::run() {
|
||||||
}
|
}
|
||||||
// post the result to the ModelBlender, which will dispatch to the model if still alive
|
// post the result to the ModelBlender, which will dispatch to the model if still alive
|
||||||
QMetaObject::invokeMethod(DependencyManager::get<ModelBlender>().data(), "setBlendedVertices",
|
QMetaObject::invokeMethod(DependencyManager::get<ModelBlender>().data(), "setBlendedVertices",
|
||||||
Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber),
|
Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber), Q_ARG(QVector<glm::vec3>, vertices),
|
||||||
Q_ARG(const Geometry::WeakPointer&, _geometry), Q_ARG(const QVector<glm::vec3>&, vertices),
|
Q_ARG(QVector<NormalType>, normalsAndTangents));
|
||||||
Q_ARG(const QVector<NormalType>&, normalsAndTangents));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions, bool forceRescale) {
|
void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions, bool forceRescale) {
|
||||||
|
@ -1526,18 +1535,15 @@ bool Model::maybeStartBlender() {
|
||||||
if (isLoaded()) {
|
if (isLoaded()) {
|
||||||
const FBXGeometry& fbxGeometry = getFBXGeometry();
|
const FBXGeometry& fbxGeometry = getFBXGeometry();
|
||||||
if (fbxGeometry.hasBlendedMeshes()) {
|
if (fbxGeometry.hasBlendedMeshes()) {
|
||||||
QThreadPool::globalInstance()->start(new Blender(getThisPointer(), ++_blendNumber, _renderGeometry,
|
QThreadPool::globalInstance()->start(new Blender(getThisPointer(), ++_blendNumber, _renderGeometry, _blendshapeCoefficients));
|
||||||
fbxGeometry.meshes, _blendshapeCoefficients));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geometry,
|
void Model::setBlendedVertices(int blendNumber, const QVector<glm::vec3>& vertices, const QVector<NormalType>& normalsAndTangents) {
|
||||||
const QVector<glm::vec3>& vertices, const QVector<NormalType>& normalsAndTangents) {
|
if (!isLoaded() || blendNumber < _appliedBlendNumber || !_blendedVertexBuffersInitialized) {
|
||||||
auto geometryRef = geometry.lock();
|
|
||||||
if (!geometryRef || _renderGeometry != geometryRef || blendNumber < _appliedBlendNumber) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_appliedBlendNumber = blendNumber;
|
_appliedBlendNumber = blendNumber;
|
||||||
|
@ -1546,26 +1552,28 @@ void Model::setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geo
|
||||||
int normalAndTangentIndex = 0;
|
int normalAndTangentIndex = 0;
|
||||||
for (int i = 0; i < fbxGeometry.meshes.size(); i++) {
|
for (int i = 0; i < fbxGeometry.meshes.size(); i++) {
|
||||||
const FBXMesh& mesh = fbxGeometry.meshes.at(i);
|
const FBXMesh& mesh = fbxGeometry.meshes.at(i);
|
||||||
if (mesh.blendshapes.isEmpty()) {
|
auto meshNormalsAndTangents = _normalsAndTangents.find(i);
|
||||||
|
if (mesh.blendshapes.isEmpty() || meshNormalsAndTangents == _normalsAndTangents.end()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto vertexCount = mesh.vertices.size();
|
const auto vertexCount = mesh.vertices.size();
|
||||||
const auto verticesSize = vertexCount * sizeof(glm::vec3);
|
const auto verticesSize = vertexCount * sizeof(glm::vec3);
|
||||||
const auto& buffer = _blendedVertexBuffers[i];
|
const auto& buffer = _blendedVertexBuffers.find(i);
|
||||||
assert(buffer && _blendedVertexBuffersInitialized);
|
assert(buffer != _blendedVertexBuffers.end());
|
||||||
buffer->resize(mesh.vertices.size() * sizeof(glm::vec3) + mesh.normalsAndTangents.size() * sizeof(NormalType));
|
buffer->second->resize(mesh.vertices.size() * sizeof(glm::vec3) + meshNormalsAndTangents->second.size() * sizeof(NormalType));
|
||||||
buffer->setSubData(0, verticesSize, (gpu::Byte*) vertices.constData() + index * sizeof(glm::vec3));
|
buffer->second->setSubData(0, verticesSize, (gpu::Byte*) vertices.constData() + index * sizeof(glm::vec3));
|
||||||
buffer->setSubData(verticesSize, mesh.normalsAndTangents.size() * sizeof(NormalType), (const gpu::Byte*) normalsAndTangents.data() + normalAndTangentIndex * sizeof(NormalType));
|
buffer->second->setSubData(verticesSize, meshNormalsAndTangents->second.size() * sizeof(NormalType), (const gpu::Byte*) normalsAndTangents.data() + normalAndTangentIndex * sizeof(NormalType));
|
||||||
|
|
||||||
index += vertexCount;
|
index += vertexCount;
|
||||||
normalAndTangentIndex += mesh.normalsAndTangents.size();
|
normalAndTangentIndex += meshNormalsAndTangents->second.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::deleteGeometry() {
|
void Model::deleteGeometry() {
|
||||||
_deleteGeometryCounter++;
|
_deleteGeometryCounter++;
|
||||||
_blendedVertexBuffers.clear();
|
_blendedVertexBuffers.clear();
|
||||||
|
_normalsAndTangents.clear();
|
||||||
_blendedVertexBuffersInitialized = false;
|
_blendedVertexBuffersInitialized = false;
|
||||||
_meshStates.clear();
|
_meshStates.clear();
|
||||||
_rig.destroyAnimGraph();
|
_rig.destroyAnimGraph();
|
||||||
|
@ -1599,6 +1607,7 @@ const render::ItemIDs& Model::fetchRenderItemIDs() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::initializeBlendshapes(const FBXMesh& mesh, int index) {
|
void Model::initializeBlendshapes(const FBXMesh& mesh, int index) {
|
||||||
|
_blendedVertexBuffers[index] = std::make_shared<gpu::Buffer>();
|
||||||
QVector<NormalType> normalsAndTangents;
|
QVector<NormalType> normalsAndTangents;
|
||||||
normalsAndTangents.resize(2 * mesh.normals.size());
|
normalsAndTangents.resize(2 * mesh.normals.size());
|
||||||
|
|
||||||
|
@ -1627,12 +1636,10 @@ void Model::initializeBlendshapes(const FBXMesh& mesh, int index) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const auto verticesSize = mesh.vertices.size() * sizeof(glm::vec3);
|
const auto verticesSize = mesh.vertices.size() * sizeof(glm::vec3);
|
||||||
_blendedVertexBuffers[index] = std::make_shared<gpu::Buffer>();
|
|
||||||
_blendedVertexBuffers[index]->resize(mesh.vertices.size() * sizeof(glm::vec3) + normalsAndTangents.size() * sizeof(NormalType));
|
_blendedVertexBuffers[index]->resize(mesh.vertices.size() * sizeof(glm::vec3) + normalsAndTangents.size() * sizeof(NormalType));
|
||||||
_blendedVertexBuffers[index]->setSubData(0, verticesSize, (const gpu::Byte*) mesh.vertices.constData());
|
_blendedVertexBuffers[index]->setSubData(0, verticesSize, (const gpu::Byte*) mesh.vertices.constData());
|
||||||
_blendedVertexBuffers[index]->setSubData(verticesSize, normalsAndTangents.size() * sizeof(NormalType), (const gpu::Byte*) normalsAndTangents.data());
|
_blendedVertexBuffers[index]->setSubData(verticesSize, normalsAndTangents.size() * sizeof(NormalType), (const gpu::Byte*) normalsAndTangents.data());
|
||||||
mesh.normalsAndTangents = normalsAndTangents;
|
_normalsAndTangents[index] = normalsAndTangents;
|
||||||
_blendedVertexBuffersInitialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::createRenderItemSet() {
|
void Model::createRenderItemSet() {
|
||||||
|
@ -1673,7 +1680,7 @@ void Model::createRenderItemSet() {
|
||||||
// Create the render payloads
|
// Create the render payloads
|
||||||
int numParts = (int)mesh->getNumParts();
|
int numParts = (int)mesh->getNumParts();
|
||||||
for (int partIndex = 0; partIndex < numParts; partIndex++) {
|
for (int partIndex = 0; partIndex < numParts; partIndex++) {
|
||||||
if (!fbxGeometry.meshes[i].blendshapes.empty()) {
|
if (!fbxGeometry.meshes[i].blendshapes.empty() && _blendedVertexBuffers.find(i) == _blendedVertexBuffers.end()) {
|
||||||
initializeBlendshapes(fbxGeometry.meshes[i], i);
|
initializeBlendshapes(fbxGeometry.meshes[i], i);
|
||||||
}
|
}
|
||||||
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
|
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
|
||||||
|
@ -1683,6 +1690,7 @@ void Model::createRenderItemSet() {
|
||||||
shapeID++;
|
shapeID++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_blendedVertexBuffersInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Model::isRenderable() const {
|
bool Model::isRenderable() const {
|
||||||
|
@ -1775,35 +1783,38 @@ ModelBlender::~ModelBlender() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelBlender::noteRequiresBlend(ModelPointer model) {
|
void ModelBlender::noteRequiresBlend(ModelPointer model) {
|
||||||
|
Lock lock(_mutex);
|
||||||
if (_pendingBlenders < QThread::idealThreadCount()) {
|
if (_pendingBlenders < QThread::idealThreadCount()) {
|
||||||
if (model->maybeStartBlender()) {
|
if (model->maybeStartBlender()) {
|
||||||
_pendingBlenders++;
|
_pendingBlenders++;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
_modelsRequiringBlends.insert(model);
|
||||||
Lock lock(_mutex);
|
|
||||||
_modelsRequiringBlends.insert(model);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelBlender::setBlendedVertices(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry,
|
void ModelBlender::setBlendedVertices(ModelPointer model, int blendNumber, QVector<glm::vec3> vertices, QVector<NormalType> normalsAndTangents) {
|
||||||
const QVector<glm::vec3>& vertices, const QVector<NormalType>& normalsAndTangents) {
|
|
||||||
if (model) {
|
if (model) {
|
||||||
model->setBlendedVertices(blendNumber, geometry, vertices, normalsAndTangents);
|
model->setBlendedVertices(blendNumber, vertices, normalsAndTangents);
|
||||||
}
|
}
|
||||||
_pendingBlenders--;
|
|
||||||
{
|
{
|
||||||
Lock lock(_mutex);
|
Lock lock(_mutex);
|
||||||
for (auto i = _modelsRequiringBlends.begin(); i != _modelsRequiringBlends.end();) {
|
_pendingBlenders--;
|
||||||
|
_modelsRequiringBlends.erase(model);
|
||||||
|
std::set<ModelWeakPointer, std::owner_less<ModelWeakPointer>> modelsToErase;
|
||||||
|
for (auto i = _modelsRequiringBlends.begin(); i != _modelsRequiringBlends.end(); i++) {
|
||||||
auto weakPtr = *i;
|
auto weakPtr = *i;
|
||||||
_modelsRequiringBlends.erase(i++); // remove front of the set
|
|
||||||
ModelPointer nextModel = weakPtr.lock();
|
ModelPointer nextModel = weakPtr.lock();
|
||||||
if (nextModel && nextModel->maybeStartBlender()) {
|
if (nextModel && nextModel->maybeStartBlender()) {
|
||||||
_pendingBlenders++;
|
_pendingBlenders++;
|
||||||
return;
|
break;
|
||||||
|
} else {
|
||||||
|
modelsToErase.insert(weakPtr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (auto& weakPtr : modelsToErase) {
|
||||||
|
_modelsRequiringBlends.erase(weakPtr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,8 +144,7 @@ public:
|
||||||
bool maybeStartBlender();
|
bool maybeStartBlender();
|
||||||
|
|
||||||
/// Sets blended vertices computed in a separate thread.
|
/// Sets blended vertices computed in a separate thread.
|
||||||
void setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geometry,
|
void setBlendedVertices(int blendNumber, const QVector<glm::vec3>& vertices, const QVector<NormalType>& normalsAndTangents);
|
||||||
const QVector<glm::vec3>& vertices, const QVector<NormalType>& normalsAndTangents);
|
|
||||||
|
|
||||||
bool isLoaded() const { return (bool)_renderGeometry && _renderGeometry->isGeometryLoaded(); }
|
bool isLoaded() const { return (bool)_renderGeometry && _renderGeometry->isGeometryLoaded(); }
|
||||||
bool isAddedToScene() const { return _addedToScene; }
|
bool isAddedToScene() const { return _addedToScene; }
|
||||||
|
@ -345,7 +344,7 @@ public:
|
||||||
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName);
|
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName);
|
||||||
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName);
|
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName);
|
||||||
|
|
||||||
bool areBlendedVertexBuffersInitialized(int index) { return _blendedVertexBuffersInitialized; }
|
std::unordered_map<int, QVector<NormalType>> _normalsAndTangents;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void loadURLFinished(bool success);
|
void loadURLFinished(bool success);
|
||||||
|
@ -521,8 +520,7 @@ public:
|
||||||
bool shouldComputeBlendshapes() { return _computeBlendshapes; }
|
bool shouldComputeBlendshapes() { return _computeBlendshapes; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setBlendedVertices(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry,
|
void setBlendedVertices(ModelPointer model, int blendNumber, QVector<glm::vec3> vertices, QVector<NormalType> normalsAndTangents);
|
||||||
const QVector<glm::vec3>& vertices, const QVector<NormalType>& normalsAndTangents);
|
|
||||||
void setComputeBlendshapes(bool computeBlendshapes) { _computeBlendshapes = computeBlendshapes; }
|
void setComputeBlendshapes(bool computeBlendshapes) { _computeBlendshapes = computeBlendshapes; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in a new issue