3
0
Fork 0
mirror of https://github.com/lubosz/overte.git synced 2025-04-27 08:55:31 +02:00

Just bringing the code up to date and forcing a build to see how Jenkins/osx is doing.

Merge branch 'master' of https://github.com/highfidelity/hifi into reset-hud-on-driving
This commit is contained in:
Howard Stearns 2016-05-20 08:04:38 -07:00
commit 3088a84035
195 changed files with 6689 additions and 5946 deletions
LICENSE
assignment-client/src
cmake/macros
domain-server/src
interface
libraries

View file

@ -6,7 +6,7 @@ Licensed under the Apache License version 2.0 (the "License");
You may not use this software except in compliance with the License.
You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
This software includes third-party software.
This software includes third-party and other platform software.
Please see each individual software license for additional details.
This software is distributed "as-is" without any warranties, conditions, or representations whether express or implied, including without limitation the implied warranties and conditions of merchantability, merchantable quality, fitness for a particular purpose, performance, durability, title, non-infringement, and those arising from statute or from custom or usage of trade or course of dealing.

View file

@ -290,7 +290,6 @@ void Agent::executeScript() {
packetReceiver.registerListener(PacketType::BulkAvatarData, avatarHashMap.data(), "processAvatarDataPacket");
packetReceiver.registerListener(PacketType::KillAvatar, avatarHashMap.data(), "processKillAvatar");
packetReceiver.registerListener(PacketType::AvatarIdentity, avatarHashMap.data(), "processAvatarIdentityPacket");
packetReceiver.registerListener(PacketType::AvatarBillboard, avatarHashMap.data(), "processAvatarBillboardPacket");
// register ourselves to the script engine
_scriptEngine->registerGlobalObject("Agent", this);
@ -341,15 +340,12 @@ void Agent::setIsAvatar(bool isAvatar) {
if (_isAvatar && !_avatarIdentityTimer) {
// set up the avatar timers
_avatarIdentityTimer = new QTimer(this);
_avatarBillboardTimer = new QTimer(this);
// connect our slot
connect(_avatarIdentityTimer, &QTimer::timeout, this, &Agent::sendAvatarIdentityPacket);
connect(_avatarBillboardTimer, &QTimer::timeout, this, &Agent::sendAvatarBillboardPacket);
// start the timers
_avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS);
_avatarBillboardTimer->start(AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS);
}
if (!_isAvatar) {
@ -359,12 +355,6 @@ void Agent::setIsAvatar(bool isAvatar) {
delete _avatarIdentityTimer;
_avatarIdentityTimer = nullptr;
}
if (_avatarBillboardTimer) {
_avatarBillboardTimer->stop();
delete _avatarBillboardTimer;
_avatarBillboardTimer = nullptr;
}
}
}
@ -375,14 +365,6 @@ void Agent::sendAvatarIdentityPacket() {
}
}
void Agent::sendAvatarBillboardPacket() {
if (_isAvatar) {
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
scriptedAvatar->sendBillboardPacket();
}
}
void Agent::processAgentAvatarAndAudio(float deltaTime) {
if (!_scriptEngine->isFinished() && _isAvatar) {
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
@ -491,7 +473,7 @@ void Agent::processAgentAvatarAndAudio(float deltaTime) {
}
void Agent::aboutToFinish() {
setIsAvatar(false);// will stop timers for sending billboards and identity packets
setIsAvatar(false);// will stop timers for sending identity packets
if (_scriptEngine) {
_scriptEngine->stop();

View file

@ -82,7 +82,6 @@ private:
void setAvatarSound(SharedSoundPointer avatarSound) { _avatarSound = avatarSound; }
void sendAvatarIdentityPacket();
void sendAvatarBillboardPacket();
QString _scriptContents;
QTimer* _scriptRequestTimeout { nullptr };
@ -92,7 +91,6 @@ private:
int _numAvatarSoundSentBytes = 0;
bool _isAvatar = false;
QTimer* _avatarIdentityTimer = nullptr;
QTimer* _avatarBillboardTimer = nullptr;
QHash<QUuid, quint16> _outgoingScriptAudioSequenceNumbers;
};

View file

@ -51,6 +51,8 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri
LogUtils::init();
QSettings::setDefaultFormat(QSettings::IniFormat);
DependencyManager::set<AccountManager>();
auto scriptableAvatar = DependencyManager::set<ScriptableAvatar>();
auto addressManager = DependencyManager::set<AddressManager>();
@ -116,7 +118,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri
_requestTimer.start(ASSIGNMENT_REQUEST_INTERVAL_MSECS);
// connections to AccountManager for authentication
connect(&AccountManager::getInstance(), &AccountManager::authRequired,
connect(DependencyManager::get<AccountManager>().data(), &AccountManager::authRequired,
this, &AssignmentClient::handleAuthenticationRequest);
// Create Singleton objects on main thread
@ -309,13 +311,13 @@ void AssignmentClient::handleAuthenticationRequest() {
QString username = sysEnvironment.value(DATA_SERVER_USERNAME_ENV);
QString password = sysEnvironment.value(DATA_SERVER_PASSWORD_ENV);
AccountManager& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
if (!username.isEmpty() && !password.isEmpty()) {
// ask the account manager to log us in from the env variables
accountManager.requestAccessToken(username, password);
accountManager->requestAccessToken(username, password);
} else {
qCWarning(assigmnentclient) << "Authentication was requested against" << qPrintable(accountManager.getAuthURL().toString())
qCWarning(assigmnentclient) << "Authentication was requested against" << qPrintable(accountManager->getAuthURL().toString())
<< "but both or one of" << qPrintable(DATA_SERVER_USERNAME_ENV)
<< "/" << qPrintable(DATA_SERVER_PASSWORD_ENV) << "are not set. Unable to authenticate.";

View file

@ -60,8 +60,8 @@ public:
virtual void trackViewerGone(const QUuid& sessionID) override;
public slots:
virtual void nodeAdded(SharedNodePointer node);
virtual void nodeKilled(SharedNodePointer node);
virtual void nodeAdded(SharedNodePointer node) override;
virtual void nodeKilled(SharedNodePointer node) override;
void pruneDeletedEntities();
protected:

View file

@ -7,18 +7,21 @@
#
macro(TARGET_NSIGHT)
if (WIN32 AND USE_NSIGHT)
# grab the global CHECKED_FOR_NSIGHT_ONCE property
get_property(NSIGHT_CHECKED GLOBAL PROPERTY CHECKED_FOR_NSIGHT_ONCE)
get_property(NSIGHT_UNAVAILABLE GLOBAL PROPERTY CHECKED_FOR_NSIGHT_ONCE)
if (NOT NSIGHT_CHECKED)
if (NOT NSIGHT_UNAVAILABLE)
# try to find the Nsight package and add it to the build if we find it
find_package(NSIGHT)
# set the global CHECKED_FOR_NSIGHT_ONCE property so that we only debug that we couldn't find it once
set_property(GLOBAL PROPERTY CHECKED_FOR_NSIGHT_ONCE TRUE)
# Cache the failure to find nsight, so that we don't check over and over
if (NOT NSIGHT_FOUND)
set_property(GLOBAL PROPERTY CHECKED_FOR_NSIGHT_ONCE TRUE)
endif()
endif ()
# try to find the Nsight package and add it to the build if we find it
if (NSIGHT_FOUND)
include_directories(${NSIGHT_INCLUDE_DIRS})
add_definitions(-DNSIGHT_FOUND)

View file

@ -485,7 +485,7 @@ void DomainGatekeeper::requestUserPublicKey(const QString& username) {
qDebug() << "Requesting public key for user" << username;
AccountManager::getInstance().sendRequest(USER_PUBLIC_KEY_PATH.arg(username),
DependencyManager::get<AccountManager>()->sendRequest(USER_PUBLIC_KEY_PATH.arg(username),
AccountManagerAuth::None,
QNetworkAccessManager::GetOperation, callbackParams);
}

View file

@ -26,6 +26,7 @@
#include <AccountManager.h>
#include <BuildInfo.h>
#include <DependencyManager.h>
#include <HifiConfigVariantMap.h>
#include <HTTPConnection.h>
#include <LogUtils.h>
@ -77,7 +78,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
// make sure we have a fresh AccountManager instance
// (need this since domain-server can restart itself and maintain static variables)
AccountManager::getInstance(true);
DependencyManager::set<AccountManager>();
auto args = arguments();
@ -195,8 +196,8 @@ bool DomainServer::optionallySetupOAuth() {
_oauthProviderURL = NetworkingConstants::METAVERSE_SERVER_URL;
}
AccountManager& accountManager = AccountManager::getInstance();
accountManager.setAuthURL(_oauthProviderURL);
auto accountManager = DependencyManager::get<AccountManager>();
accountManager->setAuthURL(_oauthProviderURL);
_oauthClientID = settingsMap.value(OAUTH_CLIENT_ID_OPTION).toString();
_oauthClientSecret = QProcessEnvironment::systemEnvironment().value(OAUTH_CLIENT_SECRET_ENV);
@ -239,7 +240,7 @@ void DomainServer::optionallyGetTemporaryName(const QStringList& arguments) {
// we've been asked to grab a temporary name from the API
// so fire off that request now
auto& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
// get callbacks for temporary domain result
JSONCallbackParameters callbackParameters;
@ -248,8 +249,8 @@ void DomainServer::optionallyGetTemporaryName(const QStringList& arguments) {
callbackParameters.errorCallbackReceiver = this;
callbackParameters.errorCallbackMethod = "handleTempDomainError";
accountManager.sendRequest("/api/v1/domains/temporary", AccountManagerAuth::None,
QNetworkAccessManager::PostOperation, callbackParameters);
accountManager->sendRequest("/api/v1/domains/temporary", AccountManagerAuth::None,
QNetworkAccessManager::PostOperation, callbackParameters);
}
}
@ -397,7 +398,7 @@ bool DomainServer::resetAccountManagerAccessToken() {
<< "at keypath metaverse.access_token or in your ENV at key DOMAIN_SERVER_ACCESS_TOKEN";
// clear any existing access token from AccountManager
AccountManager::getInstance().setAccessTokenForCurrentAuthURL(QString());
DependencyManager::get<AccountManager>()->setAccessTokenForCurrentAuthURL(QString());
return false;
}
@ -407,7 +408,7 @@ bool DomainServer::resetAccountManagerAccessToken() {
}
// give this access token to the AccountManager
AccountManager::getInstance().setAccessTokenForCurrentAuthURL(accessToken);
DependencyManager::get<AccountManager>()->setAccessTokenForCurrentAuthURL(accessToken);
return true;
@ -499,17 +500,17 @@ void DomainServer::setupICEHeartbeatForFullNetworking() {
limitedNodeList->startSTUNPublicSocketUpdate();
// to send ICE heartbeats we'd better have a private key locally with an uploaded public key
auto& accountManager = AccountManager::getInstance();
auto domainID = accountManager.getAccountInfo().getDomainID();
auto accountManager = DependencyManager::get<AccountManager>();
auto domainID = accountManager->getAccountInfo().getDomainID();
// if we have an access token and we don't have a private key or the current domain ID has changed
// we should generate a new keypair
if (!accountManager.getAccountInfo().hasPrivateKey() || domainID != limitedNodeList->getSessionUUID()) {
accountManager.generateNewDomainKeypair(limitedNodeList->getSessionUUID());
if (!accountManager->getAccountInfo().hasPrivateKey() || domainID != limitedNodeList->getSessionUUID()) {
accountManager->generateNewDomainKeypair(limitedNodeList->getSessionUUID());
}
// hookup to the signal from account manager that tells us when keypair is available
connect(&accountManager, &AccountManager::newKeypair, this, &DomainServer::handleKeypairChange);
connect(accountManager.data(), &AccountManager::newKeypair, this, &DomainServer::handleKeypairChange);
if (!_iceHeartbeatTimer) {
// setup a timer to heartbeat with the ice-server every so often
@ -962,9 +963,9 @@ void DomainServer::setupPendingAssignmentCredits() {
void DomainServer::sendPendingTransactionsToServer() {
AccountManager& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager.hasValidAccessToken()) {
if (accountManager->hasValidAccessToken()) {
// enumerate the pending transactions and send them to the server to complete payment
TransactionHash::iterator i = _pendingAssignmentCredits.begin();
@ -975,7 +976,7 @@ void DomainServer::sendPendingTransactionsToServer() {
transactionCallbackParams.jsonCallbackMethod = "transactionJSONCallback";
while (i != _pendingAssignmentCredits.end()) {
accountManager.sendRequest("api/v1/transactions",
accountManager->sendRequest("api/v1/transactions",
AccountManagerAuth::Required,
QNetworkAccessManager::PostOperation,
transactionCallbackParams, i.value()->postJson().toJson());
@ -1073,7 +1074,7 @@ void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) {
QString domainUpdateJSON = QString("{\"domain\": %1 }").arg(QString(QJsonDocument(domainObject).toJson()));
AccountManager::getInstance().sendRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)),
DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)),
AccountManagerAuth::Required,
QNetworkAccessManager::PutOperation,
JSONCallbackParameters(),
@ -1103,7 +1104,7 @@ void DomainServer::sendICEServerAddressToMetaverseAPI() {
static const QString DOMAIN_ICE_ADDRESS_UPDATE = "/api/v1/domains/%1/ice_server_address";
AccountManager::getInstance().sendRequest(DOMAIN_ICE_ADDRESS_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)),
DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_ICE_ADDRESS_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)),
AccountManagerAuth::Optional,
QNetworkAccessManager::PutOperation,
callbackParameters,
@ -1123,15 +1124,15 @@ void DomainServer::handleFailedICEServerAddressUpdate(QNetworkReply& requestRepl
void DomainServer::sendHeartbeatToIceServer() {
if (!_iceServerSocket.getAddress().isNull()) {
auto& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
if (!accountManager.getAccountInfo().hasPrivateKey()) {
if (!accountManager->getAccountInfo().hasPrivateKey()) {
qWarning() << "Cannot send an ice-server heartbeat without a private key for signature.";
qWarning() << "Waiting for keypair generation to complete before sending ICE heartbeat.";
if (!limitedNodeList->getSessionUUID().isNull()) {
accountManager.generateNewDomainKeypair(limitedNodeList->getSessionUUID());
accountManager->generateNewDomainKeypair(limitedNodeList->getSessionUUID());
} else {
qWarning() << "Attempting to send ICE server heartbeat with no domain ID. This is not supported";
}
@ -1208,7 +1209,7 @@ void DomainServer::sendHeartbeatToIceServer() {
auto plaintext = QByteArray::fromRawData(_iceServerHeartbeatPacket->getPayload(), _iceServerHeartbeatPacket->getPayloadSize());
// generate a signature for the plaintext data in the packet
auto signature = accountManager.getAccountInfo().signPlaintext(plaintext);
auto signature = accountManager->getAccountInfo().signPlaintext(plaintext);
// pack the signature with the data
heartbeatDataStream << signature;
@ -2101,7 +2102,7 @@ void DomainServer::processICEServerHeartbeatDenialPacket(QSharedPointer<Received
// we've hit our threshold of heartbeat denials, trigger a keypair re-generation
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
AccountManager::getInstance().generateNewDomainKeypair(limitedNodeList->getSessionUUID());
DependencyManager::get<AccountManager>()->generateNewDomainKeypair(limitedNodeList->getSessionUUID());
// reset our number of heartbeat denials
_numHeartbeatDenials = 0;

View file

@ -139,7 +139,7 @@ if (WIN32)
endif()
# link required hifi libraries
link_hifi_libraries(shared octree gpu gl procedural model render
link_hifi_libraries(shared octree gpu gl gpu-gl procedural model render
recording fbx networking model-networking entities avatars
audio audio-client animation script-engine physics
render-utils entities-renderer ui auto-updater

View file

@ -76,7 +76,6 @@ QtObject {
readonly property string forward: "Forward";
readonly property string frameTimer: "Show Timer";
readonly property string fullscreenMirror: "Mirror";
readonly property string glowWhenSpeaking: "Glow When Speaking";
readonly property string help: "Help...";
readonly property string increaseAvatarSize: "Increase Avatar Size";
readonly property string independentMode: "Independent Mode";

View file

@ -1,20 +0,0 @@
#version 120
//
// glow_add.frag
// fragment shader
//
// Created by Andrzej Kapolka on 8/14/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// the texture containing the original color
uniform sampler2D originalTexture;
void main(void) {
vec4 color = texture2D(originalTexture, gl_TexCoord[0].st);
gl_FragColor = color * (1.0 + color.a);
}

View file

@ -1,23 +0,0 @@
#version 120
//
// glow_add_separate.frag
// fragment shader
//
// Created by Andrzej Kapolka on 8/14/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// the texture containing the original color
uniform sampler2D originalTexture;
// the texture containing the blurred color
uniform sampler2D blurredTexture;
void main(void) {
vec4 blurred = texture2D(blurredTexture, gl_TexCoord[0].st);
gl_FragColor = blurred * blurred.a + texture2D(originalTexture, gl_TexCoord[0].st) * (1.0 + blurred.a * 0.5);
}

View file

@ -60,7 +60,7 @@
#include <FramebufferCache.h>
#include <gpu/Batch.h>
#include <gpu/Context.h>
#include <gpu/GLBackend.h>
#include <gpu/gl/GLBackend.h>
#include <HFActionEvent.h>
#include <HFBackEvent.h>
#include <InfoView.h>
@ -349,19 +349,14 @@ public:
};
#endif
enum CustomEventTypes {
Lambda = QEvent::User + 1,
Paint = Lambda + 1,
};
class LambdaEvent : public QEvent {
std::function<void()> _fun;
public:
LambdaEvent(const std::function<void()> & fun) :
QEvent(static_cast<QEvent::Type>(Lambda)), _fun(fun) {
QEvent(static_cast<QEvent::Type>(Application::Lambda)), _fun(fun) {
}
LambdaEvent(std::function<void()> && fun) :
QEvent(static_cast<QEvent::Type>(Lambda)), _fun(fun) {
QEvent(static_cast<QEvent::Type>(Application::Lambda)), _fun(fun) {
}
void call() const { _fun(); }
};
@ -407,6 +402,7 @@ bool setupEssentials(int& argc, char** argv) {
Setting::init();
// Set dependencies
DependencyManager::set<AccountManager>(std::bind(&Application::getUserAgent, qApp));
DependencyManager::set<ScriptEngines>();
DependencyManager::set<Preferences>();
DependencyManager::set<recording::Deck>();
@ -661,15 +657,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch);
// connect to appropriate slots on AccountManager
AccountManager& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
auto dialogsManager = DependencyManager::get<DialogsManager>();
connect(&accountManager, &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog);
connect(&accountManager, &AccountManager::usernameChanged, this, &Application::updateWindowTitle);
connect(accountManager.data(), &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog);
connect(accountManager.data(), &AccountManager::usernameChanged, this, &Application::updateWindowTitle);
// set the account manager's root URL and trigger a login request if we don't have the access token
accountManager.setIsAgent(true);
accountManager.setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);
accountManager->setIsAgent(true);
accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);
// sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value.
// The value will be 0 if the user blew away settings this session, which is both a feature and a bug.
@ -864,10 +860,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
if (action == controller::toInt(controller::Action::RETICLE_CLICK)) {
auto reticlePos = getApplicationCompositor().getReticlePosition();
QPoint globalPos(reticlePos.x, reticlePos.y);
// FIXME - it would be nice if this was self contained in the _compositor or Reticle class
auto localPos = isHMDMode() ? globalPos : _glWidget->mapFromGlobal(globalPos);
QPoint localPos(reticlePos.x, reticlePos.y); // both hmd and desktop already handle this in our coordinates.
if (state) {
QMouseEvent mousePress(QEvent::MouseButtonPress, localPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
sendEvent(_glWidget, &mousePress);
@ -888,15 +881,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
} else if (action == controller::toInt(controller::Action::UI_NAV_SELECT)) {
if (!offscreenUi->navigationFocused()) {
auto reticlePosition = getApplicationCompositor().getReticlePosition();
offscreenUi->toggleMenu(_glWidget->mapFromGlobal(QPoint(reticlePosition.x, reticlePosition.y)));
offscreenUi->toggleMenu(QPoint(reticlePosition.x, reticlePosition.y));
}
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) {
auto reticlePosition = getApplicationCompositor().getReticlePosition();
offscreenUi->toggleMenu(_glWidget->mapFromGlobal(QPoint(reticlePosition.x, reticlePosition.y)));
offscreenUi->toggleMenu(QPoint(reticlePosition.x, reticlePosition.y));
} else if (action == controller::toInt(controller::Action::UI_NAV_SELECT)) {
if (!offscreenUi->navigationFocused()) {
auto reticlePosition = getApplicationCompositor().getReticlePosition();
offscreenUi->toggleMenu(_glWidget->mapFromGlobal(QPoint(reticlePosition.x, reticlePosition.y)));
offscreenUi->toggleMenu(QPoint(reticlePosition.x, reticlePosition.y));
}
} else if (action == controller::toInt(controller::Action::RETICLE_X)) {
auto oldPos = getApplicationCompositor().getReticlePosition();
@ -1060,19 +1053,43 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);
qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);
_idleTimer = new QTimer(this);
connect(_idleTimer, &QTimer::timeout, [=] {
idle(usecTimestampNow());
});
connect(this, &Application::beforeAboutToQuit, [=] {
disconnect(_idleTimer);
});
// Setting the interval to zero forces this to get called whenever there are no messages
// in the queue, which can be pretty damn frequent. Hence the idle function has a bunch
// of logic to abort early if it's being called too often.
_idleTimer->start(0);
// After all of the constructor is completed, then set firstRun to false.
Setting::Handle<bool> firstRun{ Settings::firstRun, true };
firstRun.set(false);
}
QString Application::getUserAgent() {
if (QThread::currentThread() != thread()) {
QString userAgent;
QMetaObject::invokeMethod(this, "getUserAgent", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, userAgent));
return userAgent;
}
QString userAgent = "Mozilla/5.0 (HighFidelityInterface/" + BuildInfo::VERSION + "; "
+ QSysInfo::productType() + " " + QSysInfo::productVersion() + ")";
auto formatPluginName = [](QString name) -> QString { return name.trimmed().replace(" ", "-"); };
// For each plugin, add to userAgent
auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins();
for (auto& dp : displayPlugins) {
if (dp->isActive() && dp->isHmd()) {
userAgent += " " + formatPluginName(dp->getName());
}
}
auto inputPlugins= PluginManager::getInstance()->getInputPlugins();
for (auto& ip : inputPlugins) {
if (ip->isActive()) {
userAgent += " " + formatPluginName(ip->getName());
}
}
return userAgent;
}
void Application::checkChangeCursor() {
QMutexLocker locker(&_changeCursorLock);
@ -1088,11 +1105,6 @@ void Application::checkChangeCursor() {
_cursorNeedsChanging = false;
}
// After all of the constructor is completed, then set firstRun to false.
Setting::Handle<bool> firstRun{ Settings::firstRun, true };
firstRun.set(false);
}
void Application::showCursor(const QCursor& cursor) {
@ -1160,10 +1172,16 @@ void Application::cleanupBeforeQuit() {
getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts
// Clear any queued processing (I/O, FBX/OBJ/Texture parsing)
QThreadPool::globalInstance()->clear();
DependencyManager::get<ScriptEngines>()->saveScripts();
DependencyManager::get<ScriptEngines>()->shutdownScripting(); // stop all currently running global scripts
DependencyManager::destroy<ScriptEngines>();
// Cleanup all overlays after the scripts, as scripts might add more
_overlays.cleanupAllOverlays();
// first stop all timers directly or by invokeMethod
// depending on what thread they run in
locationUpdateTimer.stop();
@ -1260,8 +1278,7 @@ void Application::initializeGL() {
_isGLInitialized = true;
}
// Where the gpuContext is initialized and where the TRUE Backend is created and assigned
gpu::Context::init<gpu::GLBackend>();
gpu::Context::init<gpu::gl::GLBackend>();
_gpuContext = std::make_shared<gpu::Context>();
// The gpu context can make child contexts for transfers, so
// we need to restore primary rendering context
@ -1439,23 +1456,15 @@ void Application::initializeUi() {
});
}
void Application::paintGL() {
updateHeartbeat();
// Some plugins process message events, potentially leading to
// re-entering a paint event. don't allow further processing if this
// happens
if (_inPaint) {
// Some plugins process message events, allowing paintGL to be called reentrantly.
if (_inPaint || _aboutToQuit) {
return;
}
_inPaint = true;
Finally clearFlagLambda([this] { _inPaint = false; });
// paintGL uses a queued connection, so we can get messages from the queue even after we've quit
// and the plugins have shutdown
if (_aboutToQuit) {
return;
}
_inPaint = true;
Finally clearFlag([this] { _inPaint = false; });
_frameCount++;
_frameCounter.increment();
@ -1813,13 +1822,30 @@ bool Application::event(QEvent* event) {
return false;
}
if ((int)event->type() == (int)Lambda) {
static_cast<LambdaEvent*>(event)->call();
static bool justPresented = false;
if ((int)event->type() == (int)Present) {
if (justPresented) {
justPresented = false;
// If presentation is hogging the main thread, repost as low priority to avoid hanging the GUI.
// This has the effect of allowing presentation to exceed the paint budget by X times and
// only dropping every (1/X) frames, instead of every ceil(X) frames.
// (e.g. at a 60FPS target, painting for 17us would fall to 58.82FPS instead of 30FPS).
removePostedEvents(this, Present);
postEvent(this, new QEvent(static_cast<QEvent::Type>(Present)), Qt::LowEventPriority);
return true;
}
idle();
return true;
} else if ((int)event->type() == (int)Paint) {
justPresented = true;
paintGL();
return true;
}
if ((int)event->type() == (int)Paint) {
paintGL();
if ((int)event->type() == (int)Lambda) {
static_cast<LambdaEvent*>(event)->call();
return true;
}
@ -2269,7 +2295,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
if (event->key() == Qt::Key_Alt && _altPressed && hasFocus()) {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
auto reticlePosition = getApplicationCompositor().getReticlePosition();
offscreenUi->toggleMenu(_glWidget->mapFromGlobal(QPoint(reticlePosition.x, reticlePosition.y)));
offscreenUi->toggleMenu(QPoint(reticlePosition.x, reticlePosition.y));
}
_keysPressed.remove(event->key());
@ -2597,72 +2623,63 @@ bool Application::acceptSnapshot(const QString& urlString) {
static uint32_t _renderedFrameIndex { INVALID_FRAME };
void Application::idle(uint64_t now) {
// NOTICE NOTICE NOTICE NOTICE
// Do not insert new code between here and the PROFILE_RANGE declaration
// unless you know exactly what you're doing. This idle function can be
// called thousands per second or more, so any additional work that's done
// here will have a serious impact on CPU usage. Only add code after all
// the thottling logic, i.e. after PROFILE_RANGE
// NOTICE NOTICE NOTICE NOTICE
updateHeartbeat();
if (_aboutToQuit || _inPaint) {
return; // bail early, nothing to do here.
}
auto displayPlugin = getActiveDisplayPlugin();
// depending on whether we're throttling or not.
// Once rendering is off on another thread we should be able to have Application::idle run at start(0) in
// perpetuity and not expect events to get backed up.
bool isThrottled = displayPlugin->isThrottled();
// Only run simulation code if more than the targetFramePeriod have passed since last time we ran
// This attempts to lock the simulation at 60 updates per second, regardless of framerate
float timeSinceLastUpdateUs = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_USEC;
float secondsSinceLastUpdate = timeSinceLastUpdateUs / USECS_PER_SECOND;
if (isThrottled && (timeSinceLastUpdateUs / USECS_PER_MSEC) < THROTTLED_SIM_FRAME_PERIOD_MS) {
// Throttling both rendering and idle
return; // bail early, we're throttled and not enough time has elapsed
}
auto presentCount = displayPlugin->presentCount();
if (presentCount < _renderedFrameIndex) {
_renderedFrameIndex = INVALID_FRAME;
}
// Don't saturate the main thread with rendering and simulation,
// unless display plugin has increased by at least one frame
if (_renderedFrameIndex == INVALID_FRAME || presentCount > _renderedFrameIndex) {
// Record what present frame we're on
_renderedFrameIndex = presentCount;
// request a paint, get to it as soon as possible: high priority
postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority);
} else {
// there's no use in simulating or rendering faster then the present rate.
void Application::idle() {
// idle is called on a queued connection, so make sure we should be here.
if (_inPaint || _aboutToQuit) {
return;
}
// NOTICE NOTICE NOTICE NOTICE
// do NOT add new code above this line unless you want it to be executed potentially
// thousands of times per second
// NOTICE NOTICE NOTICE NOTICE
auto displayPlugin = getActiveDisplayPlugin();
PROFILE_RANGE(__FUNCTION__);
#ifdef DEBUG_PAINT_DELAY
static uint64_t paintDelaySamples{ 0 };
static uint64_t paintDelayUsecs{ 0 };
paintDelayUsecs += displayPlugin->getPaintDelayUsecs();
static const int PAINT_DELAY_THROTTLE = 1000;
if (++paintDelaySamples % PAINT_DELAY_THROTTLE == 0) {
qCDebug(interfaceapp).nospace() <<
"Paint delay (" << paintDelaySamples << " samples): " <<
(float)paintDelaySamples / paintDelayUsecs << "us";
}
#endif
float msecondsSinceLastUpdate = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_USEC / USECS_PER_MSEC;
// Throttle if requested
if (displayPlugin->isThrottled() && (msecondsSinceLastUpdate < THROTTLED_SIM_FRAME_PERIOD_MS)) {
return;
}
// Sync up the _renderedFrameIndex
_renderedFrameIndex = displayPlugin->presentCount();
// Request a paint ASAP
postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority + 1);
// Update the deadlock watchdog
updateHeartbeat();
auto offscreenUi = DependencyManager::get<OffscreenUi>();
// These tasks need to be done on our first idle, because we don't want the showing of
// overlay subwindows to do a showDesktop() until after the first time through
static bool firstIdle = true;
if (firstIdle) {
firstIdle = false;
auto offscreenUi = DependencyManager::get<OffscreenUi>();
connect(offscreenUi.data(), &OffscreenUi::showDesktop, this, &Application::showDesktop);
_overlayConductor.setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Overlays));
} else {
// FIXME: AvatarInputs are positioned incorrectly if instantiated before the first paint
AvatarInputs::getInstance()->update();
}
PROFILE_RANGE(__FUNCTION__);
float secondsSinceLastUpdate = msecondsSinceLastUpdate / MSECS_PER_SECOND;
// If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus.
auto offscreenUi = DependencyManager::get<OffscreenUi>();
if (_keyboardDeviceHasFocus && offscreenUi && offscreenUi->getWindow()->activeFocusItem() != offscreenUi->getRootItem()) {
_keyboardMouseDevice->pluginFocusOutEvent();
_keyboardDeviceHasFocus = false;
@ -2678,7 +2695,6 @@ void Application::idle(uint64_t now) {
checkChangeCursor();
Stats::getInstance()->updateStats();
AvatarInputs::getInstance()->update();
_simCounter.increment();
@ -2738,15 +2754,7 @@ void Application::setLowVelocityFilter(bool lowVelocityFilter) {
}
ivec2 Application::getMouse() const {
auto reticlePosition = getApplicationCompositor().getReticlePosition();
// in the HMD, the reticlePosition is the mouse position
if (isHMDMode()) {
return reticlePosition;
}
// in desktop mode, we need to map from global to widget space
return toGlm(_glWidget->mapFromGlobal(QPoint(reticlePosition.x, reticlePosition.y)));
return getApplicationCompositor().getReticlePosition();
}
FaceTracker* Application::getActiveFaceTracker() {
@ -3680,11 +3688,11 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
} else {
const JurisdictionMap& map = (jurisdictions)[nodeUUID];
unsigned char* rootCode = map.getRootOctalCode();
auto rootCode = map.getRootOctalCode();
if (rootCode) {
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
voxelDetailsForCode(rootCode.get(), rootDetails);
AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE,
rootDetails.y * TREE_SCALE,
rootDetails.z * TREE_SCALE) - glm::vec3(HALF_TREE_SCALE),
@ -3744,11 +3752,11 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
} else {
const JurisdictionMap& map = (jurisdictions)[nodeUUID];
unsigned char* rootCode = map.getRootOctalCode();
auto rootCode = map.getRootOctalCode();
if (rootCode) {
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
voxelDetailsForCode(rootCode.get(), rootDetails);
AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE,
rootDetails.y * TREE_SCALE,
rootDetails.z * TREE_SCALE) - glm::vec3(HALF_TREE_SCALE),
@ -4160,7 +4168,7 @@ void Application::updateWindowTitle() const {
auto nodeList = DependencyManager::get<NodeList>();
QString connectionStatus = nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED) ";
QString username = AccountManager::getInstance().getAccountInfo().getUsername();
QString username = DependencyManager::get<AccountManager>()->getAccountInfo().getUsername();
QString currentPlaceName = DependencyManager::get<AddressManager>()->getHost();
if (currentPlaceName.isEmpty()) {
@ -4275,9 +4283,9 @@ void Application::nodeKilled(SharedNodePointer node) {
return;
}
unsigned char* rootCode = _entityServerJurisdictions[nodeUUID].getRootOctalCode();
auto rootCode = _entityServerJurisdictions[nodeUUID].getRootOctalCode();
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
voxelDetailsForCode(rootCode.get(), rootDetails);
qCDebug(interfaceapp, "model server going away...... v[%f, %f, %f, %f]",
(double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s);
@ -4396,27 +4404,33 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer
serverType = "Entity";
}
bool found = false;
jurisdiction->withReadLock([&] {
if (jurisdiction->find(nodeUUID) != jurisdiction->end()) {
found = true;
return;
}
VoxelPositionSize rootDetails;
voxelDetailsForCode(octreeStats.getJurisdictionRoot(), rootDetails);
voxelDetailsForCode(octreeStats.getJurisdictionRoot().get(), rootDetails);
qCDebug(interfaceapp, "stats from new %s server... [%f, %f, %f, %f]",
qPrintable(serverType),
(double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s);
});
// store jurisdiction details for later use
// This is bit of fiddling is because JurisdictionMap assumes it is the owner of the values used to construct it
// but OctreeSceneStats thinks it's just returning a reference to its contents. So we need to make a copy of the
// details from the OctreeSceneStats to construct the JurisdictionMap
JurisdictionMap jurisdictionMap;
jurisdictionMap.copyContents(octreeStats.getJurisdictionRoot(), octreeStats.getJurisdictionEndNodes());
jurisdiction->withWriteLock([&] {
(*jurisdiction)[nodeUUID] = jurisdictionMap;
});
if (!found) {
// store jurisdiction details for later use
// This is bit of fiddling is because JurisdictionMap assumes it is the owner of the values used to construct it
// but OctreeSceneStats thinks it's just returning a reference to its contents. So we need to make a copy of the
// details from the OctreeSceneStats to construct the JurisdictionMap
JurisdictionMap jurisdictionMap;
jurisdictionMap.copyContents(octreeStats.getJurisdictionRoot(), octreeStats.getJurisdictionEndNodes());
jurisdiction->withWriteLock([&] {
(*jurisdiction)[nodeUUID] = jurisdictionMap;
});
}
});
return statsMessageLength;
@ -4800,8 +4814,8 @@ void Application::takeSnapshot() {
QString fileName = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot());
AccountManager& accountManager = AccountManager::getInstance();
if (!accountManager.isLoggedIn()) {
auto accountManager = DependencyManager::get<AccountManager>();
if (!accountManager->isLoggedIn()) {
return;
}

View file

@ -33,6 +33,7 @@
#include <PhysicalEntitySimulation.h>
#include <PhysicsEngine.h>
#include <plugins/Forward.h>
#include <plugins/DisplayPlugin.h>
#include <ScriptEngine.h>
#include <ShapeManager.h>
#include <SimpleMovingAverage.h>
@ -93,6 +94,12 @@ class Application : public QApplication, public AbstractViewStateInterface, publ
friend class PluginContainerProxy;
public:
enum Event {
Present = DisplayPlugin::Present,
Paint = Present + 1,
Lambda = Paint + 1
};
// FIXME? Empty methods, do we still need them?
static void initPlugins();
static void shutdownPlugins();
@ -105,6 +112,9 @@ public:
QString getPreviousScriptLocation();
void setPreviousScriptLocation(const QString& previousScriptLocation);
// Return an HTTP User-Agent string with OS and device information.
Q_INVOKABLE QString getUserAgent();
void initializeGL();
void initializeUi();
void paintGL();
@ -281,7 +291,6 @@ public slots:
private slots:
void showDesktop();
void clearDomainOctreeDetails();
void idle(uint64_t now);
void aboutToQuit();
void resettingDomain();
@ -320,6 +329,7 @@ private:
void cleanupBeforeQuit();
void idle();
void update(float deltaTime);
// Various helper functions called during update()
@ -497,7 +507,6 @@ private:
int _avatarAttachmentRequest = 0;
bool _settingsLoaded { false };
QTimer* _idleTimer { nullptr };
bool _fakedMouseEvent { false };

View file

@ -35,9 +35,9 @@ const QString API_USER_HEARTBEAT_PATH = "/api/v1/user/heartbeat";
const QString SESSION_ID_KEY = "session_id";
void DiscoverabilityManager::updateLocation() {
AccountManager& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
if (_mode.get() != Discoverability::None && accountManager.isLoggedIn()) {
if (_mode.get() != Discoverability::None && accountManager->isLoggedIn()) {
auto addressManager = DependencyManager::get<AddressManager>();
DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
@ -98,7 +98,7 @@ void DiscoverabilityManager::updateLocation() {
apiPath = API_USER_LOCATION_PATH;
}
accountManager.sendRequest(apiPath, AccountManagerAuth::Required,
accountManager->sendRequest(apiPath, AccountManagerAuth::Required,
QNetworkAccessManager::PutOperation,
callbackParameters, QJsonDocument(rootObject).toJson());
@ -116,7 +116,7 @@ void DiscoverabilityManager::updateLocation() {
heartbeatObject[SESSION_ID_KEY] = QJsonValue();
}
accountManager.sendRequest(API_USER_HEARTBEAT_PATH, AccountManagerAuth::Optional,
accountManager->sendRequest(API_USER_HEARTBEAT_PATH, AccountManagerAuth::Optional,
QNetworkAccessManager::PutOperation, callbackParameters,
QJsonDocument(heartbeatObject).toJson());
}
@ -131,8 +131,8 @@ void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply& requestReply
}
void DiscoverabilityManager::removeLocation() {
AccountManager& accountManager = AccountManager::getInstance();
accountManager.sendRequest(API_USER_LOCATION_PATH, AccountManagerAuth::Required, QNetworkAccessManager::DeleteOperation);
auto accountManager = DependencyManager::get<AccountManager>();
accountManager->sendRequest(API_USER_LOCATION_PATH, AccountManagerAuth::Required, QNetworkAccessManager::DeleteOperation);
}
void DiscoverabilityManager::setDiscoverabilityMode(Discoverability::Mode discoverabilityMode) {

View file

@ -54,7 +54,7 @@ Menu* Menu::getInstance() {
Menu::Menu() {
auto dialogsManager = DependencyManager::get<DialogsManager>();
AccountManager& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
// File/Application menu ----------------------------------
MenuWrapper* fileMenu = addMenu("File");
@ -64,9 +64,9 @@ Menu::Menu() {
addActionToQMenuAndActionHash(fileMenu, MenuOption::Login);
// connect to the appropriate signal of the AccountManager so that we can change the Login/Logout menu item
connect(&accountManager, &AccountManager::profileChanged,
connect(accountManager.data(), &AccountManager::profileChanged,
dialogsManager.data(), &DialogsManager::toggleLoginDialog);
connect(&accountManager, &AccountManager::logoutComplete,
connect(accountManager.data(), &AccountManager::logoutComplete,
dialogsManager.data(), &DialogsManager::toggleLoginDialog);
}
@ -500,7 +500,7 @@ Menu::Menu() {
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSensorToWorldMatrix, 0, false,
avatar, SLOT(setEnableDebugDrawSensorToWorldMatrix(bool)));
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::KeyboardMotorControl,
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ActionMotorControl,
Qt::CTRL | Qt::SHIFT | Qt::Key_K, true, avatar, SLOT(updateMotionBehaviorFromMenu()),
UNSPECIFIED_POSITION, "Developer");

View file

@ -111,12 +111,11 @@ namespace MenuOption {
const QString Forward = "Forward";
const QString FrameTimer = "Show Timer";
const QString FullscreenMirror = "Mirror";
const QString GlowWhenSpeaking = "Glow When Speaking";
const QString Help = "Help...";
const QString IncreaseAvatarSize = "Increase Avatar Size";
const QString IndependentMode = "Independent Mode";
const QString InputMenu = "Avatar>Input Devices";
const QString KeyboardMotorControl = "Enable Keyboard Motor Control";
const QString ActionMotorControl = "Enable Default Motor Control";
const QString LeapMotionOnHMD = "Leap Motion on HMD";
const QString LoadScript = "Open and Run Script File...";
const QString LoadScriptURL = "Open and Run Script from URL...";

View file

@ -73,7 +73,6 @@ AvatarManager::AvatarManager(QObject* parent) :
packetReceiver.registerListener(PacketType::BulkAvatarData, this, "processAvatarDataPacket");
packetReceiver.registerListener(PacketType::KillAvatar, this, "processKillAvatar");
packetReceiver.registerListener(PacketType::AvatarIdentity, this, "processAvatarIdentityPacket");
packetReceiver.registerListener(PacketType::AvatarBillboard, this, "processAvatarBillboardPacket");
}
AvatarManager::~AvatarManager() {

View file

@ -59,9 +59,10 @@ using namespace std;
const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);
const float DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES = 30.0f;
const float MAX_WALKING_SPEED = 2.5f; // human walking speed
const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // keyboard motor gets additive boost below this speed
const float MIN_AVATAR_SPEED = 0.05f; // speed is set to zero below this
const float MAX_WALKING_SPEED = 2.6f; // human walking speed
const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // action motor gets additive boost below this speed
const float MIN_AVATAR_SPEED = 0.05f;
const float MIN_AVATAR_SPEED_SQUARED = MIN_AVATAR_SPEED * MIN_AVATAR_SPEED; // speed is set to zero below this
const float YAW_SPEED_DEFAULT = 120.0f; // degrees/sec
const float PITCH_SPEED_DEFAULT = 90.0f; // degrees/sec
@ -69,8 +70,7 @@ const float PITCH_SPEED_DEFAULT = 90.0f; // degrees/sec
// TODO: normalize avatar speed for standard avatar size, then scale all motion logic
// to properly follow avatar size.
float MAX_AVATAR_SPEED = 30.0f;
float MAX_KEYBOARD_MOTOR_SPEED = MAX_AVATAR_SPEED;
float DEFAULT_KEYBOARD_MOTOR_TIMESCALE = 0.25f;
float MAX_ACTION_MOTOR_SPEED = MAX_AVATAR_SPEED;
float MIN_SCRIPTED_MOTOR_TIMESCALE = 0.005f;
float DEFAULT_SCRIPTED_MOTOR_TIMESCALE = 1.0e6f;
const int SCRIPTED_MOTOR_CAMERA_FRAME = 0;
@ -86,13 +86,13 @@ MyAvatar::MyAvatar(RigPointer rig) :
Avatar(rig),
_wasPushing(false),
_isPushing(false),
_isBeingPushed(false),
_isBraking(false),
_boomLength(ZOOM_DEFAULT),
_yawSpeed(YAW_SPEED_DEFAULT),
_pitchSpeed(PITCH_SPEED_DEFAULT),
_thrust(0.0f),
_keyboardMotorVelocity(0.0f),
_keyboardMotorTimescale(DEFAULT_KEYBOARD_MOTOR_TIMESCALE),
_actionMotorVelocity(0.0f),
_scriptedMotorVelocity(0.0f),
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE),
_scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),
@ -248,7 +248,6 @@ void MyAvatar::reset(bool andRecenter, bool andReload) {
_skeletonModel->reset();
}
getHead()->reset();
_targetVelocity = glm::vec3(0.0f);
setThrust(glm::vec3(0.0f));
if (andRecenter) {
@ -677,7 +676,11 @@ void MyAvatar::saveData() {
settings.setValue("leanScale", _leanScale);
settings.setValue("scale", _targetScale);
settings.setValue("fullAvatarURL", _fullAvatarURLFromPreferences);
settings.setValue("fullAvatarURL",
_fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl() ?
"" :
_fullAvatarURLFromPreferences.toString());
settings.setValue("fullAvatarModelName", _fullAvatarModelName);
settings.setValue("animGraphURL", _animGraphUrl);
@ -1164,8 +1167,46 @@ controller::Pose MyAvatar::getRightHandControllerPoseInAvatarFrame() const {
return getRightHandControllerPoseInWorldFrame().transform(invAvatarMatrix);
}
void MyAvatar::updateMotors() {
_characterController.clearMotors();
glm::quat motorRotation;
if (_motionBehaviors & AVATAR_MOTION_ACTION_MOTOR_ENABLED) {
if (_characterController.getState() == CharacterController::State::Hover) {
motorRotation = getHead()->getCameraOrientation();
} else {
motorRotation = getOrientation();
}
const float DEFAULT_MOTOR_TIMESCALE = 0.2f;
const float INVALID_MOTOR_TIMESCALE = 1.0e6f;
if (_isPushing || _isBraking || !_isBeingPushed) {
_characterController.addMotor(_actionMotorVelocity, motorRotation, DEFAULT_MOTOR_TIMESCALE, INVALID_MOTOR_TIMESCALE);
} else {
// _isBeingPushed must be true --> disable action motor by giving it a long timescale,
// otherwise it's attempt to "stand in in place" could defeat scripted motor/thrusts
_characterController.addMotor(_actionMotorVelocity, motorRotation, INVALID_MOTOR_TIMESCALE);
}
}
if (_motionBehaviors & AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED) {
if (_scriptedMotorFrame == SCRIPTED_MOTOR_CAMERA_FRAME) {
motorRotation = getHead()->getCameraOrientation() * glm::angleAxis(PI, Vectors::UNIT_Y);
} else if (_scriptedMotorFrame == SCRIPTED_MOTOR_AVATAR_FRAME) {
motorRotation = getOrientation() * glm::angleAxis(PI, Vectors::UNIT_Y);
} else {
// world-frame
motorRotation = glm::quat();
}
_characterController.addMotor(_scriptedMotorVelocity, motorRotation, _scriptedMotorTimescale);
}
// legacy support for 'MyAvatar::applyThrust()', which has always been implemented as a
// short-lived linearAcceleration
_characterController.setLinearAcceleration(_thrust);
_thrust = Vectors::ZERO;
}
void MyAvatar::prepareForPhysicsSimulation() {
relayDriveKeysToCharacterController();
updateMotors();
bool success;
glm::vec3 parentVelocity = getParentVelocity(success);
@ -1175,7 +1216,6 @@ void MyAvatar::prepareForPhysicsSimulation() {
}
_characterController.setParentVelocity(parentVelocity);
_characterController.setTargetVelocity(getTargetVelocity());
_characterController.setPositionAndOrientation(getPosition(), getOrientation());
if (qApp->isHMDMode()) {
bool hasDriveInput = fabsf(_driveKeys[TRANSLATE_X]) > 0.0f || fabsf(_driveKeys[TRANSLATE_Z]) > 0.0f;
@ -1188,11 +1228,17 @@ void MyAvatar::prepareForPhysicsSimulation() {
void MyAvatar::harvestResultsFromPhysicsSimulation(float deltaTime) {
glm::vec3 position = getPosition();
glm::quat orientation = getOrientation();
_characterController.getPositionAndOrientation(position, orientation);
if (_characterController.isEnabled()) {
_characterController.getPositionAndOrientation(position, orientation);
}
nextAttitude(position, orientation);
_bodySensorMatrix = _follow.postPhysicsUpdate(*this, _bodySensorMatrix);
setVelocity(_characterController.getLinearVelocity() + _characterController.getFollowVelocity());
if (_characterController.isEnabled()) {
setVelocity(_characterController.getLinearVelocity() + _characterController.getFollowVelocity());
} else {
setVelocity(getVelocity() + _characterController.getFollowVelocity());
}
}
QString MyAvatar::getScriptedMotorFrame() const {
@ -1232,7 +1278,7 @@ void MyAvatar::setScriptedMotorFrame(QString frame) {
}
void MyAvatar::clearScriptableSettings() {
_scriptedMotorVelocity = glm::vec3(0.0f);
_scriptedMotorVelocity = Vectors::ZERO;
_scriptedMotorTimescale = DEFAULT_SCRIPTED_MOTOR_TIMESCALE;
}
@ -1497,163 +1543,97 @@ void MyAvatar::updateOrientation(float deltaTime) {
}
}
glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVelocity, bool isHovering) {
if (! (_motionBehaviors & AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED)) {
return localVelocity;
}
// compute motor efficiency
// The timescale of the motor is the approximate time it takes for the motor to
// accomplish its intended localVelocity. A short timescale makes the motor strong,
// and a long timescale makes it weak. The value of timescale to use depends
// on what the motor is doing:
//
// (1) braking --> short timescale (aggressive motor assertion)
// (2) pushing --> medium timescale (mild motor assertion)
// (3) inactive --> long timescale (gentle friction for low speeds)
const float MIN_KEYBOARD_MOTOR_TIMESCALE = 0.125f;
const float MAX_KEYBOARD_MOTOR_TIMESCALE = 0.4f;
const float MIN_KEYBOARD_BRAKE_SPEED = 0.3f;
float timescale = MAX_KEYBOARD_MOTOR_TIMESCALE;
bool isThrust = (glm::length2(_thrust) > EPSILON);
if (_isPushing || isThrust ||
(_scriptedMotorTimescale < MAX_KEYBOARD_MOTOR_TIMESCALE &&
(_motionBehaviors & AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED))) {
// we don't want to brake if something is pushing the avatar around
timescale = _keyboardMotorTimescale;
void MyAvatar::updateActionMotor(float deltaTime) {
bool thrustIsPushing = (glm::length2(_thrust) > EPSILON);
bool scriptedMotorIsPushing = (_motionBehaviors & AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED)
&& _scriptedMotorTimescale < MAX_CHARACTER_MOTOR_TIMESCALE;
_isBeingPushed = thrustIsPushing || scriptedMotorIsPushing;
if (_isPushing || _isBeingPushed) {
// we don't want the motor to brake if a script is pushing the avatar around
// (we assume the avatar is driving itself via script)
_isBraking = false;
} else {
float speed = glm::length(localVelocity);
_isBraking = _wasPushing || (_isBraking && speed > MIN_KEYBOARD_BRAKE_SPEED);
if (_isBraking) {
timescale = MIN_KEYBOARD_MOTOR_TIMESCALE;
}
float speed = glm::length(_actionMotorVelocity);
const float MIN_ACTION_BRAKE_SPEED = 0.1f;
_isBraking = _wasPushing || (_isBraking && speed > MIN_ACTION_BRAKE_SPEED);
}
_wasPushing = _isPushing || isThrust;
_isPushing = false;
float motorEfficiency = glm::clamp(deltaTime / timescale, 0.0f, 1.0f);
glm::vec3 newLocalVelocity = localVelocity;
// compute action input
glm::vec3 front = (_driveKeys[TRANSLATE_Z]) * IDENTITY_FRONT;
glm::vec3 right = (_driveKeys[TRANSLATE_X]) * IDENTITY_RIGHT;
// FIXME how do I implement step translation as well?
float keyboardInput = fabsf(_driveKeys[TRANSLATE_Z]) + fabsf(_driveKeys[TRANSLATE_X]) + fabsf(_driveKeys[TRANSLATE_Y]);
if (keyboardInput) {
// Compute keyboard input
glm::vec3 front = (_driveKeys[TRANSLATE_Z]) * IDENTITY_FRONT;
glm::vec3 right = (_driveKeys[TRANSLATE_X]) * IDENTITY_RIGHT;
glm::vec3 direction = front + right;
CharacterController::State state = _characterController.getState();
if (state == CharacterController::State::Hover) {
// we're flying --> support vertical motion
glm::vec3 up = (_driveKeys[TRANSLATE_Y]) * IDENTITY_UP;
direction += up;
}
glm::vec3 direction = front + right + up;
float directionLength = glm::length(direction);
_wasPushing = _isPushing;
float directionLength = glm::length(direction);
_isPushing = directionLength > EPSILON;
//qCDebug(interfaceapp, "direction = (%.5f, %.5f, %.5f)", direction.x, direction.y, direction.z);
// Compute motor magnitude
if (directionLength > EPSILON) {
direction /= directionLength;
if (isHovering) {
// we're flying --> complex acceleration curve with high max speed
float motorSpeed = glm::length(_keyboardMotorVelocity);
float finalMaxMotorSpeed = getUniformScale() * MAX_KEYBOARD_MOTOR_SPEED;
float speedGrowthTimescale = 2.0f;
float speedIncreaseFactor = 1.8f;
motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale , 0.0f, 1.0f) * speedIncreaseFactor;
const float maxBoostSpeed = getUniformScale() * MAX_BOOST_SPEED;
if (motorSpeed < maxBoostSpeed) {
// an active keyboard motor should never be slower than this
float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed;
motorSpeed += MIN_AVATAR_SPEED * boostCoefficient;
motorEfficiency += (1.0f - motorEfficiency) * boostCoefficient;
} else if (motorSpeed > finalMaxMotorSpeed) {
motorSpeed = finalMaxMotorSpeed;
}
_keyboardMotorVelocity = motorSpeed * direction;
} else {
// we're using a floor --> simple exponential decay toward target walk speed
const float WALK_ACCELERATION_TIMESCALE = 0.7f; // seconds to decrease delta to 1/e
_keyboardMotorVelocity = MAX_WALKING_SPEED * direction;
motorEfficiency = glm::clamp(deltaTime / WALK_ACCELERATION_TIMESCALE, 0.0f, 1.0f);
}
_isPushing = true;
}
newLocalVelocity = localVelocity + motorEfficiency * (_keyboardMotorVelocity - localVelocity);
// normalize direction
if (_isPushing) {
direction /= directionLength;
} else {
_keyboardMotorVelocity = glm::vec3(0.0f);
newLocalVelocity = (1.0f - motorEfficiency) * localVelocity;
if (!isHovering && !_wasPushing) {
float speed = glm::length(newLocalVelocity);
if (speed > MIN_AVATAR_SPEED) {
// add small constant friction to help avatar drift to a stop sooner at low speeds
const float CONSTANT_FRICTION_DECELERATION = MIN_AVATAR_SPEED / 0.20f;
newLocalVelocity *= (speed - timescale * CONSTANT_FRICTION_DECELERATION) / speed;
direction = Vectors::ZERO;
}
if (state == CharacterController::State::Hover) {
// we're flying --> complex acceleration curve that builds on top of current motor speed and caps at some max speed
float motorSpeed = glm::length(_actionMotorVelocity);
float finalMaxMotorSpeed = getUniformScale() * MAX_ACTION_MOTOR_SPEED;
float speedGrowthTimescale = 2.0f;
float speedIncreaseFactor = 1.8f;
motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale , 0.0f, 1.0f) * speedIncreaseFactor;
const float maxBoostSpeed = getUniformScale() * MAX_BOOST_SPEED;
if (_isPushing) {
if (motorSpeed < maxBoostSpeed) {
// an active action motor should never be slower than this
float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed;
motorSpeed += MIN_AVATAR_SPEED * boostCoefficient;
} else if (motorSpeed > finalMaxMotorSpeed) {
motorSpeed = finalMaxMotorSpeed;
}
}
_actionMotorVelocity = motorSpeed * direction;
} else {
// we're interacting with a floor --> simple horizontal speed and exponential decay
_actionMotorVelocity = MAX_WALKING_SPEED * direction;
}
float boomChange = _driveKeys[ZOOM];
_boomLength += 2.0f * _boomLength * boomChange + boomChange * boomChange;
_boomLength = glm::clamp<float>(_boomLength, ZOOM_MIN, ZOOM_MAX);
return newLocalVelocity;
}
glm::vec3 MyAvatar::applyScriptedMotor(float deltaTime, const glm::vec3& localVelocity) {
// NOTE: localVelocity is in camera-frame because that's the frame of the default avatar motor
if (! (_motionBehaviors & AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED)) {
return localVelocity;
}
glm::vec3 deltaVelocity(0.0f);
if (_scriptedMotorFrame == SCRIPTED_MOTOR_CAMERA_FRAME) {
// camera frame
deltaVelocity = _scriptedMotorVelocity - localVelocity;
} else if (_scriptedMotorFrame == SCRIPTED_MOTOR_AVATAR_FRAME) {
// avatar frame
glm::quat rotation = glm::inverse(getHead()->getCameraOrientation()) * getOrientation();
deltaVelocity = rotation * _scriptedMotorVelocity - localVelocity;
} else {
// world-frame
glm::quat rotation = glm::inverse(getHead()->getCameraOrientation());
deltaVelocity = rotation * _scriptedMotorVelocity - localVelocity;
}
float motorEfficiency = glm::clamp(deltaTime / _scriptedMotorTimescale, 0.0f, 1.0f);
return localVelocity + motorEfficiency * deltaVelocity;
}
void MyAvatar::updatePosition(float deltaTime) {
// rotate velocity into camera frame
glm::quat rotation = getHead()->getCameraOrientation();
glm::vec3 localVelocity = glm::inverse(rotation) * _targetVelocity;
bool isHovering = _characterController.getState() == CharacterController::State::Hover;
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isHovering);
newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity);
// rotate back into world-frame
_targetVelocity = rotation * newLocalVelocity;
_targetVelocity += _thrust * deltaTime;
_thrust = glm::vec3(0.0f);
// cap avatar speed
float speed = glm::length(_targetVelocity);
if (speed > MAX_AVATAR_SPEED) {
_targetVelocity *= MAX_AVATAR_SPEED / speed;
speed = MAX_AVATAR_SPEED;
if (_motionBehaviors & AVATAR_MOTION_ACTION_MOTOR_ENABLED) {
updateActionMotor(deltaTime);
}
if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) {
// update position ourselves
applyPositionDelta(deltaTime * _targetVelocity);
vec3 velocity = getVelocity();
const float MOVING_SPEED_THRESHOLD_SQUARED = 0.0001f; // 0.01 m/s
if (!_characterController.isEnabled()) {
// _characterController is not in physics simulation but it can still compute its target velocity
updateMotors();
_characterController.computeNewVelocity(deltaTime, velocity);
float speed2 = glm::length2(velocity);
if (speed2 > MIN_AVATAR_SPEED_SQUARED) {
// update position ourselves
applyPositionDelta(deltaTime * velocity);
}
measureMotionDerivatives(deltaTime);
} // else physics will move avatar later
// update _moving flag based on speed
const float MOVING_SPEED_THRESHOLD = 0.01f;
_moving = speed > MOVING_SPEED_THRESHOLD;
_moving = speed2 > MOVING_SPEED_THRESHOLD_SQUARED;
} else {
// physics physics simulation updated elsewhere
float speed2 = glm::length2(velocity);
_moving = speed2 > MOVING_SPEED_THRESHOLD_SQUARED;
}
// capture the head rotation, in sensor space, when the user first indicates they would like to move/fly.
if (!_hoverReferenceCameraFacingIsCaptured && (fabs(_driveKeys[TRANSLATE_Z]) > 0.1f || fabs(_driveKeys[TRANSLATE_X]) > 0.1f)) {
@ -1800,10 +1780,10 @@ void MyAvatar::updateMotionBehaviorFromMenu() {
}
Menu* menu = Menu::getInstance();
if (menu->isOptionChecked(MenuOption::KeyboardMotorControl)) {
_motionBehaviors |= AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED;
if (menu->isOptionChecked(MenuOption::ActionMotorControl)) {
_motionBehaviors |= AVATAR_MOTION_ACTION_MOTOR_ENABLED;
} else {
_motionBehaviors &= ~AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED;
_motionBehaviors &= ~AVATAR_MOTION_ACTION_MOTOR_ENABLED;
}
if (menu->isOptionChecked(MenuOption::ScriptedMotorControl)) {
_motionBehaviors |= AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;

View file

@ -218,6 +218,7 @@ public:
MyCharacterController* getCharacterController() { return &_characterController; }
const MyCharacterController* getCharacterController() const { return &_characterController; }
void updateMotors();
void prepareForPhysicsSimulation();
void harvestResultsFromPhysicsSimulation(float deltaTime);
@ -350,6 +351,7 @@ private:
float _driveKeys[MAX_DRIVE_KEYS];
bool _wasPushing;
bool _isPushing;
bool _isBeingPushed;
bool _isBraking;
float _boomLength;
@ -358,9 +360,8 @@ private:
glm::vec3 _thrust; // impulse accumulator for outside sources
glm::vec3 _keyboardMotorVelocity; // target local-frame velocity of avatar (keyboard)
float _keyboardMotorTimescale; // timescale for avatar to achieve its target velocity
glm::vec3 _scriptedMotorVelocity; // target local-frame velocity of avatar (script)
glm::vec3 _actionMotorVelocity; // target local-frame velocity of avatar (default controller actions)
glm::vec3 _scriptedMotorVelocity; // target local-frame velocity of avatar (analog script)
float _scriptedMotorTimescale; // timescale for avatar to achieve its target velocity
int _scriptedMotorFrame;
quint32 _motionBehaviors;
@ -384,8 +385,7 @@ private:
// private methods
void updateOrientation(float deltaTime);
glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool isHovering);
glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity);
void updateActionMotor(float deltaTime);
void updatePosition(float deltaTime);
void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency);
void initHeadBones();

View file

@ -144,11 +144,11 @@ int main(int argc, const char* argv[]) {
// If we failed the OpenGLVersion check, log it.
if (override) {
auto& accountManager = AccountManager::getInstance();
if (accountManager.isLoggedIn()) {
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager->isLoggedIn()) {
UserActivityLogger::getInstance().insufficientGLVersion(glData);
} else {
QObject::connect(&AccountManager::getInstance(), &AccountManager::loginComplete, [glData](){
QObject::connect(accountManager.data(), &AccountManager::loginComplete, [glData](){
static bool loggedInsufficientGL = false;
if (!loggedInsufficientGL) {
UserActivityLogger::getInstance().insufficientGLVersion(glData);
@ -168,9 +168,9 @@ int main(int argc, const char* argv[]) {
QObject::connect(&server, &QLocalServer::newConnection, &app, &Application::handleLocalServerConnection, Qt::DirectConnection);
#ifdef HAS_BUGSPLAT
AccountManager& accountManager = AccountManager::getInstance();
crashReporter.mpSender.setDefaultUserName(qPrintable(accountManager.getAccountInfo().getUsername()));
QObject::connect(&accountManager, &AccountManager::usernameChanged, &app, [&crashReporter](const QString& newUsername) {
auto accountManager = DependencyManager::get<AccountManager>();
crashReporter.mpSender.setDefaultUserName(qPrintable(accountManager->getAccountInfo().getUsername()));
QObject::connect(accountManager.data(), &AccountManager::usernameChanged, &app, [&crashReporter](const QString& newUsername) {
crashReporter.mpSender.setDefaultUserName(qPrintable(newUsername));
});

View file

@ -19,14 +19,14 @@ AccountScriptingInterface* AccountScriptingInterface::getInstance() {
}
bool AccountScriptingInterface::isLoggedIn() {
AccountManager& accountManager = AccountManager::getInstance();
return accountManager.isLoggedIn();
auto accountManager = DependencyManager::get<AccountManager>();
return accountManager->isLoggedIn();
}
QString AccountScriptingInterface::getUsername() {
AccountManager& accountManager = AccountManager::getInstance();
if (accountManager.isLoggedIn()) {
return accountManager.getAccountInfo().getUsername();
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager->isLoggedIn()) {
return accountManager->getAccountInfo().getUsername();
} else {
return "Unknown user";
}

View file

@ -17,10 +17,10 @@
#include "GlobalServicesScriptingInterface.h"
GlobalServicesScriptingInterface::GlobalServicesScriptingInterface() {
AccountManager& accountManager = AccountManager::getInstance();
connect(&accountManager, &AccountManager::usernameChanged, this, &GlobalServicesScriptingInterface::myUsernameChanged);
connect(&accountManager, &AccountManager::logoutComplete, this, &GlobalServicesScriptingInterface::loggedOut);
connect(&accountManager, &AccountManager::loginComplete, this, &GlobalServicesScriptingInterface::connected);
auto accountManager = DependencyManager::get<AccountManager>();
connect(accountManager.data(), &AccountManager::usernameChanged, this, &GlobalServicesScriptingInterface::myUsernameChanged);
connect(accountManager.data(), &AccountManager::logoutComplete, this, &GlobalServicesScriptingInterface::loggedOut);
connect(accountManager.data(), &AccountManager::loginComplete, this, &GlobalServicesScriptingInterface::connected);
_downloading = false;
QTimer* checkDownloadTimer = new QTimer(this);
@ -34,10 +34,10 @@ GlobalServicesScriptingInterface::GlobalServicesScriptingInterface() {
}
GlobalServicesScriptingInterface::~GlobalServicesScriptingInterface() {
AccountManager& accountManager = AccountManager::getInstance();
disconnect(&accountManager, &AccountManager::usernameChanged, this, &GlobalServicesScriptingInterface::myUsernameChanged);
disconnect(&accountManager, &AccountManager::logoutComplete, this, &GlobalServicesScriptingInterface::loggedOut);
disconnect(&accountManager, &AccountManager::loginComplete, this, &GlobalServicesScriptingInterface::connected);
auto accountManager = DependencyManager::get<AccountManager>();
disconnect(accountManager.data(), &AccountManager::usernameChanged, this, &GlobalServicesScriptingInterface::myUsernameChanged);
disconnect(accountManager.data(), &AccountManager::logoutComplete, this, &GlobalServicesScriptingInterface::loggedOut);
disconnect(accountManager.data(), &AccountManager::loginComplete, this, &GlobalServicesScriptingInterface::connected);
}
GlobalServicesScriptingInterface* GlobalServicesScriptingInterface::getInstance() {
@ -46,7 +46,7 @@ GlobalServicesScriptingInterface* GlobalServicesScriptingInterface::getInstance(
}
const QString& GlobalServicesScriptingInterface::getUsername() const {
return AccountManager::getInstance().getAccountInfo().getUsername();
return DependencyManager::get<AccountManager>()->getAccountInfo().getUsername();
}
void GlobalServicesScriptingInterface::loggedOut() {

View file

@ -23,7 +23,6 @@ AddressBarDialog::AddressBarDialog(QQuickItem* parent) : OffscreenQmlDialog(pare
auto addressManager = DependencyManager::get<AddressManager>();
connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage);
connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage);
connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &AddressBarDialog::hide);
connect(addressManager.data(), &AddressManager::goBackPossible, this, [this] (bool isPossible) {
if (isPossible != _backEnabled) {
_backEnabled = isPossible;
@ -40,10 +39,6 @@ AddressBarDialog::AddressBarDialog(QQuickItem* parent) : OffscreenQmlDialog(pare
_forwardEnabled = !(DependencyManager::get<AddressManager>()->getForwardStack().isEmpty());
}
void AddressBarDialog::hide() {
((QQuickItem*)parent())->setEnabled(false);
}
void AddressBarDialog::loadAddress(const QString& address) {
qDebug() << "Called LoadAddress with address " << address;
if (!address.isEmpty()) {

View file

@ -33,7 +33,6 @@ signals:
protected:
void displayAddressOfflineMessage();
void displayAddressNotFoundMessage();
void hide();
Q_INVOKABLE void loadAddress(const QString& address);
Q_INVOKABLE void loadHome();

View file

@ -13,12 +13,12 @@
#include <avatar/AvatarManager.h>
#include <GLMHelpers.h>
#include <gpu/GLBackendShared.h>
#include <FramebufferCache.h>
#include <GLMHelpers.h>
#include <OffscreenUi.h>
#include <CursorManager.h>
#include <PerfStat.h>
#include <gl/Config.h>
#include "AudioClient.h"
#include "audio/AudioScope.h"
@ -55,7 +55,6 @@ ApplicationOverlay::~ApplicationOverlay() {
// Renders the overlays either to a texture or to the screen
void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
PROFILE_RANGE(__FUNCTION__);
CHECK_GL_ERROR();
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
buildFramebufferObject();
@ -89,8 +88,6 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
});
renderArgs->_batch = nullptr; // so future users of renderArgs don't try to use our batch
CHECK_GL_ERROR();
}
void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
@ -295,10 +292,6 @@ gpu::TexturePointer ApplicationOverlay::acquireOverlay() {
return gpu::TexturePointer();
}
auto result = _overlayFramebuffer->getRenderBuffer(0);
auto textureId = gpu::GLBackend::getTextureID(result, false);
if (!textureId) {
qDebug() << "Missing texture";
}
_overlayFramebuffer->setRenderBuffer(0, gpu::TexturePointer());
return result;
}

View file

@ -24,14 +24,15 @@ HIFI_QML_DEF(LoginDialog)
LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent),
_rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString())
{
connect(&AccountManager::getInstance(), &AccountManager::loginComplete,
auto accountManager = DependencyManager::get<AccountManager>();
connect(accountManager.data(), &AccountManager::loginComplete,
this, &LoginDialog::handleLoginCompleted);
connect(&AccountManager::getInstance(), &AccountManager::loginFailed,
connect(accountManager.data(), &AccountManager::loginFailed,
this, &LoginDialog::handleLoginFailed);
}
void LoginDialog::toggleAction() {
AccountManager& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
QAction* loginAction = Menu::getInstance()->getActionForOption(MenuOption::Login);
Q_CHECK_PTR(loginAction);
static QMetaObject::Connection connection;
@ -39,10 +40,10 @@ void LoginDialog::toggleAction() {
disconnect(connection);
}
if (accountManager.isLoggedIn()) {
if (accountManager->isLoggedIn()) {
// change the menu item to logout
loginAction->setText("Logout " + accountManager.getAccountInfo().getUsername());
connection = connect(loginAction, &QAction::triggered, &accountManager, &AccountManager::logout);
loginAction->setText("Logout " + accountManager->getAccountInfo().getUsername());
connection = connect(loginAction, &QAction::triggered, accountManager.data(), &AccountManager::logout);
} else {
// change the menu item to login
loginAction->setText("Login");
@ -78,7 +79,7 @@ QString LoginDialog::rootUrl() const {
void LoginDialog::login(const QString& username, const QString& password) {
qDebug() << "Attempting to login " << username;
setStatusText("Logging in...");
AccountManager::getInstance().requestAccessToken(username, password);
DependencyManager::get<AccountManager>()->requestAccessToken(username, password);
}
void LoginDialog::openUrl(const QString& url) {

View file

@ -433,13 +433,13 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser
}
const JurisdictionMap& map = serverJurisdictions[nodeUUID];
unsigned char* rootCode = map.getRootOctalCode();
auto rootCode = map.getRootOctalCode();
if (rootCode) {
QString rootCodeHex = octalCodeToHexString(rootCode);
QString rootCodeHex = octalCodeToHexString(rootCode.get());
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
voxelDetailsForCode(rootCode.get(), rootDetails);
AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
serverDetails << " jurisdiction: "
<< qPrintable(rootCodeHex)

View file

@ -92,7 +92,7 @@ QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary) {
QUrl currentURL = DependencyManager::get<AddressManager>()->currentAddress();
shot.setText(URL, currentURL.toString());
QString username = AccountManager::getInstance().getAccountInfo().getUsername();
QString username = DependencyManager::get<AccountManager>()->getAccountInfo().getUsername();
// normalize username, replace all non alphanumeric with '-'
username.replace(QRegExp("[^A-Za-z0-9_]"), "-");
@ -144,14 +144,15 @@ const QString SUCCESS_LABEL_TEMPLATE = "Success!!! Go check out your image ...<b
QString SnapshotUploader::uploadSnapshot(const QUrl& fileUrl) {
if (AccountManager::getInstance().getAccountInfo().getDiscourseApiKey().isEmpty()) {
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager->getAccountInfo().getDiscourseApiKey().isEmpty()) {
OffscreenUi::warning(nullptr, "", "Your Discourse API key is missing, you cannot share snapshots. Please try to relog.");
return QString();
}
QHttpPart apiKeyPart;
apiKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"api_key\""));
apiKeyPart.setBody(AccountManager::getInstance().getAccountInfo().getDiscourseApiKey().toLatin1());
apiKeyPart.setBody(accountManager->getAccountInfo().getDiscourseApiKey().toLatin1());
QString filename = fileUrl.toLocalFile();
qDebug() << filename;
@ -206,7 +207,7 @@ QString SnapshotUploader::sendForumPost(const QString& snapshotPath, const QStri
QUrl forumUrl(FORUM_POST_URL);
QUrlQuery query;
query.addQueryItem("api_key", AccountManager::getInstance().getAccountInfo().getDiscourseApiKey());
query.addQueryItem("api_key", DependencyManager::get<AccountManager>()->getAccountInfo().getDiscourseApiKey());
query.addQueryItem("topic_id", FORUM_REPLY_TO_TOPIC);
query.addQueryItem("raw", FORUM_POST_TEMPLATE.arg(snapshotPath, notes));
forumUrl.setQuery(query);

View file

@ -20,14 +20,12 @@ Overlay::Overlay() :
_renderItemID(render::Item::INVALID_ITEM_ID),
_isLoaded(true),
_alpha(DEFAULT_ALPHA),
_glowLevel(0.0f),
_pulse(0.0f),
_pulseMax(0.0f),
_pulseMin(0.0f),
_pulsePeriod(1.0f),
_pulseDirection(1.0f),
_lastPulseUpdate(usecTimestampNow()),
_glowLevelPulse(0.0f),
_alphaPulse(0.0f),
_colorPulse(0.0f),
_color(DEFAULT_OVERLAY_COLOR),
@ -40,14 +38,12 @@ Overlay::Overlay(const Overlay* overlay) :
_renderItemID(render::Item::INVALID_ITEM_ID),
_isLoaded(overlay->_isLoaded),
_alpha(overlay->_alpha),
_glowLevel(overlay->_glowLevel),
_pulse(overlay->_pulse),
_pulseMax(overlay->_pulseMax),
_pulseMin(overlay->_pulseMin),
_pulsePeriod(overlay->_pulsePeriod),
_pulseDirection(overlay->_pulseDirection),
_lastPulseUpdate(usecTimestampNow()),
_glowLevelPulse(overlay->_glowLevelPulse),
_alphaPulse(overlay->_alphaPulse),
_colorPulse(overlay->_colorPulse),
_color(overlay->_color),
@ -69,10 +65,6 @@ void Overlay::setProperties(const QVariantMap& properties) {
if (properties["alpha"].isValid()) {
setAlpha(properties["alpha"].toFloat());
}
if (properties["glowLevel"].isValid()) {
setGlowLevel(properties["glowLevel"].toFloat());
}
if (properties["pulseMax"].isValid()) {
setPulseMax(properties["pulseMax"].toFloat());
@ -86,10 +78,6 @@ void Overlay::setProperties(const QVariantMap& properties) {
setPulsePeriod(properties["pulsePeriod"].toFloat());
}
if (properties["glowLevelPulse"].isValid()) {
setGlowLevelPulse(properties["glowLevelPulse"].toFloat());
}
if (properties["alphaPulse"].isValid()) {
setAlphaPulse(properties["alphaPulse"].toFloat());
}
@ -118,9 +106,6 @@ QVariant Overlay::getProperty(const QString& property) {
if (property == "alpha") {
return _alpha;
}
if (property == "glowLevel") {
return _glowLevel;
}
if (property == "pulseMax") {
return _pulseMax;
}
@ -130,9 +115,6 @@ QVariant Overlay::getProperty(const QString& property) {
if (property == "pulsePeriod") {
return _pulsePeriod;
}
if (property == "glowLevelPulse") {
return _glowLevelPulse;
}
if (property == "alphaPulse") {
return _alphaPulse;
}
@ -176,16 +158,8 @@ float Overlay::getAlpha() {
return (_alphaPulse >= 0.0f) ? _alpha * pulseLevel : _alpha * (1.0f - pulseLevel);
}
float Overlay::getGlowLevel() {
if (_glowLevelPulse == 0.0f) {
return _glowLevel;
}
float pulseLevel = updatePulse();
return (_glowLevelPulse >= 0.0f) ? _glowLevel * pulseLevel : _glowLevel * (1.0f - pulseLevel);
}
// glow level travels from min to max, then max to min in one period.
// pulse travels from min to max, then max to min in one period.
float Overlay::updatePulse() {
if (_pulsePeriod <= 0.0f) {
return _pulse;
@ -196,25 +170,25 @@ float Overlay::updatePulse() {
float elapsedPeriods = elapsedSeconds / _pulsePeriod;
// we can safely remove any "full" periods, since those just rotate us back
// to our final glow level
// to our final pulse level
elapsedPeriods = fmod(elapsedPeriods, 1.0f);
_lastPulseUpdate = now;
float glowDistance = (_pulseMax - _pulseMin);
float glowDistancePerPeriod = glowDistance * 2.0f;
float pulseDistance = (_pulseMax - _pulseMin);
float pulseDistancePerPeriod = pulseDistance * 2.0f;
float glowDelta = _pulseDirection * glowDistancePerPeriod * elapsedPeriods;
float newGlow = _pulse + glowDelta;
float pulseDelta = _pulseDirection * pulseDistancePerPeriod * elapsedPeriods;
float newPulse = _pulse + pulseDelta;
float limit = (_pulseDirection > 0.0f) ? _pulseMax : _pulseMin;
float passedLimit = (_pulseDirection > 0.0f) ? (newGlow >= limit) : (newGlow <= limit);
float passedLimit = (_pulseDirection > 0.0f) ? (newPulse >= limit) : (newPulse <= limit);
if (passedLimit) {
float glowDeltaToLimit = newGlow - limit;
float glowDeltaFromLimitBack = glowDelta - glowDeltaToLimit;
glowDelta = -glowDeltaFromLimitBack;
float pulseDeltaToLimit = newPulse - limit;
float pulseDeltaFromLimitBack = pulseDelta - pulseDeltaToLimit;
pulseDelta = -pulseDeltaFromLimitBack;
_pulseDirection *= -1.0f;
}
_pulse += glowDelta;
_pulse += pulseDelta;
return _pulse;
}

View file

@ -49,7 +49,6 @@ public:
bool getVisible() const { return _visible; }
xColor getColor();
float getAlpha();
float getGlowLevel();
Anchor getAnchor() const { return _anchor; }
float getPulseMax() const { return _pulseMax; }
@ -57,7 +56,6 @@ public:
float getPulsePeriod() const { return _pulsePeriod; }
float getPulseDirection() const { return _pulseDirection; }
float getGlowLevelPulse() const { return _glowLevelPulse; }
float getColorPulse() const { return _colorPulse; }
float getAlphaPulse() const { return _alphaPulse; }
@ -65,7 +63,6 @@ public:
void setVisible(bool visible) { _visible = visible; }
void setColor(const xColor& color) { _color = color; }
void setAlpha(float alpha) { _alpha = alpha; }
void setGlowLevel(float value) { _glowLevel = value; }
void setAnchor(Anchor anchor) { _anchor = anchor; }
void setPulseMax(float value) { _pulseMax = value; }
@ -73,8 +70,6 @@ public:
void setPulsePeriod(float value) { _pulsePeriod = value; }
void setPulseDirection(float value) { _pulseDirection = value; }
void setGlowLevelPulse(float value) { _glowLevelPulse = value; }
void setColorPulse(float value) { _colorPulse = value; }
void setAlphaPulse(float value) { _alphaPulse = value; }
@ -92,7 +87,6 @@ protected:
bool _isLoaded;
float _alpha;
float _glowLevel;
float _pulse;
float _pulseMax;
@ -101,7 +95,6 @@ protected:
float _pulseDirection;
quint64 _lastPulseUpdate;
float _glowLevelPulse; // ratio of the pulse to the glow level
float _alphaPulse; // ratio of the pulse to the alpha
float _colorPulse; // ratio of the pulse to the color

View file

@ -36,15 +36,8 @@
#include <QtQuick/QQuickWindow>
Overlays::Overlays() : _nextOverlayID(1) {
connect(qApp, &Application::beforeAboutToQuit, [=] {
cleanupAllOverlays();
});
}
Overlays::~Overlays() {
}
Overlays::Overlays() :
_nextOverlayID(1) {}
void Overlays::cleanupAllOverlays() {
{

View file

@ -62,7 +62,6 @@ class Overlays : public QObject {
public:
Overlays();
~Overlays();
void init();
void update(float deltatime);
@ -73,6 +72,8 @@ public:
Overlay::Pointer getOverlay(unsigned int id) const;
OverlayPanel::Pointer getPanel(unsigned int id) const { return _panels[id]; }
void cleanupAllOverlays();
public slots:
/// adds an overlay with the specific properties
unsigned int addOverlay(const QString& type, const QVariant& properties);
@ -145,7 +146,6 @@ signals:
private:
void cleanupOverlaysToDelete();
void cleanupAllOverlays();
QMap<unsigned int, Overlay::Pointer> _overlaysHUD;
QMap<unsigned int, Overlay::Pointer> _overlaysWorld;

View file

@ -1,3 +1,3 @@
set(TARGET_NAME animation)
setup_hifi_library(Network Script)
link_hifi_libraries(shared gpu model fbx)
link_hifi_libraries(shared model fbx)

View file

@ -58,7 +58,6 @@ AvatarData::AvatarData() :
_headData(NULL),
_displayNameTargetAlpha(1.0f),
_displayNameAlpha(1.0f),
_billboard(),
_errorLogExpiry(0),
_owningAvatarMixer(),
_targetVelocity(0.0f),
@ -990,7 +989,7 @@ QByteArray AvatarData::identityByteArray() {
QByteArray identityData;
QDataStream identityStream(&identityData, QIODevice::Append);
QUrl emptyURL("");
const QUrl& urlToSend = (_skeletonModelURL == AvatarData::defaultFullAvatarModelUrl()) ? emptyURL : _skeletonModelURL;
const QUrl& urlToSend = _skeletonModelURL.scheme() == "file" ? emptyURL : _skeletonModelURL;
QUrl unusedModelURL; // legacy faceModel support
@ -999,13 +998,6 @@ QByteArray AvatarData::identityByteArray() {
return identityData;
}
bool AvatarData::hasBillboardChangedAfterParsing(const QByteArray& data) {
if (data == _billboard) {
return false;
}
_billboard = data;
return true;
}
void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) {
const QUrl& expanded = skeletonModelURL.isEmpty() ? AvatarData::defaultFullAvatarModelUrl() : skeletonModelURL;
@ -1103,33 +1095,6 @@ void AvatarData::detachAll(const QString& modelURL, const QString& jointName) {
setAttachmentData(attachmentData);
}
void AvatarData::setBillboard(const QByteArray& billboard) {
_billboard = billboard;
qCDebug(avatars) << "Changing billboard for avatar.";
}
void AvatarData::setBillboardFromURL(const QString &billboardURL) {
_billboardURL = billboardURL;
qCDebug(avatars) << "Changing billboard for avatar to PNG at" << qPrintable(billboardURL);
QNetworkRequest billboardRequest;
billboardRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
billboardRequest.setUrl(QUrl(billboardURL));
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* networkReply = networkAccessManager.get(billboardRequest);
connect(networkReply, SIGNAL(finished()), this, SLOT(setBillboardFromNetworkReply()));
}
void AvatarData::setBillboardFromNetworkReply() {
QNetworkReply* networkReply = static_cast<QNetworkReply*>(sender());
setBillboard(networkReply->readAll());
networkReply->deleteLater();
}
void AvatarData::setJointMappingsFromNetworkReply() {
QNetworkReply* networkReply = static_cast<QNetworkReply*>(sender());
@ -1204,21 +1169,6 @@ void AvatarData::sendIdentityPacket() {
});
}
void AvatarData::sendBillboardPacket() {
if (!_billboard.isEmpty()) {
auto nodeList = DependencyManager::get<NodeList>();
// This makes sure the billboard won't be too large to send.
// Once more protocol changes are done and we can send blocks of data we can support sending > MTU sized billboards.
if (_billboard.size() <= NLPacket::maxPayloadSize(PacketType::AvatarBillboard)) {
auto billboardPacket = NLPacket::create(PacketType::AvatarBillboard, _billboard.size());
billboardPacket->write(_billboard);
nodeList->broadcastToNodes(std::move(billboardPacket), NodeSet() << NodeType::AvatarMixer);
}
}
}
void AvatarData::updateJointMappings() {
_jointIndices.clear();
_jointNames.clear();

View file

@ -65,11 +65,11 @@ using AvatarHash = QHash<QUuid, AvatarSharedPointer>;
using AvatarDataSequenceNumber = uint16_t;
// avatar motion behaviors
const quint32 AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED = 1U << 0;
const quint32 AVATAR_MOTION_ACTION_MOTOR_ENABLED = 1U << 0;
const quint32 AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED = 1U << 1;
const quint32 AVATAR_MOTION_DEFAULTS =
AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED |
AVATAR_MOTION_ACTION_MOTOR_ENABLED |
AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
// these bits will be expanded as features are exposed
@ -107,7 +107,6 @@ static const float MIN_AVATAR_SCALE = .005f;
const float MAX_AUDIO_LOUDNESS = 1000.0f; // close enough for mouth animation
const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000;
const int AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS = 5000;
// See also static AvatarData::defaultFullAvatarModelUrl().
const QString DEFAULT_FULL_AVATAR_MODEL_NAME = QString("Default");
@ -160,7 +159,6 @@ class AvatarData : public QObject, public SpatiallyNestable {
Q_PROPERTY(QString displayName READ getDisplayName WRITE setDisplayName)
Q_PROPERTY(QString skeletonModelURL READ getSkeletonModelURLFromScript WRITE setSkeletonModelURLFromScript)
Q_PROPERTY(QVector<AttachmentData> attachmentData READ getAttachmentData WRITE setAttachmentData)
Q_PROPERTY(QString billboardURL READ getBillboardURL WRITE setBillboardFromURL)
Q_PROPERTY(QStringList jointNames READ getJointNames)
@ -285,8 +283,6 @@ public:
bool hasIdentityChangedAfterParsing(const QByteArray& data);
QByteArray identityByteArray();
bool hasBillboardChangedAfterParsing(const QByteArray& data);
const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; }
const QString& getDisplayName() const { return _displayName; }
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
@ -304,12 +300,6 @@ public:
Q_INVOKABLE void detachOne(const QString& modelURL, const QString& jointName = QString());
Q_INVOKABLE void detachAll(const QString& modelURL, const QString& jointName = QString());
virtual void setBillboard(const QByteArray& billboard);
const QByteArray& getBillboard() const { return _billboard; }
void setBillboardFromURL(const QString& billboardURL);
const QString& getBillboardURL() { return _billboardURL; }
QString getSkeletonModelURLFromScript() const { return _skeletonModelURL.toString(); }
void setSkeletonModelURLFromScript(const QString& skeletonModelString) { setSkeletonModelURL(QUrl(skeletonModelString)); }
@ -336,9 +326,7 @@ public:
public slots:
void sendAvatarDataPacket();
void sendIdentityPacket();
void sendBillboardPacket();
void setBillboardFromNetworkReply();
void setJointMappingsFromNetworkReply();
void setSessionUUID(const QUuid& sessionUUID) { setID(sessionUUID); }
@ -377,9 +365,6 @@ protected:
float _displayNameTargetAlpha;
float _displayNameAlpha;
QByteArray _billboard;
QString _billboardURL;
QHash<QString, int> _jointIndices; ///< 1-based, since zero is returned for missing keys
QStringList _jointNames; ///< in order of depth-first traversal

View file

@ -136,17 +136,6 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer<ReceivedMessage>
}
}
void AvatarHashMap::processAvatarBillboardPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
auto avatar = newOrExistingAvatar(sessionUUID, sendingNode);
QByteArray billboard = message->read(message->getBytesLeftToRead());
if (avatar->getBillboard() != billboard) {
avatar->setBillboard(billboard);
}
}
void AvatarHashMap::processKillAvatar(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
// read the node id
QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));

View file

@ -53,7 +53,6 @@ private slots:
void processAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
void processAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
void processAvatarBillboardPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
void processKillAvatar(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
protected:

View file

@ -1,6 +1,6 @@
set(TARGET_NAME display-plugins)
setup_hifi_library(OpenGL)
link_hifi_libraries(shared plugins gl ui)
link_hifi_libraries(shared plugins gl gpu-gl ui)
target_opengl()

View file

@ -17,7 +17,7 @@
#include <QtGui/QImage>
#include <gl/QOpenGLContextWrapper.h>
#include <gpu/Texture.h>
#include <gl/GLWidget.h>
#include <NumericalConstants.h>
#include <DependencyManager.h>
@ -26,7 +26,6 @@
#include <gl/Config.h>
#include <gl/GLEscrow.h>
#include <GLMHelpers.h>
#include <gpu/GLBackend.h>
#include <CursorManager.h>
#include "CompositorHelper.h"
@ -629,14 +628,15 @@ uint32_t OpenGLDisplayPlugin::getSceneTextureId() const {
if (!_currentSceneTexture) {
return 0;
}
return gpu::GLBackend::getTextureID(_currentSceneTexture, false);
return _currentSceneTexture->getHardwareId();
}
uint32_t OpenGLDisplayPlugin::getOverlayTextureId() const {
if (!_currentOverlayTexture) {
return 0;
}
return gpu::GLBackend::getTextureID(_currentOverlayTexture, false);
return _currentOverlayTexture->getHardwareId();
}
void OpenGLDisplayPlugin::eyeViewport(Eye eye) const {

View file

@ -16,7 +16,6 @@
#include <GLMHelpers.h>
#include <plugins/PluginContainer.h>
#include <gpu/GLBackend.h>
#include <CursorManager.h>
#include <gl/GLWidget.h>
#include <shared/NsightHelpers.h>

View file

@ -13,7 +13,6 @@
#include <QtWidgets/QApplication>
#include <QtWidgets/QDesktopWidget>
#include <gpu/GLBackend.h>
#include <ViewFrustum.h>
#include <MatrixStack.h>
#include <plugins/PluginContainer.h>

View file

@ -1,7 +1,7 @@
set(TARGET_NAME entities-renderer)
AUTOSCRIBE_SHADER_LIB(gpu model render render-utils)
setup_hifi_library(Widgets Network Script)
link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils gl)
link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils)
target_bullet()

View file

@ -13,6 +13,7 @@
#include <QEventLoop>
#include <QScriptSyntaxCheckResult>
#include <QThreadPool>
#include <ColorUtils.h>
#include <AbstractScriptingServicesInterface.h>
@ -77,9 +78,30 @@ EntityTreeRenderer::~EntityTreeRenderer() {
int EntityTreeRenderer::_entitiesScriptEngineCount = 0;
void EntityTreeRenderer::setupEntitiesScriptEngine() {
QSharedPointer<ScriptEngine> oldEngine = _entitiesScriptEngine; // save the old engine through this function, so the EntityScriptingInterface doesn't have problems with it.
_entitiesScriptEngine = QSharedPointer<ScriptEngine>(new ScriptEngine(NO_SCRIPT, QString("Entities %1").arg(++_entitiesScriptEngineCount)), &QObject::deleteLater);
void entitiesScriptEngineDeleter(ScriptEngine* engine) {
class WaitRunnable : public QRunnable {
public:
WaitRunnable(ScriptEngine* engine) : _engine(engine) {}
virtual void run() override {
_engine->waitTillDoneRunning();
_engine->deleteLater();
}
private:
ScriptEngine* _engine;
};
// Wait for the scripting thread from the thread pool to avoid hanging the main thread
QThreadPool::globalInstance()->start(new WaitRunnable(engine));
}
void EntityTreeRenderer::resetEntitiesScriptEngine() {
// Keep a ref to oldEngine until newEngine is ready so EntityScriptingInterface has something to use
auto oldEngine = _entitiesScriptEngine;
auto newEngine = new ScriptEngine(NO_SCRIPT, QString("Entities %1").arg(++_entitiesScriptEngineCount));
_entitiesScriptEngine = QSharedPointer<ScriptEngine>(newEngine, entitiesScriptEngineDeleter);
_scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine.data());
_entitiesScriptEngine->runInThread();
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(_entitiesScriptEngine.data());
@ -87,16 +109,16 @@ void EntityTreeRenderer::setupEntitiesScriptEngine() {
void EntityTreeRenderer::clear() {
leaveAllEntities();
if (_entitiesScriptEngine) {
// Unload and stop the engine here (instead of in its deleter) to
// avoid marshalling unload signals back to this thread
_entitiesScriptEngine->unloadAllEntityScripts();
_entitiesScriptEngine->stop();
}
if (_wantScripts && !_shuttingDown) {
// NOTE: you can't actually need to delete it here because when we call setupEntitiesScriptEngine it will
// assign a new instance to our shared pointer, which will deref the old instance and ultimately call
// the custom deleter which calls deleteLater
setupEntitiesScriptEngine();
resetEntitiesScriptEngine();
}
auto scene = _viewState->getMain3DScene();
@ -125,7 +147,7 @@ void EntityTreeRenderer::init() {
entityTree->setFBXService(this);
if (_wantScripts) {
setupEntitiesScriptEngine();
resetEntitiesScriptEngine();
}
forceRecheckEntities(); // setup our state to force checking our inside/outsideness of entities

View file

@ -126,7 +126,7 @@ protected:
}
private:
void setupEntitiesScriptEngine();
void resetEntitiesScriptEngine();
void addEntityToScene(EntityItemPointer entity);
bool findBestZoneAndMaybeContainingEntities(const glm::vec3& avatarPosition, QVector<EntityItemID>* entitiesContainingAvatar);

View file

@ -162,6 +162,19 @@ void RenderableModelEntityItem::remapTextures() {
}
}
void RenderableModelEntityItem::doInitialModelSimulation() {
_model->setScaleToFit(true, getDimensions());
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
_model->setRotation(getRotation());
_model->setTranslation(getPosition());
{
PerformanceTimer perfTimer("_model->simulate");
_model->simulate(0.0f);
}
_needsInitialSimulation = false;
}
// TODO: we need a solution for changes to the postion/rotation/etc of a model...
// this current code path only addresses that in this setup case... not the changing/moving case
bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) {
@ -172,22 +185,12 @@ bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) {
getModel(renderer);
}
if (renderArgs && _model && _needsInitialSimulation && _model->isActive() && _model->isLoaded()) {
_model->setScaleToFit(true, getDimensions());
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
_model->setRotation(getRotation());
_model->setTranslation(getPosition());
// make sure to simulate so everything gets set up correctly for rendering
{
PerformanceTimer perfTimer("_model->simulate");
_model->simulate(0.0f);
}
_needsInitialSimulation = false;
doInitialModelSimulation();
_model->renderSetup(renderArgs);
}
bool ready = !_needsInitialSimulation && _model && _model->readyToAddToScene(renderArgs);
return ready;
return ready;
}
class RenderableModelEntityItemMeta {
@ -348,18 +351,7 @@ void RenderableModelEntityItem::updateModelBounds() {
_model->getRotation() != getRotation() ||
_model->getRegistrationPoint() != getRegistrationPoint())
&& _model->isActive() && _dimensionsInitialized) {
_model->setScaleToFit(true, dimensions);
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
_model->setRotation(getRotation());
_model->setTranslation(getPosition());
// make sure to simulate so everything gets set up correctly for rendering
{
PerformanceTimer perfTimer("_model->simulate");
_model->simulate(0.0f);
}
_needsInitialSimulation = false;
doInitialModelSimulation();
_needsJointSimulation = false;
}
}
@ -592,8 +584,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() {
if (_needsInitialSimulation) {
// the _model's offset will be wrong until _needsInitialSimulation is false
PerformanceTimer perfTimer("_model->simulate");
_model->simulate(0.0f);
_needsInitialSimulation = false;
doInitialModelSimulation();
}
return true;
@ -807,6 +798,29 @@ void RenderableModelEntityItem::locationChanged(bool tellPhysics) {
if (_model && _model->isActive()) {
_model->setRotation(getRotation());
_model->setTranslation(getPosition());
void* key = (void*)this;
std::weak_ptr<RenderableModelEntityItem> weakSelf =
std::static_pointer_cast<RenderableModelEntityItem>(getThisPointer());
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf]() {
auto self = weakSelf.lock();
if (!self) {
return;
}
render::ItemID myMetaItem = self->getMetaRenderItem();
if (myMetaItem == render::Item::INVALID_ITEM_ID) {
return;
}
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
render::PendingChanges pendingChanges;
pendingChanges.updateItem(myMetaItem);
scene->enqueuePendingChanges(pendingChanges);
});
}
}

View file

@ -38,6 +38,8 @@ public:
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
void doInitialModelSimulation();
virtual bool readyToAddToScene(RenderArgs* renderArgs = nullptr);
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
@ -87,6 +89,8 @@ public:
bool hasRenderAnimation() const { return !_renderAnimationProperties.getURL().isEmpty(); }
const QString& getRenderAnimationURL() const { return _renderAnimationProperties.getURL(); }
render::ItemID getMetaRenderItem() { return _myMetaItem; }
private:
QVariantMap parseTexturesToMap(QString textures);
void remapTextures();

View file

@ -267,7 +267,7 @@ void RenderableParticleEffectEntityItem::updateRenderItem() {
if (numBytes == 0) {
return;
}
memcpy(particleBuffer->editData(), particlePrimitives->data(), numBytes);
particleBuffer->setData(numBytes, (const gpu::Byte*)particlePrimitives->data());
// Update transform and bounds
payload.setModelTransform(transform);

View file

@ -1,6 +1,6 @@
set(TARGET_NAME entities)
setup_hifi_library(Network Script)
link_hifi_libraries(avatars shared audio octree gpu model fbx networking animation)
link_hifi_libraries(avatars shared audio octree model fbx networking animation)
target_bullet()

View file

@ -36,9 +36,6 @@ EntityItemProperties BoxEntityItem::getProperties(EntityPropertyFlags desiredPro
properties._color = getXColor();
properties._colorChanged = false;
properties._glowLevel = getGlowLevel();
properties._glowLevelChanged = false;
return properties;
}

View file

@ -46,7 +46,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
_lastEditedFromRemoteInRemoteTime(0),
_created(UNKNOWN_CREATED_TIME),
_changedOnServer(0),
_glowLevel(ENTITY_ITEM_DEFAULT_GLOW_LEVEL),
_localRenderAlpha(ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA),
_density(ENTITY_ITEM_DEFAULT_DENSITY),
_volumeMultiplier(1.0f),
@ -1116,7 +1115,6 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper
COPY_ENTITY_PROPERTY_TO_PROPERTIES(registrationPoint, getRegistrationPoint);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(angularVelocity, getLocalAngularVelocity);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(angularDamping, getAngularDamping);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(glowLevel, getGlowLevel);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(localRenderAlpha, getLocalRenderAlpha);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(visible, getVisible);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionless, getCollisionless);
@ -1211,7 +1209,6 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(scriptTimestamp, setScriptTimestamp);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionSoundURL, setCollisionSoundURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(localRenderAlpha, setLocalRenderAlpha);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked);

View file

@ -186,9 +186,6 @@ public:
inline const glm::vec3 getDimensions() const { return getScale(); }
virtual void setDimensions(const glm::vec3& value);
float getGlowLevel() const { return _glowLevel; }
void setGlowLevel(float glowLevel) { _glowLevel = glowLevel; }
float getLocalRenderAlpha() const { return _localRenderAlpha; }
void setLocalRenderAlpha(float localRenderAlpha) { _localRenderAlpha = localRenderAlpha; }
@ -460,7 +457,6 @@ protected:
mutable bool _recalcMinAACube = true;
mutable bool _recalcMaxAACube = true;
float _glowLevel;
float _localRenderAlpha;
float _density = ENTITY_ITEM_DEFAULT_DENSITY; // kg/m^3
// NOTE: _volumeMultiplier is used to allow some mass properties code exist in the EntityItem base class

View file

@ -38,10 +38,8 @@ _idSet(false),
_lastEdited(0),
_type(EntityTypes::Unknown),
_glowLevel(0.0f),
_localRenderAlpha(1.0f),
_glowLevelChanged(false),
_localRenderAlphaChanged(false),
_defaultSettings(true),
@ -542,7 +540,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation);
// FIXME - I don't think these properties are supported any more
//COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel);
//COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha);
return properties;
@ -582,7 +579,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitterShouldTrail , bool, setEmitterShouldTrail);
COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(glowLevel, float, setGlowLevel);
COPY_PROPERTY_FROM_QSCRIPTVALUE(localRenderAlpha, float, setLocalRenderAlpha);
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionless, bool, setCollisionless);
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(ignoreForCollisions, bool, setCollisionless, getCollisionless); // legacy support
@ -1468,7 +1464,6 @@ void EntityItemProperties::markAllChanged() {
_alphaChanged = true;
_modelURLChanged = true;
_compoundShapeURLChanged = true;
_glowLevelChanged = true;
_localRenderAlphaChanged = true;
_isSpotlightChanged = true;
_collisionlessChanged = true;

View file

@ -218,9 +218,7 @@ public:
bool containsPositionChange() const { return _positionChanged; }
bool containsDimensionsChange() const { return _dimensionsChanged; }
float getGlowLevel() const { return _glowLevel; }
float getLocalRenderAlpha() const { return _localRenderAlpha; }
void setGlowLevel(float value) { _glowLevel = value; _glowLevelChanged = true; }
void setLocalRenderAlpha(float value) { _localRenderAlpha = value; _localRenderAlphaChanged = true; }
static bool encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties,
@ -231,7 +229,6 @@ public:
static bool decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
EntityItemID& entityID, EntityItemProperties& properties);
bool glowLevelChanged() const { return _glowLevelChanged; }
bool localRenderAlphaChanged() const { return _localRenderAlphaChanged; }
void clearID() { _id = UNKNOWN_ENTITY_ID; _idSet = false; }
@ -287,9 +284,7 @@ private:
EntityTypes::EntityType _type;
void setType(const QString& typeName) { _type = EntityTypes::getEntityTypeFromName(typeName); }
float _glowLevel;
float _localRenderAlpha;
bool _glowLevelChanged;
bool _localRenderAlphaChanged;
bool _defaultSettings;
bool _dimensionsInitialized = true; // Only false if creating an entity localy with no dimensions properties

View file

@ -31,7 +31,6 @@ const QUuid ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QUuid();
const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f;
const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f;
const float ENTITY_ITEM_DEFAULT_GLOW_LEVEL = 0.0f;
const bool ENTITY_ITEM_DEFAULT_VISIBLE = true;
const QString ENTITY_ITEM_DEFAULT_SCRIPT = QString("");

View file

@ -1376,6 +1376,10 @@ bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extra
item->globalizeProperties(properties, "Cannot find %3 parent of %2 %1", args->root);
}
}
// set creation time to "now" for imported entities
properties.setCreated(usecTimestampNow());
properties.markAllChanged(); // so the entire property set is considered new, since we're making a new entity
// queue the packet to send to the server

View file

@ -53,10 +53,6 @@ EntityItemProperties LineEntityItem::getProperties(EntityPropertyFlags desiredPr
COPY_ENTITY_PROPERTY_TO_PROPERTIES(linePoints, getLinePoints);
properties._glowLevel = getGlowLevel();
properties._glowLevelChanged = false;
return properties;
}

View file

@ -58,7 +58,6 @@ EntityItemProperties ModelEntityItem::getProperties(EntityPropertyFlags desiredP
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(glowLevel, getGlowLevel);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointRotationsSet, getJointRotationsSet);

View file

@ -304,7 +304,6 @@ EntityItemProperties ParticleEffectEntityItem::getProperties(EntityPropertyFlags
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(glowLevel, getGlowLevel);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType); // FIXME - this doesn't appear to get used
COPY_ENTITY_PROPERTY_TO_PROPERTIES(maxParticles, getMaxParticles);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifespan, getLifespan);
@ -343,7 +342,6 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, updateShapeType);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(maxParticles, setMaxParticles);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifespan, setLifespan);

View file

@ -58,9 +58,6 @@ EntityItemProperties PolyLineEntityItem::getProperties(EntityPropertyFlags desir
COPY_ENTITY_PROPERTY_TO_PROPERTIES(normals, getNormals);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(strokeWidths, getStrokeWidths);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures);
properties._glowLevel = getGlowLevel();
properties._glowLevelChanged = false;
return properties;
}

View file

@ -23,7 +23,6 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTreePointer tree,
_foundOld(false),
_foundNew(false),
_removeOld(false),
_dontMove(false), // assume we'll be moving
_changeTime(usecTimestampNow()),
_oldEntityCube(),
_newEntityCube(),
@ -43,32 +42,23 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTreePointer tree,
_oldEntityCube = _existingEntity->getQueryAACube();
_oldEntityBox = _oldEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds
// If our new properties don't have bounds details (no change to position, etc) or if this containing element would
// be the best fit for our new properties, then just do the new portion of the store pass, since the change path will
// be the same for both parts of the update
bool oldElementBestFit = _containingElement->bestFitBounds(newQueryAACube);
_newEntityCube = newQueryAACube;
_newEntityBox = _newEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds
// set oldElementBestFit true if the entity was in the correct element before this operator was run.
bool oldElementBestFit = _containingElement->bestFitBounds(_oldEntityBox);
// For some reason we've seen a case where the original containing element isn't a best fit for the old properties
// in this case we want to move it, even if the properties haven't changed.
if (!oldElementBestFit) {
_newEntityCube = _oldEntityCube;
_oldEntityBox = _existingEntity->getElement()->getAACube();
_removeOld = true; // our properties are going to move us, so remember this for later processing
if (_wantDebug) {
qCDebug(entities) << " **** UNUSUAL CASE **** no changes, but not best fit... consider it a move.... **";
}
} else {
_foundOld = true;
_newEntityCube = _oldEntityCube;
_dontMove = true;
if (_wantDebug) {
qCDebug(entities) << " **** TYPICAL NO MOVE CASE **** oldElementBestFit:" << oldElementBestFit;
qCDebug(entities) << " **** UNUSUAL CASE **** not best fit.... **";
}
}
_newEntityBox = _newEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds
if (_wantDebug) {
qCDebug(entities) << " _entityItemID:" << _entityItemID;
qCDebug(entities) << " _containingElementCube:" << _containingElementCube;

View file

@ -37,7 +37,6 @@ private:
bool _foundOld;
bool _foundNew;
bool _removeOld;
bool _dontMove;
quint64 _changeTime;
AACube _oldEntityCube;

View file

@ -1,3 +1,3 @@
set(TARGET_NAME fbx)
setup_hifi_library()
link_hifi_libraries(shared gpu model networking octree)
link_hifi_libraries(shared model networking)

View file

@ -1332,7 +1332,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
}
// NOTE: shapeVertices are in joint-frame
QVector<ShapeVertices> shapeVertices;
std::vector<ShapeVertices> shapeVertices;
shapeVertices.resize(geometry.joints.size());
// find our special joints
@ -1523,7 +1523,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
float clusterScale = extractUniformScale(fbxCluster.inverseBindMatrix);
glm::mat4 meshToJoint = glm::inverse(joint.bindTransform) * modelTransform;
ShapeVertices& points = shapeVertices[jointIndex];
ShapeVertices& points = shapeVertices.at(jointIndex);
float totalWeight = 0.0f;
for (int j = 0; j < cluster.indices.size(); j++) {
@ -1585,7 +1585,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
// transform cluster vertices to joint-frame and save for later
float clusterScale = extractUniformScale(firstFBXCluster.inverseBindMatrix);
glm::mat4 meshToJoint = glm::inverse(joint.bindTransform) * modelTransform;
ShapeVertices& points = shapeVertices[jointIndex];
ShapeVertices& points = shapeVertices.at(jointIndex);
foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
const glm::mat4 vertexTransform = meshToJoint * glm::translate(vertex);
points.push_back(extractTranslation(vertexTransform) * clusterScale);
@ -1626,7 +1626,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
FBXJoint& joint = geometry.joints[i];
// NOTE: points are in joint-frame
ShapeVertices& points = shapeVertices[i];
ShapeVertices& points = shapeVertices.at(i);
if (points.size() > 0) {
// compute average point
glm::vec3 avgPoint = glm::vec3(0.0f);

View file

@ -624,7 +624,6 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping,
return geometryPtr;
}
void fbxDebugDump(const FBXGeometry& fbxgeo) {
qCDebug(modelformat) << "---------------- fbxGeometry ----------------";
qCDebug(modelformat) << " hasSkeletonJoints =" << fbxgeo.hasSkeletonJoints;

View file

@ -12,47 +12,21 @@
#ifndef hifi_gpu_GPUConfig_h
#define hifi_gpu_GPUConfig_h
#define GL_GLEXT_PROTOTYPES 1
#define GPU_CORE 1
#define GPU_LEGACY 0
#define GPU_CORE_41 410
#define GPU_CORE_43 430
#define GPU_CORE_MINIMUM GPU_CORE_41
#if defined(__APPLE__)
#include <GL/glew.h>
#define GPU_FEATURE_PROFILE GPU_CORE
#define GPU_INPUT_PROFILE GPU_CORE_41
#if defined(__APPLE__)
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#elif defined(WIN32)
#include <GL/glew.h>
#endif
#if defined(WIN32)
#include <GL/wglew.h>
#define GPU_FEATURE_PROFILE GPU_CORE
#define GPU_INPUT_PROFILE GPU_CORE_43
#else
#include <GL/glew.h>
#define GPU_FEATURE_PROFILE GPU_CORE
#define GPU_INPUT_PROFILE GPU_CORE_43
#endif
#if (GPU_INPUT_PROFILE == GPU_CORE_43)
// Deactivate SSBO for now, we've run into some issues
// on GL 4.3 capable GPUs not behaving as expected
//#define GPU_SSBO_DRAW_CALL_INFO
#endif
#endif // hifi_gpu_GPUConfig_h

View file

@ -19,6 +19,8 @@
#include "GLWidget.h"
#include "GLHelpers.h"
#define MINIMUM_GL_VERSION 410
OpenGLVersionChecker::OpenGLVersionChecker(int& argc, char** argv) :
QApplication(argc, argv)
{
@ -58,8 +60,8 @@ QJsonObject OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]"));
int majorNumber = versionParts[0].toInt();
int minorNumber = versionParts[1].toInt();
int minimumMajorNumber = GPU_CORE_MINIMUM / 100;
int minimumMinorNumber = (GPU_CORE_MINIMUM - minimumMajorNumber * 100) / 10;
int minimumMajorNumber = MINIMUM_GL_VERSION / 100;
int minimumMinorNumber = (MINIMUM_GL_VERSION - minimumMajorNumber * 100) / 10;
valid = (majorNumber > minimumMajorNumber
|| (majorNumber == minimumMajorNumber && minorNumber >= minimumMinorNumber));

View file

@ -13,6 +13,17 @@
#include <QOpenGLContext>
uint32_t QOpenGLContextWrapper::currentContextVersion() {
QOpenGLContext* context = QOpenGLContext::currentContext();
if (!context) {
return 0;
}
auto format = context->format();
auto version = (format.majorVersion() << 8) + format.minorVersion();
return version;
}
QOpenGLContext* QOpenGLContextWrapper::currentContext() {
return QOpenGLContext::currentContext();
}

View file

@ -12,6 +12,8 @@
#ifndef hifi_QOpenGLContextWrapper_h
#define hifi_QOpenGLContextWrapper_h
#include <stdint.h>
class QOpenGLContext;
class QSurface;
class QSurfaceFormat;
@ -30,6 +32,7 @@ public:
void moveToThread(QThread* thread);
static QOpenGLContext* currentContext();
static uint32_t currentContextVersion();
QOpenGLContext* getContext() {
return _context;

View file

@ -0,0 +1,8 @@
set(TARGET_NAME gpu-gl)
AUTOSCRIBE_SHADER_LIB(gpu)
setup_hifi_library()
link_hifi_libraries(shared gl gpu)
GroupSources("src")
target_glew()
target_opengl()

View file

@ -0,0 +1,547 @@
//
// GLBackend.cpp
// libraries/gpu/src/gpu
//
// Created by Sam Gateau on 10/27/2014.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackend.h"
#include <mutex>
#include <queue>
#include <list>
#include <functional>
#include <glm/gtc/type_ptr.hpp>
#include "../gl41/GL41Backend.h"
#if defined(NSIGHT_FOUND)
#include "nvToolsExt.h"
#endif
#include <GPUIdent.h>
#include <gl/QOpenGLContextWrapper.h>
#include <QtCore/QProcessEnvironment>
#include "GLTexture.h"
#include "GLShader.h"
using namespace gpu;
using namespace gpu::gl;
static const QString DEBUG_FLAG("HIFI_ENABLE_OPENGL_45");
static bool enableOpenGL45 = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
Backend* GLBackend::createBackend() {
#if 0
// FIXME provide a mechanism to override the backend for testing
// Where the gpuContext is initialized and where the TRUE Backend is created and assigned
auto version = QOpenGLContextWrapper::currentContextVersion();
GLBackend* result;
if (enableOpenGL45 && version >= 0x0405) {
result = new gpu::gl45::GLBackend;
} else {
result = new gpu::gl41::GLBackend;
}
#else
GLBackend* result = new gpu::gl41::GL41Backend;
#endif
result->initInput();
result->initTransform();
gl::GLTexture::initTextureTransferHelper();
return result;
}
bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) {
return GLShader::makeProgram(shader, slotBindings);
}
GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
{
(&::gpu::gl::GLBackend::do_draw),
(&::gpu::gl::GLBackend::do_drawIndexed),
(&::gpu::gl::GLBackend::do_drawInstanced),
(&::gpu::gl::GLBackend::do_drawIndexedInstanced),
(&::gpu::gl::GLBackend::do_multiDrawIndirect),
(&::gpu::gl::GLBackend::do_multiDrawIndexedIndirect),
(&::gpu::gl::GLBackend::do_setInputFormat),
(&::gpu::gl::GLBackend::do_setInputBuffer),
(&::gpu::gl::GLBackend::do_setIndexBuffer),
(&::gpu::gl::GLBackend::do_setIndirectBuffer),
(&::gpu::gl::GLBackend::do_setModelTransform),
(&::gpu::gl::GLBackend::do_setViewTransform),
(&::gpu::gl::GLBackend::do_setProjectionTransform),
(&::gpu::gl::GLBackend::do_setViewportTransform),
(&::gpu::gl::GLBackend::do_setDepthRangeTransform),
(&::gpu::gl::GLBackend::do_setPipeline),
(&::gpu::gl::GLBackend::do_setStateBlendFactor),
(&::gpu::gl::GLBackend::do_setStateScissorRect),
(&::gpu::gl::GLBackend::do_setUniformBuffer),
(&::gpu::gl::GLBackend::do_setResourceTexture),
(&::gpu::gl::GLBackend::do_setFramebuffer),
(&::gpu::gl::GLBackend::do_clearFramebuffer),
(&::gpu::gl::GLBackend::do_blit),
(&::gpu::gl::GLBackend::do_generateTextureMips),
(&::gpu::gl::GLBackend::do_beginQuery),
(&::gpu::gl::GLBackend::do_endQuery),
(&::gpu::gl::GLBackend::do_getQuery),
(&::gpu::gl::GLBackend::do_resetStages),
(&::gpu::gl::GLBackend::do_runLambda),
(&::gpu::gl::GLBackend::do_startNamedCall),
(&::gpu::gl::GLBackend::do_stopNamedCall),
(&::gpu::gl::GLBackend::do_glActiveBindTexture),
(&::gpu::gl::GLBackend::do_glUniform1i),
(&::gpu::gl::GLBackend::do_glUniform1f),
(&::gpu::gl::GLBackend::do_glUniform2f),
(&::gpu::gl::GLBackend::do_glUniform3f),
(&::gpu::gl::GLBackend::do_glUniform4f),
(&::gpu::gl::GLBackend::do_glUniform3fv),
(&::gpu::gl::GLBackend::do_glUniform4fv),
(&::gpu::gl::GLBackend::do_glUniform4iv),
(&::gpu::gl::GLBackend::do_glUniformMatrix4fv),
(&::gpu::gl::GLBackend::do_glColor4f),
(&::gpu::gl::GLBackend::do_pushProfileRange),
(&::gpu::gl::GLBackend::do_popProfileRange),
};
extern std::function<uint32(const Texture& texture)> TEXTURE_ID_RESOLVER;
void GLBackend::init() {
static std::once_flag once;
std::call_once(once, [] {
TEXTURE_ID_RESOLVER = [](const Texture& texture)->uint32 {
auto object = Backend::getGPUObject<GLTexture>(texture);
if (!object) {
return 0;
}
if (object->getSyncState() != GLSyncState::Idle) {
return object->_downsampleSource._texture;
}
return object->_texture;
};
QString vendor{ (const char*)glGetString(GL_VENDOR) };
QString renderer{ (const char*)glGetString(GL_RENDERER) };
qCDebug(gpugllogging) << "GL Version: " << QString((const char*) glGetString(GL_VERSION));
qCDebug(gpugllogging) << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
qCDebug(gpugllogging) << "GL Vendor: " << vendor;
qCDebug(gpugllogging) << "GL Renderer: " << renderer;
GPUIdent* gpu = GPUIdent::getInstance(vendor, renderer);
// From here on, GPUIdent::getInstance()->getMumble() should efficiently give the same answers.
qCDebug(gpugllogging) << "GPU:";
qCDebug(gpugllogging) << "\tcard:" << gpu->getName();
qCDebug(gpugllogging) << "\tdriver:" << gpu->getDriver();
qCDebug(gpugllogging) << "\tdedicated memory:" << gpu->getMemory() << "MB";
glewExperimental = true;
GLenum err = glewInit();
glGetError(); // clear the potential error from glewExperimental
if (GLEW_OK != err) {
// glewInit failed, something is seriously wrong.
qCDebug(gpugllogging, "Error: %s\n", glewGetErrorString(err));
}
qCDebug(gpugllogging, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
#if defined(Q_OS_WIN)
if (wglewGetExtension("WGL_EXT_swap_control")) {
int swapInterval = wglGetSwapIntervalEXT();
qCDebug(gpugllogging, "V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF"));
}
#endif
#if defined(Q_OS_LINUX)
// TODO: Write the correct code for Linux...
/* if (wglewGetExtension("WGL_EXT_swap_control")) {
int swapInterval = wglGetSwapIntervalEXT();
qCDebug(gpugllogging, "V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF"));
}*/
#endif
});
}
GLBackend::GLBackend() {
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_uboAlignment);
}
GLBackend::~GLBackend() {
resetStages();
killInput();
killTransform();
}
void GLBackend::renderPassTransfer(Batch& batch) {
const size_t numCommands = batch.getCommands().size();
const Batch::Commands::value_type* command = batch.getCommands().data();
const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data();
_inRenderTransferPass = true;
{ // Sync all the buffers
PROFILE_RANGE("syncGPUBuffer");
for (auto& cached : batch._buffers._items) {
if (cached._data) {
syncGPUObject(*cached._data);
}
}
}
{ // Sync all the buffers
PROFILE_RANGE("syncCPUTransform");
_transform._cameras.clear();
_transform._cameraOffsets.clear();
for (_commandIndex = 0; _commandIndex < numCommands; ++_commandIndex) {
switch (*command) {
case Batch::COMMAND_draw:
case Batch::COMMAND_drawIndexed:
case Batch::COMMAND_drawInstanced:
case Batch::COMMAND_drawIndexedInstanced:
case Batch::COMMAND_multiDrawIndirect:
case Batch::COMMAND_multiDrawIndexedIndirect:
_transform.preUpdate(_commandIndex, _stereo);
break;
case Batch::COMMAND_setViewportTransform:
case Batch::COMMAND_setViewTransform:
case Batch::COMMAND_setProjectionTransform: {
CommandCall call = _commandCalls[(*command)];
(this->*(call))(batch, *offset);
break;
}
default:
break;
}
command++;
offset++;
}
}
{ // Sync the transform buffers
PROFILE_RANGE("syncGPUTransform");
transferTransformState(batch);
}
_inRenderTransferPass = false;
}
void GLBackend::renderPassDraw(Batch& batch) {
_currentDraw = -1;
_transform._camerasItr = _transform._cameraOffsets.begin();
const size_t numCommands = batch.getCommands().size();
const Batch::Commands::value_type* command = batch.getCommands().data();
const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data();
for (_commandIndex = 0; _commandIndex < numCommands; ++_commandIndex) {
switch (*command) {
// Ignore these commands on this pass, taken care of in the transfer pass
// Note we allow COMMAND_setViewportTransform to occur in both passes
// as it both updates the transform object (and thus the uniforms in the
// UBO) as well as executes the actual viewport call
case Batch::COMMAND_setModelTransform:
case Batch::COMMAND_setViewTransform:
case Batch::COMMAND_setProjectionTransform:
break;
case Batch::COMMAND_draw:
case Batch::COMMAND_drawIndexed:
case Batch::COMMAND_drawInstanced:
case Batch::COMMAND_drawIndexedInstanced:
case Batch::COMMAND_multiDrawIndirect:
case Batch::COMMAND_multiDrawIndexedIndirect: {
// updates for draw calls
++_currentDraw;
updateInput();
updateTransform(batch);
updatePipeline();
CommandCall call = _commandCalls[(*command)];
(this->*(call))(batch, *offset);
break;
}
default: {
CommandCall call = _commandCalls[(*command)];
(this->*(call))(batch, *offset);
break;
}
}
command++;
offset++;
}
}
void GLBackend::render(Batch& batch) {
// Finalize the batch by moving all the instanced rendering into the command buffer
batch.preExecute();
_stereo._skybox = batch.isSkyboxEnabled();
// Allow the batch to override the rendering stereo settings
// for things like full framebuffer copy operations (deferred lighting passes)
bool savedStereo = _stereo._enable;
if (!batch.isStereoEnabled()) {
_stereo._enable = false;
}
{
PROFILE_RANGE("Transfer");
renderPassTransfer(batch);
}
{
PROFILE_RANGE(_stereo._enable ? "Render Stereo" : "Render");
renderPassDraw(batch);
}
// Restore the saved stereo state for the next batch
_stereo._enable = savedStereo;
}
void GLBackend::syncCache() {
syncTransformStateCache();
syncPipelineStateCache();
syncInputStateCache();
syncOutputStateCache();
glEnable(GL_LINE_SMOOTH);
}
void GLBackend::setupStereoSide(int side) {
ivec4 vp = _transform._viewport;
vp.z /= 2;
glViewport(vp.x + side * vp.z, vp.y, vp.z, vp.w);
_transform.bindCurrentCamera(side);
}
void GLBackend::do_resetStages(Batch& batch, size_t paramOffset) {
resetStages();
}
void GLBackend::do_runLambda(Batch& batch, size_t paramOffset) {
std::function<void()> f = batch._lambdas.get(batch._params[paramOffset]._uint);
f();
}
void GLBackend::do_startNamedCall(Batch& batch, size_t paramOffset) {
batch._currentNamedCall = batch._names.get(batch._params[paramOffset]._uint);
_currentDraw = -1;
}
void GLBackend::do_stopNamedCall(Batch& batch, size_t paramOffset) {
batch._currentNamedCall.clear();
}
void GLBackend::resetStages() {
resetInputStage();
resetPipelineStage();
resetTransformStage();
resetUniformStage();
resetResourceStage();
resetOutputStage();
resetQueryStage();
(void) CHECK_GL_ERROR();
}
void GLBackend::do_pushProfileRange(Batch& batch, size_t paramOffset) {
#if defined(NSIGHT_FOUND)
auto name = batch._profileRanges.get(batch._params[paramOffset]._uint);
nvtxRangePush(name.c_str());
#endif
}
void GLBackend::do_popProfileRange(Batch& batch, size_t paramOffset) {
#if defined(NSIGHT_FOUND)
nvtxRangePop();
#endif
}
// 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
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
// As long as we don;t use several versions of shaders we can avoid this more complex code path
// #define GET_UNIFORM_LOCATION(shaderUniformLoc) _pipeline._programShader->getUniformLocation(shaderUniformLoc, isStereo());
#define GET_UNIFORM_LOCATION(shaderUniformLoc) shaderUniformLoc
void GLBackend::do_glActiveBindTexture(Batch& batch, size_t paramOffset) {
glActiveTexture(batch._params[paramOffset + 2]._uint);
glBindTexture(
GET_UNIFORM_LOCATION(batch._params[paramOffset + 1]._uint),
batch._params[paramOffset + 0]._uint);
(void)CHECK_GL_ERROR();
}
void GLBackend::do_glUniform1i(Batch& batch, size_t paramOffset) {
if (_pipeline._program == 0) {
// We should call updatePipeline() to bind the program but we are not doing that
// because these uniform setters are deprecated and we don;t want to create side effect
return;
}
updatePipeline();
glUniform1f(
GET_UNIFORM_LOCATION(batch._params[paramOffset + 1]._int),
batch._params[paramOffset + 0]._int);
(void)CHECK_GL_ERROR();
}
void GLBackend::do_glUniform1f(Batch& batch, size_t paramOffset) {
if (_pipeline._program == 0) {
// We should call updatePipeline() to bind the program but we are not doing that
// because these uniform setters are deprecated and we don;t want to create side effect
return;
}
updatePipeline();
glUniform1f(
GET_UNIFORM_LOCATION(batch._params[paramOffset + 1]._int),
batch._params[paramOffset + 0]._float);
(void)CHECK_GL_ERROR();
}
void GLBackend::do_glUniform2f(Batch& batch, size_t paramOffset) {
if (_pipeline._program == 0) {
// We should call updatePipeline() to bind the program but we are not doing that
// because these uniform setters are deprecated and we don;t want to create side effect
return;
}
updatePipeline();
glUniform2f(
GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int),
batch._params[paramOffset + 1]._float,
batch._params[paramOffset + 0]._float);
(void)CHECK_GL_ERROR();
}
void GLBackend::do_glUniform3f(Batch& batch, size_t paramOffset) {
if (_pipeline._program == 0) {
// We should call updatePipeline() to bind the program but we are not doing that
// because these uniform setters are deprecated and we don;t want to create side effect
return;
}
updatePipeline();
glUniform3f(
GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int),
batch._params[paramOffset + 2]._float,
batch._params[paramOffset + 1]._float,
batch._params[paramOffset + 0]._float);
(void)CHECK_GL_ERROR();
}
void GLBackend::do_glUniform4f(Batch& batch, size_t paramOffset) {
if (_pipeline._program == 0) {
// We should call updatePipeline() to bind the program but we are not doing that
// because these uniform setters are deprecated and we don;t want to create side effect
return;
}
updatePipeline();
glUniform4f(
GET_UNIFORM_LOCATION(batch._params[paramOffset + 4]._int),
batch._params[paramOffset + 3]._float,
batch._params[paramOffset + 2]._float,
batch._params[paramOffset + 1]._float,
batch._params[paramOffset + 0]._float);
(void)CHECK_GL_ERROR();
}
void GLBackend::do_glUniform3fv(Batch& batch, size_t paramOffset) {
if (_pipeline._program == 0) {
// We should call updatePipeline() to bind the program but we are not doing that
// because these uniform setters are deprecated and we don;t want to create side effect
return;
}
updatePipeline();
glUniform3fv(
GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int),
batch._params[paramOffset + 1]._uint,
(const GLfloat*)batch.editData(batch._params[paramOffset + 0]._uint));
(void)CHECK_GL_ERROR();
}
void GLBackend::do_glUniform4fv(Batch& batch, size_t paramOffset) {
if (_pipeline._program == 0) {
// We should call updatePipeline() to bind the program but we are not doing that
// because these uniform setters are deprecated and we don;t want to create side effect
return;
}
updatePipeline();
GLint location = GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int);
GLsizei count = batch._params[paramOffset + 1]._uint;
const GLfloat* value = (const GLfloat*)batch.editData(batch._params[paramOffset + 0]._uint);
glUniform4fv(location, count, value);
(void)CHECK_GL_ERROR();
}
void GLBackend::do_glUniform4iv(Batch& batch, size_t paramOffset) {
if (_pipeline._program == 0) {
// We should call updatePipeline() to bind the program but we are not doing that
// because these uniform setters are deprecated and we don;t want to create side effect
return;
}
updatePipeline();
glUniform4iv(
GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int),
batch._params[paramOffset + 1]._uint,
(const GLint*)batch.editData(batch._params[paramOffset + 0]._uint));
(void)CHECK_GL_ERROR();
}
void GLBackend::do_glUniformMatrix4fv(Batch& batch, size_t paramOffset) {
if (_pipeline._program == 0) {
// We should call updatePipeline() to bind the program but we are not doing that
// because these uniform setters are deprecated and we don;t want to create side effect
return;
}
updatePipeline();
glUniformMatrix4fv(
GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int),
batch._params[paramOffset + 2]._uint,
batch._params[paramOffset + 1]._uint,
(const GLfloat*)batch.editData(batch._params[paramOffset + 0]._uint));
(void)CHECK_GL_ERROR();
}
void GLBackend::do_glColor4f(Batch& batch, size_t paramOffset) {
glm::vec4 newColor(
batch._params[paramOffset + 3]._float,
batch._params[paramOffset + 2]._float,
batch._params[paramOffset + 1]._float,
batch._params[paramOffset + 0]._float);
if (_input._colorAttribute != newColor) {
_input._colorAttribute = newColor;
glVertexAttrib4fv(gpu::Stream::COLOR, &_input._colorAttribute.r);
}
(void)CHECK_GL_ERROR();
}

View file

@ -0,0 +1,332 @@
//
// GLBackend.h
// libraries/gpu/src/gpu
//
// Created by Sam Gateau on 10/27/2014.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_gl_GLBackend_h
#define hifi_gpu_gl_GLBackend_h
#include <assert.h>
#include <functional>
#include <bitset>
#include <queue>
#include <utility>
#include <list>
#include <array>
#include <QtCore/QLoggingCategory>
#include <gl/Config.h>
#include <gpu/Forward.h>
#include <gpu/Context.h>
#include "GLShared.h"
namespace gpu { namespace gl {
class GLBackend : public Backend {
// Context Backend static interface required
friend class gpu::Context;
static void init();
static Backend* createBackend();
static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings);
protected:
explicit GLBackend(bool syncCache);
GLBackend();
public:
~GLBackend();
void render(Batch& batch) final;
// This call synchronize the Full Backend cache with the current GLState
// THis is only intended to be used when mixing raw gl calls with the gpu api usage in order to sync
// the gpu::Backend state with the true gl state which has probably been messed up by these ugly naked gl calls
// Let's try to avoid to do that as much as possible!
void syncCache() final;
// This is the ugly "download the pixels to sysmem for taking a snapshot"
// Just avoid using it, it's ugly and will break performances
virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) final;
static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS;
static const int MAX_NUM_INPUT_BUFFERS = 16;
size_t getNumInputBuffers() const { return _input._invalidBuffers.size(); }
// this is the maximum per shader stage on the low end apple
// TODO make it platform dependant at init time
static const int MAX_NUM_UNIFORM_BUFFERS = 12;
size_t getMaxNumUniformBuffers() const { return MAX_NUM_UNIFORM_BUFFERS; }
// this is the maximum per shader stage on the low end apple
// TODO make it platform dependant at init time
static const int MAX_NUM_RESOURCE_TEXTURES = 16;
size_t getMaxNumResourceTextures() const { return MAX_NUM_RESOURCE_TEXTURES; }
// Draw Stage
virtual void do_draw(Batch& batch, size_t paramOffset) = 0;
virtual void do_drawIndexed(Batch& batch, size_t paramOffset) = 0;
virtual void do_drawInstanced(Batch& batch, size_t paramOffset) = 0;
virtual void do_drawIndexedInstanced(Batch& batch, size_t paramOffset) = 0;
virtual void do_multiDrawIndirect(Batch& batch, size_t paramOffset) = 0;
virtual void do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset) = 0;
// Input Stage
virtual void do_setInputFormat(Batch& batch, size_t paramOffset) final;
virtual void do_setInputBuffer(Batch& batch, size_t paramOffset) final;
virtual void do_setIndexBuffer(Batch& batch, size_t paramOffset) final;
virtual void do_setIndirectBuffer(Batch& batch, size_t paramOffset) final;
virtual void do_generateTextureMips(Batch& batch, size_t paramOffset) final;
// Transform Stage
virtual void do_setModelTransform(Batch& batch, size_t paramOffset) final;
virtual void do_setViewTransform(Batch& batch, size_t paramOffset) final;
virtual void do_setProjectionTransform(Batch& batch, size_t paramOffset) final;
virtual void do_setViewportTransform(Batch& batch, size_t paramOffset) final;
virtual void do_setDepthRangeTransform(Batch& batch, size_t paramOffset) final;
// Uniform Stage
virtual void do_setUniformBuffer(Batch& batch, size_t paramOffset) final;
// Resource Stage
virtual void do_setResourceTexture(Batch& batch, size_t paramOffset) final;
// Pipeline Stage
virtual void do_setPipeline(Batch& batch, size_t paramOffset) final;
// Output stage
virtual void do_setFramebuffer(Batch& batch, size_t paramOffset) final;
virtual void do_clearFramebuffer(Batch& batch, size_t paramOffset) final;
virtual void do_blit(Batch& batch, size_t paramOffset) = 0;
// Query section
virtual void do_beginQuery(Batch& batch, size_t paramOffset) final;
virtual void do_endQuery(Batch& batch, size_t paramOffset) final;
virtual void do_getQuery(Batch& batch, size_t paramOffset) final;
// Reset stages
virtual void do_resetStages(Batch& batch, size_t paramOffset) final;
virtual void do_runLambda(Batch& batch, size_t paramOffset) final;
virtual void do_startNamedCall(Batch& batch, size_t paramOffset) final;
virtual void do_stopNamedCall(Batch& batch, size_t paramOffset) final;
virtual void do_pushProfileRange(Batch& batch, size_t paramOffset) final;
virtual void do_popProfileRange(Batch& batch, size_t paramOffset) final;
// 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
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
virtual void do_glActiveBindTexture(Batch& batch, size_t paramOffset) final;
virtual void do_glUniform1i(Batch& batch, size_t paramOffset) final;
virtual void do_glUniform1f(Batch& batch, size_t paramOffset) final;
virtual void do_glUniform2f(Batch& batch, size_t paramOffset) final;
virtual void do_glUniform3f(Batch& batch, size_t paramOffset) final;
virtual void do_glUniform4f(Batch& batch, size_t paramOffset) final;
virtual void do_glUniform3fv(Batch& batch, size_t paramOffset) final;
virtual void do_glUniform4fv(Batch& batch, size_t paramOffset) final;
virtual void do_glUniform4iv(Batch& batch, size_t paramOffset) final;
virtual void do_glUniformMatrix4fv(Batch& batch, size_t paramOffset) final;
virtual void do_glColor4f(Batch& batch, size_t paramOffset) final;
// The State setters called by the GLState::Commands when a new state is assigned
virtual void do_setStateFillMode(int32 mode) final;
virtual void do_setStateCullMode(int32 mode) final;
virtual void do_setStateFrontFaceClockwise(bool isClockwise) final;
virtual void do_setStateDepthClampEnable(bool enable) final;
virtual void do_setStateScissorEnable(bool enable) final;
virtual void do_setStateMultisampleEnable(bool enable) final;
virtual void do_setStateAntialiasedLineEnable(bool enable) final;
virtual void do_setStateDepthBias(Vec2 bias) 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_setStateAlphaToCoverageEnable(bool enable) final;
virtual void do_setStateSampleMask(uint32 mask) final;
virtual void do_setStateBlend(State::BlendFunction blendFunction) final;
virtual void do_setStateColorWriteMask(uint32 mask) final;
virtual void do_setStateBlendFactor(Batch& batch, size_t paramOffset) final;
virtual void do_setStateScissorRect(Batch& batch, size_t paramOffset) final;
protected:
virtual GLuint getFramebufferID(const FramebufferPointer& framebuffer) = 0;
virtual GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) = 0;
virtual GLuint getBufferID(const Buffer& buffer) = 0;
virtual GLBuffer* syncGPUObject(const Buffer& buffer) = 0;
virtual GLuint getTextureID(const TexturePointer& texture, bool needTransfer = true) = 0;
virtual GLTexture* syncGPUObject(const TexturePointer& texture, bool sync = true) = 0;
virtual GLuint getQueryID(const QueryPointer& query) = 0;
virtual GLQuery* syncGPUObject(const Query& query) = 0;
static const size_t INVALID_OFFSET = (size_t)-1;
bool _inRenderTransferPass { false };
int32_t _uboAlignment { 0 };
int _currentDraw { -1 };
void renderPassTransfer(Batch& batch);
void renderPassDraw(Batch& batch);
void setupStereoSide(int side);
virtual void initInput() final;
virtual void killInput() final;
virtual void syncInputStateCache() final;
virtual void resetInputStage() final;
virtual void updateInput() = 0;
struct InputStageState {
bool _invalidFormat { true };
Stream::FormatPointer _format;
typedef std::bitset<MAX_NUM_ATTRIBUTES> ActivationCache;
ActivationCache _attributeActivation { 0 };
typedef std::bitset<MAX_NUM_INPUT_BUFFERS> BuffersState;
BuffersState _invalidBuffers { 0 };
Buffers _buffers;
Offsets _bufferOffsets;
Offsets _bufferStrides;
std::vector<GLuint> _bufferVBOs;
glm::vec4 _colorAttribute{ 0.0f };
BufferPointer _indexBuffer;
Offset _indexBufferOffset { 0 };
Type _indexBufferType { UINT32 };
BufferPointer _indirectBuffer;
Offset _indirectBufferOffset{ 0 };
Offset _indirectBufferStride{ 0 };
GLuint _defaultVAO { 0 };
InputStageState() :
_buffers(_invalidBuffers.size()),
_bufferOffsets(_invalidBuffers.size(), 0),
_bufferStrides(_invalidBuffers.size(), 0),
_bufferVBOs(_invalidBuffers.size(), 0) {}
} _input;
virtual void initTransform() = 0;
void killTransform();
// Synchronize the state cache of this Backend with the actual real state of the GL Context
void syncTransformStateCache();
void updateTransform(const Batch& batch);
void resetTransformStage();
struct TransformStageState {
using CameraBufferElement = TransformCamera;
using TransformCameras = std::vector<CameraBufferElement>;
TransformCamera _camera;
TransformCameras _cameras;
mutable std::map<std::string, GLvoid*> _drawCallInfoOffsets;
GLuint _objectBuffer { 0 };
GLuint _cameraBuffer { 0 };
GLuint _drawCallInfoBuffer { 0 };
GLuint _objectBufferTexture { 0 };
size_t _cameraUboSize { 0 };
Transform _view;
Mat4 _projection;
Vec4i _viewport { 0, 0, 1, 1 };
Vec2 _depthRange { 0.0f, 1.0f };
bool _invalidView { false };
bool _invalidProj { false };
bool _invalidViewport { false };
using Pair = std::pair<size_t, size_t>;
using List = std::list<Pair>;
List _cameraOffsets;
mutable List::const_iterator _camerasItr;
mutable size_t _currentCameraOffset{ INVALID_OFFSET };
void preUpdate(size_t commandIndex, const StereoState& stereo);
void update(size_t commandIndex, const StereoState& stereo) const;
void bindCurrentCamera(int stereoSide) const;
} _transform;
virtual void transferTransformState(const Batch& batch) const = 0;
struct UniformStageState {
std::array<BufferPointer, MAX_NUM_UNIFORM_BUFFERS> _buffers;
//Buffers _buffers { };
} _uniform;
void releaseUniformBuffer(uint32_t slot);
void resetUniformStage();
// update resource cache and do the gl unbind call with the current gpu::Texture cached at slot s
void releaseResourceTexture(uint32_t slot);
void resetResourceStage();
struct ResourceStageState {
std::array<TexturePointer, MAX_NUM_RESOURCE_TEXTURES> _textures;
//Textures _textures { { MAX_NUM_RESOURCE_TEXTURES } };
int findEmptyTextureSlot() const;
} _resource;
size_t _commandIndex{ 0 };
// Standard update pipeline check that the current Program and current State or good to go for a
void updatePipeline();
// Force to reset all the state fields indicated by the 'toBeReset" signature
void resetPipelineState(State::Signature toBeReset);
// Synchronize the state cache of this Backend with the actual real state of the GL Context
void syncPipelineStateCache();
void resetPipelineStage();
struct PipelineStageState {
PipelinePointer _pipeline;
GLuint _program { 0 };
GLShader* _programShader { nullptr };
bool _invalidProgram { false };
State::Data _stateCache { State::DEFAULT };
State::Signature _stateSignatureCache { 0 };
GLState* _state { nullptr };
bool _invalidState { false };
} _pipeline;
// Synchronize the state cache of this Backend with the actual real state of the GL Context
void syncOutputStateCache();
void resetOutputStage();
struct OutputStageState {
FramebufferPointer _framebuffer { nullptr };
GLuint _drawFBO { 0 };
} _output;
void resetQueryStage();
struct QueryStageState {
};
void resetStages();
typedef void (GLBackend::*CommandCall)(Batch&, size_t);
static CommandCall _commandCalls[Batch::NUM_COMMANDS];
friend class GLState;
};
} }
#endif

View file

@ -0,0 +1,152 @@
//
// GLBackendInput.cpp
// libraries/gpu/src/gpu
//
// Created by Sam Gateau on 3/8/2015.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackend.h"
#include "GLShared.h"
using namespace gpu;
using namespace gpu::gl;
void GLBackend::do_setInputFormat(Batch& batch, size_t paramOffset) {
Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint);
if (format != _input._format) {
_input._format = format;
_input._invalidFormat = true;
}
}
void GLBackend::do_setInputBuffer(Batch& batch, size_t paramOffset) {
Offset stride = batch._params[paramOffset + 0]._uint;
Offset offset = batch._params[paramOffset + 1]._uint;
BufferPointer buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
uint32 channel = batch._params[paramOffset + 3]._uint;
if (channel < getNumInputBuffers()) {
bool isModified = false;
if (_input._buffers[channel] != buffer) {
_input._buffers[channel] = buffer;
GLuint vbo = 0;
if (buffer) {
vbo = getBufferID((*buffer));
}
_input._bufferVBOs[channel] = vbo;
isModified = true;
}
if (_input._bufferOffsets[channel] != offset) {
_input._bufferOffsets[channel] = offset;
isModified = true;
}
if (_input._bufferStrides[channel] != stride) {
_input._bufferStrides[channel] = stride;
isModified = true;
}
if (isModified) {
_input._invalidBuffers.set(channel);
}
}
}
void GLBackend::initInput() {
if(!_input._defaultVAO) {
glGenVertexArrays(1, &_input._defaultVAO);
}
glBindVertexArray(_input._defaultVAO);
(void) CHECK_GL_ERROR();
}
void GLBackend::killInput() {
glBindVertexArray(0);
if(_input._defaultVAO) {
glDeleteVertexArrays(1, &_input._defaultVAO);
}
(void) CHECK_GL_ERROR();
}
void GLBackend::syncInputStateCache() {
for (uint32_t i = 0; i < _input._attributeActivation.size(); i++) {
GLint active = 0;
glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &active);
_input._attributeActivation[i] = active;
}
//_input._defaultVAO
glBindVertexArray(_input._defaultVAO);
}
void GLBackend::resetInputStage() {
// Reset index buffer
_input._indexBufferType = UINT32;
_input._indexBufferOffset = 0;
_input._indexBuffer.reset();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
(void) CHECK_GL_ERROR();
glBindBuffer(GL_ARRAY_BUFFER, 0);
for (uint32_t i = 0; i < _input._attributeActivation.size(); i++) {
glDisableVertexAttribArray(i);
glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, 0, 0);
}
// Reset vertex buffer and format
_input._format.reset();
_input._invalidFormat = false;
_input._attributeActivation.reset();
for (uint32_t i = 0; i < _input._buffers.size(); i++) {
_input._buffers[i].reset();
_input._bufferOffsets[i] = 0;
_input._bufferStrides[i] = 0;
_input._bufferVBOs[i] = 0;
}
_input._invalidBuffers.reset();
}
void GLBackend::do_setIndexBuffer(Batch& batch, size_t paramOffset) {
_input._indexBufferType = (Type)batch._params[paramOffset + 2]._uint;
_input._indexBufferOffset = batch._params[paramOffset + 0]._uint;
BufferPointer indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint);
if (indexBuffer != _input._indexBuffer) {
_input._indexBuffer = indexBuffer;
if (indexBuffer) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferID(*indexBuffer));
} else {
// FIXME do we really need this? Is there ever a draw call where we care that the element buffer is null?
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
}
(void) CHECK_GL_ERROR();
}
void GLBackend::do_setIndirectBuffer(Batch& batch, size_t paramOffset) {
_input._indirectBufferOffset = batch._params[paramOffset + 1]._uint;
_input._indirectBufferStride = batch._params[paramOffset + 2]._uint;
BufferPointer buffer = batch._buffers.get(batch._params[paramOffset]._uint);
if (buffer != _input._indirectBuffer) {
_input._indirectBuffer = buffer;
if (buffer) {
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, getBufferID(*buffer));
} else {
// FIXME do we really need this? Is there ever a draw call where we care that the element buffer is null?
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
}
}
(void)CHECK_GL_ERROR();
}

View file

@ -0,0 +1,165 @@
//
// GLBackendTexture.cpp
// libraries/gpu/src/gpu
//
// Created by Sam Gateau on 1/19/2015.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackend.h"
#include "GLShared.h"
#include "GLFramebuffer.h"
#include <QtGui/QImage>
using namespace gpu;
using namespace gpu::gl;
void GLBackend::syncOutputStateCache() {
GLint currentFBO;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &currentFBO);
_output._drawFBO = currentFBO;
_output._framebuffer.reset();
}
void GLBackend::resetOutputStage() {
if (_output._framebuffer) {
_output._framebuffer.reset();
_output._drawFBO = 0;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
glEnable(GL_FRAMEBUFFER_SRGB);
}
void GLBackend::do_setFramebuffer(Batch& batch, size_t paramOffset) {
auto framebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint);
if (_output._framebuffer != framebuffer) {
auto newFBO = getFramebufferID(framebuffer);
if (_output._drawFBO != newFBO) {
_output._drawFBO = newFBO;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, newFBO);
}
_output._framebuffer = framebuffer;
}
}
void GLBackend::do_clearFramebuffer(Batch& batch, size_t paramOffset) {
if (_stereo._enable && !_pipeline._stateCache.scissorEnable) {
qWarning("Clear without scissor in stereo mode");
}
uint32 masks = batch._params[paramOffset + 7]._uint;
Vec4 color;
color.x = batch._params[paramOffset + 6]._float;
color.y = batch._params[paramOffset + 5]._float;
color.z = batch._params[paramOffset + 4]._float;
color.w = batch._params[paramOffset + 3]._float;
float depth = batch._params[paramOffset + 2]._float;
int stencil = batch._params[paramOffset + 1]._int;
int useScissor = batch._params[paramOffset + 0]._int;
GLuint glmask = 0;
if (masks & Framebuffer::BUFFER_STENCIL) {
glClearStencil(stencil);
glmask |= GL_STENCIL_BUFFER_BIT;
// TODO: we will probably need to also check the write mask of stencil like we do
// for depth buffer, but as would say a famous Fez owner "We'll cross that bridge when we come to it"
}
bool restoreDepthMask = false;
if (masks & Framebuffer::BUFFER_DEPTH) {
glClearDepth(depth);
glmask |= GL_DEPTH_BUFFER_BIT;
bool cacheDepthMask = _pipeline._stateCache.depthTest.getWriteMask();
if (!cacheDepthMask) {
restoreDepthMask = true;
glDepthMask(GL_TRUE);
}
}
std::vector<GLenum> drawBuffers;
if (masks & Framebuffer::BUFFER_COLORS) {
if (_output._framebuffer) {
for (unsigned int i = 0; i < Framebuffer::MAX_NUM_RENDER_BUFFERS; i++) {
if (masks & (1 << i)) {
drawBuffers.push_back(GL_COLOR_ATTACHMENT0 + i);
}
}
if (!drawBuffers.empty()) {
glDrawBuffers((GLsizei)drawBuffers.size(), drawBuffers.data());
glClearColor(color.x, color.y, color.z, color.w);
glmask |= GL_COLOR_BUFFER_BIT;
(void) CHECK_GL_ERROR();
}
} else {
glClearColor(color.x, color.y, color.z, color.w);
glmask |= GL_COLOR_BUFFER_BIT;
}
// Force the color mask cache to WRITE_ALL if not the case
do_setStateColorWriteMask(State::ColorMask::WRITE_ALL);
}
// Apply scissor if needed and if not already on
bool doEnableScissor = (useScissor && (!_pipeline._stateCache.scissorEnable));
if (doEnableScissor) {
glEnable(GL_SCISSOR_TEST);
}
// Clear!
glClear(glmask);
// Restore scissor if needed
if (doEnableScissor) {
glDisable(GL_SCISSOR_TEST);
}
// Restore write mask meaning turn back off
if (restoreDepthMask) {
glDepthMask(GL_FALSE);
}
// Restore the color draw buffers only if a frmaebuffer is bound
if (_output._framebuffer && !drawBuffers.empty()) {
auto glFramebuffer = syncGPUObject(*_output._framebuffer);
if (glFramebuffer) {
glDrawBuffers((GLsizei)glFramebuffer->_colorBuffers.size(), glFramebuffer->_colorBuffers.data());
}
}
(void) CHECK_GL_ERROR();
}
void GLBackend::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) {
auto readFBO = getFramebufferID(srcFramebuffer);
if (srcFramebuffer && readFBO) {
if ((srcFramebuffer->getWidth() < (region.x + region.z)) || (srcFramebuffer->getHeight() < (region.y + region.w))) {
qCDebug(gpugllogging) << "GLBackend::downloadFramebuffer : srcFramebuffer is too small to provide the region queried";
return;
}
}
if ((destImage.width() < region.z) || (destImage.height() < region.w)) {
qCDebug(gpugllogging) << "GLBackend::downloadFramebuffer : destImage is too small to receive the region of the framebuffer";
return;
}
GLenum format = GL_BGRA;
if (destImage.format() != QImage::Format_ARGB32) {
qCDebug(gpugllogging) << "GLBackend::downloadFramebuffer : destImage format must be FORMAT_ARGB32 to receive the region of the framebuffer";
return;
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, getFramebufferID(srcFramebuffer));
glReadPixels(region.x, region.y, region.z, region.w, format, GL_UNSIGNED_BYTE, destImage.bits());
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
(void) CHECK_GL_ERROR();
}

View file

@ -8,54 +8,16 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackendShared.h"
#include "Format.h"
#include "GLBackend.h"
#include "GLShared.h"
#include "GLPipeline.h"
#include "GLShader.h"
#include "GLState.h"
#include "GLBuffer.h"
#include "GLTexture.h"
using namespace gpu;
GLBackend::GLPipeline::GLPipeline() :
_program(nullptr),
_state(nullptr)
{}
GLBackend::GLPipeline::~GLPipeline() {
_program = nullptr;
_state = nullptr;
}
GLBackend::GLPipeline* GLBackend::syncGPUObject(const Pipeline& pipeline) {
GLPipeline* object = Backend::getGPUObject<GLBackend::GLPipeline>(pipeline);
// If GPU object already created then good
if (object) {
return object;
}
// No object allocated yet, let's see if it's worth it...
ShaderPointer shader = pipeline.getProgram();
GLShader* programObject = GLBackend::syncGPUObject((*shader));
if (programObject == nullptr) {
return nullptr;
}
StatePointer state = pipeline.getState();
GLState* stateObject = GLBackend::syncGPUObject((*state));
if (stateObject == nullptr) {
return nullptr;
}
// Program and state are valid, we can create the pipeline object
if (!object) {
object = new GLPipeline();
Backend::setGPUObject(pipeline, object);
}
object->_program = programObject;
object->_state = stateObject;
return object;
}
using namespace gpu::gl;
void GLBackend::do_setPipeline(Batch& batch, size_t paramOffset) {
PipelinePointer pipeline = batch._pipelines.get(batch._params[paramOffset + 0]._uint);
@ -78,7 +40,7 @@ void GLBackend::do_setPipeline(Batch& batch, size_t paramOffset) {
_pipeline._state = nullptr;
_pipeline._invalidState = true;
} else {
auto pipelineObject = syncGPUObject((*pipeline));
auto pipelineObject = GLPipeline::sync(*pipeline);
if (!pipelineObject) {
return;
}
@ -155,20 +117,16 @@ void GLBackend::resetPipelineStage() {
glUseProgram(0);
}
void GLBackend::releaseUniformBuffer(uint32_t slot) {
#if (GPU_FEATURE_PROFILE == GPU_CORE)
auto& buf = _uniform._buffers[slot];
if (buf) {
auto* object = Backend::getGPUObject<GLBackend::GLBuffer>(*buf);
auto* object = Backend::getGPUObject<GLBuffer>(*buf);
if (object) {
glBindBufferBase(GL_UNIFORM_BUFFER, slot, 0); // RELEASE
(void) CHECK_GL_ERROR();
}
buf.reset();
}
#endif
}
void GLBackend::resetUniformStage() {
@ -183,10 +141,6 @@ void GLBackend::do_setUniformBuffer(Batch& batch, size_t paramOffset) {
GLintptr rangeStart = batch._params[paramOffset + 1]._uint;
GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint;
#if (GPU_FEATURE_PROFILE == GPU_CORE)
if (!uniformBuffer) {
releaseUniformBuffer(slot);
return;
@ -198,7 +152,7 @@ void GLBackend::do_setUniformBuffer(Batch& batch, size_t paramOffset) {
}
// Sync BufferObject
auto* object = GLBackend::syncGPUObject(*uniformBuffer);
auto* object = syncGPUObject(*uniformBuffer);
if (object) {
glBindBufferRange(GL_UNIFORM_BUFFER, slot, object->_buffer, rangeStart, rangeSize);
@ -208,39 +162,22 @@ void GLBackend::do_setUniformBuffer(Batch& batch, size_t paramOffset) {
releaseResourceTexture(slot);
return;
}
#else
// because we rely on the program uniform mechanism we need to have
// the program bound, thank you MacOSX Legacy profile.
updatePipeline();
GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart);
glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data);
// NOT working so we ll stick to the uniform float array until we move to core profile
// GLuint bo = getBufferID(*uniformBuffer);
//glUniformBufferEXT(_shader._program, slot, bo);
(void) CHECK_GL_ERROR();
#endif
}
void GLBackend::releaseResourceTexture(uint32_t slot) {
auto& tex = _resource._textures[slot];
if (tex) {
auto* object = Backend::getGPUObject<GLBackend::GLTexture>(*tex);
auto* object = Backend::getGPUObject<GLTexture>(*tex);
if (object) {
GLuint target = object->_target;
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(target, 0); // RELEASE
(void) CHECK_GL_ERROR();
}
tex.reset();
}
}
void GLBackend::resetResourceStage() {
for (uint32_t i = 0; i < _resource._textures.size(); i++) {
releaseResourceTexture(i);
@ -264,7 +201,7 @@ void GLBackend::do_setResourceTexture(Batch& batch, size_t paramOffset) {
_stats._RSNumTextureBounded++;
// Always make sure the GLObject is in sync
GLTexture* object = GLBackend::syncGPUObject(resourceTexture);
GLTexture* object = syncGPUObject(resourceTexture);
if (object) {
GLuint to = object->_texture;
GLuint target = object->_target;

View file

@ -0,0 +1,49 @@
//
// GLBackendQuery.cpp
// libraries/gpu/src/gpu
//
// Created by Sam Gateau on 7/7/2015.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackend.h"
#include "GLQuery.h"
using namespace gpu;
using namespace gpu::gl;
void GLBackend::do_beginQuery(Batch& batch, size_t paramOffset) {
auto query = batch._queries.get(batch._params[paramOffset]._uint);
GLQuery* glquery = syncGPUObject(*query);
if (glquery) {
glBeginQuery(GL_TIME_ELAPSED, glquery->_qo);
(void)CHECK_GL_ERROR();
}
}
void GLBackend::do_endQuery(Batch& batch, size_t paramOffset) {
auto query = batch._queries.get(batch._params[paramOffset]._uint);
GLQuery* glquery = syncGPUObject(*query);
if (glquery) {
glEndQuery(GL_TIME_ELAPSED);
(void)CHECK_GL_ERROR();
}
}
void GLBackend::do_getQuery(Batch& batch, size_t paramOffset) {
auto query = batch._queries.get(batch._params[paramOffset]._uint);
GLQuery* glquery = syncGPUObject(*query);
if (glquery) {
glGetQueryObjectui64v(glquery->_qo, GL_QUERY_RESULT_AVAILABLE, &glquery->_result);
if (glquery->_result == GL_TRUE) {
glGetQueryObjectui64v(glquery->_qo, GL_QUERY_RESULT, &glquery->_result);
query->triggerReturnHandler(glquery->_result);
}
(void)CHECK_GL_ERROR();
}
}
void GLBackend::resetQueryStage() {
}

View file

@ -0,0 +1,309 @@
//
// GLBackendState.cpp
// libraries/gpu/src/gpu
//
// Created by Sam Gateau on 3/22/2015.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackend.h"
#include "GLState.h"
using namespace gpu;
using namespace gpu::gl;
void GLBackend::resetPipelineState(State::Signature nextSignature) {
auto currentNotSignature = ~_pipeline._stateSignatureCache;
auto nextNotSignature = ~nextSignature;
auto fieldsToBeReset = currentNotSignature ^ (currentNotSignature | nextNotSignature);
if (fieldsToBeReset.any()) {
for (auto i = 0; i < State::NUM_FIELDS; i++) {
if (fieldsToBeReset[i]) {
GLState::_resetStateCommands[i]->run(this);
_pipeline._stateSignatureCache.reset(i);
}
}
}
}
void GLBackend::syncPipelineStateCache() {
State::Data state;
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
// Point size is always on
// FIXME CORE
//glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
glEnable(GL_PROGRAM_POINT_SIZE_EXT);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
// Default line width accross the board
glLineWidth(1.0f);
getCurrentGLState(state);
State::Signature signature = State::evalSignature(state);
_pipeline._stateCache = state;
_pipeline._stateSignatureCache = signature;
}
void GLBackend::do_setStateFillMode(int32 mode) {
if (_pipeline._stateCache.fillMode != mode) {
static GLenum GL_FILL_MODES[] = { GL_POINT, GL_LINE, GL_FILL };
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL_MODES[mode]);
(void)CHECK_GL_ERROR();
_pipeline._stateCache.fillMode = State::FillMode(mode);
}
}
void GLBackend::do_setStateCullMode(int32 mode) {
if (_pipeline._stateCache.cullMode != mode) {
static GLenum GL_CULL_MODES[] = { GL_FRONT_AND_BACK, GL_FRONT, GL_BACK };
if (mode == State::CULL_NONE) {
glDisable(GL_CULL_FACE);
glCullFace(GL_FRONT_AND_BACK);
} else {
glEnable(GL_CULL_FACE);
glCullFace(GL_CULL_MODES[mode]);
}
(void)CHECK_GL_ERROR();
_pipeline._stateCache.cullMode = State::CullMode(mode);
}
}
void GLBackend::do_setStateFrontFaceClockwise(bool isClockwise) {
if (_pipeline._stateCache.frontFaceClockwise != isClockwise) {
static GLenum GL_FRONT_FACES[] = { GL_CCW, GL_CW };
glFrontFace(GL_FRONT_FACES[isClockwise]);
(void)CHECK_GL_ERROR();
_pipeline._stateCache.frontFaceClockwise = isClockwise;
}
}
void GLBackend::do_setStateDepthClampEnable(bool enable) {
if (_pipeline._stateCache.depthClampEnable != enable) {
if (enable) {
glEnable(GL_DEPTH_CLAMP);
} else {
glDisable(GL_DEPTH_CLAMP);
}
(void)CHECK_GL_ERROR();
_pipeline._stateCache.depthClampEnable = enable;
}
}
void GLBackend::do_setStateScissorEnable(bool enable) {
if (_pipeline._stateCache.scissorEnable != enable) {
if (enable) {
glEnable(GL_SCISSOR_TEST);
} else {
glDisable(GL_SCISSOR_TEST);
}
(void)CHECK_GL_ERROR();
_pipeline._stateCache.scissorEnable = enable;
}
}
void GLBackend::do_setStateMultisampleEnable(bool enable) {
if (_pipeline._stateCache.multisampleEnable != enable) {
if (enable) {
glEnable(GL_MULTISAMPLE);
} else {
glDisable(GL_MULTISAMPLE);
}
(void)CHECK_GL_ERROR();
_pipeline._stateCache.multisampleEnable = enable;
}
}
void GLBackend::do_setStateAntialiasedLineEnable(bool enable) {
if (_pipeline._stateCache.antialisedLineEnable != enable) {
if (enable) {
glEnable(GL_LINE_SMOOTH);
} else {
glDisable(GL_LINE_SMOOTH);
}
(void)CHECK_GL_ERROR();
_pipeline._stateCache.antialisedLineEnable = enable;
}
}
void GLBackend::do_setStateDepthBias(Vec2 bias) {
if ((bias.x != _pipeline._stateCache.depthBias) || (bias.y != _pipeline._stateCache.depthBiasSlopeScale)) {
if ((bias.x != 0.0f) || (bias.y != 0.0f)) {
glEnable(GL_POLYGON_OFFSET_FILL);
glEnable(GL_POLYGON_OFFSET_LINE);
glEnable(GL_POLYGON_OFFSET_POINT);
glPolygonOffset(bias.x, bias.y);
} else {
glDisable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
glDisable(GL_POLYGON_OFFSET_POINT);
}
(void)CHECK_GL_ERROR();
_pipeline._stateCache.depthBias = bias.x;
_pipeline._stateCache.depthBiasSlopeScale = bias.y;
}
}
void GLBackend::do_setStateDepthTest(State::DepthTest test) {
if (_pipeline._stateCache.depthTest != test) {
if (test.isEnabled()) {
glEnable(GL_DEPTH_TEST);
glDepthMask(test.getWriteMask());
glDepthFunc(COMPARISON_TO_GL[test.getFunction()]);
} else {
glDisable(GL_DEPTH_TEST);
}
if (CHECK_GL_ERROR()) {
qDebug() << "DepthTest" << (test.isEnabled() ? "Enabled" : "Disabled")
<< "Mask=" << (test.getWriteMask() ? "Write" : "no Write")
<< "Func=" << test.getFunction()
<< "Raw=" << test.getRaw();
}
_pipeline._stateCache.depthTest = test;
}
}
void GLBackend::do_setStateStencil(State::StencilActivation activation, State::StencilTest frontTest, State::StencilTest backTest) {
if ((_pipeline._stateCache.stencilActivation != activation)
|| (_pipeline._stateCache.stencilTestFront != frontTest)
|| (_pipeline._stateCache.stencilTestBack != backTest)) {
if (activation.isEnabled()) {
glEnable(GL_STENCIL_TEST);
if (activation.getWriteMaskFront() != activation.getWriteMaskBack()) {
glStencilMaskSeparate(GL_FRONT, activation.getWriteMaskFront());
glStencilMaskSeparate(GL_BACK, activation.getWriteMaskBack());
} else {
glStencilMask(activation.getWriteMaskFront());
}
static GLenum STENCIL_OPS[] = {
GL_KEEP,
GL_ZERO,
GL_REPLACE,
GL_INCR_WRAP,
GL_DECR_WRAP,
GL_INVERT,
GL_INCR,
GL_DECR };
if (frontTest != backTest) {
glStencilOpSeparate(GL_FRONT, STENCIL_OPS[frontTest.getFailOp()], STENCIL_OPS[frontTest.getPassOp()], STENCIL_OPS[frontTest.getDepthFailOp()]);
glStencilFuncSeparate(GL_FRONT, COMPARISON_TO_GL[frontTest.getFunction()], frontTest.getReference(), frontTest.getReadMask());
glStencilOpSeparate(GL_BACK, STENCIL_OPS[backTest.getFailOp()], STENCIL_OPS[backTest.getPassOp()], STENCIL_OPS[backTest.getDepthFailOp()]);
glStencilFuncSeparate(GL_BACK, COMPARISON_TO_GL[backTest.getFunction()], backTest.getReference(), backTest.getReadMask());
} else {
glStencilOp(STENCIL_OPS[frontTest.getFailOp()], STENCIL_OPS[frontTest.getPassOp()], STENCIL_OPS[frontTest.getDepthFailOp()]);
glStencilFunc(COMPARISON_TO_GL[frontTest.getFunction()], frontTest.getReference(), frontTest.getReadMask());
}
} else {
glDisable(GL_STENCIL_TEST);
}
(void)CHECK_GL_ERROR();
_pipeline._stateCache.stencilActivation = activation;
_pipeline._stateCache.stencilTestFront = frontTest;
_pipeline._stateCache.stencilTestBack = backTest;
}
}
void GLBackend::do_setStateAlphaToCoverageEnable(bool enable) {
if (_pipeline._stateCache.alphaToCoverageEnable != enable) {
if (enable) {
glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
} else {
glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
}
(void)CHECK_GL_ERROR();
_pipeline._stateCache.alphaToCoverageEnable = enable;
}
}
void GLBackend::do_setStateSampleMask(uint32 mask) {
if (_pipeline._stateCache.sampleMask != mask) {
if (mask == 0xFFFFFFFF) {
glDisable(GL_SAMPLE_MASK);
} else {
glEnable(GL_SAMPLE_MASK);
glSampleMaski(0, mask);
}
(void)CHECK_GL_ERROR();
_pipeline._stateCache.sampleMask = mask;
}
}
void GLBackend::do_setStateBlend(State::BlendFunction function) {
if (_pipeline._stateCache.blendFunction != function) {
if (function.isEnabled()) {
glEnable(GL_BLEND);
glBlendEquationSeparate(BLEND_OPS_TO_GL[function.getOperationColor()], BLEND_OPS_TO_GL[function.getOperationAlpha()]);
(void)CHECK_GL_ERROR();
glBlendFuncSeparate(BLEND_ARGS_TO_GL[function.getSourceColor()], BLEND_ARGS_TO_GL[function.getDestinationColor()],
BLEND_ARGS_TO_GL[function.getSourceAlpha()], BLEND_ARGS_TO_GL[function.getDestinationAlpha()]);
} else {
glDisable(GL_BLEND);
}
(void)CHECK_GL_ERROR();
_pipeline._stateCache.blendFunction = function;
}
}
void GLBackend::do_setStateColorWriteMask(uint32 mask) {
if (_pipeline._stateCache.colorWriteMask != mask) {
glColorMask(mask & State::ColorMask::WRITE_RED,
mask & State::ColorMask::WRITE_GREEN,
mask & State::ColorMask::WRITE_BLUE,
mask & State::ColorMask::WRITE_ALPHA);
(void)CHECK_GL_ERROR();
_pipeline._stateCache.colorWriteMask = mask;
}
}
void GLBackend::do_setStateBlendFactor(Batch& batch, size_t paramOffset) {
Vec4 factor(batch._params[paramOffset + 0]._float,
batch._params[paramOffset + 1]._float,
batch._params[paramOffset + 2]._float,
batch._params[paramOffset + 3]._float);
glBlendColor(factor.x, factor.y, factor.z, factor.w);
(void)CHECK_GL_ERROR();
}
void GLBackend::do_setStateScissorRect(Batch& batch, size_t paramOffset) {
Vec4i rect;
memcpy(&rect, batch.editData(batch._params[paramOffset]._uint), sizeof(Vec4i));
if (_stereo._enable) {
rect.z /= 2;
if (_stereo._pass) {
rect.x += rect.z;
}
}
glScissor(rect.x, rect.y, rect.z, rect.w);
(void)CHECK_GL_ERROR();
}

View file

@ -0,0 +1,30 @@
//
// GLBackendTexture.cpp
// libraries/gpu/src/gpu
//
// Created by Sam Gateau on 1/19/2015.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackend.h"
#include "GLTexture.h"
using namespace gpu;
using namespace gpu::gl;
void GLBackend::do_generateTextureMips(Batch& batch, size_t paramOffset) {
TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);
if (!resourceTexture) {
return;
}
// DO not transfer the texture, this call is expected for rendering texture
GLTexture* object = syncGPUObject(resourceTexture, false);
if (!object) {
return;
}
object->generateMips();
}

View file

@ -8,11 +8,10 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackendShared.h"
#include "Format.h"
#include "GLBackend.h"
using namespace gpu;
using namespace gpu::gl;
// Transform Stage
void GLBackend::do_setModelTransform(Batch& batch, size_t paramOffset) {
@ -51,26 +50,11 @@ void GLBackend::do_setDepthRangeTransform(Batch& batch, size_t paramOffset) {
}
}
void GLBackend::initTransform() {
glGenBuffers(1, &_transform._objectBuffer);
glGenBuffers(1, &_transform._cameraBuffer);
glGenBuffers(1, &_transform._drawCallInfoBuffer);
#ifndef GPU_SSBO_DRAW_CALL_INFO
glGenTextures(1, &_transform._objectBufferTexture);
#endif
size_t cameraSize = sizeof(TransformStageState::CameraBufferElement);
while (_transform._cameraUboSize < cameraSize) {
_transform._cameraUboSize += _uboAlignment;
}
}
void GLBackend::killTransform() {
glDeleteBuffers(1, &_transform._objectBuffer);
glDeleteBuffers(1, &_transform._cameraBuffer);
glDeleteBuffers(1, &_transform._drawCallInfoBuffer);
#ifndef GPU_SSBO_DRAW_CALL_INFO
glDeleteTextures(1, &_transform._objectBufferTexture);
#endif
}
void GLBackend::syncTransformStateCache() {
@ -118,64 +102,6 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo
_invalidView = _invalidProj = _invalidViewport = false;
}
void GLBackend::TransformStageState::transfer(const Batch& batch) const {
// FIXME not thread safe
static std::vector<uint8_t> bufferData;
if (!_cameras.empty()) {
bufferData.resize(_cameraUboSize * _cameras.size());
for (size_t i = 0; i < _cameras.size(); ++i) {
memcpy(bufferData.data() + (_cameraUboSize * i), &_cameras[i], sizeof(CameraBufferElement));
}
glBindBuffer(GL_UNIFORM_BUFFER, _cameraBuffer);
glBufferData(GL_UNIFORM_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
if (!batch._objects.empty()) {
auto byteSize = batch._objects.size() * sizeof(Batch::TransformObject);
bufferData.resize(byteSize);
memcpy(bufferData.data(), batch._objects.data(), byteSize);
#ifdef GPU_SSBO_DRAW_CALL_INFO
glBindBuffer(GL_SHADER_STORAGE_BUFFER, _objectBuffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
#else
glBindBuffer(GL_TEXTURE_BUFFER, _objectBuffer);
glBufferData(GL_TEXTURE_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_TEXTURE_BUFFER, 0);
#endif
}
if (!batch._namedData.empty()) {
bufferData.clear();
for (auto& data : batch._namedData) {
auto currentSize = bufferData.size();
auto bytesToCopy = data.second.drawCallInfos.size() * sizeof(Batch::DrawCallInfo);
bufferData.resize(currentSize + bytesToCopy);
memcpy(bufferData.data() + currentSize, data.second.drawCallInfos.data(), bytesToCopy);
_drawCallInfoOffsets[data.first] = (GLvoid*)currentSize;
}
glBindBuffer(GL_ARRAY_BUFFER, _drawCallInfoBuffer);
glBufferData(GL_ARRAY_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
#ifdef GPU_SSBO_DRAW_CALL_INFO
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, TRANSFORM_OBJECT_SLOT, _objectBuffer);
#else
glActiveTexture(GL_TEXTURE0 + TRANSFORM_OBJECT_SLOT);
glBindTexture(GL_TEXTURE_BUFFER, _objectBufferTexture);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, _objectBuffer);
#endif
CHECK_GL_ERROR();
// Make sure the current Camera offset is unknown before render Draw
_currentCameraOffset = INVALID_OFFSET;
}
void GLBackend::TransformStageState::update(size_t commandIndex, const StereoState& stereo) const {
size_t offset = INVALID_OFFSET;
while ((_camerasItr != _cameraOffsets.end()) && (commandIndex >= (*_camerasItr).first)) {

View file

@ -0,0 +1,28 @@
//
// Created by Bradley Austin Davis on 2016/05/15
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBuffer.h"
using namespace gpu;
using namespace gpu::gl;
GLBuffer::~GLBuffer() {
glDeleteBuffers(1, &_id);
Backend::decrementBufferGPUCount();
Backend::updateBufferGPUMemoryUsage(_size, 0);
}
GLBuffer::GLBuffer(const Buffer& buffer, GLuint id) :
GLObject(buffer, id),
_size((GLuint)buffer._sysmem.getSize()),
_stamp(buffer._sysmem.getStamp())
{
Backend::incrementBufferGPUCount();
Backend::updateBufferGPUMemoryUsage(0, _size);
}

View file

@ -0,0 +1,57 @@
//
// Created by Bradley Austin Davis on 2016/05/15
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_gl_GLBuffer_h
#define hifi_gpu_gl_GLBuffer_h
#include "GLShared.h"
namespace gpu { namespace gl {
class GLBuffer : public GLObject<Buffer> {
public:
template <typename GLBufferType>
static GLBufferType* sync(const Buffer& buffer) {
GLBufferType* object = Backend::getGPUObject<GLBufferType>(buffer);
// Has the storage size changed?
if (!object || object->_stamp != buffer.getSysmem().getStamp()) {
object = new GLBufferType(buffer, object);
}
if (0 != (buffer._flags & Buffer::DIRTY)) {
object->transfer();
}
return object;
}
template <typename GLBufferType>
static GLuint getId(const Buffer& buffer) {
GLBuffer* bo = sync<GLBufferType>(buffer);
if (bo) {
return bo->_buffer;
} else {
return 0;
}
}
const GLuint& _buffer { _id };
const GLuint _size;
const Stamp _stamp;
~GLBuffer();
virtual void transfer() = 0;
protected:
GLBuffer(const Buffer& buffer, GLuint id);
};
} }
#endif

View file

@ -0,0 +1,39 @@
//
// Created by Bradley Austin Davis on 2016/05/15
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLFramebuffer.h"
using namespace gpu;
using namespace gpu::gl;
bool GLFramebuffer::checkStatus(GLenum target) const {
bool result = false;
switch (_status) {
case GL_FRAMEBUFFER_COMPLETE:
// Success !
result = true;
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT.";
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT.";
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER.";
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER.";
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_UNSUPPORTED.";
break;
}
return result;
}

View file

@ -0,0 +1,76 @@
//
// Created by Bradley Austin Davis on 2016/05/15
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_gl_GLFramebuffer_h
#define hifi_gpu_gl_GLFramebuffer_h
#include "GLShared.h"
namespace gpu { namespace gl {
class GLFramebuffer : public GLObject<Framebuffer> {
public:
template <typename GLFramebufferType>
static GLFramebufferType* sync(const Framebuffer& framebuffer) {
GLFramebufferType* object = Backend::getGPUObject<GLFramebufferType>(framebuffer);
bool needsUpate { false };
if (!object ||
framebuffer.getDepthStamp() != object->_depthStamp ||
framebuffer.getColorStamps() != object->_colorStamps) {
needsUpate = true;
}
// If GPU object already created and in sync
if (!needsUpate) {
return object;
} else if (framebuffer.isEmpty()) {
// NO framebuffer definition yet so let's avoid thinking
return nullptr;
}
// need to have a gpu object?
if (!object) {
// All is green, assign the gpuobject to the Framebuffer
object = new GLFramebufferType(framebuffer);
Backend::setGPUObject(framebuffer, object);
(void)CHECK_GL_ERROR();
}
object->update();
return object;
}
template <typename GLFramebufferType>
static GLuint getId(const Framebuffer& framebuffer) {
GLFramebufferType* fbo = sync<GLFramebufferType>(framebuffer);
if (fbo) {
return fbo->_id;
} else {
return 0;
}
}
const GLuint& _fbo { _id };
std::vector<GLenum> _colorBuffers;
Stamp _depthStamp { 0 };
std::vector<Stamp> _colorStamps;
protected:
GLenum _status { GL_FRAMEBUFFER_COMPLETE };
virtual void update() = 0;
bool checkStatus(GLenum target) const;
GLFramebuffer(const Framebuffer& framebuffer, GLuint id) : GLObject(framebuffer, id) {}
~GLFramebuffer() { if (_id) { glDeleteFramebuffers(1, &_id); } };
};
} }
#endif

View file

@ -0,0 +1,48 @@
//
// Created by Bradley Austin Davis on 2016/05/15
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLPipeline.h"
#include "GLShader.h"
#include "GLState.h"
using namespace gpu;
using namespace gpu::gl;
GLPipeline* GLPipeline::sync(const Pipeline& pipeline) {
GLPipeline* object = Backend::getGPUObject<GLPipeline>(pipeline);
// If GPU object already created then good
if (object) {
return object;
}
// No object allocated yet, let's see if it's worth it...
ShaderPointer shader = pipeline.getProgram();
GLShader* programObject = GLShader::sync(*shader);
if (programObject == nullptr) {
return nullptr;
}
StatePointer state = pipeline.getState();
GLState* stateObject = GLState::sync(*state);
if (stateObject == nullptr) {
return nullptr;
}
// Program and state are valid, we can create the pipeline object
if (!object) {
object = new GLPipeline();
Backend::setGPUObject(pipeline, object);
}
object->_program = programObject;
object->_state = stateObject;
return object;
}

View file

@ -0,0 +1,26 @@
//
// Created by Bradley Austin Davis on 2016/05/15
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_gl_GLPipeline_h
#define hifi_gpu_gl_GLPipeline_h
#include "GLShared.h"
namespace gpu { namespace gl {
class GLPipeline : public GPUObject {
public:
static GLPipeline* sync(const Pipeline& pipeline);
GLShader* _program { nullptr };
GLState* _state { nullptr };
};
} }
#endif

View file

@ -0,0 +1,57 @@
//
// Created by Bradley Austin Davis on 2016/05/15
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_gl_GLQuery_h
#define hifi_gpu_gl_GLQuery_h
#include "GLShared.h"
namespace gpu { namespace gl {
class GLQuery : public GLObject<Query> {
using Parent = gpu::gl::GLObject<Query>;
public:
template <typename GLQueryType>
static GLQueryType* sync(const Query& query) {
GLQueryType* object = Backend::getGPUObject<GLQueryType>(query);
// need to have a gpu object?
if (!object) {
// All is green, assign the gpuobject to the Query
object = new GLQueryType(query);
(void)CHECK_GL_ERROR();
Backend::setGPUObject(query, object);
}
return object;
}
template <typename GLQueryType>
static GLuint getId(const QueryPointer& query) {
if (!query) {
return 0;
}
GLQuery* object = sync<GLQueryType>(*query);
if (!object) {
return 0;
}
return object->_qo;
}
const GLuint& _qo { _id };
GLuint64 _result { (GLuint64)-1 };
protected:
GLQuery(const Query& query, GLuint id) : Parent(query, id) {}
~GLQuery() { if (_id) { glDeleteQueries(1, &_id); } }
};
} }
#endif

View file

@ -0,0 +1,182 @@
//
// Created by Bradley Austin Davis on 2016/05/15
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLShader.h"
#include "GLBackend.h"
using namespace gpu;
using namespace gpu::gl;
GLShader::GLShader() {
}
GLShader::~GLShader() {
for (auto& so : _shaderObjects) {
if (so.glshader != 0) {
glDeleteShader(so.glshader);
}
if (so.glprogram != 0) {
glDeleteProgram(so.glprogram);
}
}
}
GLShader* compileBackendShader(const Shader& shader) {
// Any GLSLprogram ? normally yes...
const std::string& shaderSource = shader.getSource().getCode();
// GLSL version
const std::string glslVersion = {
"#version 410 core"
};
// Shader domain
const int NUM_SHADER_DOMAINS = 2;
const GLenum SHADER_DOMAINS[NUM_SHADER_DOMAINS] = {
GL_VERTEX_SHADER,
GL_FRAGMENT_SHADER
};
GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
// Domain specific defines
const std::string domainDefines[NUM_SHADER_DOMAINS] = {
"#define GPU_VERTEX_SHADER",
"#define GPU_PIXEL_SHADER"
};
// Versions specific of the shader
const std::string versionDefines[GLShader::NumVersions] = {
""
};
GLShader::ShaderObjects shaderObjects;
for (int version = 0; version < GLShader::NumVersions; version++) {
auto& shaderObject = shaderObjects[version];
std::string shaderDefines = glslVersion + "\n" + domainDefines[shader.getType()] + "\n" + versionDefines[version];
bool result = compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, shaderObject.glprogram);
if (!result) {
return nullptr;
}
}
// So far so good, the shader is created successfully
GLShader* object = new GLShader();
object->_shaderObjects = shaderObjects;
return object;
}
GLShader* compileBackendProgram(const Shader& program) {
if (!program.isProgram()) {
return nullptr;
}
GLShader::ShaderObjects programObjects;
for (int version = 0; version < GLShader::NumVersions; version++) {
auto& programObject = programObjects[version];
// Let's go through every shaders and make sure they are ready to go
std::vector< GLuint > shaderGLObjects;
for (auto subShader : program.getShaders()) {
auto object = GLShader::sync(*subShader);
if (object) {
shaderGLObjects.push_back(object->_shaderObjects[version].glshader);
} else {
qCDebug(gpugllogging) << "GLShader::compileBackendProgram - One of the shaders of the program is not compiled?";
return nullptr;
}
}
GLuint glprogram = compileProgram(shaderGLObjects);
if (glprogram == 0) {
return nullptr;
}
programObject.glprogram = glprogram;
makeProgramBindings(programObject);
}
// So far so good, the program versions have all been created successfully
GLShader* object = new GLShader();
object->_shaderObjects = programObjects;
return object;
}
GLShader* GLShader::sync(const Shader& shader) {
GLShader* object = Backend::getGPUObject<GLShader>(shader);
// If GPU object already created then good
if (object) {
return object;
}
// need to have a gpu object?
if (shader.isProgram()) {
GLShader* tempObject = compileBackendProgram(shader);
if (tempObject) {
object = tempObject;
Backend::setGPUObject(shader, object);
}
} else if (shader.isDomain()) {
GLShader* tempObject = compileBackendShader(shader);
if (tempObject) {
object = tempObject;
Backend::setGPUObject(shader, object);
}
}
return object;
}
bool GLShader::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) {
// First make sure the Shader has been compiled
GLShader* object = sync(shader);
if (!object) {
return false;
}
// Apply bindings to all program versions and generate list of slots from default version
for (int version = 0; version < GLShader::NumVersions; version++) {
auto& shaderObject = object->_shaderObjects[version];
if (shaderObject.glprogram) {
Shader::SlotSet buffers;
makeUniformBlockSlots(shaderObject.glprogram, slotBindings, buffers);
Shader::SlotSet uniforms;
Shader::SlotSet textures;
Shader::SlotSet samplers;
makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, samplers);
Shader::SlotSet inputs;
makeInputSlots(shaderObject.glprogram, slotBindings, inputs);
Shader::SlotSet outputs;
makeOutputSlots(shaderObject.glprogram, slotBindings, outputs);
// Define the public slots only from the default version
if (version == 0) {
shader.defineSlots(uniforms, buffers, textures, samplers, inputs, outputs);
} else {
GLShader::UniformMapping mapping;
for (auto srcUniform : shader.getUniforms()) {
mapping[srcUniform._location] = uniforms.findLocation(srcUniform._name);
}
object->_uniformMappings.push_back(mapping);
}
}
}
return true;
}

View file

@ -0,0 +1,52 @@
//
// Created by Bradley Austin Davis on 2016/05/15
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_gl_GLShader_h
#define hifi_gpu_gl_GLShader_h
#include "GLShared.h"
namespace gpu { namespace gl {
class GLShader : public GPUObject {
public:
static GLShader* sync(const Shader& shader);
static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings);
enum Version {
Mono = 0,
NumVersions
};
using ShaderObject = gpu::gl::ShaderObject;
using ShaderObjects = std::array< ShaderObject, NumVersions >;
using UniformMapping = std::map<GLint, GLint>;
using UniformMappingVersions = std::vector<UniformMapping>;
GLShader();
~GLShader();
ShaderObjects _shaderObjects;
UniformMappingVersions _uniformMappings;
GLuint getProgram(Version version = Mono) const {
return _shaderObjects[version].glprogram;
}
GLint getUniformLocation(GLint srcLoc, Version version = Mono) {
// THIS will be used in the future PR as we grow the number of versions
// return _uniformMappings[version][srcLoc];
return srcLoc;
}
};
} }
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,150 @@
//
// Created by Bradley Austin Davis on 2016/05/15
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_GLShared_h
#define hifi_gpu_GLShared_h
#include <gl/Config.h>
#include <gpu/Forward.h>
#include <gpu/Format.h>
#include <gpu/Context.h>
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(gpugllogging)
namespace gpu { namespace gl {
gpu::Size getDedicatedMemory();
ComparisonFunction comparisonFuncFromGL(GLenum func);
State::StencilOp stencilOpFromGL(GLenum stencilOp);
State::BlendOp blendOpFromGL(GLenum blendOp);
State::BlendArg blendArgFromGL(GLenum blendArg);
void getCurrentGLState(State::Data& state);
struct ShaderObject {
GLuint glshader { 0 };
GLuint glprogram { 0 };
GLint transformCameraSlot { -1 };
GLint transformObjectSlot { -1 };
};
int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers);
int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers);
int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs);
int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs);
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject);
GLuint compileProgram(const std::vector<GLuint>& glshaders);
void makeProgramBindings(ShaderObject& shaderObject);
enum GLSyncState {
// The object is currently undergoing no processing, although it's content
// may be out of date, or it's storage may be invalid relative to the
// owning GPU object
Idle,
// The object has been queued for transfer to the GPU
Pending,
// The object has been transferred to the GPU, but is awaiting
// any post transfer operations that may need to occur on the
// primary rendering thread
Transferred,
};
static const GLenum BLEND_OPS_TO_GL[State::NUM_BLEND_OPS] = {
GL_FUNC_ADD,
GL_FUNC_SUBTRACT,
GL_FUNC_REVERSE_SUBTRACT,
GL_MIN,
GL_MAX
};
static const GLenum BLEND_ARGS_TO_GL[State::NUM_BLEND_ARGS] = {
GL_ZERO,
GL_ONE,
GL_SRC_COLOR,
GL_ONE_MINUS_SRC_COLOR,
GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA,
GL_DST_ALPHA,
GL_ONE_MINUS_DST_ALPHA,
GL_DST_COLOR,
GL_ONE_MINUS_DST_COLOR,
GL_SRC_ALPHA_SATURATE,
GL_CONSTANT_COLOR,
GL_ONE_MINUS_CONSTANT_COLOR,
GL_CONSTANT_ALPHA,
GL_ONE_MINUS_CONSTANT_ALPHA,
};
static const GLenum COMPARISON_TO_GL[gpu::NUM_COMPARISON_FUNCS] = {
GL_NEVER,
GL_LESS,
GL_EQUAL,
GL_LEQUAL,
GL_GREATER,
GL_NOTEQUAL,
GL_GEQUAL,
GL_ALWAYS
};
static const GLenum PRIMITIVE_TO_GL[gpu::NUM_PRIMITIVES] = {
GL_POINTS,
GL_LINES,
GL_LINE_STRIP,
GL_TRIANGLES,
GL_TRIANGLE_STRIP,
GL_TRIANGLE_FAN,
};
static const GLenum ELEMENT_TYPE_TO_GL[gpu::NUM_TYPES] = {
GL_FLOAT,
GL_INT,
GL_UNSIGNED_INT,
GL_HALF_FLOAT,
GL_SHORT,
GL_UNSIGNED_SHORT,
GL_BYTE,
GL_UNSIGNED_BYTE,
// Normalized values
GL_INT,
GL_UNSIGNED_INT,
GL_SHORT,
GL_UNSIGNED_SHORT,
GL_BYTE,
GL_UNSIGNED_BYTE
};
bool checkGLError(const char* name = nullptr);
bool checkGLErrorDebug(const char* name = nullptr);
template <typename GPUType>
struct GLObject : public GPUObject {
public:
GLObject(const GPUType& gpuObject, GLuint id) : _gpuObject(gpuObject), _id(id) {}
virtual ~GLObject() { }
const GPUType& _gpuObject;
const GLuint _id;
};
class GlBuffer;
class GLFramebuffer;
class GLPipeline;
class GLQuery;
class GLState;
class GLShader;
class GLTexture;
} } // namespace gpu::gl
#define CHECK_GL_ERROR() gpu::gl::checkGLErrorDebug(__FUNCTION__)
#endif

View file

@ -0,0 +1,233 @@
//
// Created by Bradley Austin Davis on 2016/05/15
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLState.h"
#include "GLBackend.h"
using namespace gpu;
using namespace gpu::gl;
typedef GLState::Command Command;
typedef GLState::CommandPointer CommandPointer;
typedef GLState::Command1<uint32> Command1U;
typedef GLState::Command1<int32> Command1I;
typedef GLState::Command1<bool> Command1B;
typedef GLState::Command1<Vec2> CommandDepthBias;
typedef GLState::Command1<State::DepthTest> CommandDepthTest;
typedef GLState::Command3<State::StencilActivation, State::StencilTest, State::StencilTest> CommandStencil;
typedef GLState::Command1<State::BlendFunction> CommandBlend;
const GLState::Commands makeResetStateCommands();
// NOTE: This must stay in sync with the ordering of the State::Field enum
const GLState::Commands makeResetStateCommands() {
// Since State::DEFAULT is a static defined in another .cpp the initialisation order is random
// and we have a 50/50 chance that State::DEFAULT is not yet initialized.
// Since State::DEFAULT = State::Data() it is much easier to not use the actual State::DEFAULT
// but another State::Data object with a default initialization.
const State::Data DEFAULT = State::Data();
auto depthBiasCommand = std::make_shared<CommandDepthBias>(&GLBackend::do_setStateDepthBias,
Vec2(DEFAULT.depthBias, DEFAULT.depthBiasSlopeScale));
auto stencilCommand = std::make_shared<CommandStencil>(&GLBackend::do_setStateStencil, DEFAULT.stencilActivation,
DEFAULT.stencilTestFront, DEFAULT.stencilTestBack);
// The state commands to reset to default,
// WARNING depending on the order of the State::Field enum
return {
std::make_shared<Command1I>(&GLBackend::do_setStateFillMode, DEFAULT.fillMode),
std::make_shared<Command1I>(&GLBackend::do_setStateCullMode, DEFAULT.cullMode),
std::make_shared<Command1B>(&GLBackend::do_setStateFrontFaceClockwise, DEFAULT.frontFaceClockwise),
std::make_shared<Command1B>(&GLBackend::do_setStateDepthClampEnable, DEFAULT.depthClampEnable),
std::make_shared<Command1B>(&GLBackend::do_setStateScissorEnable, DEFAULT.scissorEnable),
std::make_shared<Command1B>(&GLBackend::do_setStateMultisampleEnable, DEFAULT.multisampleEnable),
std::make_shared<Command1B>(&GLBackend::do_setStateAntialiasedLineEnable, DEFAULT.antialisedLineEnable),
// Depth bias has 2 fields in State but really one call in GLBackend
CommandPointer(depthBiasCommand),
CommandPointer(depthBiasCommand),
std::make_shared<CommandDepthTest>(&GLBackend::do_setStateDepthTest, DEFAULT.depthTest),
// Depth bias has 3 fields in State but really one call in GLBackend
CommandPointer(stencilCommand),
CommandPointer(stencilCommand),
CommandPointer(stencilCommand),
std::make_shared<Command1U>(&GLBackend::do_setStateSampleMask, DEFAULT.sampleMask),
std::make_shared<Command1B>(&GLBackend::do_setStateAlphaToCoverageEnable, DEFAULT.alphaToCoverageEnable),
std::make_shared<CommandBlend>(&GLBackend::do_setStateBlend, DEFAULT.blendFunction),
std::make_shared<Command1U>(&GLBackend::do_setStateColorWriteMask, DEFAULT.colorWriteMask)
};
}
const GLState::Commands GLState::_resetStateCommands = makeResetStateCommands();
void generateFillMode(GLState::Commands& commands, State::FillMode fillMode) {
commands.push_back(std::make_shared<Command1I>(&GLBackend::do_setStateFillMode, int32(fillMode)));
}
void generateCullMode(GLState::Commands& commands, State::CullMode cullMode) {
commands.push_back(std::make_shared<Command1I>(&GLBackend::do_setStateCullMode, int32(cullMode)));
}
void generateFrontFaceClockwise(GLState::Commands& commands, bool isClockwise) {
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateFrontFaceClockwise, isClockwise));
}
void generateDepthClampEnable(GLState::Commands& commands, bool enable) {
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateDepthClampEnable, enable));
}
void generateScissorEnable(GLState::Commands& commands, bool enable) {
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateScissorEnable, enable));
}
void generateMultisampleEnable(GLState::Commands& commands, bool enable) {
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateMultisampleEnable, enable));
}
void generateAntialiasedLineEnable(GLState::Commands& commands, bool enable) {
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateAntialiasedLineEnable, enable));
}
void generateDepthBias(GLState::Commands& commands, const State& state) {
commands.push_back(std::make_shared<CommandDepthBias>(&GLBackend::do_setStateDepthBias, Vec2(state.getDepthBias(), state.getDepthBiasSlopeScale())));
}
void generateDepthTest(GLState::Commands& commands, const State::DepthTest& test) {
commands.push_back(std::make_shared<CommandDepthTest>(&GLBackend::do_setStateDepthTest, int32(test.getRaw())));
}
void generateStencil(GLState::Commands& commands, const State& state) {
commands.push_back(std::make_shared<CommandStencil>(&GLBackend::do_setStateStencil, state.getStencilActivation(), state.getStencilTestFront(), state.getStencilTestBack()));
}
void generateAlphaToCoverageEnable(GLState::Commands& commands, bool enable) {
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateAlphaToCoverageEnable, enable));
}
void generateSampleMask(GLState::Commands& commands, uint32 mask) {
commands.push_back(std::make_shared<Command1U>(&GLBackend::do_setStateSampleMask, mask));
}
void generateBlend(GLState::Commands& commands, const State& state) {
commands.push_back(std::make_shared<CommandBlend>(&GLBackend::do_setStateBlend, state.getBlendFunction()));
}
void generateColorWriteMask(GLState::Commands& commands, uint32 mask) {
commands.push_back(std::make_shared<Command1U>(&GLBackend::do_setStateColorWriteMask, mask));
}
GLState* GLState::sync(const State& state) {
GLState* object = Backend::getGPUObject<GLState>(state);
// If GPU object already created then good
if (object) {
return object;
}
// Else allocate and create the GLState
if (!object) {
object = new GLState();
Backend::setGPUObject(state, object);
}
// here, we need to regenerate something so let's do it all
object->_commands.clear();
object->_stamp = state.getStamp();
object->_signature = state.getSignature();
bool depthBias = false;
bool stencilState = false;
// go thorugh the list of state fields in the State and record the corresponding gl command
for (int i = 0; i < State::NUM_FIELDS; i++) {
if (state.getSignature()[i]) {
switch (i) {
case State::FILL_MODE: {
generateFillMode(object->_commands, state.getFillMode());
break;
}
case State::CULL_MODE: {
generateCullMode(object->_commands, state.getCullMode());
break;
}
case State::DEPTH_BIAS:
case State::DEPTH_BIAS_SLOPE_SCALE: {
depthBias = true;
break;
}
case State::FRONT_FACE_CLOCKWISE: {
generateFrontFaceClockwise(object->_commands, state.isFrontFaceClockwise());
break;
}
case State::DEPTH_CLAMP_ENABLE: {
generateDepthClampEnable(object->_commands, state.isDepthClampEnable());
break;
}
case State::SCISSOR_ENABLE: {
generateScissorEnable(object->_commands, state.isScissorEnable());
break;
}
case State::MULTISAMPLE_ENABLE: {
generateMultisampleEnable(object->_commands, state.isMultisampleEnable());
break;
}
case State::ANTIALISED_LINE_ENABLE: {
generateAntialiasedLineEnable(object->_commands, state.isAntialiasedLineEnable());
break;
}
case State::DEPTH_TEST: {
generateDepthTest(object->_commands, state.getDepthTest());
break;
}
case State::STENCIL_ACTIVATION:
case State::STENCIL_TEST_FRONT:
case State::STENCIL_TEST_BACK: {
stencilState = true;
break;
}
case State::SAMPLE_MASK: {
generateSampleMask(object->_commands, state.getSampleMask());
break;
}
case State::ALPHA_TO_COVERAGE_ENABLE: {
generateAlphaToCoverageEnable(object->_commands, state.isAlphaToCoverageEnabled());
break;
}
case State::BLEND_FUNCTION: {
generateBlend(object->_commands, state);
break;
}
case State::COLOR_WRITE_MASK: {
generateColorWriteMask(object->_commands, state.getColorWriteMask());
break;
}
}
}
}
if (depthBias) {
generateDepthBias(object->_commands, state);
}
if (stencilState) {
generateStencil(object->_commands, state);
}
return object;
}

View file

@ -0,0 +1,73 @@
//
// Created by Bradley Austin Davis on 2016/05/15
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_gl_GLState_h
#define hifi_gpu_gl_GLState_h
#include "GLShared.h"
#include <gpu/State.h>
namespace gpu { namespace gl {
class GLBackend;
class GLState : public GPUObject {
public:
static GLState* sync(const State& state);
class Command {
public:
virtual void run(GLBackend* backend) = 0;
Command() {}
virtual ~Command() {};
};
template <class T> class Command1 : public Command {
public:
typedef void (GLBackend::*GLFunction)(T);
void run(GLBackend* backend) { (backend->*(_func))(_param); }
Command1(GLFunction func, T param) : _func(func), _param(param) {};
GLFunction _func;
T _param;
};
template <class T, class U> class Command2 : public Command {
public:
typedef void (GLBackend::*GLFunction)(T, U);
void run(GLBackend* backend) { (backend->*(_func))(_param0, _param1); }
Command2(GLFunction func, T param0, U param1) : _func(func), _param0(param0), _param1(param1) {};
GLFunction _func;
T _param0;
U _param1;
};
template <class T, class U, class V> class Command3 : public Command {
public:
typedef void (GLBackend::*GLFunction)(T, U, V);
void run(GLBackend* backend) { (backend->*(_func))(_param0, _param1, _param2); }
Command3(GLFunction func, T param0, U param1, V param2) : _func(func), _param0(param0), _param1(param1), _param2(param2) {};
GLFunction _func;
T _param0;
U _param1;
V _param2;
};
typedef std::shared_ptr< Command > CommandPointer;
typedef std::vector< CommandPointer > Commands;
Commands _commands;
Stamp _stamp;
State::Signature _signature;
// The state commands to reset to default,
static const Commands _resetStateCommands;
friend class GLBackend;
};
} }
#endif

View file

@ -1,14 +1,16 @@
//
// Created by Bradley Austin Davis on 2016/04/03
// Created by Bradley Austin Davis on 2016/05/15
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackendShared.h"
#include "GLTexelFormat.h"
using namespace gpu;
using namespace gpu::gl;
GLTexelFormat GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) {
GLTexelFormat texel = { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE };
@ -22,7 +24,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
switch (dstFormat.getDimension()) {
case gpu::SCALAR: {
texel.format = GL_RED;
texel.type = _elementTypeToGLType[dstFormat.getType()];
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
switch (dstFormat.getSemantic()) {
case gpu::RGB:
@ -43,14 +45,14 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
texel.internalFormat = GL_DEPTH24_STENCIL8;
break;
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
}
case gpu::VEC2: {
texel.format = GL_RG;
texel.type = _elementTypeToGLType[dstFormat.getType()];
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
switch (dstFormat.getSemantic()) {
case gpu::RGB:
@ -58,7 +60,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
texel.internalFormat = GL_RG8;
break;
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
@ -67,7 +69,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
case gpu::VEC3: {
texel.format = GL_RGB;
texel.type = _elementTypeToGLType[dstFormat.getType()];
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
switch (dstFormat.getSemantic()) {
case gpu::RGB:
@ -81,7 +83,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
texel.internalFormat = GL_COMPRESSED_SRGB;
break;
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
@ -89,7 +91,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
case gpu::VEC4: {
texel.format = GL_RGBA;
texel.type = _elementTypeToGLType[dstFormat.getType()];
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
switch (srcFormat.getSemantic()) {
case gpu::BGRA:
@ -123,7 +125,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
break;
case gpu::COMPRESSED_SRGBA:
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA;
break;
// FIXME: WE will want to support this later
@ -144,13 +146,13 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
*/
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
}
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
return texel;
} else {
@ -159,7 +161,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
switch (dstFormat.getDimension()) {
case gpu::SCALAR: {
texel.format = GL_RED;
texel.type = _elementTypeToGLType[dstFormat.getType()];
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
switch (dstFormat.getSemantic()) {
case gpu::COMPRESSED_R: {
@ -286,7 +288,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
texel.internalFormat = GL_DEPTH24_STENCIL8;
break;
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
@ -294,7 +296,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
case gpu::VEC2: {
texel.format = GL_RG;
texel.type = _elementTypeToGLType[dstFormat.getType()];
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
switch (dstFormat.getSemantic()) {
case gpu::RGB:
@ -302,7 +304,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
texel.internalFormat = GL_RG8;
break;
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
@ -311,7 +313,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
case gpu::VEC3: {
texel.format = GL_RGB;
texel.type = _elementTypeToGLType[dstFormat.getType()];
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
switch (dstFormat.getSemantic()) {
case gpu::RGB:
@ -329,14 +331,14 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
texel.internalFormat = GL_COMPRESSED_SRGB;
break;
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
}
case gpu::VEC4: {
texel.format = GL_RGBA;
texel.type = _elementTypeToGLType[dstFormat.getType()];
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
switch (dstFormat.getSemantic()) {
case gpu::RGB:
@ -411,13 +413,13 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA;
break;
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
break;
}
default:
qCDebug(gpulogging) << "Unknown combination of texel format";
qCDebug(gpugllogging) << "Unknown combination of texel format";
}
return texel;
}

View file

@ -0,0 +1,32 @@
//
// Created by Bradley Austin Davis on 2016/05/15
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_gl_GLTexelFormat_h
#define hifi_gpu_gl_GLTexelFormat_h
#include "GLShared.h"
namespace gpu { namespace gl {
class GLTexelFormat {
public:
GLenum internalFormat;
GLenum format;
GLenum type;
static GLTexelFormat evalGLTexelFormat(const Element& dstFormat) {
return evalGLTexelFormat(dstFormat, dstFormat);
}
static GLTexelFormat evalGLTexelFormatInternal(const Element& dstFormat);
static GLTexelFormat evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat);
};
} }
#endif

View file

@ -0,0 +1,292 @@
//
// Created by Bradley Austin Davis on 2016/05/15
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLTexture.h"
#include <NumericalConstants.h>
#include "GLTextureTransfer.h"
using namespace gpu;
using namespace gpu::gl;
std::shared_ptr<GLTextureTransferHelper> GLTexture::_textureTransferHelper;
static std::map<uint16, size_t> _textureCountByMips;
static uint16 _currentMaxMipCount { 0 };
// FIXME placeholder for texture memory over-use
#define DEFAULT_MAX_MEMORY_MB 256
const GLenum GLTexture::CUBE_FACE_LAYOUT[6] = {
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
};
const GLenum GLTexture::WRAP_MODES[Sampler::NUM_WRAP_MODES] = {
GL_REPEAT, // WRAP_REPEAT,
GL_MIRRORED_REPEAT, // WRAP_MIRROR,
GL_CLAMP_TO_EDGE, // WRAP_CLAMP,
GL_CLAMP_TO_BORDER, // WRAP_BORDER,
GL_MIRROR_CLAMP_TO_EDGE_EXT // WRAP_MIRROR_ONCE,
};
const GLFilterMode GLTexture::FILTER_MODES[Sampler::NUM_FILTERS] = {
{ GL_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_POINT,
{ GL_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR,
{ GL_LINEAR, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_POINT,
{ GL_LINEAR, GL_LINEAR }, //FILTER_MIN_MAG_LINEAR,
{ GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_MIP_POINT,
{ GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST }, //FILTER_MIN_MAG_POINT_MIP_LINEAR,
{ GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT,
{ GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR }, //FILTER_MIN_POINT_MAG_MIP_LINEAR,
{ GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_MIP_POINT,
{ GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR,
{ GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR }, //FILTER_MIN_MAG_LINEAR_MIP_POINT,
{ GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR }, //FILTER_MIN_MAG_MIP_LINEAR,
{ GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR } //FILTER_ANISOTROPIC,
};
GLenum GLTexture::getGLTextureType(const Texture& texture) {
switch (texture.getType()) {
case Texture::TEX_2D:
return GL_TEXTURE_2D;
break;
case Texture::TEX_CUBE:
return GL_TEXTURE_CUBE_MAP;
break;
default:
qFatal("Unsupported texture type");
}
Q_UNREACHABLE();
return GL_TEXTURE_2D;
}
const std::vector<GLenum>& GLTexture::getFaceTargets(GLenum target) {
static std::vector<GLenum> cubeFaceTargets {
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
};
static std::vector<GLenum> faceTargets {
GL_TEXTURE_2D
};
switch (target) {
case GL_TEXTURE_2D:
return faceTargets;
case GL_TEXTURE_CUBE_MAP:
return cubeFaceTargets;
default:
Q_UNREACHABLE();
break;
}
Q_UNREACHABLE();
return faceTargets;
}
float GLTexture::getMemoryPressure() {
// Check for an explicit memory limit
auto availableTextureMemory = Texture::getAllowedGPUMemoryUsage();
// If no memory limit has been set, use a percentage of the total dedicated memory
if (!availableTextureMemory) {
auto totalGpuMemory = gpu::gl::getDedicatedMemory();
// If no limit has been explicitly set, and the dedicated memory can't be determined,
// just use a fallback fixed value of 256 MB
if (!totalGpuMemory) {
totalGpuMemory = MB_TO_BYTES(DEFAULT_MAX_MEMORY_MB);
}
// Allow 75% of all available GPU memory to be consumed by textures
// FIXME overly conservative?
availableTextureMemory = (totalGpuMemory >> 2) * 3;
}
// Return the consumed texture memory divided by the available texture memory.
auto consumedGpuMemory = Context::getTextureGPUMemoryUsage();
return (float)consumedGpuMemory / (float)availableTextureMemory;
}
GLTexture::DownsampleSource::DownsampleSource(GLTexture* oldTexture) :
_texture(oldTexture ? oldTexture->takeOwnership() : 0),
_minMip(oldTexture ? oldTexture->_minMip : 0),
_maxMip(oldTexture ? oldTexture->_maxMip : 0)
{
}
GLTexture::DownsampleSource::~DownsampleSource() {
if (_texture) {
glDeleteTextures(1, &_texture);
Backend::decrementTextureGPUCount();
}
}
GLTexture::GLTexture(const gpu::Texture& texture, GLuint id, GLTexture* originalTexture, bool transferrable) :
GLObject(texture, id),
_storageStamp(texture.getStamp()),
_target(getGLTextureType(texture)),
_maxMip(texture.maxMip()),
_minMip(texture.minMip()),
_virtualSize(texture.evalTotalSize()),
_transferrable(transferrable),
_downsampleSource(originalTexture)
{
if (_transferrable) {
uint16 mipCount = usedMipLevels();
_currentMaxMipCount = std::max(_currentMaxMipCount, mipCount);
if (!_textureCountByMips.count(mipCount)) {
_textureCountByMips[mipCount] = 1;
} else {
++_textureCountByMips[mipCount];
}
}
Backend::incrementTextureGPUCount();
Backend::updateTextureGPUVirtualMemoryUsage(0, _virtualSize);
}
// Create the texture and allocate storage
GLTexture::GLTexture(const Texture& texture, GLuint id, bool transferrable) :
GLTexture(texture, id, nullptr, transferrable)
{
// FIXME, do during allocation
//Backend::updateTextureGPUMemoryUsage(0, _size);
Backend::setGPUObject(texture, this);
}
// Create the texture and copy from the original higher resolution version
GLTexture::GLTexture(const gpu::Texture& texture, GLuint id, GLTexture* originalTexture) :
GLTexture(texture, id, originalTexture, originalTexture->_transferrable)
{
Q_ASSERT(_minMip >= originalTexture->_minMip);
// Set the GPU object last because that implicitly destroys the originalTexture object
Backend::setGPUObject(texture, this);
}
GLTexture::~GLTexture() {
if (_transferrable) {
uint16 mipCount = usedMipLevels();
Q_ASSERT(_textureCountByMips.count(mipCount));
auto& numTexturesForMipCount = _textureCountByMips[mipCount];
--numTexturesForMipCount;
if (0 == numTexturesForMipCount) {
_textureCountByMips.erase(mipCount);
if (mipCount == _currentMaxMipCount) {
_currentMaxMipCount = (_textureCountByMips.empty() ? 0 : _textureCountByMips.rbegin()->first);
}
}
}
Backend::decrementTextureGPUCount();
Backend::updateTextureGPUMemoryUsage(_size, 0);
Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, 0);
}
void GLTexture::createTexture() {
withPreservedTexture([&] {
allocateStorage();
(void)CHECK_GL_ERROR();
syncSampler();
(void)CHECK_GL_ERROR();
});
}
void GLTexture::setSize(GLuint size) const {
Backend::updateTextureGPUMemoryUsage(_size, size);
const_cast<GLuint&>(_size) = size;
}
bool GLTexture::isInvalid() const {
return _storageStamp < _gpuObject.getStamp();
}
bool GLTexture::isOutdated() const {
return GLSyncState::Idle == _syncState && _contentStamp < _gpuObject.getDataStamp();
}
bool GLTexture::isOverMaxMemory() const {
// FIXME switch to using the max mip count used from the previous frame
if (usedMipLevels() < _currentMaxMipCount) {
return false;
}
Q_ASSERT(usedMipLevels() == _currentMaxMipCount);
if (getMemoryPressure() < 1.0f) {
return false;
}
return true;
}
bool GLTexture::isReady() const {
// If we have an invalid texture, we're never ready
if (isInvalid()) {
return false;
}
// If we're out of date, but the transfer is in progress, report ready
// as a special case
auto syncState = _syncState.load();
if (isOutdated()) {
return Idle != syncState;
}
if (Idle != syncState) {
return false;
}
return true;
}
// Do any post-transfer operations that might be required on the main context / rendering thread
void GLTexture::postTransfer() {
setSyncState(GLSyncState::Idle);
++_transferCount;
//// The public gltexture becaomes available
//_id = _privateTexture;
_downsampleSource.reset();
// At this point the mip pixels have been loaded, we can notify the gpu texture to abandon it's memory
switch (_gpuObject.getType()) {
case Texture::TEX_2D:
for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) {
if (_gpuObject.isStoredMipFaceAvailable(i)) {
_gpuObject.notifyMipFaceGPULoaded(i);
}
}
break;
case Texture::TEX_CUBE:
// transfer pixels from each faces
for (uint8_t f = 0; f < CUBE_NUM_FACES; f++) {
for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) {
if (_gpuObject.isStoredMipFaceAvailable(i, f)) {
_gpuObject.notifyMipFaceGPULoaded(i, f);
}
}
}
break;
default:
qCWarning(gpugllogging) << __FUNCTION__ << " case for Texture Type " << _gpuObject.getType() << " not supported";
break;
}
}
void GLTexture::initTextureTransferHelper() {
_textureTransferHelper = std::make_shared<GLTextureTransferHelper>();
}

View file

@ -0,0 +1,199 @@
//
// Created by Bradley Austin Davis on 2016/05/15
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_gl_GLTexture_h
#define hifi_gpu_gl_GLTexture_h
#include "GLShared.h"
#include "GLTextureTransfer.h"
namespace gpu { namespace gl {
struct GLFilterMode {
GLint minFilter;
GLint magFilter;
};
class GLTexture : public GLObject<Texture> {
public:
static void initTextureTransferHelper();
static std::shared_ptr<GLTextureTransferHelper> _textureTransferHelper;
template <typename GLTextureType>
static GLTextureType* sync(const TexturePointer& texturePointer, bool needTransfer) {
const Texture& texture = *texturePointer;
if (!texture.isDefined()) {
// NO texture definition yet so let's avoid thinking
return nullptr;
}
// If the object hasn't been created, or the object definition is out of date, drop and re-create
GLTextureType* object = Backend::getGPUObject<GLTextureType>(texture);
// Create the texture if need be (force re-creation if the storage stamp changes
// for easier use of immutable storage)
if (!object || object->isInvalid()) {
// This automatically any previous texture
object = new GLTextureType(texture, needTransfer);
if (!object->_transferrable) {
object->createTexture();
object->_contentStamp = texture.getDataStamp();
object->postTransfer();
}
}
// Object maybe doens't neet to be tranasferred after creation
if (!object->_transferrable) {
return object;
}
// If we just did a transfer, return the object after doing post-transfer work
if (GLSyncState::Transferred == object->getSyncState()) {
object->postTransfer();
return object;
}
if (object->isReady()) {
// Do we need to reduce texture memory usage?
if (object->isOverMaxMemory() && texturePointer->incremementMinMip()) {
// WARNING, this code path will essentially `delete this`,
// so no dereferencing of this instance should be done past this point
object = new GLTextureType(texture, object);
_textureTransferHelper->transferTexture(texturePointer);
}
} else if (object->isOutdated()) {
// Object might be outdated, if so, start the transfer
// (outdated objects that are already in transfer will have reported 'true' for ready()
_textureTransferHelper->transferTexture(texturePointer);
}
return object;
}
template <typename GLTextureType>
static GLuint getId(const TexturePointer& texture, bool shouldSync) {
if (!texture) {
return 0;
}
GLTextureType* object { nullptr };
if (shouldSync) {
object = sync<GLTextureType>(texture, shouldSync);
} else {
object = Backend::getGPUObject<GLTextureType>(*texture);
}
if (!object) {
return 0;
}
GLuint result = object->_id;
// Don't return textures that are in transfer state
if ((object->getSyncState() != GLSyncState::Idle) ||
// Don't return transferrable textures that have never completed transfer
(!object->_transferrable || 0 != object->_transferCount)) {
// Will be either 0 or the original texture being downsampled.
result = object->_downsampleSource._texture;
}
return result;
}
// Used by derived classes and helpers to ensure the actual GL object exceeds the lifetime of `this`
GLuint takeOwnership() {
GLuint result = _id;
const_cast<GLuint&>(_id) = 0;
return result;
}
~GLTexture();
const GLuint& _texture { _id };
const Stamp _storageStamp;
const GLenum _target;
const uint16 _maxMip;
const uint16 _minMip;
const GLuint _virtualSize; // theoretical size as expected
Stamp _contentStamp { 0 };
const bool _transferrable;
Size _transferCount { 0 };
struct DownsampleSource {
using Pointer = std::shared_ptr<DownsampleSource>;
DownsampleSource() : _texture(0), _minMip(0), _maxMip(0) {}
DownsampleSource(GLTexture* originalTexture);
~DownsampleSource();
void reset() const { const_cast<GLuint&>(_texture) = 0; }
const GLuint _texture { 0 };
const uint16 _minMip { 0 };
const uint16 _maxMip { 0 };
} _downsampleSource;
GLuint size() const { return _size; }
GLSyncState getSyncState() const { return _syncState; }
// Is the storage out of date relative to the gpu texture?
bool isInvalid() const;
// Is the content out of date relative to the gpu texture?
bool isOutdated() const;
// Is the texture in a state where it can be rendered with no work?
bool isReady() const;
// Execute any post-move operations that must occur only on the main thread
void postTransfer();
bool isOverMaxMemory() const;
protected:
static const size_t CUBE_NUM_FACES = 6;
static const GLenum CUBE_FACE_LAYOUT[6];
static const GLFilterMode FILTER_MODES[Sampler::NUM_FILTERS];
static const GLenum WRAP_MODES[Sampler::NUM_WRAP_MODES];
static const std::vector<GLenum>& getFaceTargets(GLenum textureType);
static GLenum getGLTextureType(const Texture& texture);
// Return a floating point value indicating how much of the allowed
// texture memory we are currently consuming. A value of 0 indicates
// no texture memory usage, while a value of 1 indicates all available / allowed memory
// is consumed. A value above 1 indicates that there is a problem.
static float getMemoryPressure();
const GLuint _size { 0 }; // true size as reported by the gl api
std::atomic<GLSyncState> _syncState { GLSyncState::Idle };
GLTexture(const Texture& texture, GLuint id, bool transferrable);
GLTexture(const Texture& texture, GLuint id, GLTexture* originalTexture);
void setSyncState(GLSyncState syncState) { _syncState = syncState; }
uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; }
void createTexture();
virtual void allocateStorage() const = 0;
virtual void updateSize() const = 0;
virtual void transfer() const = 0;
virtual void syncSampler() const = 0;
virtual void generateMips() const = 0;
virtual void withPreservedTexture(std::function<void()> f) const = 0;
protected:
void setSize(GLuint size) const;
private:
GLTexture(const gpu::Texture& gpuTexture, GLuint id, GLTexture* originalTexture, bool transferrable);
friend class GLTextureTransferHelper;
friend class GLBackend;
};
} }
#endif

View file

@ -5,17 +5,18 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLBackendTextureTransfer.h"
#include "GLBackendShared.h"
#include "GLTextureTransfer.h"
#ifdef THREADED_TEXTURE_TRANSFER
#include <gl/OffscreenGLCanvas.h>
#include <gl/QOpenGLContextWrapper.h>
#endif
#include "GLShared.h"
#include "GLTexture.h"
using namespace gpu;
using namespace gpu::gl;
GLTextureTransferHelper::GLTextureTransferHelper() {
#ifdef THREADED_TEXTURE_TRANSFER
@ -42,7 +43,7 @@ GLTextureTransferHelper::~GLTextureTransferHelper() {
}
void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texturePointer) {
GLBackend::GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(*texturePointer);
GLTexture* object = Backend::getGPUObject<GLTexture>(*texturePointer);
Backend::incrementTextureGPUTransferCount();
#ifdef THREADED_TEXTURE_TRANSFER
GLsync fence { 0 };
@ -50,14 +51,14 @@ void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texture
//glFlush();
TextureTransferPackage package { texturePointer, fence };
object->setSyncState(GLBackend::GLTexture::Pending);
object->setSyncState(GLSyncState::Pending);
queueItem(package);
#else
object->withPreservedTexture([&] {
do_transfer(*object);
});
object->_contentStamp = texturePointer->getDataStamp();
object->setSyncState(GLBackend::GLTexture::Transferred);
object->setSyncState(GLSyncState::Transferred);
#endif
}
@ -75,7 +76,7 @@ void GLTextureTransferHelper::shutdown() {
#endif
}
void GLTextureTransferHelper::do_transfer(GLBackend::GLTexture& texture) {
void GLTextureTransferHelper::do_transfer(GLTexture& texture) {
texture.createTexture();
texture.transfer();
texture.updateSize();
@ -96,7 +97,7 @@ bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
package.fence = 0;
}
GLBackend::GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(*texturePointer);
GLTexture* object = Backend::getGPUObject<GLTexture>(*texturePointer);
do_transfer(*object);
glBindTexture(object->_target, 0);
@ -105,7 +106,7 @@ bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
glDeleteSync(writeSync);
object->_contentStamp = texturePointer->getDataStamp();
object->setSyncState(GLBackend::GLTexture::Transferred);
object->setSyncState(GLSyncState::Transferred);
}
return true;
}

View file

@ -5,11 +5,15 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_gl_GLTextureTransfer_h
#define hifi_gpu_gl_GLTextureTransfer_h
#include <QtGlobal>
#include <QSharedPointer>
#include <QtCore/QSharedPointer>
#include <GenericQueueThread.h>
#include "GLBackendShared.h"
#include "GLShared.h"
#ifdef Q_OS_WIN
#define THREADED_TEXTURE_TRANSFER
@ -17,7 +21,7 @@
class OffscreenGLCanvas;
namespace gpu {
namespace gpu { namespace gl {
struct TextureTransferPackage {
std::weak_ptr<Texture> texture;
@ -26,6 +30,7 @@ struct TextureTransferPackage {
class GLTextureTransferHelper : public GenericQueueThread<TextureTransferPackage> {
public:
using Pointer = std::shared_ptr<GLTextureTransferHelper>;
GLTextureTransferHelper();
~GLTextureTransferHelper();
void transferTexture(const gpu::TexturePointer& texturePointer);
@ -35,10 +40,12 @@ protected:
void setup() override;
void shutdown() override;
bool processQueueItems(const Queue& messages) override;
void do_transfer(GLBackend::GLTexture& texturePointer);
void do_transfer(GLTexture& texturePointer);
private:
QSharedPointer<OffscreenGLCanvas> _canvas;
};
}
} }
#endif

View file

@ -0,0 +1,175 @@
//
// Created by Sam Gateau on 10/27/2014.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GL41Backend.h"
#include <mutex>
#include <queue>
#include <list>
#include <functional>
#include <glm/gtc/type_ptr.hpp>
Q_LOGGING_CATEGORY(gpugl41logging, "hifi.gpu.gl41")
using namespace gpu;
using namespace gpu::gl41;
void GL41Backend::do_draw(Batch& batch, size_t paramOffset) {
Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType];
uint32 numVertices = batch._params[paramOffset + 1]._uint;
uint32 startVertex = batch._params[paramOffset + 0]._uint;
if (isStereo()) {
setupStereoSide(0);
glDrawArrays(mode, startVertex, numVertices);
setupStereoSide(1);
glDrawArrays(mode, startVertex, numVertices);
_stats._DSNumTriangles += 2 * numVertices / 3;
_stats._DSNumDrawcalls += 2;
} else {
glDrawArrays(mode, startVertex, numVertices);
_stats._DSNumTriangles += numVertices / 3;
_stats._DSNumDrawcalls++;
}
_stats._DSNumAPIDrawcalls++;
(void) CHECK_GL_ERROR();
}
void GL41Backend::do_drawIndexed(Batch& batch, size_t paramOffset) {
Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType];
uint32 numIndices = batch._params[paramOffset + 1]._uint;
uint32 startIndex = batch._params[paramOffset + 0]._uint;
GLenum glType = gl::ELEMENT_TYPE_TO_GL[_input._indexBufferType];
auto typeByteSize = TYPE_SIZE[_input._indexBufferType];
GLvoid* indexBufferByteOffset = reinterpret_cast<GLvoid*>(startIndex * typeByteSize + _input._indexBufferOffset);
if (isStereo()) {
setupStereoSide(0);
glDrawElements(mode, numIndices, glType, indexBufferByteOffset);
setupStereoSide(1);
glDrawElements(mode, numIndices, glType, indexBufferByteOffset);
_stats._DSNumTriangles += 2 * numIndices / 3;
_stats._DSNumDrawcalls += 2;
} else {
glDrawElements(mode, numIndices, glType, indexBufferByteOffset);
_stats._DSNumTriangles += numIndices / 3;
_stats._DSNumDrawcalls++;
}
_stats._DSNumAPIDrawcalls++;
(void) CHECK_GL_ERROR();
}
void GL41Backend::do_drawInstanced(Batch& batch, size_t paramOffset) {
GLint numInstances = batch._params[paramOffset + 4]._uint;
Primitive primitiveType = (Primitive)batch._params[paramOffset + 3]._uint;
GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType];
uint32 numVertices = batch._params[paramOffset + 2]._uint;
uint32 startVertex = batch._params[paramOffset + 1]._uint;
if (isStereo()) {
GLint trueNumInstances = 2 * numInstances;
setupStereoSide(0);
glDrawArraysInstancedARB(mode, startVertex, numVertices, numInstances);
setupStereoSide(1);
glDrawArraysInstancedARB(mode, startVertex, numVertices, numInstances);
_stats._DSNumTriangles += (trueNumInstances * numVertices) / 3;
_stats._DSNumDrawcalls += trueNumInstances;
} else {
glDrawArraysInstancedARB(mode, startVertex, numVertices, numInstances);
_stats._DSNumTriangles += (numInstances * numVertices) / 3;
_stats._DSNumDrawcalls += numInstances;
}
_stats._DSNumAPIDrawcalls++;
(void) CHECK_GL_ERROR();
}
void glbackend_glDrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance) {
#if (GPU_INPUT_PROFILE == GPU_CORE_43)
glDrawElementsInstancedBaseVertexBaseInstance(mode, count, type, indices, primcount, basevertex, baseinstance);
#else
glDrawElementsInstanced(mode, count, type, indices, primcount);
#endif
}
void GL41Backend::do_drawIndexedInstanced(Batch& batch, size_t paramOffset) {
GLint numInstances = batch._params[paramOffset + 4]._uint;
GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 3]._uint];
uint32 numIndices = batch._params[paramOffset + 2]._uint;
uint32 startIndex = batch._params[paramOffset + 1]._uint;
// FIXME glDrawElementsInstancedBaseVertexBaseInstance is only available in GL 4.3
// and higher, so currently we ignore this field
uint32 startInstance = batch._params[paramOffset + 0]._uint;
GLenum glType = gl::ELEMENT_TYPE_TO_GL[_input._indexBufferType];
auto typeByteSize = TYPE_SIZE[_input._indexBufferType];
GLvoid* indexBufferByteOffset = reinterpret_cast<GLvoid*>(startIndex * typeByteSize + _input._indexBufferOffset);
if (isStereo()) {
GLint trueNumInstances = 2 * numInstances;
setupStereoSide(0);
glbackend_glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance);
setupStereoSide(1);
glbackend_glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance);
_stats._DSNumTriangles += (trueNumInstances * numIndices) / 3;
_stats._DSNumDrawcalls += trueNumInstances;
} else {
glbackend_glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance);
_stats._DSNumTriangles += (numInstances * numIndices) / 3;
_stats._DSNumDrawcalls += numInstances;
}
_stats._DSNumAPIDrawcalls++;
(void)CHECK_GL_ERROR();
}
void GL41Backend::do_multiDrawIndirect(Batch& batch, size_t paramOffset) {
#if (GPU_INPUT_PROFILE == GPU_CORE_43)
uint commandCount = batch._params[paramOffset + 0]._uint;
GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 1]._uint];
glMultiDrawArraysIndirect(mode, reinterpret_cast<GLvoid*>(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride);
_stats._DSNumDrawcalls += commandCount;
_stats._DSNumAPIDrawcalls++;
#else
// FIXME implement the slow path
#endif
(void)CHECK_GL_ERROR();
}
void GL41Backend::do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset) {
#if (GPU_INPUT_PROFILE == GPU_CORE_43)
uint commandCount = batch._params[paramOffset + 0]._uint;
GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 1]._uint];
GLenum indexType = gl::ELEMENT_TYPE_TO_GL[_input._indexBufferType];
glMultiDrawElementsIndirect(mode, indexType, reinterpret_cast<GLvoid*>(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride);
_stats._DSNumDrawcalls += commandCount;
_stats._DSNumAPIDrawcalls++;
#else
// FIXME implement the slow path
#endif
(void)CHECK_GL_ERROR();
}

View file

@ -0,0 +1,96 @@
//
// GL41Backend.h
// libraries/gpu/src/gpu
//
// Created by Sam Gateau on 10/27/2014.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_41_GL41Backend_h
#define hifi_gpu_41_GL41Backend_h
#include <gl/Config.h>
#include "../gl/GLBackend.h"
#include "../gl/GLTexture.h"
#define GPU_CORE_41 410
#define GPU_CORE_43 430
#ifdef Q_OS_MAC
#define GPU_INPUT_PROFILE GPU_CORE_41
#else
#define GPU_INPUT_PROFILE GPU_CORE_43
#endif
namespace gpu { namespace gl41 {
class GL41Backend : public gl::GLBackend {
using Parent = gl::GLBackend;
// Context Backend static interface required
friend class Context;
public:
explicit GL41Backend(bool syncCache) : Parent(syncCache) {}
GL41Backend() : Parent() {}
class GL41Texture : public gpu::gl::GLTexture {
using Parent = gpu::gl::GLTexture;
GLuint allocate();
public:
GL41Texture(const Texture& buffer, bool transferrable);
GL41Texture(const Texture& buffer, GL41Texture* original);
protected:
void transferMip(uint16_t mipLevel, uint8_t face = 0) const;
void allocateStorage() const override;
void updateSize() const override;
void transfer() const override;
void syncSampler() const override;
void generateMips() const override;
void withPreservedTexture(std::function<void()> f) const override;
};
protected:
GLuint getFramebufferID(const FramebufferPointer& framebuffer) override;
gl::GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override;
GLuint getBufferID(const Buffer& buffer) override;
gl::GLBuffer* syncGPUObject(const Buffer& buffer) override;
GLuint getTextureID(const TexturePointer& texture, bool needTransfer = true) override;
gl::GLTexture* syncGPUObject(const TexturePointer& texture, bool sync = true) override;
GLuint getQueryID(const QueryPointer& query) override;
gl::GLQuery* syncGPUObject(const Query& query) override;
// Draw Stage
void do_draw(Batch& batch, size_t paramOffset) override;
void do_drawIndexed(Batch& batch, size_t paramOffset) override;
void do_drawInstanced(Batch& batch, size_t paramOffset) override;
void do_drawIndexedInstanced(Batch& batch, size_t paramOffset) override;
void do_multiDrawIndirect(Batch& batch, size_t paramOffset) override;
void do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset) override;
// Input Stage
void updateInput() override;
// Synchronize the state cache of this Backend with the actual real state of the GL Context
void transferTransformState(const Batch& batch) const override;
void initTransform() override;
void updateTransform(const Batch& batch);
void resetTransformStage();
// Output stage
void do_blit(Batch& batch, size_t paramOffset) override;
};
} }
Q_DECLARE_LOGGING_CATEGORY(gpugl41logging)
#endif

Some files were not shown because too many files have changed in this diff Show more