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:
commit
3088a84035
195 changed files with 6689 additions and 5946 deletions
LICENSE
assignment-client/src
cmake/macros
domain-server/src
interface
CMakeLists.txt
resources
src
libraries
animation
avatars/src
display-plugins
CMakeLists.txt
src/display-plugins
entities-renderer
entities
fbx
gl/src/gl
gpu-gl
CMakeLists.txt
src/gpu
gl
GLBackend.cppGLBackend.hGLBackendInput.cppGLBackendOutput.cppGLBackendPipeline.cppGLBackendQuery.cppGLBackendState.cppGLBackendTexture.cppGLBackendTransform.cppGLBuffer.cppGLBuffer.hGLFramebuffer.cppGLFramebuffer.hGLPipeline.cppGLPipeline.hGLQuery.hGLShader.cppGLShader.hGLShared.cppGLShared.hGLState.cppGLState.hGLTexelFormat.cppGLTexelFormat.hGLTexture.cppGLTexture.hGLTextureTransfer.cppGLTextureTransfer.h
gl41
2
LICENSE
2
LICENSE
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
|
|
@ -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.";
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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...";
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -33,7 +33,6 @@ signals:
|
|||
protected:
|
||||
void displayAddressOfflineMessage();
|
||||
void displayAddressNotFoundMessage();
|
||||
void hide();
|
||||
|
||||
Q_INVOKABLE void loadAddress(const QString& address);
|
||||
Q_INVOKABLE void loadHome();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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() {
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QDesktopWidget>
|
||||
|
||||
#include <gpu/GLBackend.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include <MatrixStack.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -126,7 +126,7 @@ protected:
|
|||
}
|
||||
|
||||
private:
|
||||
void setupEntitiesScriptEngine();
|
||||
void resetEntitiesScriptEngine();
|
||||
|
||||
void addEntityToScene(EntityItemPointer entity);
|
||||
bool findBestZoneAndMaybeContainingEntities(const glm::vec3& avatarPosition, QVector<EntityItemID>* entitiesContainingAvatar);
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -36,9 +36,6 @@ EntityItemProperties BoxEntityItem::getProperties(EntityPropertyFlags desiredPro
|
|||
properties._color = getXColor();
|
||||
properties._colorChanged = false;
|
||||
|
||||
properties._glowLevel = getGlowLevel();
|
||||
properties._glowLevelChanged = false;
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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("");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -53,10 +53,6 @@ EntityItemProperties LineEntityItem::getProperties(EntityPropertyFlags desiredPr
|
|||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(linePoints, getLinePoints);
|
||||
|
||||
|
||||
properties._glowLevel = getGlowLevel();
|
||||
properties._glowLevelChanged = false;
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -37,7 +37,6 @@ private:
|
|||
bool _foundOld;
|
||||
bool _foundNew;
|
||||
bool _removeOld;
|
||||
bool _dontMove;
|
||||
quint64 _changeTime;
|
||||
|
||||
AACube _oldEntityCube;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
8
libraries/gpu-gl/CMakeLists.txt
Normal file
8
libraries/gpu-gl/CMakeLists.txt
Normal 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()
|
547
libraries/gpu-gl/src/gpu/gl/GLBackend.cpp
Normal file
547
libraries/gpu-gl/src/gpu/gl/GLBackend.cpp
Normal 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();
|
||||
}
|
332
libraries/gpu-gl/src/gpu/gl/GLBackend.h
Normal file
332
libraries/gpu-gl/src/gpu/gl/GLBackend.h
Normal 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
|
152
libraries/gpu-gl/src/gpu/gl/GLBackendInput.cpp
Normal file
152
libraries/gpu-gl/src/gpu/gl/GLBackendInput.cpp
Normal 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();
|
||||
}
|
165
libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp
Normal file
165
libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp
Normal 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, ¤tFBO);
|
||||
|
||||
_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();
|
||||
}
|
89
libraries/gpu/src/gpu/GLBackendPipeline.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp
Executable file → Normal file
89
libraries/gpu/src/gpu/GLBackendPipeline.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp
Executable file → Normal 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;
|
49
libraries/gpu-gl/src/gpu/gl/GLBackendQuery.cpp
Normal file
49
libraries/gpu-gl/src/gpu/gl/GLBackendQuery.cpp
Normal 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() {
|
||||
}
|
309
libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp
Normal file
309
libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp
Normal 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();
|
||||
}
|
||||
|
30
libraries/gpu-gl/src/gpu/gl/GLBackendTexture.cpp
Normal file
30
libraries/gpu-gl/src/gpu/gl/GLBackendTexture.cpp
Normal 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();
|
||||
}
|
78
libraries/gpu/src/gpu/GLBackendTransform.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendTransform.cpp
Executable file → Normal file
78
libraries/gpu/src/gpu/GLBackendTransform.cpp → libraries/gpu-gl/src/gpu/gl/GLBackendTransform.cpp
Executable file → Normal 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)) {
|
28
libraries/gpu-gl/src/gpu/gl/GLBuffer.cpp
Normal file
28
libraries/gpu-gl/src/gpu/gl/GLBuffer.cpp
Normal 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);
|
||||
}
|
||||
|
57
libraries/gpu-gl/src/gpu/gl/GLBuffer.h
Normal file
57
libraries/gpu-gl/src/gpu/gl/GLBuffer.h
Normal 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
|
39
libraries/gpu-gl/src/gpu/gl/GLFramebuffer.cpp
Normal file
39
libraries/gpu-gl/src/gpu/gl/GLFramebuffer.cpp
Normal 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;
|
||||
}
|
76
libraries/gpu-gl/src/gpu/gl/GLFramebuffer.h
Normal file
76
libraries/gpu-gl/src/gpu/gl/GLFramebuffer.h
Normal 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
|
48
libraries/gpu-gl/src/gpu/gl/GLPipeline.cpp
Normal file
48
libraries/gpu-gl/src/gpu/gl/GLPipeline.cpp
Normal 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;
|
||||
}
|
26
libraries/gpu-gl/src/gpu/gl/GLPipeline.h
Normal file
26
libraries/gpu-gl/src/gpu/gl/GLPipeline.h
Normal 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
|
57
libraries/gpu-gl/src/gpu/gl/GLQuery.h
Normal file
57
libraries/gpu-gl/src/gpu/gl/GLQuery.h
Normal 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
|
182
libraries/gpu-gl/src/gpu/gl/GLShader.cpp
Normal file
182
libraries/gpu-gl/src/gpu/gl/GLShader.cpp
Normal 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;
|
||||
}
|
||||
|
52
libraries/gpu-gl/src/gpu/gl/GLShader.h
Normal file
52
libraries/gpu-gl/src/gpu/gl/GLShader.h
Normal 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
|
1176
libraries/gpu/src/gpu/GLBackendShader.cpp → libraries/gpu-gl/src/gpu/gl/GLShared.cpp
Executable file → Normal file
1176
libraries/gpu/src/gpu/GLBackendShader.cpp → libraries/gpu-gl/src/gpu/gl/GLShared.cpp
Executable file → Normal file
File diff suppressed because it is too large
Load diff
150
libraries/gpu-gl/src/gpu/gl/GLShared.h
Normal file
150
libraries/gpu-gl/src/gpu/gl/GLShared.h
Normal 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
|
||||
|
||||
|
||||
|
233
libraries/gpu-gl/src/gpu/gl/GLState.cpp
Normal file
233
libraries/gpu-gl/src/gpu/gl/GLState.cpp
Normal 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;
|
||||
}
|
||||
|
73
libraries/gpu-gl/src/gpu/gl/GLState.h
Normal file
73
libraries/gpu-gl/src/gpu/gl/GLState.h
Normal 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
|
|
@ -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;
|
||||
}
|
32
libraries/gpu-gl/src/gpu/gl/GLTexelFormat.h
Normal file
32
libraries/gpu-gl/src/gpu/gl/GLTexelFormat.h
Normal 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
|
292
libraries/gpu-gl/src/gpu/gl/GLTexture.cpp
Normal file
292
libraries/gpu-gl/src/gpu/gl/GLTexture.cpp
Normal 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>();
|
||||
}
|
199
libraries/gpu-gl/src/gpu/gl/GLTexture.h
Normal file
199
libraries/gpu-gl/src/gpu/gl/GLTexture.h
Normal 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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
175
libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp
Normal file
175
libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp
Normal 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();
|
||||
}
|
96
libraries/gpu-gl/src/gpu/gl41/GL41Backend.h
Normal file
96
libraries/gpu-gl/src/gpu/gl41/GL41Backend.h
Normal 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
Loading…
Reference in a new issue