mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 16:41:02 +02:00
Merge branch 'master' into 20872
This commit is contained in:
commit
b33d28852b
69 changed files with 1774 additions and 1234 deletions
|
@ -144,6 +144,9 @@ void Agent::run() {
|
||||||
connect(messagesThread, &QThread::started, messagesClient.data(), &MessagesClient::init);
|
connect(messagesThread, &QThread::started, messagesClient.data(), &MessagesClient::init);
|
||||||
messagesThread->start();
|
messagesThread->start();
|
||||||
|
|
||||||
|
// make sure we hear about connected nodes so we can grab an ATP script if a request is pending
|
||||||
|
connect(nodeList.data(), &LimitedNodeList::nodeActivated, this, &Agent::nodeActivated);
|
||||||
|
|
||||||
nodeList->addSetOfNodeTypesToNodeInterestSet({
|
nodeList->addSetOfNodeTypesToNodeInterestSet({
|
||||||
NodeType::AudioMixer, NodeType::AvatarMixer, NodeType::EntityServer, NodeType::MessagesMixer, NodeType::AssetServer
|
NodeType::AudioMixer, NodeType::AvatarMixer, NodeType::EntityServer, NodeType::MessagesMixer, NodeType::AssetServer
|
||||||
});
|
});
|
||||||
|
@ -164,52 +167,85 @@ void Agent::requestScript() {
|
||||||
scriptURL = QUrl(_payload);
|
scriptURL = QUrl(_payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup a network access manager and
|
// make sure this is not a script request for the file scheme
|
||||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
if (scriptURL.scheme() == URL_SCHEME_FILE) {
|
||||||
|
qWarning() << "Cannot load script for Agent from local filesystem.";
|
||||||
|
scriptRequestFinished();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QNetworkDiskCache* cache = new QNetworkDiskCache();
|
auto request = ResourceManager::createResourceRequest(this, scriptURL);
|
||||||
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
|
||||||
cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "agentCache");
|
|
||||||
networkAccessManager.setCache(cache);
|
|
||||||
|
|
||||||
QNetworkRequest networkRequest = QNetworkRequest(scriptURL);
|
if (!request) {
|
||||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
qWarning() << "Could not create ResourceRequest for Agent script at" << scriptURL.toString();
|
||||||
|
scriptRequestFinished();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// setup a timeout for script request
|
// setup a timeout for script request
|
||||||
static const int SCRIPT_TIMEOUT_MS = 10000;
|
static const int SCRIPT_TIMEOUT_MS = 10000;
|
||||||
_scriptRequestTimeout = new QTimer(this);
|
_scriptRequestTimeout = new QTimer;
|
||||||
connect(_scriptRequestTimeout, &QTimer::timeout, this, &Agent::scriptRequestFinished);
|
connect(_scriptRequestTimeout, &QTimer::timeout, this, &Agent::scriptRequestFinished);
|
||||||
_scriptRequestTimeout->start(SCRIPT_TIMEOUT_MS);
|
_scriptRequestTimeout->start(SCRIPT_TIMEOUT_MS);
|
||||||
|
|
||||||
qDebug() << "Downloading script at" << scriptURL.toString();
|
connect(request, &ResourceRequest::finished, this, &Agent::scriptRequestFinished);
|
||||||
QNetworkReply* reply = networkAccessManager.get(networkRequest);
|
|
||||||
connect(reply, &QNetworkReply::finished, this, &Agent::scriptRequestFinished);
|
if (scriptURL.scheme() == URL_SCHEME_ATP) {
|
||||||
|
// we have an ATP URL for the script - if we're not currently connected to the AssetServer
|
||||||
|
// then wait for the nodeConnected signal to fire off the request
|
||||||
|
|
||||||
|
auto assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||||
|
if (!assetServer || !assetServer->getActiveSocket()) {
|
||||||
|
qDebug() << "Waiting to connect to Asset Server for ATP script download.";
|
||||||
|
_pendingScriptRequest = request;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qInfo() << "Requesting script at URL" << qPrintable(request->getUrl().toString());
|
||||||
|
|
||||||
|
request->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Agent::nodeActivated(SharedNodePointer activatedNode) {
|
||||||
|
if (_pendingScriptRequest) {
|
||||||
|
qInfo() << "Requesting script at URL" << qPrintable(_pendingScriptRequest->getUrl().toString());
|
||||||
|
|
||||||
|
_pendingScriptRequest->send();
|
||||||
|
|
||||||
|
_pendingScriptRequest = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Agent::scriptRequestFinished() {
|
void Agent::scriptRequestFinished() {
|
||||||
auto reply = qobject_cast<QNetworkReply*>(sender());
|
auto request = qobject_cast<ResourceRequest*>(sender());
|
||||||
|
|
||||||
_scriptRequestTimeout->stop();
|
// stop the script request timeout, if it's running
|
||||||
|
if (_scriptRequestTimeout) {
|
||||||
|
QMetaObject::invokeMethod(_scriptRequestTimeout, "stop");
|
||||||
|
_scriptRequestTimeout->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
if (reply && reply->error() == QNetworkReply::NoError) {
|
if (request && request->getResult() == ResourceRequest::Success) {
|
||||||
_scriptContents = reply->readAll();
|
_scriptContents = request->getData();
|
||||||
qDebug() << "Downloaded script:" << _scriptContents;
|
qInfo() << "Downloaded script:" << _scriptContents;
|
||||||
|
|
||||||
// we could just call executeScript directly - we use a QueuedConnection to allow scriptRequestFinished
|
// we could just call executeScript directly - we use a QueuedConnection to allow scriptRequestFinished
|
||||||
// to return before calling executeScript
|
// to return before calling executeScript
|
||||||
QMetaObject::invokeMethod(this, "executeScript", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "executeScript", Qt::QueuedConnection);
|
||||||
} else {
|
} else {
|
||||||
if (reply) {
|
if (request) {
|
||||||
qDebug() << "Failed to download script at" << reply->url().toString() << " - bailing on assignment.";
|
qWarning() << "Failed to download script at" << request->getUrl().toString() << " - bailing on assignment.";
|
||||||
qDebug() << "QNetworkReply error was" << reply->errorString();
|
qWarning() << "ResourceRequest error was" << request->getResult();
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Failed to download script - request timed out. Bailing on assignment.";
|
qWarning() << "Failed to download script - request timed out. Bailing on assignment.";
|
||||||
}
|
}
|
||||||
|
|
||||||
setFinished(true);
|
setFinished(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
reply->deleteLater();
|
request->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Agent::executeScript() {
|
void Agent::executeScript() {
|
||||||
|
|
|
@ -69,6 +69,8 @@ private slots:
|
||||||
|
|
||||||
void processAgentAvatarAndAudio(float deltaTime);
|
void processAgentAvatarAndAudio(float deltaTime);
|
||||||
|
|
||||||
|
void nodeActivated(SharedNodePointer activatedNode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<ScriptEngine> _scriptEngine;
|
std::unique_ptr<ScriptEngine> _scriptEngine;
|
||||||
EntityEditPacketSender _entityEditSender;
|
EntityEditPacketSender _entityEditSender;
|
||||||
|
@ -84,6 +86,7 @@ private:
|
||||||
|
|
||||||
QString _scriptContents;
|
QString _scriptContents;
|
||||||
QTimer* _scriptRequestTimeout { nullptr };
|
QTimer* _scriptRequestTimeout { nullptr };
|
||||||
|
ResourceRequest* _pendingScriptRequest { nullptr };
|
||||||
bool _isListeningToAudioStream = false;
|
bool _isListeningToAudioStream = false;
|
||||||
SharedSoundPointer _avatarSound;
|
SharedSoundPointer _avatarSound;
|
||||||
int _numAvatarSoundSentBytes = 0;
|
int _numAvatarSoundSentBytes = 0;
|
||||||
|
|
|
@ -122,67 +122,49 @@ void AssetServer::completeSetup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// load whatever mappings we currently have from the local file
|
// load whatever mappings we currently have from the local file
|
||||||
loadMappingsFromFile();
|
if (loadMappingsFromFile()) {
|
||||||
|
qInfo() << "Serving files from: " << _filesDirectory.path();
|
||||||
|
|
||||||
qInfo() << "Serving files from: " << _filesDirectory.path();
|
// Check the asset directory to output some information about what we have
|
||||||
|
auto files = _filesDirectory.entryList(QDir::Files);
|
||||||
|
|
||||||
// Check the asset directory to output some information about what we have
|
QRegExp hashFileRegex { ASSET_HASH_REGEX_STRING };
|
||||||
auto files = _filesDirectory.entryList(QDir::Files);
|
auto hashedFiles = files.filter(hashFileRegex);
|
||||||
|
|
||||||
QRegExp hashFileRegex { ASSET_HASH_REGEX_STRING };
|
qInfo() << "There are" << hashedFiles.size() << "asset files in the asset directory.";
|
||||||
auto hashedFiles = files.filter(hashFileRegex);
|
|
||||||
|
|
||||||
qInfo() << "There are" << hashedFiles.size() << "asset files in the asset directory.";
|
if (_fileMappings.count() > 0) {
|
||||||
|
cleanupUnmappedFiles();
|
||||||
|
}
|
||||||
|
|
||||||
performMappingMigration();
|
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
|
||||||
|
} else {
|
||||||
|
qCritical() << "Asset Server assignment will not continue because mapping file could not be loaded.";
|
||||||
|
setFinished(true);
|
||||||
|
}
|
||||||
|
|
||||||
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetServer::performMappingMigration() {
|
void AssetServer::cleanupUnmappedFiles() {
|
||||||
QRegExp hashFileRegex { "^[a-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}(\\.[\\w]+)+$" };
|
QRegExp hashFileRegex { "^[a-f0-9]{" + QString::number(SHA256_HASH_HEX_LENGTH) + "}" };
|
||||||
|
|
||||||
auto files = _resourcesDirectory.entryInfoList(QDir::Files);
|
auto files = _filesDirectory.entryInfoList(QDir::Files);
|
||||||
|
|
||||||
|
// grab the currently mapped hashes
|
||||||
|
auto mappedHashes = _fileMappings.values();
|
||||||
|
|
||||||
|
qInfo() << "Performing unmapped asset cleanup.";
|
||||||
|
|
||||||
for (const auto& fileInfo : files) {
|
for (const auto& fileInfo : files) {
|
||||||
if (hashFileRegex.exactMatch(fileInfo.fileName())) {
|
if (hashFileRegex.exactMatch(fileInfo.fileName())) {
|
||||||
// we have a pre-mapping file that we should migrate to the new mapping system
|
if (!mappedHashes.contains(fileInfo.fileName())) {
|
||||||
qDebug() << "Migrating pre-mapping file" << fileInfo.fileName();
|
// remove the unmapped file
|
||||||
|
QFile removeableFile { fileInfo.absoluteFilePath() };
|
||||||
|
|
||||||
// rename the file to the same name with no extension
|
if (removeableFile.remove()) {
|
||||||
QFile oldFile { fileInfo.absoluteFilePath() };
|
qDebug() << "\tDeleted" << fileInfo.fileName() << "from asset files directory since it is unmapped.";
|
||||||
|
|
||||||
auto oldAbsolutePath = fileInfo.absoluteFilePath();
|
|
||||||
auto oldFilename = fileInfo.fileName();
|
|
||||||
auto hash = oldFilename.left(SHA256_HASH_HEX_LENGTH);
|
|
||||||
auto fullExtension = oldFilename.mid(oldFilename.indexOf('.'));
|
|
||||||
|
|
||||||
qDebug() << "\tMoving" << oldAbsolutePath << "to" << oldAbsolutePath.replace(fullExtension, "");
|
|
||||||
|
|
||||||
bool renamed = oldFile.copy(_filesDirectory.filePath(hash));
|
|
||||||
if (!renamed) {
|
|
||||||
qWarning() << "\tCould not migrate pre-mapping file" << fileInfo.fileName();
|
|
||||||
} else {
|
|
||||||
qDebug() << "\tRenamed pre-mapping file" << fileInfo.fileName();
|
|
||||||
|
|
||||||
// add a new mapping with the old extension and a truncated version of the hash
|
|
||||||
const int TRUNCATED_HASH_NUM_CHAR = 16;
|
|
||||||
auto fakeFileName = "/" + hash.left(TRUNCATED_HASH_NUM_CHAR) + fullExtension;
|
|
||||||
|
|
||||||
qDebug() << "\tAdding a migration mapping from" << fakeFileName << "to" << hash;
|
|
||||||
|
|
||||||
auto it = _fileMappings.find(fakeFileName);
|
|
||||||
if (it == _fileMappings.end()) {
|
|
||||||
_fileMappings[fakeFileName] = hash;
|
|
||||||
|
|
||||||
if (writeMappingsToFile()) {
|
|
||||||
// mapping added and persisted, we can remove the migrated file
|
|
||||||
oldFile.remove();
|
|
||||||
qDebug() << "\tMigration completed for" << oldFilename;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "\tCould not add migration mapping for" << hash << "since a mapping for" << fakeFileName
|
qDebug() << "\tAttempt to delete unmapped file" << fileInfo.fileName() << "failed";
|
||||||
<< "already exists.";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -451,7 +433,7 @@ void AssetServer::sendStatsPacket() {
|
||||||
|
|
||||||
static const QString MAP_FILE_NAME = "map.json";
|
static const QString MAP_FILE_NAME = "map.json";
|
||||||
|
|
||||||
void AssetServer::loadMappingsFromFile() {
|
bool AssetServer::loadMappingsFromFile() {
|
||||||
|
|
||||||
auto mapFilePath = _resourcesDirectory.absoluteFilePath(MAP_FILE_NAME);
|
auto mapFilePath = _resourcesDirectory.absoluteFilePath(MAP_FILE_NAME);
|
||||||
|
|
||||||
|
@ -488,15 +470,17 @@ void AssetServer::loadMappingsFromFile() {
|
||||||
}
|
}
|
||||||
|
|
||||||
qInfo() << "Loaded" << _fileMappings.count() << "mappings from map file at" << mapFilePath;
|
qInfo() << "Loaded" << _fileMappings.count() << "mappings from map file at" << mapFilePath;
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qCritical() << "Failed to read mapping file at" << mapFilePath << "- assignment will not continue.";
|
qCritical() << "Failed to read mapping file at" << mapFilePath;
|
||||||
setFinished(true);
|
return false;
|
||||||
} else {
|
} else {
|
||||||
qInfo() << "No existing mappings loaded from file since no file was found at" << mapFilePath;
|
qInfo() << "No existing mappings loaded from file since no file was found at" << mapFilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AssetServer::writeMappingsToFile() {
|
bool AssetServer::writeMappingsToFile() {
|
||||||
|
@ -566,6 +550,8 @@ bool AssetServer::deleteMappings(AssetPathList& paths) {
|
||||||
// take a copy of the current mappings in case persistence of these deletes fails
|
// take a copy of the current mappings in case persistence of these deletes fails
|
||||||
auto oldMappings = _fileMappings;
|
auto oldMappings = _fileMappings;
|
||||||
|
|
||||||
|
QSet<QString> hashesToCheckForDeletion;
|
||||||
|
|
||||||
// enumerate the paths to delete and remove them all
|
// enumerate the paths to delete and remove them all
|
||||||
for (auto& path : paths) {
|
for (auto& path : paths) {
|
||||||
|
|
||||||
|
@ -579,6 +565,9 @@ bool AssetServer::deleteMappings(AssetPathList& paths) {
|
||||||
|
|
||||||
while (it != _fileMappings.end()) {
|
while (it != _fileMappings.end()) {
|
||||||
if (it.key().startsWith(path)) {
|
if (it.key().startsWith(path)) {
|
||||||
|
// add this hash to the list we need to check for asset removal from the server
|
||||||
|
hashesToCheckForDeletion << it.value().toString();
|
||||||
|
|
||||||
it = _fileMappings.erase(it);
|
it = _fileMappings.erase(it);
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
|
@ -595,6 +584,9 @@ bool AssetServer::deleteMappings(AssetPathList& paths) {
|
||||||
} else {
|
} else {
|
||||||
auto oldMapping = _fileMappings.take(path);
|
auto oldMapping = _fileMappings.take(path);
|
||||||
if (!oldMapping.isNull()) {
|
if (!oldMapping.isNull()) {
|
||||||
|
// add this hash to the list we need to check for asset removal from server
|
||||||
|
hashesToCheckForDeletion << oldMapping.toString();
|
||||||
|
|
||||||
qDebug() << "Deleted a mapping:" << path << "=>" << oldMapping.toString();
|
qDebug() << "Deleted a mapping:" << path << "=>" << oldMapping.toString();
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Unable to delete a mapping that was not found:" << path;
|
qDebug() << "Unable to delete a mapping that was not found:" << path;
|
||||||
|
@ -605,6 +597,30 @@ bool AssetServer::deleteMappings(AssetPathList& paths) {
|
||||||
// deleted the old mappings, attempt to persist to file
|
// deleted the old mappings, attempt to persist to file
|
||||||
if (writeMappingsToFile()) {
|
if (writeMappingsToFile()) {
|
||||||
// persistence succeeded we are good to go
|
// persistence succeeded we are good to go
|
||||||
|
|
||||||
|
// grab the current mapped hashes
|
||||||
|
auto mappedHashes = _fileMappings.values();
|
||||||
|
|
||||||
|
// enumerate the mapped hashes and clear the list of hashes to check for anything that's present
|
||||||
|
for (auto& hashVariant : mappedHashes) {
|
||||||
|
auto it = hashesToCheckForDeletion.find(hashVariant.toString());
|
||||||
|
if (it != hashesToCheckForDeletion.end()) {
|
||||||
|
hashesToCheckForDeletion.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we now have a set of hashes that are unmapped - we will delete those asset files
|
||||||
|
for (auto& hash : hashesToCheckForDeletion) {
|
||||||
|
// remove the unmapped file
|
||||||
|
QFile removeableFile { _filesDirectory.absoluteFilePath(hash) };
|
||||||
|
|
||||||
|
if (removeableFile.remove()) {
|
||||||
|
qDebug() << "\tDeleted" << hash << "from asset files directory since it is now unmapped.";
|
||||||
|
} else {
|
||||||
|
qDebug() << "\tAttempt to delete unmapped file" << hash << "failed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Failed to persist deleted mappings, rolling back";
|
qWarning() << "Failed to persist deleted mappings, rolling back";
|
||||||
|
|
|
@ -48,7 +48,7 @@ private:
|
||||||
void handleRenameMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket);
|
void handleRenameMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket);
|
||||||
|
|
||||||
// Mapping file operations must be called from main assignment thread only
|
// Mapping file operations must be called from main assignment thread only
|
||||||
void loadMappingsFromFile();
|
bool loadMappingsFromFile();
|
||||||
bool writeMappingsToFile();
|
bool writeMappingsToFile();
|
||||||
|
|
||||||
/// Set the mapping for path to hash
|
/// Set the mapping for path to hash
|
||||||
|
@ -60,7 +60,8 @@ private:
|
||||||
/// Rename mapping from `oldPath` to `newPath`. Returns true if successful
|
/// Rename mapping from `oldPath` to `newPath`. Returns true if successful
|
||||||
bool renameMapping(AssetPath oldPath, AssetPath newPath);
|
bool renameMapping(AssetPath oldPath, AssetPath newPath);
|
||||||
|
|
||||||
void performMappingMigration();
|
// deletes any unmapped files from the local asset directory
|
||||||
|
void cleanupUnmappedFiles();
|
||||||
|
|
||||||
Mappings _fileMappings;
|
Mappings _fileMappings;
|
||||||
|
|
||||||
|
|
|
@ -870,7 +870,7 @@ function saveSettings() {
|
||||||
// check if we've set the basic http password - if so convert it to base64
|
// check if we've set the basic http password - if so convert it to base64
|
||||||
if (formJSON["security"]) {
|
if (formJSON["security"]) {
|
||||||
var password = formJSON["security"]["http_password"];
|
var password = formJSON["security"]["http_password"];
|
||||||
if (password.length > 0) {
|
if (password && password.length > 0) {
|
||||||
formJSON["security"]["http_password"] = sha256_digest(password);
|
formJSON["security"]["http_password"] = sha256_digest(password);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1678,10 +1678,12 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
|
||||||
// we've pulled a username and password - now check if there is a match in our basic auth hash
|
// we've pulled a username and password - now check if there is a match in our basic auth hash
|
||||||
QString settingsUsername = valueForKeyPath(settingsMap, BASIC_AUTH_USERNAME_KEY_PATH)->toString();
|
QString settingsUsername = valueForKeyPath(settingsMap, BASIC_AUTH_USERNAME_KEY_PATH)->toString();
|
||||||
const QVariant* settingsPasswordVariant = valueForKeyPath(settingsMap, BASIC_AUTH_PASSWORD_KEY_PATH);
|
const QVariant* settingsPasswordVariant = valueForKeyPath(settingsMap, BASIC_AUTH_PASSWORD_KEY_PATH);
|
||||||
|
|
||||||
QString settingsPassword = settingsPasswordVariant ? settingsPasswordVariant->toString() : "";
|
QString settingsPassword = settingsPasswordVariant ? settingsPasswordVariant->toString() : "";
|
||||||
QString hexHeaderPassword = QCryptographicHash::hash(headerPassword.toUtf8(), QCryptographicHash::Sha256).toHex();
|
QString hexHeaderPassword = QCryptographicHash::hash(headerPassword.toUtf8(), QCryptographicHash::Sha256).toHex();
|
||||||
|
|
||||||
if (settingsUsername == headerUsername && hexHeaderPassword == settingsPassword) {
|
if (settingsUsername == headerUsername
|
||||||
|
&& (settingsPassword.isEmpty() || hexHeaderPassword == settingsPassword)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,10 +95,6 @@ var SHOULD_SHOW_PROPERTY_MENU = false;
|
||||||
var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to edit on this domain."
|
var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to edit on this domain."
|
||||||
var INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG = "You do not have the necessary permissions to place items on this domain."
|
var INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG = "You do not have the necessary permissions to place items on this domain."
|
||||||
|
|
||||||
var modelURLs = [
|
|
||||||
"Insert the URL to your FBX"
|
|
||||||
];
|
|
||||||
|
|
||||||
var mode = 0;
|
var mode = 0;
|
||||||
var isActive = false;
|
var isActive = false;
|
||||||
|
|
||||||
|
@ -432,7 +428,7 @@ var toolBar = (function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newModelButton === toolBar.clicked(clickedOverlay)) {
|
if (newModelButton === toolBar.clicked(clickedOverlay)) {
|
||||||
url = Window.prompt("Model URL", modelURLs[Math.floor(Math.random() * modelURLs.length)]);
|
url = Window.prompt("Model URL");
|
||||||
if (url !== null && url !== "") {
|
if (url !== null && url !== "") {
|
||||||
addModel(url);
|
addModel(url);
|
||||||
}
|
}
|
||||||
|
|
133
examples/golfclub/golfClub.js
Normal file
133
examples/golfclub/golfClub.js
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
//
|
||||||
|
// golfClub.js
|
||||||
|
//
|
||||||
|
// Created by Philip Rosedale on April 11, 2016.
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
// A simple golf club. If you have equipped it, and pull trigger, it will either make
|
||||||
|
// you a new golf ball, or take you to your ball if one is not made.
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var ball = null;
|
||||||
|
var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||||
|
var collisionSoundURL = HIFI_PUBLIC_BUCKET + "sounds/Collisions-ballhitsandcatches/billiards/collision1.wav";
|
||||||
|
var triggerState = false;
|
||||||
|
var BALL_GRAVITY = -9.8;
|
||||||
|
var BALL_START_VELOCITY = 0.1;
|
||||||
|
var BALL_MAX_RANGE = 10;
|
||||||
|
var BALL_DROP_DISTANCE = 0.6;
|
||||||
|
var BALL_DIAMETER = 0.07;
|
||||||
|
var BALL_LIFETIME = 3600;
|
||||||
|
var MAX_BRAKING_SPEED = 0.2;
|
||||||
|
var BALL_BRAKING_RATE = 0.5;
|
||||||
|
|
||||||
|
var TRIGGER_CONTROLS = [
|
||||||
|
Controller.Standard.LT,
|
||||||
|
Controller.Standard.RT,
|
||||||
|
];
|
||||||
|
|
||||||
|
function triggerPulled(hand) {
|
||||||
|
// Return true if the trigger has just been pulled
|
||||||
|
var triggerValue = Controller.getValue(TRIGGER_CONTROLS[hand]);
|
||||||
|
var oldTriggerState = triggerState;
|
||||||
|
var TRIGGER_PULL_THRESHOLD = 0.5;
|
||||||
|
var TRIGGER_RELEASE_THRESHOLD = 0.4;
|
||||||
|
if (triggerValue > TRIGGER_PULL_THRESHOLD) {
|
||||||
|
triggerState = true;
|
||||||
|
} else if (triggerValue < TRIGGER_RELEASE_THRESHOLD) {
|
||||||
|
triggerState = false;
|
||||||
|
}
|
||||||
|
return (triggerState && (oldTriggerState != triggerState));
|
||||||
|
}
|
||||||
|
|
||||||
|
function ballPosition(ball) {
|
||||||
|
// return the position of this entity
|
||||||
|
var properties = Entities.getEntityProperties(ball, ['position']);
|
||||||
|
if (!properties) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return properties.position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotoPointOnGround(position, away) {
|
||||||
|
// Position yourself facing in the direction you were originally facing, but with a
|
||||||
|
// point on the ground *away* meters from *position* and in front of you.
|
||||||
|
|
||||||
|
var offset = Quat.getFront(MyAvatar.orientation);
|
||||||
|
offset.y = 0.0;
|
||||||
|
offset = Vec3.multiply(-away, Vec3.normalize(offset));
|
||||||
|
var newAvatarPosition = Vec3.sum(position, offset);
|
||||||
|
|
||||||
|
// Assuming position is on ground, put me distance from eyes to hips higher, plus a 50% adjust for longer legs.
|
||||||
|
// TODO: Need avatar callback for exact foot-to-hips height.
|
||||||
|
|
||||||
|
var halfHeight = avatarHalfHeight();
|
||||||
|
print("Height = " + halfHeight);
|
||||||
|
newAvatarPosition.y += (halfHeight * 1.5);
|
||||||
|
MyAvatar.position = newAvatarPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inFrontOfMe() {
|
||||||
|
return Vec3.sum(MyAvatar.position, Vec3.multiply(BALL_DROP_DISTANCE, Quat.getFront(MyAvatar.orientation)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function avatarHalfHeight() {
|
||||||
|
return MyAvatar.getDefaultEyePosition().y - MyAvatar.position.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function brakeBall(ball) {
|
||||||
|
// Check the ball's velocity and slow it down if beyond a threshold
|
||||||
|
var properties = Entities.getEntityProperties(ball, ['velocity']);
|
||||||
|
if (properties) {
|
||||||
|
var velocity = Vec3.length(properties.velocity);
|
||||||
|
if ((velocity > 0) && (velocity < MAX_BRAKING_SPEED)) {
|
||||||
|
Entities.editEntity(ball, { velocity: Vec3.multiply(BALL_BRAKING_RATE, properties.velocity) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeBall(position) {
|
||||||
|
// Create a new sphere entity
|
||||||
|
ball = Entities.addEntity({
|
||||||
|
type: "Sphere",
|
||||||
|
position: position,
|
||||||
|
color: { red: 255, green: 255, blue: 255 },
|
||||||
|
dimensions: { x: BALL_DIAMETER, y: BALL_DIAMETER, z: BALL_DIAMETER },
|
||||||
|
gravity: { x: 0, y: BALL_GRAVITY, z: 0 },
|
||||||
|
velocity: { x: 0, y: BALL_START_VELOCITY, z: 0 },
|
||||||
|
friction: 0.5,
|
||||||
|
restitution: 0.5,
|
||||||
|
shapeType: "sphere",
|
||||||
|
dynamic: true,
|
||||||
|
lifetime: BALL_LIFETIME,
|
||||||
|
collisionSoundURL: collisionSoundURL
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkClub(params) {
|
||||||
|
var hand = params[0] == "left" ? 0 : 1;
|
||||||
|
var makeNewBall = false;
|
||||||
|
if (triggerPulled(hand)) {
|
||||||
|
// If trigger just pulled, either drop new ball or go to existing one
|
||||||
|
var position = ballPosition(ball);
|
||||||
|
if (position && (Vec3.distance(MyAvatar.position, position) < BALL_MAX_RANGE)) {
|
||||||
|
gotoPointOnGround(position, BALL_DROP_DISTANCE);
|
||||||
|
} else {
|
||||||
|
Entities.deleteEntity(ball);
|
||||||
|
makeBall(inFrontOfMe());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
brakeBall(ball);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.continueEquip = function(id, params) {
|
||||||
|
// While holding the club, continuously check for trigger pull and brake ball if moving.
|
||||||
|
checkClub(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
36
examples/golfclub/golfClub.json
Normal file
36
examples/golfclub/golfClub.json
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"Entities": [
|
||||||
|
{
|
||||||
|
"collisionsWillMove": 1,
|
||||||
|
"compoundShapeURL": "http://hifi-content.s3.amazonaws.com/caitlyn/dev/Tutorials/Putter_phys.obj",
|
||||||
|
"created": "2016-04-07T23:19:30Z",
|
||||||
|
"description": "Spawns ball or jumps to ball with trigger",
|
||||||
|
"dimensions": {
|
||||||
|
"x": 0.043093059211969376,
|
||||||
|
"y": 1.1488667726516724,
|
||||||
|
"z": 0.42455694079399109
|
||||||
|
},
|
||||||
|
"dynamic": 1,
|
||||||
|
"id": "{266a9bc2-cff5-4128-b347-5eab519d8209}",
|
||||||
|
"modelURL": "http://hifi-content.s3.amazonaws.com/caitlyn/dev/Tutorials/putter_VR.fbx",
|
||||||
|
"name": "Golf Putter",
|
||||||
|
"queryAACube": {
|
||||||
|
"scale": 1.2255613803863525,
|
||||||
|
"x": -0.61278069019317627,
|
||||||
|
"y": -0.61278069019317627,
|
||||||
|
"z": -0.61278069019317627
|
||||||
|
},
|
||||||
|
"rotation": {
|
||||||
|
"w": 0.41972994804382324,
|
||||||
|
"x": 0.78570234775543213,
|
||||||
|
"y": -0.41875332593917847,
|
||||||
|
"z": 0.17653167247772217
|
||||||
|
},
|
||||||
|
"script": "https://s3.amazonaws.com/hifi-public/philip/golfClub.js",
|
||||||
|
"shapeType": "compound",
|
||||||
|
"type": "Model",
|
||||||
|
"userData": "{\"wearable\":{\"joints\":{\"LeftHand\":[{\"x\":-0.1631782054901123,\"y\":0.44648152589797974,\"z\":0.10100018978118896},{\"x\":-0.9181621670722961,\"y\":-0.0772884339094162,\"z\":-0.3870723247528076,\"w\":-0.0343472845852375}],\"RightHand\":[{\"x\":0.16826771199703217,\"y\":0.4757269620895386,\"z\":0.07139724493026733},{\"x\":-0.7976328134536743,\"y\":-0.0011603273451328278,\"z\":0.6030101776123047,\"w\":-0.012610925361514091}]}}}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Version": 57
|
||||||
|
}
|
|
@ -84,6 +84,11 @@ Item {
|
||||||
prop: "frameTextureCount",
|
prop: "frameTextureCount",
|
||||||
label: "Frame",
|
label: "Frame",
|
||||||
color: "#E2334D"
|
color: "#E2334D"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "textureGPUTransferCount",
|
||||||
|
label: "Transfer",
|
||||||
|
color: "#9495FF"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -104,7 +109,18 @@ Item {
|
||||||
prop: "textureGPUMemoryUsage",
|
prop: "textureGPUMemoryUsage",
|
||||||
label: "GPU",
|
label: "GPU",
|
||||||
color: "#1AC567"
|
color: "#1AC567"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "textureGPUVirtualMemoryUsage",
|
||||||
|
label: "GPU Virtual",
|
||||||
|
color: "#9495FF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "frameTextureMemoryUsage",
|
||||||
|
label: "Frame",
|
||||||
|
color: "#E2334D"
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +195,7 @@ Item {
|
||||||
object: Render.getConfig("DrawLight"),
|
object: Render.getConfig("DrawLight"),
|
||||||
prop: "numDrawn",
|
prop: "numDrawn",
|
||||||
label: "Lights",
|
label: "Lights",
|
||||||
color: "#E2334D"
|
color: "#FED959"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,12 +48,22 @@ Item {
|
||||||
Text {
|
Text {
|
||||||
color: root.fontColor;
|
color: root.fontColor;
|
||||||
font.pixelSize: root.fontSize
|
font.pixelSize: root.fontSize
|
||||||
text: "Render Rate: " + root.renderrate
|
text: "Render Rate: " + root.renderrate.toFixed(2);
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
color: root.fontColor;
|
color: root.fontColor;
|
||||||
font.pixelSize: root.fontSize
|
font.pixelSize: root.fontSize
|
||||||
text: "Present Rate: " + root.presentrate
|
text: "Present Rate: " + root.presentrate.toFixed(2);
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
color: root.fontColor;
|
||||||
|
font.pixelSize: root.fontSize
|
||||||
|
text: "Present New Rate: " + root.presentnewrate.toFixed(2);
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
color: root.fontColor;
|
||||||
|
font.pixelSize: root.fontSize
|
||||||
|
text: "Present Drop Rate: " + root.presentdroprate.toFixed(2);
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
color: root.fontColor;
|
color: root.fontColor;
|
||||||
|
|
|
@ -116,7 +116,7 @@ Column {
|
||||||
|
|
||||||
LinearGradient {
|
LinearGradient {
|
||||||
id: bottomBar
|
id: bottomBar
|
||||||
visible: isCollapsible
|
visible: desktop.gradientsSupported && isCollapsible
|
||||||
width: frame.width
|
width: frame.width
|
||||||
height: visible ? 4 : 0
|
height: visible ? 4 : 0
|
||||||
x: -hifi.dimensions.contentMargin.x
|
x: -hifi.dimensions.contentMargin.x
|
||||||
|
|
|
@ -34,6 +34,10 @@ FocusScope {
|
||||||
// The VR version of the primary menu
|
// The VR version of the primary menu
|
||||||
property var rootMenu: Menu { objectName: "rootMenu" }
|
property var rootMenu: Menu { objectName: "rootMenu" }
|
||||||
|
|
||||||
|
// FIXME: Alpha gradients display as fuschia under QtQuick 2.5 on OSX/AMD
|
||||||
|
// because shaders are 4.2, and do not include #version declarations.
|
||||||
|
property bool gradientsSupported: Qt.platform.os != "osx" && !~GL.vendor.indexOf("ATI")
|
||||||
|
|
||||||
readonly property alias zLevels: zLevels
|
readonly property alias zLevels: zLevels
|
||||||
QtObject {
|
QtObject {
|
||||||
id: zLevels;
|
id: zLevels;
|
||||||
|
|
|
@ -20,6 +20,8 @@ Item {
|
||||||
|
|
||||||
default property var decoration
|
default property var decoration
|
||||||
|
|
||||||
|
property bool gradientsSupported: desktop.gradientsSupported
|
||||||
|
|
||||||
readonly property int iconSize: 22
|
readonly property int iconSize: 22
|
||||||
readonly property int frameMargin: 9
|
readonly property int frameMargin: 9
|
||||||
readonly property int frameMarginLeft: frameMargin
|
readonly property int frameMarginLeft: frameMargin
|
||||||
|
@ -59,9 +61,7 @@ Item {
|
||||||
height: 1.66 * window.height
|
height: 1.66 * window.height
|
||||||
x: (window.width - width) / 2
|
x: (window.width - width) / 2
|
||||||
y: window.height / 2 - 0.375 * height
|
y: window.height / 2 - 0.375 * height
|
||||||
// FIXME: Alpha gradients display as fuschia under QtQuick 2.5 on OSX.
|
visible: gradientsSupported && window && window.focus && pane.visible
|
||||||
// Check again when have a later version of QtQuick.
|
|
||||||
visible: window && window.focus && pane.visible && Qt.platform.os != "osx"
|
|
||||||
gradient: Gradient {
|
gradient: Gradient {
|
||||||
// GradientStop position 0.5 is at full circumference of circle that fits inside the square.
|
// GradientStop position 0.5 is at full circumference of circle that fits inside the square.
|
||||||
GradientStop { position: 0.0; color: "#ff000000" } // black, 100% opacity
|
GradientStop { position: 0.0; color: "#ff000000" } // black, 100% opacity
|
||||||
|
|
|
@ -51,6 +51,7 @@ Fadable {
|
||||||
// property bool pinnable: false
|
// property bool pinnable: false
|
||||||
// property bool pinned: false
|
// property bool pinned: false
|
||||||
property bool resizable: false
|
property bool resizable: false
|
||||||
|
property bool gradientsSupported: desktop.gradientsSupported
|
||||||
|
|
||||||
property vector2d minSize: Qt.vector2d(100, 100)
|
property vector2d minSize: Qt.vector2d(100, 100)
|
||||||
property vector2d maxSize: Qt.vector2d(1280, 800)
|
property vector2d maxSize: Qt.vector2d(1280, 800)
|
||||||
|
@ -142,9 +143,7 @@ Fadable {
|
||||||
}
|
}
|
||||||
|
|
||||||
LinearGradient {
|
LinearGradient {
|
||||||
// FIXME: Alpha gradients display as fuschia under QtQuick 2.5 on OSX.
|
visible: gradientsSupported && modality != Qt.ApplicationModal
|
||||||
// Check again when have a later version of QtQuick.
|
|
||||||
visible: modality != Qt.ApplicationModal && Qt.platform.os != "osx"
|
|
||||||
anchors.top: contentBackground.bottom
|
anchors.top: contentBackground.bottom
|
||||||
anchors.left: contentBackground.left
|
anchors.left: contentBackground.left
|
||||||
width: contentBackground.width - 1
|
width: contentBackground.width - 1
|
||||||
|
|
|
@ -511,8 +511,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
_sessionRunTimer(startupTimer),
|
_sessionRunTimer(startupTimer),
|
||||||
_previousSessionCrashed(setupEssentials(argc, argv)),
|
_previousSessionCrashed(setupEssentials(argc, argv)),
|
||||||
_undoStackScriptingInterface(&_undoStack),
|
_undoStackScriptingInterface(&_undoStack),
|
||||||
_frameCount(0),
|
|
||||||
_fps(60.0f),
|
|
||||||
_physicsEngine(new PhysicsEngine(Vectors::ZERO)),
|
_physicsEngine(new PhysicsEngine(Vectors::ZERO)),
|
||||||
_entityClipboardRenderer(false, this, this),
|
_entityClipboardRenderer(false, this, this),
|
||||||
_entityClipboard(new EntityTree()),
|
_entityClipboard(new EntityTree()),
|
||||||
|
@ -1332,11 +1330,13 @@ void Application::initializeGL() {
|
||||||
_idleLoopStdev.reset();
|
_idleLoopStdev.reset();
|
||||||
|
|
||||||
// update before the first render
|
// update before the first render
|
||||||
update(1.0f / _fps);
|
update(0);
|
||||||
|
|
||||||
InfoView::show(INFO_HELP_PATH, true);
|
InfoView::show(INFO_HELP_PATH, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void setupPreferences();
|
extern void setupPreferences();
|
||||||
|
|
||||||
void Application::initializeUi() {
|
void Application::initializeUi() {
|
||||||
AddressBarDialog::registerType();
|
AddressBarDialog::registerType();
|
||||||
ErrorDialog::registerType();
|
ErrorDialog::registerType();
|
||||||
|
@ -1348,6 +1348,9 @@ void Application::initializeUi() {
|
||||||
|
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
offscreenUi->create(_offscreenContext->getContext());
|
offscreenUi->create(_offscreenContext->getContext());
|
||||||
|
|
||||||
|
auto rootContext = offscreenUi->getRootContext();
|
||||||
|
|
||||||
offscreenUi->setProxyWindow(_window->windowHandle());
|
offscreenUi->setProxyWindow(_window->windowHandle());
|
||||||
offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
|
offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
|
||||||
// OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to
|
// OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to
|
||||||
|
@ -1358,7 +1361,6 @@ void Application::initializeUi() {
|
||||||
// do better detection in the offscreen UI of what has focus
|
// do better detection in the offscreen UI of what has focus
|
||||||
offscreenUi->setNavigationFocused(false);
|
offscreenUi->setNavigationFocused(false);
|
||||||
|
|
||||||
auto rootContext = offscreenUi->getRootContext();
|
|
||||||
auto engine = rootContext->engine();
|
auto engine = rootContext->engine();
|
||||||
connect(engine, &QQmlEngine::quit, [] {
|
connect(engine, &QQmlEngine::quit, [] {
|
||||||
qApp->quit();
|
qApp->quit();
|
||||||
|
@ -1463,7 +1465,6 @@ void Application::initializeUi() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::paintGL() {
|
void Application::paintGL() {
|
||||||
|
|
||||||
updateHeartbeat();
|
updateHeartbeat();
|
||||||
|
|
||||||
// Some plugins process message events, potentially leading to
|
// Some plugins process message events, potentially leading to
|
||||||
|
@ -1481,24 +1482,7 @@ void Application::paintGL() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_frameCount++;
|
_frameCount++;
|
||||||
|
_frameCounter.increment();
|
||||||
// update fps moving average
|
|
||||||
uint64_t now = usecTimestampNow();
|
|
||||||
static uint64_t lastPaintBegin{ now };
|
|
||||||
uint64_t diff = now - lastPaintBegin;
|
|
||||||
float instantaneousFps = 0.0f;
|
|
||||||
if (diff != 0) {
|
|
||||||
instantaneousFps = (float)USECS_PER_SECOND / (float)diff;
|
|
||||||
_framesPerSecond.updateAverage(_lastInstantaneousFps);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastPaintBegin = now;
|
|
||||||
|
|
||||||
// update fps once a second
|
|
||||||
if (now - _lastFramesPerSecondUpdate > USECS_PER_SECOND) {
|
|
||||||
_fps = _framesPerSecond.getAverage();
|
|
||||||
_lastFramesPerSecondUpdate = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, (uint64_t)_frameCount);
|
PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, (uint64_t)_frameCount);
|
||||||
PerformanceTimer perfTimer("paintGL");
|
PerformanceTimer perfTimer("paintGL");
|
||||||
|
@ -1655,7 +1639,7 @@ void Application::paintGL() {
|
||||||
}
|
}
|
||||||
// Update camera position
|
// Update camera position
|
||||||
if (!isHMDMode()) {
|
if (!isHMDMode()) {
|
||||||
_myCamera.update(1.0f / _fps);
|
_myCamera.update(1.0f / _frameCounter.rate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1752,8 +1736,6 @@ void Application::paintGL() {
|
||||||
batch.resetStages();
|
batch.resetStages();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastInstantaneousFps = instantaneousFps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::runTests() {
|
void Application::runTests() {
|
||||||
|
@ -2625,32 +2607,19 @@ bool Application::acceptSnapshot(const QString& urlString) {
|
||||||
static uint32_t _renderedFrameIndex { INVALID_FRAME };
|
static uint32_t _renderedFrameIndex { INVALID_FRAME };
|
||||||
|
|
||||||
void Application::idle(uint64_t now) {
|
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();
|
updateHeartbeat();
|
||||||
|
|
||||||
if (_aboutToQuit || _inPaint) {
|
if (_aboutToQuit || _inPaint) {
|
||||||
return; // bail early, nothing to do here.
|
return; // bail early, nothing to do here.
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
} else if (offscreenUi && offscreenUi->getWindow()->activeFocusItem() == offscreenUi->getRootItem()) {
|
|
||||||
_keyboardDeviceHasFocus = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto displayPlugin = getActiveDisplayPlugin();
|
auto displayPlugin = getActiveDisplayPlugin();
|
||||||
// depending on whether we're throttling or not.
|
// 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
|
// Once rendering is off on another thread we should be able to have Application::idle run at start(0) in
|
||||||
|
@ -2684,8 +2653,36 @@ void Application::idle(uint64_t now) {
|
||||||
return;
|
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
|
||||||
|
|
||||||
PROFILE_RANGE(__FUNCTION__);
|
PROFILE_RANGE(__FUNCTION__);
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
} else if (offscreenUi && offscreenUi->getWindow()->activeFocusItem() == offscreenUi->getRootItem()) {
|
||||||
|
_keyboardDeviceHasFocus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// We're going to execute idle processing, so restart the last idle timer
|
// We're going to execute idle processing, so restart the last idle timer
|
||||||
_lastTimeUpdated.start();
|
_lastTimeUpdated.start();
|
||||||
|
|
||||||
|
@ -2694,14 +2691,7 @@ void Application::idle(uint64_t now) {
|
||||||
Stats::getInstance()->updateStats();
|
Stats::getInstance()->updateStats();
|
||||||
AvatarInputs::getInstance()->update();
|
AvatarInputs::getInstance()->update();
|
||||||
|
|
||||||
{
|
_simCounter.increment();
|
||||||
static uint64_t lastIdleStart{ now };
|
|
||||||
uint64_t idleStartToStartDuration = now - lastIdleStart;
|
|
||||||
if (idleStartToStartDuration != 0) {
|
|
||||||
_simsPerSecond.updateAverage((float)USECS_PER_SECOND / (float)idleStartToStartDuration);
|
|
||||||
}
|
|
||||||
lastIdleStart = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
PerformanceTimer perfTimer("idle");
|
PerformanceTimer perfTimer("idle");
|
||||||
// Drop focus from _keyboardFocusedItem if no keyboard messages for 30 seconds
|
// Drop focus from _keyboardFocusedItem if no keyboard messages for 30 seconds
|
||||||
|
@ -2757,30 +2747,6 @@ void Application::idle(uint64_t now) {
|
||||||
emit checkBackgroundDownloads();
|
emit checkBackgroundDownloads();
|
||||||
}
|
}
|
||||||
|
|
||||||
float Application::getAverageSimsPerSecond() {
|
|
||||||
uint64_t now = usecTimestampNow();
|
|
||||||
|
|
||||||
if (now - _lastSimsPerSecondUpdate > USECS_PER_SECOND) {
|
|
||||||
_simsPerSecondReport = _simsPerSecond.getAverage();
|
|
||||||
_lastSimsPerSecondUpdate = now;
|
|
||||||
}
|
|
||||||
return _simsPerSecondReport;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::setAvatarSimrateSample(float sample) {
|
|
||||||
_avatarSimsPerSecond.updateAverage(sample);
|
|
||||||
}
|
|
||||||
|
|
||||||
float Application::getAvatarSimrate() {
|
|
||||||
uint64_t now = usecTimestampNow();
|
|
||||||
|
|
||||||
if (now - _lastAvatarSimsPerSecondUpdate > USECS_PER_SECOND) {
|
|
||||||
_avatarSimsPerSecondReport = _avatarSimsPerSecond.getAverage();
|
|
||||||
_lastAvatarSimsPerSecondUpdate = now;
|
|
||||||
}
|
|
||||||
return _avatarSimsPerSecondReport;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::setLowVelocityFilter(bool lowVelocityFilter) {
|
void Application::setLowVelocityFilter(bool lowVelocityFilter) {
|
||||||
controller::InputDevice::setLowVelocityFilter(lowVelocityFilter);
|
controller::InputDevice::setLowVelocityFilter(lowVelocityFilter);
|
||||||
}
|
}
|
||||||
|
@ -3051,7 +3017,7 @@ void Application::updateLOD() const {
|
||||||
PerformanceTimer perfTimer("LOD");
|
PerformanceTimer perfTimer("LOD");
|
||||||
// adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode
|
// adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode
|
||||||
if (!isThrottleRendering()) {
|
if (!isThrottleRendering()) {
|
||||||
DependencyManager::get<LODManager>()->autoAdjustLOD(_fps);
|
DependencyManager::get<LODManager>()->autoAdjustLOD(_frameCounter.rate());
|
||||||
} else {
|
} else {
|
||||||
DependencyManager::get<LODManager>()->resetLODAdjust();
|
DependencyManager::get<LODManager>()->resetLODAdjust();
|
||||||
}
|
}
|
||||||
|
@ -3482,17 +3448,13 @@ void Application::update(float deltaTime) {
|
||||||
// AvatarManager update
|
// AvatarManager update
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("AvatarManger");
|
PerformanceTimer perfTimer("AvatarManger");
|
||||||
|
_avatarSimCounter.increment();
|
||||||
qApp->setAvatarSimrateSample(1.0f / deltaTime);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
PROFILE_RANGE_EX("OtherAvatars", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount());
|
PROFILE_RANGE_EX("OtherAvatars", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount());
|
||||||
avatarManager->updateOtherAvatars(deltaTime);
|
avatarManager->updateOtherAvatars(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update sensorToWorldMatrix for camera and hand controllers
|
|
||||||
getMyAvatar()->updateSensorToWorldMatrix();
|
|
||||||
|
|
||||||
qApp->updateMyAvatarLookAtPosition();
|
qApp->updateMyAvatarLookAtPosition();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -3805,7 +3767,8 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
||||||
bool Application::isHMDMode() const {
|
bool Application::isHMDMode() const {
|
||||||
return getActiveDisplayPlugin()->isHmd();
|
return getActiveDisplayPlugin()->isHmd();
|
||||||
}
|
}
|
||||||
float Application::getTargetFrameRate() { return getActiveDisplayPlugin()->getTargetFrameRate(); }
|
|
||||||
|
float Application::getTargetFrameRate() const { return getActiveDisplayPlugin()->getTargetFrameRate(); }
|
||||||
|
|
||||||
QRect Application::getDesirableApplicationGeometry() const {
|
QRect Application::getDesirableApplicationGeometry() const {
|
||||||
QRect applicationGeometry = getWindow()->geometry();
|
QRect applicationGeometry = getWindow()->geometry();
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include <StDev.h>
|
#include <StDev.h>
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
#include <AbstractUriHandler.h>
|
#include <AbstractUriHandler.h>
|
||||||
|
#include <shared/RateCounter.h>
|
||||||
|
|
||||||
#include "avatar/MyAvatar.h"
|
#include "avatar/MyAvatar.h"
|
||||||
#include "Bookmarks.h"
|
#include "Bookmarks.h"
|
||||||
|
@ -155,10 +156,9 @@ public:
|
||||||
|
|
||||||
bool isForeground() const { return _isForeground; }
|
bool isForeground() const { return _isForeground; }
|
||||||
|
|
||||||
uint32_t getFrameCount() const { return _frameCount; }
|
size_t getFrameCount() const { return _frameCount; }
|
||||||
float getFps() const { return _fps; }
|
float getFps() const { return _frameCounter.rate(); }
|
||||||
float getTargetFrameRate(); // frames/second
|
float getTargetFrameRate() const; // frames/second
|
||||||
float getLastInstanteousFps() const { return _lastInstantaneousFps; }
|
|
||||||
|
|
||||||
float getFieldOfView() { return _fieldOfView.get(); }
|
float getFieldOfView() { return _fieldOfView.get(); }
|
||||||
void setFieldOfView(float fov);
|
void setFieldOfView(float fov);
|
||||||
|
@ -216,10 +216,9 @@ public:
|
||||||
const QRect& getMirrorViewRect() const { return _mirrorViewRect; }
|
const QRect& getMirrorViewRect() const { return _mirrorViewRect; }
|
||||||
|
|
||||||
void updateMyAvatarLookAtPosition();
|
void updateMyAvatarLookAtPosition();
|
||||||
float getAvatarSimrate();
|
|
||||||
void setAvatarSimrateSample(float sample);
|
|
||||||
|
|
||||||
float getAverageSimsPerSecond();
|
float getAvatarSimrate() const { return _avatarSimCounter.rate(); }
|
||||||
|
float getAverageSimsPerSecond() const { return _simCounter.rate(); }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void svoImportRequested(const QString& url);
|
void svoImportRequested(const QString& url);
|
||||||
|
@ -396,12 +395,15 @@ private:
|
||||||
QUndoStack _undoStack;
|
QUndoStack _undoStack;
|
||||||
UndoStackScriptingInterface _undoStackScriptingInterface;
|
UndoStackScriptingInterface _undoStackScriptingInterface;
|
||||||
|
|
||||||
|
uint32_t _frameCount { 0 };
|
||||||
|
|
||||||
// Frame Rate Measurement
|
// Frame Rate Measurement
|
||||||
int _frameCount;
|
RateCounter<> _frameCounter;
|
||||||
float _fps;
|
RateCounter<> _avatarSimCounter;
|
||||||
|
RateCounter<> _simCounter;
|
||||||
|
|
||||||
QElapsedTimer _timerStart;
|
QElapsedTimer _timerStart;
|
||||||
QElapsedTimer _lastTimeUpdated;
|
QElapsedTimer _lastTimeUpdated;
|
||||||
float _lastInstantaneousFps { 0.0f };
|
|
||||||
|
|
||||||
ShapeManager _shapeManager;
|
ShapeManager _shapeManager;
|
||||||
PhysicalEntitySimulation _entitySimulation;
|
PhysicalEntitySimulation _entitySimulation;
|
||||||
|
@ -488,12 +490,6 @@ private:
|
||||||
|
|
||||||
EntityItemID _keyboardFocusedItem;
|
EntityItemID _keyboardFocusedItem;
|
||||||
quint64 _lastAcceptedKeyPress = 0;
|
quint64 _lastAcceptedKeyPress = 0;
|
||||||
|
|
||||||
SimpleMovingAverage _framesPerSecond{10};
|
|
||||||
quint64 _lastFramesPerSecondUpdate = 0;
|
|
||||||
SimpleMovingAverage _simsPerSecond{10};
|
|
||||||
int _simsPerSecondReport = 0;
|
|
||||||
quint64 _lastSimsPerSecondUpdate = 0;
|
|
||||||
bool _isForeground = true; // starts out assumed to be in foreground
|
bool _isForeground = true; // starts out assumed to be in foreground
|
||||||
bool _inPaint = false;
|
bool _inPaint = false;
|
||||||
bool _isGLInitialized { false };
|
bool _isGLInitialized { false };
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#include "FileLogger.h"
|
#include "FileLogger.h"
|
||||||
|
|
||||||
#include <QtCore/QDateTime>
|
#include <QtCore/QDateTime>
|
||||||
#include <QtCore/QFile>
|
|
||||||
#include <QtCore/QDir>
|
#include <QtCore/QDir>
|
||||||
#include <QtGui/QDesktopServices>
|
#include <QtGui/QDesktopServices>
|
||||||
|
|
||||||
|
@ -25,11 +24,14 @@
|
||||||
static const QString FILENAME_FORMAT = "hifi-log_%1_%2.txt";
|
static const QString FILENAME_FORMAT = "hifi-log_%1_%2.txt";
|
||||||
static const QString DATETIME_FORMAT = "yyyy-MM-dd_hh.mm.ss";
|
static const QString DATETIME_FORMAT = "yyyy-MM-dd_hh.mm.ss";
|
||||||
static const QString LOGS_DIRECTORY = "Logs";
|
static const QString LOGS_DIRECTORY = "Logs";
|
||||||
// Max log size is 1 MB
|
// Max log size is 512 KB. We send log files to our crash reporter, so we want to keep this relatively
|
||||||
static const qint64 MAX_LOG_SIZE = 1024 * 1024;
|
// small so it doesn't go over the 2MB zipped limit for all of the files we send.
|
||||||
|
static const qint64 MAX_LOG_SIZE = 512 * 1024;
|
||||||
// Max log age is 1 hour
|
// Max log age is 1 hour
|
||||||
static const uint64_t MAX_LOG_AGE_USECS = USECS_PER_SECOND * 3600;
|
static const uint64_t MAX_LOG_AGE_USECS = USECS_PER_SECOND * 3600;
|
||||||
|
|
||||||
|
static FilePersistThread* _persistThreadInstance;
|
||||||
|
|
||||||
QString getLogRollerFilename() {
|
QString getLogRollerFilename() {
|
||||||
QString result = FileUtils::standardPath(LOGS_DIRECTORY);
|
QString result = FileUtils::standardPath(LOGS_DIRECTORY);
|
||||||
QHostAddress clientAddress = getGuessedLocalAddress();
|
QHostAddress clientAddress = getGuessedLocalAddress();
|
||||||
|
@ -43,51 +45,53 @@ const QString& getLogFilename() {
|
||||||
return fileName;
|
return fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FilePersistThread::FilePersistThread(const FileLogger& logger) : _logger(logger) {
|
||||||
|
setObjectName("LogFileWriter");
|
||||||
|
|
||||||
class FilePersistThread : public GenericQueueThread < QString > {
|
// A file may exist from a previous run - if it does, roll the file and suppress notifying listeners.
|
||||||
public:
|
QFile file(_logger._fileName);
|
||||||
FilePersistThread(const FileLogger& logger) : _logger(logger) {
|
if (file.exists()) {
|
||||||
setObjectName("LogFileWriter");
|
rollFileIfNecessary(file, false);
|
||||||
}
|
}
|
||||||
|
_lastRollTime = usecTimestampNow();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
void FilePersistThread::rollFileIfNecessary(QFile& file, bool notifyListenersIfRolled) {
|
||||||
void rollFileIfNecessary(QFile& file) {
|
uint64_t now = usecTimestampNow();
|
||||||
uint64_t now = usecTimestampNow();
|
if ((file.size() > MAX_LOG_SIZE) || (now - _lastRollTime) > MAX_LOG_AGE_USECS) {
|
||||||
if ((file.size() > MAX_LOG_SIZE) || (now - _lastRollTime) > MAX_LOG_AGE_USECS) {
|
QString newFileName = getLogRollerFilename();
|
||||||
QString newFileName = getLogRollerFilename();
|
if (file.copy(newFileName)) {
|
||||||
if (file.copy(newFileName)) {
|
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
||||||
_lastRollTime = now;
|
file.close();
|
||||||
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
qDebug() << "Rolled log file:" << newFileName;
|
||||||
file.close();
|
|
||||||
qDebug() << "Rolled log file:" << newFileName;
|
if (notifyListenersIfRolled) {
|
||||||
|
emit rollingLogFile(newFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_lastRollTime = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool processQueueItems(const Queue& messages) {
|
bool FilePersistThread::processQueueItems(const Queue& messages) {
|
||||||
QFile file(_logger._fileName);
|
QFile file(_logger._fileName);
|
||||||
rollFileIfNecessary(file);
|
rollFileIfNecessary(file);
|
||||||
if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
|
if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
|
||||||
QTextStream out(&file);
|
QTextStream out(&file);
|
||||||
foreach(const QString& message, messages) {
|
foreach(const QString& message, messages) {
|
||||||
out << message;
|
out << message;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
private:
|
return true;
|
||||||
const FileLogger& _logger;
|
}
|
||||||
uint64_t _lastRollTime = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
static FilePersistThread* _persistThreadInstance;
|
|
||||||
|
|
||||||
FileLogger::FileLogger(QObject* parent) :
|
FileLogger::FileLogger(QObject* parent) :
|
||||||
AbstractLoggerInterface(parent), _fileName(getLogFilename())
|
AbstractLoggerInterface(parent), _fileName(getLogFilename())
|
||||||
{
|
{
|
||||||
_persistThreadInstance = new FilePersistThread(*this);
|
_persistThreadInstance = new FilePersistThread(*this);
|
||||||
_persistThreadInstance->initialize(true, QThread::LowestPriority);
|
_persistThreadInstance->initialize(true, QThread::LowestPriority);
|
||||||
|
connect(_persistThreadInstance, &FilePersistThread::rollingLogFile, this, &FileLogger::rollingLogFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileLogger::~FileLogger() {
|
FileLogger::~FileLogger() {
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#include "AbstractLoggerInterface.h"
|
#include "AbstractLoggerInterface.h"
|
||||||
#include <GenericQueueThread.h>
|
#include <GenericQueueThread.h>
|
||||||
|
|
||||||
|
#include <QtCore/QFile>
|
||||||
|
|
||||||
class FileLogger : public AbstractLoggerInterface {
|
class FileLogger : public AbstractLoggerInterface {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -27,11 +29,32 @@ public:
|
||||||
virtual QString getLogData() override;
|
virtual QString getLogData() override;
|
||||||
virtual void locateLog() override;
|
virtual void locateLog() override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void rollingLogFile(QString newFilename);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const QString _fileName;
|
const QString _fileName;
|
||||||
friend class FilePersistThread;
|
friend class FilePersistThread;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FilePersistThread : public GenericQueueThread < QString > {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
FilePersistThread(const FileLogger& logger);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void rollingLogFile(QString newFilename);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void rollFileIfNecessary(QFile& file, bool notifyListenersIfRolled = true);
|
||||||
|
virtual bool processQueueItems(const Queue& messages);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const FileLogger& _logger;
|
||||||
|
uint64_t _lastRollTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // hifi_FileLogger_h
|
#endif // hifi_FileLogger_h
|
||||||
|
|
|
@ -294,20 +294,18 @@ void MyAvatar::update(float deltaTime) {
|
||||||
auto audio = DependencyManager::get<AudioClient>();
|
auto audio = DependencyManager::get<AudioClient>();
|
||||||
head->setAudioLoudness(audio->getLastInputLoudness());
|
head->setAudioLoudness(audio->getLastInputLoudness());
|
||||||
head->setAudioAverageLoudness(audio->getAudioAverageInputLoudness());
|
head->setAudioAverageLoudness(audio->getAudioAverageInputLoudness());
|
||||||
|
|
||||||
simulate(deltaTime);
|
simulate(deltaTime);
|
||||||
|
|
||||||
currentEnergy += energyChargeRate;
|
currentEnergy += energyChargeRate;
|
||||||
currentEnergy -= getAccelerationEnergy();
|
currentEnergy -= getAccelerationEnergy();
|
||||||
currentEnergy -= getAudioEnergy();
|
currentEnergy -= getAudioEnergy();
|
||||||
|
|
||||||
if(didTeleport()) {
|
if(didTeleport()) {
|
||||||
currentEnergy = 0.0f;
|
currentEnergy = 0.0f;
|
||||||
}
|
}
|
||||||
currentEnergy = max(0.0f, min(currentEnergy,1.0f));
|
currentEnergy = max(0.0f, min(currentEnergy,1.0f));
|
||||||
emit energyChanged(currentEnergy);
|
emit energyChanged(currentEnergy);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern QByteArray avatarStateToFrame(const AvatarData* _avatar);
|
extern QByteArray avatarStateToFrame(const AvatarData* _avatar);
|
||||||
|
@ -333,6 +331,10 @@ void MyAvatar::simulate(float deltaTime) {
|
||||||
updatePosition(deltaTime);
|
updatePosition(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update sensorToWorldMatrix for camera and hand controllers
|
||||||
|
// before we perform rig animations and IK.
|
||||||
|
updateSensorToWorldMatrix();
|
||||||
|
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("skeleton");
|
PerformanceTimer perfTimer("skeleton");
|
||||||
_skeletonModel->simulate(deltaTime);
|
_skeletonModel->simulate(deltaTime);
|
||||||
|
@ -1975,9 +1977,14 @@ void MyAvatar::FollowHelper::decrementTimeRemaining(float dt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
||||||
const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 6.0f); // 30 degrees
|
auto cameraMode = qApp->getCamera()->getMode();
|
||||||
glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix);
|
if (cameraMode == CAMERA_MODE_THIRD_PERSON) {
|
||||||
return glm::dot(myAvatar.getHMDSensorFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD;
|
return false;
|
||||||
|
} else {
|
||||||
|
const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 6.0f); // 30 degrees
|
||||||
|
glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix);
|
||||||
|
return glm::dot(myAvatar.getHMDSensorFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
||||||
|
|
|
@ -44,7 +44,7 @@ int main(int argc, const char* argv[]) {
|
||||||
MiniDmpSender mpSender { BUG_SPLAT_DATABASE, BUG_SPLAT_APPLICATION_NAME, qPrintable(BuildInfo::VERSION),
|
MiniDmpSender mpSender { BUG_SPLAT_DATABASE, BUG_SPLAT_APPLICATION_NAME, qPrintable(BuildInfo::VERSION),
|
||||||
nullptr, BUG_SPLAT_FLAGS };
|
nullptr, BUG_SPLAT_FLAGS };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QString applicationName = "High Fidelity Interface - " + qgetenv("USERNAME");
|
QString applicationName = "High Fidelity Interface - " + qgetenv("USERNAME");
|
||||||
|
|
||||||
bool instanceMightBeRunning = true;
|
bool instanceMightBeRunning = true;
|
||||||
|
@ -105,13 +105,14 @@ int main(int argc, const char* argv[]) {
|
||||||
// This is done separately from the main Application so that start-up and shut-down logic within the main Application is
|
// This is done separately from the main Application so that start-up and shut-down logic within the main Application is
|
||||||
// not made more complicated than it already is.
|
// not made more complicated than it already is.
|
||||||
bool override = false;
|
bool override = false;
|
||||||
QString glVersion;
|
QJsonObject glData;
|
||||||
{
|
{
|
||||||
OpenGLVersionChecker openGLVersionChecker(argc, const_cast<char**>(argv));
|
OpenGLVersionChecker openGLVersionChecker(argc, const_cast<char**>(argv));
|
||||||
bool valid = true;
|
bool valid = true;
|
||||||
glVersion = openGLVersionChecker.checkVersion(valid, override);
|
glData = openGLVersionChecker.checkVersion(valid, override);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
if (override) {
|
if (override) {
|
||||||
|
auto glVersion = glData["version"].toString();
|
||||||
qCDebug(interfaceapp, "Running on insufficient OpenGL version: %s.", glVersion.toStdString().c_str());
|
qCDebug(interfaceapp, "Running on insufficient OpenGL version: %s.", glVersion.toStdString().c_str());
|
||||||
} else {
|
} else {
|
||||||
qCDebug(interfaceapp, "Early exit due to OpenGL version.");
|
qCDebug(interfaceapp, "Early exit due to OpenGL version.");
|
||||||
|
@ -148,12 +149,12 @@ int main(int argc, const char* argv[]) {
|
||||||
if (override) {
|
if (override) {
|
||||||
auto& accountManager = AccountManager::getInstance();
|
auto& accountManager = AccountManager::getInstance();
|
||||||
if (accountManager.isLoggedIn()) {
|
if (accountManager.isLoggedIn()) {
|
||||||
UserActivityLogger::getInstance().insufficientGLVersion(glVersion);
|
UserActivityLogger::getInstance().insufficientGLVersion(glData);
|
||||||
} else {
|
} else {
|
||||||
QObject::connect(&AccountManager::getInstance(), &AccountManager::loginComplete, [glVersion](){
|
QObject::connect(&AccountManager::getInstance(), &AccountManager::loginComplete, [glData](){
|
||||||
static bool loggedInsufficientGL = false;
|
static bool loggedInsufficientGL = false;
|
||||||
if (!loggedInsufficientGL) {
|
if (!loggedInsufficientGL) {
|
||||||
UserActivityLogger::getInstance().insufficientGLVersion(glVersion);
|
UserActivityLogger::getInstance().insufficientGLVersion(glData);
|
||||||
loggedInsufficientGL = true;
|
loggedInsufficientGL = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -177,8 +178,18 @@ int main(int argc, const char* argv[]) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// BugSplat WILL NOT work with file paths that do not use OS native separators.
|
// BugSplat WILL NOT work with file paths that do not use OS native separators.
|
||||||
auto logPath = QDir::toNativeSeparators(app.getLogger()->getFilename());
|
auto logger = app.getLogger();
|
||||||
|
auto logPath = QDir::toNativeSeparators(logger->getFilename());
|
||||||
mpSender.sendAdditionalFile(qPrintable(logPath));
|
mpSender.sendAdditionalFile(qPrintable(logPath));
|
||||||
|
|
||||||
|
QMetaObject::Connection connection;
|
||||||
|
connection = QObject::connect(logger, &FileLogger::rollingLogFile, &app, [&mpSender, &connection](QString newFilename) {
|
||||||
|
// We only want to add the first rolled log file (the "beginning" of the log) to BugSplat to ensure we don't exceed the 2MB
|
||||||
|
// zipped limit, so we disconnect here.
|
||||||
|
QObject::disconnect(connection);
|
||||||
|
auto rolledLogPath = QDir::toNativeSeparators(newFilename);
|
||||||
|
mpSender.sendAdditionalFile(qPrintable(rolledLogPath));
|
||||||
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
printSystemInformation();
|
printSystemInformation();
|
||||||
|
|
|
@ -117,11 +117,15 @@ void Stats::updateStats(bool force) {
|
||||||
// we need to take one avatar out so we don't include ourselves
|
// we need to take one avatar out so we don't include ourselves
|
||||||
STAT_UPDATE(avatarCount, avatarManager->size() - 1);
|
STAT_UPDATE(avatarCount, avatarManager->size() - 1);
|
||||||
STAT_UPDATE(serverCount, (int)nodeList->size());
|
STAT_UPDATE(serverCount, (int)nodeList->size());
|
||||||
STAT_UPDATE(renderrate, (int)qApp->getFps());
|
STAT_UPDATE(renderrate, qApp->getFps());
|
||||||
if (qApp->getActiveDisplayPlugin()) {
|
if (qApp->getActiveDisplayPlugin()) {
|
||||||
STAT_UPDATE(presentrate, (int)round(qApp->getActiveDisplayPlugin()->presentRate()));
|
STAT_UPDATE(presentrate, qApp->getActiveDisplayPlugin()->presentRate());
|
||||||
|
STAT_UPDATE(presentnewrate, qApp->getActiveDisplayPlugin()->newFramePresentRate());
|
||||||
|
STAT_UPDATE(presentdroprate, qApp->getActiveDisplayPlugin()->droppedFrameRate());
|
||||||
} else {
|
} else {
|
||||||
STAT_UPDATE(presentrate, -1);
|
STAT_UPDATE(presentrate, -1);
|
||||||
|
STAT_UPDATE(presentnewrate, -1);
|
||||||
|
STAT_UPDATE(presentdroprate, -1);
|
||||||
}
|
}
|
||||||
STAT_UPDATE(simrate, (int)qApp->getAverageSimsPerSecond());
|
STAT_UPDATE(simrate, (int)qApp->getAverageSimsPerSecond());
|
||||||
STAT_UPDATE(avatarSimrate, (int)qApp->getAvatarSimrate());
|
STAT_UPDATE(avatarSimrate, (int)qApp->getAvatarSimrate());
|
||||||
|
|
|
@ -32,8 +32,10 @@ class Stats : public QQuickItem {
|
||||||
Q_PROPERTY(float audioPacketlossDownstream READ getAudioPacketLossDownstream)
|
Q_PROPERTY(float audioPacketlossDownstream READ getAudioPacketLossDownstream)
|
||||||
|
|
||||||
STATS_PROPERTY(int, serverCount, 0)
|
STATS_PROPERTY(int, serverCount, 0)
|
||||||
STATS_PROPERTY(int, renderrate, 0)
|
STATS_PROPERTY(float, renderrate, 0)
|
||||||
STATS_PROPERTY(int, presentrate, 0)
|
STATS_PROPERTY(float, presentrate, 0)
|
||||||
|
STATS_PROPERTY(float, presentnewrate, 0)
|
||||||
|
STATS_PROPERTY(float, presentdroprate, 0)
|
||||||
STATS_PROPERTY(int, simrate, 0)
|
STATS_PROPERTY(int, simrate, 0)
|
||||||
STATS_PROPERTY(int, avatarSimrate, 0)
|
STATS_PROPERTY(int, avatarSimrate, 0)
|
||||||
STATS_PROPERTY(int, avatarCount, 0)
|
STATS_PROPERTY(int, avatarCount, 0)
|
||||||
|
@ -117,6 +119,8 @@ signals:
|
||||||
void serverCountChanged();
|
void serverCountChanged();
|
||||||
void renderrateChanged();
|
void renderrateChanged();
|
||||||
void presentrateChanged();
|
void presentrateChanged();
|
||||||
|
void presentnewrateChanged();
|
||||||
|
void presentdroprateChanged();
|
||||||
void simrateChanged();
|
void simrateChanged();
|
||||||
void avatarSimrateChanged();
|
void avatarSimrateChanged();
|
||||||
void avatarCountChanged();
|
void avatarCountChanged();
|
||||||
|
|
|
@ -30,8 +30,6 @@ bool Basic2DWindowOpenGLDisplayPlugin::internalActivate() {
|
||||||
}
|
}
|
||||||
}, true, false);
|
}, true, false);
|
||||||
|
|
||||||
updateFramerate();
|
|
||||||
|
|
||||||
return Parent::internalActivate();
|
return Parent::internalActivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ class Basic2DWindowOpenGLDisplayPlugin : public OpenGLDisplayPlugin {
|
||||||
public:
|
public:
|
||||||
virtual const QString& getName() const override { return NAME; }
|
virtual const QString& getName() const override { return NAME; }
|
||||||
|
|
||||||
virtual float getTargetFrameRate() override { return _framerateTarget ? (float) _framerateTarget : TARGET_FRAMERATE_Basic2DWindowOpenGL; }
|
virtual float getTargetFrameRate() const override { return _framerateTarget ? (float) _framerateTarget : TARGET_FRAMERATE_Basic2DWindowOpenGL; }
|
||||||
|
|
||||||
virtual bool internalActivate() override;
|
virtual bool internalActivate() override;
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <CursorManager.h>
|
#include <CursorManager.h>
|
||||||
#include "CompositorHelper.h"
|
#include "CompositorHelper.h"
|
||||||
|
|
||||||
|
|
||||||
#if THREADED_PRESENT
|
#if THREADED_PRESENT
|
||||||
|
|
||||||
// FIXME, for display plugins that don't block on something like vsync, just
|
// FIXME, for display plugins that don't block on something like vsync, just
|
||||||
|
@ -415,25 +416,18 @@ void OpenGLDisplayPlugin::updateTextures() {
|
||||||
if (_sceneTextureEscrow.fetchAndReleaseWithGpuWait(_currentSceneTexture)) {
|
if (_sceneTextureEscrow.fetchAndReleaseWithGpuWait(_currentSceneTexture)) {
|
||||||
#endif
|
#endif
|
||||||
updateFrameData();
|
updateFrameData();
|
||||||
}
|
_newFrameRate.increment();
|
||||||
|
}
|
||||||
|
|
||||||
_overlayTextureEscrow.fetchSignaledAndRelease(_currentOverlayTexture);
|
_overlayTextureEscrow.fetchSignaledAndRelease(_currentOverlayTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDisplayPlugin::updateFrameData() {
|
void OpenGLDisplayPlugin::updateFrameData() {
|
||||||
Lock lock(_mutex);
|
Lock lock(_mutex);
|
||||||
|
auto previousFrameIndex = _currentRenderFrameIndex;
|
||||||
_currentRenderFrameIndex = _sceneTextureToFrameIndexMap[_currentSceneTexture];
|
_currentRenderFrameIndex = _sceneTextureToFrameIndexMap[_currentSceneTexture];
|
||||||
}
|
auto skippedCount = (_currentRenderFrameIndex - previousFrameIndex) - 1;
|
||||||
|
_droppedFrameRate.increment(skippedCount);
|
||||||
void OpenGLDisplayPlugin::updateFramerate() {
|
|
||||||
uint64_t now = usecTimestampNow();
|
|
||||||
static uint64_t lastSwapEnd { now };
|
|
||||||
uint64_t diff = now - lastSwapEnd;
|
|
||||||
lastSwapEnd = now;
|
|
||||||
if (diff != 0) {
|
|
||||||
Lock lock(_mutex);
|
|
||||||
_usecsPerFrame.updateAverage(diff);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDisplayPlugin::compositeOverlay() {
|
void OpenGLDisplayPlugin::compositeOverlay() {
|
||||||
|
@ -545,19 +539,20 @@ void OpenGLDisplayPlugin::present() {
|
||||||
compositeLayers();
|
compositeLayers();
|
||||||
// Take the composite framebuffer and send it to the output device
|
// Take the composite framebuffer and send it to the output device
|
||||||
internalPresent();
|
internalPresent();
|
||||||
updateFramerate();
|
_presentRate.increment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float OpenGLDisplayPlugin::presentRate() {
|
float OpenGLDisplayPlugin::newFramePresentRate() const {
|
||||||
float result { -1.0f };
|
return _newFrameRate.rate();
|
||||||
{
|
}
|
||||||
Lock lock(_mutex);
|
|
||||||
result = _usecsPerFrame.getAverage();
|
float OpenGLDisplayPlugin::droppedFrameRate() const {
|
||||||
}
|
return _droppedFrameRate.rate();
|
||||||
result = 1.0f / result;
|
}
|
||||||
result *= USECS_PER_SECOND;
|
|
||||||
return result;
|
float OpenGLDisplayPlugin::presentRate() const {
|
||||||
|
return _presentRate.rate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDisplayPlugin::drawUnitQuad() {
|
void OpenGLDisplayPlugin::drawUnitQuad() {
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "DisplayPlugin.h"
|
#include "DisplayPlugin.h"
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <QtCore/QTimer>
|
#include <QtCore/QTimer>
|
||||||
#include <QtGui/QImage>
|
#include <QtGui/QImage>
|
||||||
|
@ -18,6 +19,7 @@
|
||||||
#include <SimpleMovingAverage.h>
|
#include <SimpleMovingAverage.h>
|
||||||
#include <gl/OglplusHelpers.h>
|
#include <gl/OglplusHelpers.h>
|
||||||
#include <gl/GLEscrow.h>
|
#include <gl/GLEscrow.h>
|
||||||
|
#include <shared/RateCounter.h>
|
||||||
|
|
||||||
#define THREADED_PRESENT 1
|
#define THREADED_PRESENT 1
|
||||||
|
|
||||||
|
@ -41,7 +43,6 @@ public:
|
||||||
|
|
||||||
void submitSceneTexture(uint32_t frameIndex, const gpu::TexturePointer& sceneTexture) override;
|
void submitSceneTexture(uint32_t frameIndex, const gpu::TexturePointer& sceneTexture) override;
|
||||||
void submitOverlayTexture(const gpu::TexturePointer& overlayTexture) override;
|
void submitOverlayTexture(const gpu::TexturePointer& overlayTexture) override;
|
||||||
float presentRate() override;
|
|
||||||
|
|
||||||
glm::uvec2 getRecommendedRenderSize() const override {
|
glm::uvec2 getRecommendedRenderSize() const override {
|
||||||
return getSurfacePixels();
|
return getSurfacePixels();
|
||||||
|
@ -53,6 +54,12 @@ public:
|
||||||
|
|
||||||
QImage getScreenshot() const override;
|
QImage getScreenshot() const override;
|
||||||
|
|
||||||
|
float presentRate() const override;
|
||||||
|
|
||||||
|
float newFramePresentRate() const override;
|
||||||
|
|
||||||
|
float droppedFrameRate() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
#if THREADED_PRESENT
|
#if THREADED_PRESENT
|
||||||
friend class PresentThread;
|
friend class PresentThread;
|
||||||
|
@ -88,7 +95,6 @@ protected:
|
||||||
|
|
||||||
void present();
|
void present();
|
||||||
void updateTextures();
|
void updateTextures();
|
||||||
void updateFramerate();
|
|
||||||
void drawUnitQuad();
|
void drawUnitQuad();
|
||||||
void swapBuffers();
|
void swapBuffers();
|
||||||
void eyeViewport(Eye eye) const;
|
void eyeViewport(Eye eye) const;
|
||||||
|
@ -101,7 +107,9 @@ protected:
|
||||||
ShapeWrapperPtr _plane;
|
ShapeWrapperPtr _plane;
|
||||||
|
|
||||||
mutable Mutex _mutex;
|
mutable Mutex _mutex;
|
||||||
SimpleMovingAverage _usecsPerFrame { 10 };
|
RateCounter<> _droppedFrameRate;
|
||||||
|
RateCounter<> _newFrameRate;
|
||||||
|
RateCounter<> _presentRate;
|
||||||
QMap<gpu::TexturePointer, uint32_t> _sceneTextureToFrameIndexMap;
|
QMap<gpu::TexturePointer, uint32_t> _sceneTextureToFrameIndexMap;
|
||||||
uint32_t _currentRenderFrameIndex { 0 };
|
uint32_t _currentRenderFrameIndex { 0 };
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,7 @@ void EntityTree::postAddEntity(EntityItemPointer entity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!entity->isParentIDValid()) {
|
if (!entity->isParentIDValid()) {
|
||||||
|
QWriteLocker locker(&_missingParentLock);
|
||||||
_missingParent.append(entity);
|
_missingParent.append(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,10 +257,12 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
|
||||||
bool success;
|
bool success;
|
||||||
AACube queryCube = childEntity->getQueryAACube(success);
|
AACube queryCube = childEntity->getQueryAACube(success);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
QWriteLocker locker(&_missingParentLock);
|
||||||
_missingParent.append(childEntity);
|
_missingParent.append(childEntity);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!childEntity->isParentIDValid()) {
|
if (!childEntity->isParentIDValid()) {
|
||||||
|
QWriteLocker locker(&_missingParentLock);
|
||||||
_missingParent.append(childEntity);
|
_missingParent.append(childEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,6 +349,7 @@ EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const Enti
|
||||||
if (result->getAncestorMissing()) {
|
if (result->getAncestorMissing()) {
|
||||||
// we added the entity, but didn't know about all its ancestors, so it went into the wrong place.
|
// we added the entity, but didn't know about all its ancestors, so it went into the wrong place.
|
||||||
// add it to a list of entities needing to be fixed once their parents are known.
|
// add it to a list of entities needing to be fixed once their parents are known.
|
||||||
|
QWriteLocker locker(&_missingParentLock);
|
||||||
_missingParent.append(result);
|
_missingParent.append(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1008,10 +1012,27 @@ void EntityTree::entityChanged(EntityItemPointer entity) {
|
||||||
void EntityTree::fixupMissingParents() {
|
void EntityTree::fixupMissingParents() {
|
||||||
MovingEntitiesOperator moveOperator(getThisPointer());
|
MovingEntitiesOperator moveOperator(getThisPointer());
|
||||||
|
|
||||||
QMutableVectorIterator<EntityItemWeakPointer> iter(_missingParent);
|
QList<EntityItemPointer> missingParents;
|
||||||
while (iter.hasNext()) {
|
{
|
||||||
EntityItemWeakPointer entityWP = iter.next();
|
QWriteLocker locker(&_missingParentLock);
|
||||||
EntityItemPointer entity = entityWP.lock();
|
QMutableVectorIterator<EntityItemWeakPointer> iter(_missingParent);
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
EntityItemWeakPointer entityWP = iter.next();
|
||||||
|
EntityItemPointer entity = entityWP.lock();
|
||||||
|
if (entity) {
|
||||||
|
if (entity->isParentIDValid()) {
|
||||||
|
iter.remove();
|
||||||
|
} else {
|
||||||
|
missingParents.append(entity);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// entity was deleted before we found its parent.
|
||||||
|
iter.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (EntityItemPointer entity : missingParents) {
|
||||||
if (entity) {
|
if (entity) {
|
||||||
bool queryAACubeSuccess;
|
bool queryAACubeSuccess;
|
||||||
AACube newCube = entity->getQueryAACube(queryAACubeSuccess);
|
AACube newCube = entity->getQueryAACube(queryAACubeSuccess);
|
||||||
|
@ -1040,12 +1061,8 @@ void EntityTree::fixupMissingParents() {
|
||||||
|
|
||||||
if (queryAACubeSuccess && doMove) {
|
if (queryAACubeSuccess && doMove) {
|
||||||
moveOperator.addEntityToMoveList(entity, newCube);
|
moveOperator.addEntityToMoveList(entity, newCube);
|
||||||
iter.remove();
|
|
||||||
entity->markAncestorMissing(false);
|
entity->markAncestorMissing(false);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// entity was deleted before we found its parent.
|
|
||||||
iter.remove();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -324,6 +324,8 @@ protected:
|
||||||
|
|
||||||
void fixupMissingParents(); // try to hook members of _missingParent to parent instances
|
void fixupMissingParents(); // try to hook members of _missingParent to parent instances
|
||||||
QVector<EntityItemWeakPointer> _missingParent; // entites with a parentID but no (yet) known parent instance
|
QVector<EntityItemWeakPointer> _missingParent; // entites with a parentID but no (yet) known parent instance
|
||||||
|
mutable QReadWriteLock _missingParentLock;
|
||||||
|
|
||||||
// we maintain a list of avatarIDs to notice when an entity is a child of one.
|
// we maintain a list of avatarIDs to notice when an entity is a child of one.
|
||||||
QSet<QUuid> _avatarIDs; // IDs of avatars connected to entity server
|
QSet<QUuid> _avatarIDs; // IDs of avatars connected to entity server
|
||||||
QHash<QUuid, QSet<EntityItemID>> _childrenOfAvatars; // which entities are children of which avatars
|
QHash<QUuid, QSet<EntityItemID>> _childrenOfAvatars; // which entities are children of which avatars
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <QtGui/QSurfaceFormat>
|
#include <QtGui/QSurfaceFormat>
|
||||||
#include <QtOpenGL/QGL>
|
#include <QtOpenGL/QGL>
|
||||||
|
#include <QOpenGLContext>
|
||||||
|
|
||||||
const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() {
|
const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() {
|
||||||
static QSurfaceFormat format;
|
static QSurfaceFormat format;
|
||||||
|
@ -37,3 +38,21 @@ const QGLFormat& getDefaultGLFormat() {
|
||||||
});
|
});
|
||||||
return glFormat;
|
return glFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonObject getGLContextData() {
|
||||||
|
if (!QOpenGLContext::currentContext()) {
|
||||||
|
return QJsonObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString glVersion = QString((const char*)glGetString(GL_VERSION));
|
||||||
|
QString glslVersion = QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||||
|
QString glVendor = QString((const char*) glGetString(GL_VENDOR));
|
||||||
|
QString glRenderer = QString((const char*)glGetString(GL_RENDERER));
|
||||||
|
|
||||||
|
return QJsonObject {
|
||||||
|
{ "version", glVersion },
|
||||||
|
{ "slVersion", glslVersion },
|
||||||
|
{ "vendor", glVendor },
|
||||||
|
{ "renderer", glRenderer },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#ifndef hifi_GLHelpers_h
|
#ifndef hifi_GLHelpers_h
|
||||||
#define hifi_GLHelpers_h
|
#define hifi_GLHelpers_h
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
// 16 bits of depth precision
|
// 16 bits of depth precision
|
||||||
#define DEFAULT_GL_DEPTH_BUFFER_BITS 16
|
#define DEFAULT_GL_DEPTH_BUFFER_BITS 16
|
||||||
// 8 bits of stencil buffer (typically you really only need 1 bit for functionality
|
// 8 bits of stencil buffer (typically you really only need 1 bit for functionality
|
||||||
|
@ -24,4 +26,6 @@ void setGLFormatVersion(F& format, int major = 4, int minor = 5) { format.setVer
|
||||||
|
|
||||||
const QSurfaceFormat& getDefaultOpenGLSurfaceFormat();
|
const QSurfaceFormat& getDefaultOpenGLSurfaceFormat();
|
||||||
const QGLFormat& getDefaultGLFormat();
|
const QGLFormat& getDefaultGLFormat();
|
||||||
|
QJsonObject getGLContextData();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#include "OffscreenGLCanvas.h"
|
#include "OffscreenGLCanvas.h"
|
||||||
#include "GLEscrow.h"
|
#include "GLEscrow.h"
|
||||||
|
#include "GLHelpers.h"
|
||||||
|
|
||||||
|
|
||||||
// Time between receiving a request to render the offscreen UI actually triggering
|
// Time between receiving a request to render the offscreen UI actually triggering
|
||||||
|
@ -222,6 +223,11 @@ void OffscreenQmlRenderThread::init() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Expose GL data to QML
|
||||||
|
auto glData = getGLContextData();
|
||||||
|
auto setGL = [=]{ _surface->getRootContext()->setContextProperty("GL", glData); };
|
||||||
|
_surface->executeOnUiThread(setGL);
|
||||||
|
|
||||||
_renderControl->initialize(_canvas.getContext());
|
_renderControl->initialize(_canvas.getContext());
|
||||||
setupFbo();
|
setupFbo();
|
||||||
_escrow.setRecycler([this](GLuint texture){
|
_escrow.setRecycler([this](GLuint texture){
|
||||||
|
|
|
@ -13,16 +13,18 @@
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "GLWidget.h"
|
#include "GLWidget.h"
|
||||||
|
#include "GLHelpers.h"
|
||||||
|
|
||||||
OpenGLVersionChecker::OpenGLVersionChecker(int& argc, char** argv) :
|
OpenGLVersionChecker::OpenGLVersionChecker(int& argc, char** argv) :
|
||||||
QApplication(argc, argv)
|
QApplication(argc, argv)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QString OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
|
QJsonObject OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
|
||||||
valid = true;
|
valid = true;
|
||||||
override = false;
|
override = false;
|
||||||
|
|
||||||
|
@ -38,12 +40,12 @@ QString OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
|
||||||
messageBox.setStandardButtons(QMessageBox::Ok);
|
messageBox.setStandardButtons(QMessageBox::Ok);
|
||||||
messageBox.setDefaultButton(QMessageBox::Ok);
|
messageBox.setDefaultButton(QMessageBox::Ok);
|
||||||
messageBox.exec();
|
messageBox.exec();
|
||||||
return QString();
|
return QJsonObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve OpenGL version
|
// Retrieve OpenGL version
|
||||||
glWidget->initializeGL();
|
glWidget->initializeGL();
|
||||||
QString glVersion = QString((const char*)glGetString(GL_VERSION));
|
QJsonObject glData = getGLContextData();
|
||||||
delete glWidget;
|
delete glWidget;
|
||||||
|
|
||||||
// Compare against minimum
|
// Compare against minimum
|
||||||
|
@ -51,6 +53,8 @@ QString OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
|
||||||
// - major_number.minor_number
|
// - major_number.minor_number
|
||||||
// - major_number.minor_number.release_number
|
// - major_number.minor_number.release_number
|
||||||
// Reference: https://www.opengl.org/sdk/docs/man/docbook4/xhtml/glGetString.xml
|
// Reference: https://www.opengl.org/sdk/docs/man/docbook4/xhtml/glGetString.xml
|
||||||
|
const QString version { "version" };
|
||||||
|
QString glVersion = glData[version].toString();
|
||||||
QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]"));
|
QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]"));
|
||||||
int majorNumber = versionParts[0].toInt();
|
int majorNumber = versionParts[0].toInt();
|
||||||
int minorNumber = versionParts[1].toInt();
|
int minorNumber = versionParts[1].toInt();
|
||||||
|
@ -72,5 +76,5 @@ QString OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
|
||||||
override = messageBox.exec() == QMessageBox::Ignore;
|
override = messageBox.exec() == QMessageBox::Ignore;
|
||||||
}
|
}
|
||||||
|
|
||||||
return glVersion;
|
return glData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ class OpenGLVersionChecker : public QApplication {
|
||||||
public:
|
public:
|
||||||
OpenGLVersionChecker(int& argc, char** argv);
|
OpenGLVersionChecker(int& argc, char** argv);
|
||||||
|
|
||||||
static QString checkVersion(bool& valid, bool& override);
|
static QJsonObject checkVersion(bool& valid, bool& override);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_OpenGLVersionChecker_h
|
#endif // hifi_OpenGLVersionChecker_h
|
||||||
|
|
|
@ -114,6 +114,8 @@ std::atomic<Buffer::Size> Context::_bufferGPUMemoryUsage{ 0 };
|
||||||
|
|
||||||
std::atomic<uint32_t> Context::_textureGPUCount{ 0 };
|
std::atomic<uint32_t> Context::_textureGPUCount{ 0 };
|
||||||
std::atomic<Texture::Size> Context::_textureGPUMemoryUsage{ 0 };
|
std::atomic<Texture::Size> Context::_textureGPUMemoryUsage{ 0 };
|
||||||
|
std::atomic<Texture::Size> Context::_textureGPUVirtualMemoryUsage{ 0 };
|
||||||
|
std::atomic<uint32_t> Context::_textureGPUTransferCount{ 0 };
|
||||||
|
|
||||||
void Context::incrementBufferGPUCount() {
|
void Context::incrementBufferGPUCount() {
|
||||||
_bufferGPUCount++;
|
_bufferGPUCount++;
|
||||||
|
@ -149,6 +151,24 @@ void Context::updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSiz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Context::updateTextureGPUVirtualMemoryUsage(Size prevObjectSize, Size newObjectSize) {
|
||||||
|
if (prevObjectSize == newObjectSize) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (newObjectSize > prevObjectSize) {
|
||||||
|
_textureGPUVirtualMemoryUsage.fetch_add(newObjectSize - prevObjectSize);
|
||||||
|
} else {
|
||||||
|
_textureGPUVirtualMemoryUsage.fetch_sub(prevObjectSize - newObjectSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Context::incrementTextureGPUTransferCount() {
|
||||||
|
_textureGPUTransferCount++;
|
||||||
|
}
|
||||||
|
void Context::decrementTextureGPUTransferCount() {
|
||||||
|
_textureGPUTransferCount--;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t Context::getBufferGPUCount() {
|
uint32_t Context::getBufferGPUCount() {
|
||||||
return _bufferGPUCount.load();
|
return _bufferGPUCount.load();
|
||||||
}
|
}
|
||||||
|
@ -165,10 +185,20 @@ Context::Size Context::getTextureGPUMemoryUsage() {
|
||||||
return _textureGPUMemoryUsage.load();
|
return _textureGPUMemoryUsage.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Context::Size Context::getTextureGPUVirtualMemoryUsage() {
|
||||||
|
return _textureGPUVirtualMemoryUsage.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Context::getTextureGPUTransferCount() {
|
||||||
|
return _textureGPUTransferCount.load();
|
||||||
|
}
|
||||||
|
|
||||||
void Backend::incrementBufferGPUCount() { Context::incrementBufferGPUCount(); }
|
void Backend::incrementBufferGPUCount() { Context::incrementBufferGPUCount(); }
|
||||||
void Backend::decrementBufferGPUCount() { Context::decrementBufferGPUCount(); }
|
void Backend::decrementBufferGPUCount() { Context::decrementBufferGPUCount(); }
|
||||||
void Backend::updateBufferGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateBufferGPUMemoryUsage(prevObjectSize, newObjectSize); }
|
void Backend::updateBufferGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateBufferGPUMemoryUsage(prevObjectSize, newObjectSize); }
|
||||||
void Backend::incrementTextureGPUCount() { Context::incrementTextureGPUCount(); }
|
void Backend::incrementTextureGPUCount() { Context::incrementTextureGPUCount(); }
|
||||||
void Backend::decrementTextureGPUCount() { Context::decrementTextureGPUCount(); }
|
void Backend::decrementTextureGPUCount() { Context::decrementTextureGPUCount(); }
|
||||||
void Backend::updateTextureGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateTextureGPUMemoryUsage(prevObjectSize, newObjectSize); }
|
void Backend::updateTextureGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateTextureGPUMemoryUsage(prevObjectSize, newObjectSize); }
|
||||||
|
void Backend::updateTextureGPUVirtualMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateTextureGPUVirtualMemoryUsage(prevObjectSize, newObjectSize); }
|
||||||
|
void Backend::incrementTextureGPUTransferCount() { Context::incrementTextureGPUTransferCount(); }
|
||||||
|
void Backend::decrementTextureGPUTransferCount() { Context::decrementTextureGPUTransferCount(); }
|
||||||
|
|
|
@ -34,6 +34,7 @@ public:
|
||||||
int _ISNumIndexBufferChanges = 0;
|
int _ISNumIndexBufferChanges = 0;
|
||||||
|
|
||||||
int _RSNumTextureBounded = 0;
|
int _RSNumTextureBounded = 0;
|
||||||
|
int _RSAmountTextureMemoryBounded = 0;
|
||||||
|
|
||||||
int _DSNumAPIDrawcalls = 0;
|
int _DSNumAPIDrawcalls = 0;
|
||||||
int _DSNumDrawcalls = 0;
|
int _DSNumDrawcalls = 0;
|
||||||
|
@ -128,6 +129,9 @@ public:
|
||||||
static void incrementTextureGPUCount();
|
static void incrementTextureGPUCount();
|
||||||
static void decrementTextureGPUCount();
|
static void decrementTextureGPUCount();
|
||||||
static void updateTextureGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize);
|
static void updateTextureGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize);
|
||||||
|
static void updateTextureGPUVirtualMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize);
|
||||||
|
static void incrementTextureGPUTransferCount();
|
||||||
|
static void decrementTextureGPUTransferCount();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
StereoState _stereo;
|
StereoState _stereo;
|
||||||
|
@ -177,6 +181,8 @@ public:
|
||||||
|
|
||||||
static uint32_t getTextureGPUCount();
|
static uint32_t getTextureGPUCount();
|
||||||
static Size getTextureGPUMemoryUsage();
|
static Size getTextureGPUMemoryUsage();
|
||||||
|
static Size getTextureGPUVirtualMemoryUsage();
|
||||||
|
static uint32_t getTextureGPUTransferCount();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Context(const Context& context);
|
Context(const Context& context);
|
||||||
|
@ -202,6 +208,9 @@ protected:
|
||||||
static void incrementTextureGPUCount();
|
static void incrementTextureGPUCount();
|
||||||
static void decrementTextureGPUCount();
|
static void decrementTextureGPUCount();
|
||||||
static void updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
|
static void updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
|
||||||
|
static void updateTextureGPUVirtualMemoryUsage(Size prevObjectSize, Size newObjectSize);
|
||||||
|
static void incrementTextureGPUTransferCount();
|
||||||
|
static void decrementTextureGPUTransferCount();
|
||||||
|
|
||||||
// Buffer and Texture Counters
|
// Buffer and Texture Counters
|
||||||
static std::atomic<uint32_t> _bufferGPUCount;
|
static std::atomic<uint32_t> _bufferGPUCount;
|
||||||
|
@ -209,6 +218,9 @@ protected:
|
||||||
|
|
||||||
static std::atomic<uint32_t> _textureGPUCount;
|
static std::atomic<uint32_t> _textureGPUCount;
|
||||||
static std::atomic<Size> _textureGPUMemoryUsage;
|
static std::atomic<Size> _textureGPUMemoryUsage;
|
||||||
|
static std::atomic<Size> _textureGPUVirtualMemoryUsage;
|
||||||
|
static std::atomic<uint32_t> _textureGPUTransferCount;
|
||||||
|
|
||||||
|
|
||||||
friend class Backend;
|
friend class Backend;
|
||||||
};
|
};
|
||||||
|
|
|
@ -192,6 +192,25 @@ enum Semantic {
|
||||||
SRGBA,
|
SRGBA,
|
||||||
SBGRA,
|
SBGRA,
|
||||||
|
|
||||||
|
// These are generic compression format smeantic for images
|
||||||
|
_FIRST_COMPRESSED,
|
||||||
|
COMPRESSED_R,
|
||||||
|
|
||||||
|
COMPRESSED_RGB,
|
||||||
|
COMPRESSED_RGBA,
|
||||||
|
|
||||||
|
COMPRESSED_SRGB,
|
||||||
|
COMPRESSED_SRGBA,
|
||||||
|
|
||||||
|
// FIXME: Will have to be supported later:
|
||||||
|
/*COMPRESSED_BC3_RGBA, // RGBA_S3TC_DXT5_EXT,
|
||||||
|
COMPRESSED_BC3_SRGBA, // SRGB_ALPHA_S3TC_DXT5_EXT
|
||||||
|
|
||||||
|
COMPRESSED_BC7_RGBA,
|
||||||
|
COMPRESSED_BC7_SRGBA, */
|
||||||
|
|
||||||
|
_LAST_COMPRESSED,
|
||||||
|
|
||||||
R11G11B10,
|
R11G11B10,
|
||||||
|
|
||||||
UNIFORM,
|
UNIFORM,
|
||||||
|
@ -224,6 +243,7 @@ public:
|
||||||
|
|
||||||
Dimension getDimension() const { return (Dimension)_dimension; }
|
Dimension getDimension() const { return (Dimension)_dimension; }
|
||||||
|
|
||||||
|
bool isCompressed() const { return uint8(getSemantic() - _FIRST_COMPRESSED) <= uint8(_LAST_COMPRESSED - _FIRST_COMPRESSED); }
|
||||||
|
|
||||||
Type getType() const { return (Type)_type; }
|
Type getType() const { return (Type)_type; }
|
||||||
bool isNormalized() const { return (getType() >= NORMALIZED_START); }
|
bool isNormalized() const { return (getType() >= NORMALIZED_START); }
|
||||||
|
|
|
@ -76,15 +76,22 @@ public:
|
||||||
|
|
||||||
class GLTexture : public GPUObject {
|
class GLTexture : public GPUObject {
|
||||||
public:
|
public:
|
||||||
|
// The public gl texture object
|
||||||
|
GLuint _texture{ 0 };
|
||||||
|
|
||||||
const Stamp _storageStamp;
|
const Stamp _storageStamp;
|
||||||
Stamp _contentStamp { 0 };
|
Stamp _contentStamp { 0 };
|
||||||
const GLuint _texture;
|
|
||||||
const GLenum _target;
|
const GLenum _target;
|
||||||
|
|
||||||
GLTexture(const gpu::Texture& gpuTexture);
|
GLTexture(const gpu::Texture& gpuTexture);
|
||||||
~GLTexture();
|
~GLTexture();
|
||||||
|
|
||||||
|
void createTexture();
|
||||||
|
|
||||||
GLuint size() const { return _size; }
|
GLuint size() const { return _size; }
|
||||||
|
GLuint virtualSize() const { return _virtualSize; }
|
||||||
|
|
||||||
|
void updateSize();
|
||||||
|
|
||||||
enum SyncState {
|
enum SyncState {
|
||||||
// The texture is currently undergoing no processing, although it's content
|
// The texture is currently undergoing no processing, although it's content
|
||||||
|
@ -119,16 +126,26 @@ public:
|
||||||
|
|
||||||
static const size_t CUBE_NUM_FACES = 6;
|
static const size_t CUBE_NUM_FACES = 6;
|
||||||
static const GLenum CUBE_FACE_LAYOUT[6];
|
static const GLenum CUBE_FACE_LAYOUT[6];
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// at creation the true texture is created in GL
|
||||||
|
// it becomes public only when ready.
|
||||||
|
GLuint _privateTexture{ 0 };
|
||||||
|
|
||||||
|
void setSize(GLuint size);
|
||||||
|
void setVirtualSize(GLuint size);
|
||||||
|
|
||||||
|
GLuint _size; // true size as reported by the gl api
|
||||||
|
GLuint _virtualSize; // theorical size as expected
|
||||||
|
GLuint _numLevels{ 0 };
|
||||||
|
|
||||||
void transferMip(GLenum target, const Texture::PixelsPointer& mip) const;
|
void transferMip(GLenum target, const Texture::PixelsPointer& mip) const;
|
||||||
|
|
||||||
const GLuint _size;
|
|
||||||
// The owning texture
|
// The owning texture
|
||||||
const Texture& _gpuTexture;
|
const Texture& _gpuTexture;
|
||||||
std::atomic<SyncState> _syncState { SyncState::Idle };
|
std::atomic<SyncState> _syncState { SyncState::Idle };
|
||||||
};
|
};
|
||||||
static GLTexture* syncGPUObject(const TexturePointer& texture);
|
static GLTexture* syncGPUObject(const TexturePointer& texture, bool needTransfer = true);
|
||||||
static GLuint getTextureID(const TexturePointer& texture, bool sync = true);
|
static GLuint getTextureID(const TexturePointer& texture, bool sync = true);
|
||||||
|
|
||||||
// very specific for now
|
// very specific for now
|
||||||
|
|
|
@ -83,7 +83,7 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe
|
||||||
for (auto& b : framebuffer.getRenderBuffers()) {
|
for (auto& b : framebuffer.getRenderBuffers()) {
|
||||||
surface = b._texture;
|
surface = b._texture;
|
||||||
if (surface) {
|
if (surface) {
|
||||||
gltexture = GLBackend::syncGPUObject(surface);
|
gltexture = GLBackend::syncGPUObject(surface, false); // Grab the gltexture and don't transfer
|
||||||
} else {
|
} else {
|
||||||
gltexture = nullptr;
|
gltexture = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe
|
||||||
if (framebuffer.getDepthStamp() != object->_depthStamp) {
|
if (framebuffer.getDepthStamp() != object->_depthStamp) {
|
||||||
auto surface = framebuffer.getDepthStencilBuffer();
|
auto surface = framebuffer.getDepthStencilBuffer();
|
||||||
if (framebuffer.hasDepthStencil() && surface) {
|
if (framebuffer.hasDepthStencil() && surface) {
|
||||||
gltexture = GLBackend::syncGPUObject(surface);
|
gltexture = GLBackend::syncGPUObject(surface, false); // Grab the gltexture and don't transfer
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gltexture) {
|
if (gltexture) {
|
||||||
|
|
|
@ -266,6 +266,8 @@ void GLBackend::do_setResourceTexture(Batch& batch, size_t paramOffset) {
|
||||||
|
|
||||||
_resource._textures[slot] = resourceTexture;
|
_resource._textures[slot] = resourceTexture;
|
||||||
|
|
||||||
|
_stats._RSAmountTextureMemoryBounded += object->size();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
releaseResourceTexture(slot);
|
releaseResourceTexture(slot);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -45,6 +45,20 @@ static const GLenum _elementTypeToGLType[gpu::NUM_TYPES] = {
|
||||||
GL_UNSIGNED_BYTE
|
GL_UNSIGNED_BYTE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GLTexelFormat {
|
||||||
|
public:
|
||||||
|
GLenum internalFormat;
|
||||||
|
GLenum format;
|
||||||
|
GLenum type;
|
||||||
|
|
||||||
|
static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat) {
|
||||||
|
return evalGLTexelFormat(dstFormat, dstFormat);
|
||||||
|
}
|
||||||
|
static GLTexelFormat evalGLTexelFormatInternal(const gpu::Element& dstFormat);
|
||||||
|
|
||||||
|
static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat, const gpu::Element& srcFormat);
|
||||||
|
};
|
||||||
|
|
||||||
// Stupid preprocessor trick to turn the line macro into a string
|
// Stupid preprocessor trick to turn the line macro into a string
|
||||||
#define CHECK_GL_ERROR_HELPER(x) #x
|
#define CHECK_GL_ERROR_HELPER(x) #x
|
||||||
// FIXME doesn't build on Linux or Mac. Hmmmm
|
// FIXME doesn't build on Linux or Mac. Hmmmm
|
||||||
|
|
426
libraries/gpu/src/gpu/GLBackendTexelFormat.cpp
Normal file
426
libraries/gpu/src/gpu/GLBackendTexelFormat.cpp
Normal file
|
@ -0,0 +1,426 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2016/04/03
|
||||||
|
// 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"
|
||||||
|
|
||||||
|
using namespace gpu;
|
||||||
|
|
||||||
|
GLTexelFormat GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) {
|
||||||
|
GLTexelFormat texel = { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE };
|
||||||
|
return texel;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat) {
|
||||||
|
if (dstFormat != srcFormat) {
|
||||||
|
GLTexelFormat texel = { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE };
|
||||||
|
|
||||||
|
switch (dstFormat.getDimension()) {
|
||||||
|
case gpu::SCALAR: {
|
||||||
|
texel.format = GL_RED;
|
||||||
|
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||||
|
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
texel.internalFormat = GL_R8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case gpu::COMPRESSED_R:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_RED_RGTC1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case gpu::DEPTH:
|
||||||
|
texel.internalFormat = GL_DEPTH_COMPONENT32;
|
||||||
|
break;
|
||||||
|
case gpu::DEPTH_STENCIL:
|
||||||
|
texel.type = GL_UNSIGNED_INT_24_8;
|
||||||
|
texel.format = GL_DEPTH_STENCIL;
|
||||||
|
texel.internalFormat = GL_DEPTH24_STENCIL8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case gpu::VEC2: {
|
||||||
|
texel.format = GL_RG;
|
||||||
|
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||||
|
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
texel.internalFormat = GL_RG8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case gpu::VEC3: {
|
||||||
|
texel.format = GL_RGB;
|
||||||
|
|
||||||
|
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||||
|
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
texel.internalFormat = GL_RGB8;
|
||||||
|
break;
|
||||||
|
case gpu::COMPRESSED_RGB:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_RGB;
|
||||||
|
break;
|
||||||
|
case gpu::COMPRESSED_SRGB:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_SRGB;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case gpu::VEC4: {
|
||||||
|
texel.format = GL_RGBA;
|
||||||
|
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||||
|
|
||||||
|
switch (srcFormat.getSemantic()) {
|
||||||
|
case gpu::BGRA:
|
||||||
|
case gpu::SBGRA:
|
||||||
|
texel.format = GL_BGRA;
|
||||||
|
break;
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
case gpu::SRGB:
|
||||||
|
case gpu::SRGBA:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
texel.internalFormat = GL_RGB8;
|
||||||
|
break;
|
||||||
|
case gpu::RGBA:
|
||||||
|
texel.internalFormat = GL_RGBA8;
|
||||||
|
break;
|
||||||
|
case gpu::SRGB:
|
||||||
|
texel.internalFormat = GL_SRGB8;
|
||||||
|
break;
|
||||||
|
case gpu::SRGBA:
|
||||||
|
texel.internalFormat = GL_SRGB8_ALPHA8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case gpu::COMPRESSED_RGBA:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_RGBA;
|
||||||
|
break;
|
||||||
|
case gpu::COMPRESSED_SRGBA:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
// FIXME: WE will want to support this later
|
||||||
|
/*
|
||||||
|
case gpu::COMPRESSED_BC3_RGBA:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||||
|
break;
|
||||||
|
case gpu::COMPRESSED_BC3_SRGBA:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case gpu::COMPRESSED_BC7_RGBA:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
|
||||||
|
break;
|
||||||
|
case gpu::COMPRESSED_BC7_SRGBA:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
|
||||||
|
default:
|
||||||
|
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
return texel;
|
||||||
|
} else {
|
||||||
|
GLTexelFormat texel = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE };
|
||||||
|
|
||||||
|
switch (dstFormat.getDimension()) {
|
||||||
|
case gpu::SCALAR: {
|
||||||
|
texel.format = GL_RED;
|
||||||
|
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||||
|
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::COMPRESSED_R: {
|
||||||
|
texel.internalFormat = GL_COMPRESSED_RED_RGTC1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
case gpu::SRGB:
|
||||||
|
case gpu::SRGBA:
|
||||||
|
texel.internalFormat = GL_RED;
|
||||||
|
switch (dstFormat.getType()) {
|
||||||
|
case gpu::UINT32: {
|
||||||
|
texel.internalFormat = GL_R32UI;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::INT32: {
|
||||||
|
texel.internalFormat = GL_R32I;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::NUINT32: {
|
||||||
|
texel.internalFormat = GL_R8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::NINT32: {
|
||||||
|
texel.internalFormat = GL_R8_SNORM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::FLOAT: {
|
||||||
|
texel.internalFormat = GL_R32F;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::UINT16: {
|
||||||
|
texel.internalFormat = GL_R16UI;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::INT16: {
|
||||||
|
texel.internalFormat = GL_R16I;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::NUINT16: {
|
||||||
|
texel.internalFormat = GL_R16;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::NINT16: {
|
||||||
|
texel.internalFormat = GL_R16_SNORM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::HALF: {
|
||||||
|
texel.internalFormat = GL_R16F;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::UINT8: {
|
||||||
|
texel.internalFormat = GL_R8UI;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::INT8: {
|
||||||
|
texel.internalFormat = GL_R8I;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::NUINT8: {
|
||||||
|
if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) {
|
||||||
|
texel.internalFormat = GL_SLUMINANCE8;
|
||||||
|
} else {
|
||||||
|
texel.internalFormat = GL_R8;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::NINT8: {
|
||||||
|
texel.internalFormat = GL_R8_SNORM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::NUM_TYPES: { // quiet compiler
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case gpu::R11G11B10:
|
||||||
|
texel.format = GL_RGB;
|
||||||
|
// the type should be float
|
||||||
|
texel.internalFormat = GL_R11F_G11F_B10F;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case gpu::DEPTH:
|
||||||
|
texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it
|
||||||
|
texel.internalFormat = GL_DEPTH_COMPONENT32;
|
||||||
|
switch (dstFormat.getType()) {
|
||||||
|
case gpu::UINT32:
|
||||||
|
case gpu::INT32:
|
||||||
|
case gpu::NUINT32:
|
||||||
|
case gpu::NINT32: {
|
||||||
|
texel.internalFormat = GL_DEPTH_COMPONENT32;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::FLOAT: {
|
||||||
|
texel.internalFormat = GL_DEPTH_COMPONENT32F;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::UINT16:
|
||||||
|
case gpu::INT16:
|
||||||
|
case gpu::NUINT16:
|
||||||
|
case gpu::NINT16:
|
||||||
|
case gpu::HALF: {
|
||||||
|
texel.internalFormat = GL_DEPTH_COMPONENT16;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::UINT8:
|
||||||
|
case gpu::INT8:
|
||||||
|
case gpu::NUINT8:
|
||||||
|
case gpu::NINT8: {
|
||||||
|
texel.internalFormat = GL_DEPTH_COMPONENT24;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case gpu::NUM_TYPES: { // quiet compiler
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case gpu::DEPTH_STENCIL:
|
||||||
|
texel.type = GL_UNSIGNED_INT_24_8;
|
||||||
|
texel.format = GL_DEPTH_STENCIL;
|
||||||
|
texel.internalFormat = GL_DEPTH24_STENCIL8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case gpu::VEC2: {
|
||||||
|
texel.format = GL_RG;
|
||||||
|
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||||
|
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
texel.internalFormat = GL_RG8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case gpu::VEC3: {
|
||||||
|
texel.format = GL_RGB;
|
||||||
|
|
||||||
|
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||||
|
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
case gpu::RGBA:
|
||||||
|
texel.internalFormat = GL_RGB8;
|
||||||
|
break;
|
||||||
|
case gpu::SRGB:
|
||||||
|
case gpu::SRGBA:
|
||||||
|
texel.internalFormat = GL_SRGB8; // standard 2.2 gamma correction color
|
||||||
|
break;
|
||||||
|
case gpu::COMPRESSED_RGB:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_RGB;
|
||||||
|
break;
|
||||||
|
case gpu::COMPRESSED_SRGB:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_SRGB;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case gpu::VEC4: {
|
||||||
|
texel.format = GL_RGBA;
|
||||||
|
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
||||||
|
|
||||||
|
switch (dstFormat.getSemantic()) {
|
||||||
|
case gpu::RGB:
|
||||||
|
texel.internalFormat = GL_RGB8;
|
||||||
|
break;
|
||||||
|
case gpu::RGBA:
|
||||||
|
texel.internalFormat = GL_RGBA8;
|
||||||
|
switch (dstFormat.getType()) {
|
||||||
|
case gpu::UINT32:
|
||||||
|
texel.format = GL_RGBA_INTEGER;
|
||||||
|
texel.internalFormat = GL_RGBA32UI;
|
||||||
|
break;
|
||||||
|
case gpu::INT32:
|
||||||
|
texel.format = GL_RGBA_INTEGER;
|
||||||
|
texel.internalFormat = GL_RGBA32I;
|
||||||
|
break;
|
||||||
|
case gpu::FLOAT:
|
||||||
|
texel.internalFormat = GL_RGBA32F;
|
||||||
|
break;
|
||||||
|
case gpu::UINT16:
|
||||||
|
texel.format = GL_RGBA_INTEGER;
|
||||||
|
texel.internalFormat = GL_RGBA16UI;
|
||||||
|
break;
|
||||||
|
case gpu::INT16:
|
||||||
|
texel.format = GL_RGBA_INTEGER;
|
||||||
|
texel.internalFormat = GL_RGBA16I;
|
||||||
|
break;
|
||||||
|
case gpu::NUINT16:
|
||||||
|
texel.format = GL_RGBA;
|
||||||
|
texel.internalFormat = GL_RGBA16;
|
||||||
|
break;
|
||||||
|
case gpu::NINT16:
|
||||||
|
texel.format = GL_RGBA;
|
||||||
|
texel.internalFormat = GL_RGBA16_SNORM;
|
||||||
|
break;
|
||||||
|
case gpu::HALF:
|
||||||
|
texel.format = GL_RGBA;
|
||||||
|
texel.internalFormat = GL_RGBA16F;
|
||||||
|
break;
|
||||||
|
case gpu::UINT8:
|
||||||
|
texel.format = GL_RGBA_INTEGER;
|
||||||
|
texel.internalFormat = GL_RGBA8UI;
|
||||||
|
break;
|
||||||
|
case gpu::INT8:
|
||||||
|
texel.format = GL_RGBA_INTEGER;
|
||||||
|
texel.internalFormat = GL_RGBA8I;
|
||||||
|
break;
|
||||||
|
case gpu::NUINT8:
|
||||||
|
texel.format = GL_RGBA;
|
||||||
|
texel.internalFormat = GL_RGBA8;
|
||||||
|
break;
|
||||||
|
case gpu::NINT8:
|
||||||
|
texel.format = GL_RGBA;
|
||||||
|
texel.internalFormat = GL_RGBA8_SNORM;
|
||||||
|
break;
|
||||||
|
case gpu::NUINT32:
|
||||||
|
case gpu::NINT32:
|
||||||
|
case gpu::NUM_TYPES: // quiet compiler
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case gpu::SRGB:
|
||||||
|
texel.format = GL_RGB;
|
||||||
|
texel.internalFormat = GL_SRGB8;
|
||||||
|
break;
|
||||||
|
case gpu::SRGBA:
|
||||||
|
texel.format = GL_RGBA;
|
||||||
|
texel.internalFormat = GL_SRGB8_ALPHA8; // standard 2.2 gamma correction color
|
||||||
|
break;
|
||||||
|
case gpu::COMPRESSED_RGBA:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_RGBA;
|
||||||
|
break;
|
||||||
|
case gpu::COMPRESSED_SRGBA:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||||
|
}
|
||||||
|
return texel;
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,6 @@
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
|
|
||||||
#include "GLBackendShared.h"
|
#include "GLBackendShared.h"
|
||||||
#include "GLTexelFormat.h"
|
|
||||||
#include "GLBackendTextureTransfer.h"
|
#include "GLBackendTextureTransfer.h"
|
||||||
|
|
||||||
using namespace gpu;
|
using namespace gpu;
|
||||||
|
@ -49,49 +48,145 @@ const GLenum GLBackend::GLTexture::CUBE_FACE_LAYOUT[6] = {
|
||||||
|
|
||||||
// Create the texture and allocate storage
|
// Create the texture and allocate storage
|
||||||
GLBackend::GLTexture::GLTexture(const Texture& texture) :
|
GLBackend::GLTexture::GLTexture(const Texture& texture) :
|
||||||
_storageStamp(texture.getStamp()), _texture(allocateSingleTexture()),
|
_storageStamp(texture.getStamp()),
|
||||||
_target(gpuToGLTextureType(texture)), _size((GLuint)texture.getSize()), _gpuTexture(texture)
|
_target(gpuToGLTextureType(texture)),
|
||||||
|
_size(0),
|
||||||
|
_virtualSize(0),
|
||||||
|
_numLevels(texture.maxMip() + 1),
|
||||||
|
_gpuTexture(texture)
|
||||||
{
|
{
|
||||||
Backend::incrementTextureGPUCount();
|
Backend::incrementTextureGPUCount();
|
||||||
Backend::updateTextureGPUMemoryUsage(0, _size);
|
|
||||||
Backend::setGPUObject(texture, this);
|
Backend::setGPUObject(texture, this);
|
||||||
|
|
||||||
GLsizei width = texture.getWidth();
|
|
||||||
GLsizei height = texture.getHeight();
|
// updateSize();
|
||||||
GLsizei levels = 1;
|
GLuint virtualSize = _gpuTexture.evalTotalSize();
|
||||||
if (texture.maxMip() > 0) {
|
setVirtualSize(virtualSize);
|
||||||
if (texture.isAutogenerateMips()) {
|
setSize(virtualSize);
|
||||||
while ((width | height) >> levels) {
|
}
|
||||||
++levels;
|
|
||||||
|
void GLBackend::GLTexture::createTexture() {
|
||||||
|
_privateTexture = allocateSingleTexture();
|
||||||
|
|
||||||
|
GLsizei width = _gpuTexture.getWidth();
|
||||||
|
GLsizei height = _gpuTexture.getHeight();
|
||||||
|
|
||||||
|
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuTexture.getTexelFormat());
|
||||||
|
|
||||||
|
GLint boundTex = -1;
|
||||||
|
switch (_target) {
|
||||||
|
case GL_TEXTURE_2D:
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GL_TEXTURE_CUBE_MAP:
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
qFatal("Unsupported texture type");
|
||||||
|
}
|
||||||
|
(void)CHECK_GL_ERROR();
|
||||||
|
|
||||||
|
glBindTexture(_target, _privateTexture);
|
||||||
|
|
||||||
|
(void)CHECK_GL_ERROR();
|
||||||
|
// Fixme: this usage of TexStorage doesn;t work wtih compressed texture, altuogh it should.
|
||||||
|
// GO through the process of allocating the correct storage
|
||||||
|
/* if (GLEW_VERSION_4_2 && !texture.getTexelFormat().isCompressed()) {
|
||||||
|
glTexStorage2D(_target, _numLevels, texelFormat.internalFormat, width, height);
|
||||||
|
(void)CHECK_GL_ERROR();
|
||||||
|
} else*/
|
||||||
|
{
|
||||||
|
glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0);
|
||||||
|
glTexParameteri(_target, GL_TEXTURE_MAX_LEVEL, _numLevels - 1);
|
||||||
|
|
||||||
|
// for (int l = 0; l < _numLevels; l++) {
|
||||||
|
{ int l = 0;
|
||||||
|
if (_gpuTexture.getType() == gpu::Texture::TEX_CUBE) {
|
||||||
|
for (size_t face = 0; face < CUBE_NUM_FACES; face++) {
|
||||||
|
glTexImage2D(CUBE_FACE_LAYOUT[face], l, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, NULL);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
glTexImage2D(_target, l, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, NULL);
|
||||||
}
|
}
|
||||||
levels = std::max(1, std::min(texture.maxMip() + 1, levels));
|
width = std::max(1, (width / 2));
|
||||||
|
height = std::max(1, (height / 2));
|
||||||
|
}
|
||||||
|
(void)CHECK_GL_ERROR();
|
||||||
}
|
}
|
||||||
|
|
||||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat());
|
syncSampler(_gpuTexture.getSampler(), _gpuTexture.getType(), this);
|
||||||
withPreservedTexture(_target, [&] {
|
(void)CHECK_GL_ERROR();
|
||||||
glBindTexture(_target, _texture);
|
|
||||||
(void)CHECK_GL_ERROR();
|
|
||||||
// GO through the process of allocating the correct storage
|
glBindTexture(_target, boundTex);
|
||||||
if (GLEW_VERSION_4_2) {
|
(void)CHECK_GL_ERROR();
|
||||||
glTexStorage2D(_target, levels, texelFormat.internalFormat, width, height);
|
|
||||||
} else {
|
|
||||||
glTexImage2D(_target, 0, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, 0);
|
|
||||||
}
|
|
||||||
(void)CHECK_GL_ERROR();
|
|
||||||
syncSampler(texture.getSampler(), texture.getType(), this);
|
|
||||||
(void)CHECK_GL_ERROR();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GLBackend::GLTexture::~GLTexture() {
|
GLBackend::GLTexture::~GLTexture() {
|
||||||
if (_texture != 0) {
|
if (_privateTexture != 0) {
|
||||||
glDeleteTextures(1, &_texture);
|
glDeleteTextures(1, &_privateTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
Backend::updateTextureGPUMemoryUsage(_size, 0);
|
Backend::updateTextureGPUMemoryUsage(_size, 0);
|
||||||
|
Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, 0);
|
||||||
Backend::decrementTextureGPUCount();
|
Backend::decrementTextureGPUCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GLBackend::GLTexture::setSize(GLuint size) {
|
||||||
|
Backend::updateTextureGPUMemoryUsage(_size, size);
|
||||||
|
_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLBackend::GLTexture::setVirtualSize(GLuint size) {
|
||||||
|
Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, size);
|
||||||
|
_virtualSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLBackend::GLTexture::updateSize() {
|
||||||
|
GLuint virtualSize = _gpuTexture.evalTotalSize();
|
||||||
|
setVirtualSize(virtualSize);
|
||||||
|
if (!_texture) {
|
||||||
|
setSize(virtualSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_gpuTexture.getTexelFormat().isCompressed()) {
|
||||||
|
GLenum proxyType = GL_TEXTURE_2D;
|
||||||
|
GLuint numFaces = 1;
|
||||||
|
if (_gpuTexture.getType() == gpu::Texture::TEX_CUBE) {
|
||||||
|
proxyType = CUBE_FACE_LAYOUT[0];
|
||||||
|
numFaces = CUBE_NUM_FACES;
|
||||||
|
}
|
||||||
|
GLint gpuSize{ 0 };
|
||||||
|
glGetTexLevelParameteriv(proxyType, 0, GL_TEXTURE_COMPRESSED, &gpuSize);
|
||||||
|
(void)CHECK_GL_ERROR();
|
||||||
|
|
||||||
|
if (gpuSize) {
|
||||||
|
for (GLuint level = 0; level < _numLevels; level++) {
|
||||||
|
GLint levelSize{ 0 };
|
||||||
|
glGetTexLevelParameteriv(proxyType, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &levelSize);
|
||||||
|
levelSize *= numFaces;
|
||||||
|
|
||||||
|
if (levelSize <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gpuSize += levelSize;
|
||||||
|
}
|
||||||
|
(void)CHECK_GL_ERROR();
|
||||||
|
|
||||||
|
setSize(gpuSize);
|
||||||
|
} else {
|
||||||
|
setSize(virtualSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
setSize(virtualSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool GLBackend::GLTexture::isInvalid() const {
|
bool GLBackend::GLTexture::isInvalid() const {
|
||||||
return _storageStamp < _gpuTexture.getStamp();
|
return _storageStamp < _gpuTexture.getStamp();
|
||||||
}
|
}
|
||||||
|
@ -117,44 +212,25 @@ bool GLBackend::GLTexture::isReady() const {
|
||||||
return Idle == syncState;
|
return Idle == syncState;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#define USE_PBO
|
|
||||||
|
|
||||||
// Move content bits from the CPU to the GPU for a given mip / face
|
// Move content bits from the CPU to the GPU for a given mip / face
|
||||||
void GLBackend::GLTexture::transferMip(GLenum target, const Texture::PixelsPointer& mip) const {
|
void GLBackend::GLTexture::transferMip(GLenum target, const Texture::PixelsPointer& mip) const {
|
||||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuTexture.getTexelFormat(), mip->getFormat());
|
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuTexture.getTexelFormat(), mip->getFormat());
|
||||||
#ifdef USE_PBO
|
glTexSubImage2D(target, 0, 0, 0, _gpuTexture.getWidth(), _gpuTexture.getHeight(), texelFormat.format, texelFormat.type, mip->readData()); glTexSubImage2D(target, 0, 0, 0, _gpuTexture.getWidth(), _gpuTexture.getHeight(), texelFormat.format, texelFormat.type, mip->readData());
|
||||||
GLuint pixelBufferID;
|
|
||||||
glGenBuffers(1, &pixelBufferID);
|
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBufferID);
|
|
||||||
//if (GLEW_VERSION_4_4) {
|
|
||||||
// glBufferStorage(GL_PIXEL_UNPACK_BUFFER, mip->getSize(), nullptr, GL_STREAM_DRAW);
|
|
||||||
//} else {
|
|
||||||
glBufferData(GL_PIXEL_UNPACK_BUFFER, mip->getSize(), nullptr, GL_STREAM_DRAW);
|
|
||||||
//}
|
|
||||||
void* mappedBuffer = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
|
|
||||||
memcpy(mappedBuffer, mip->readData(), mip->getSize());
|
|
||||||
//// use while PBO is still bound, assumes GL_TEXTURE_2D and offset 0
|
|
||||||
glTexSubImage2D(target, 0, 0, 0, _gpuTexture.getWidth(), _gpuTexture.getHeight(), texelFormat.format, texelFormat.type, 0);
|
|
||||||
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
|
||||||
glDeleteBuffers(1, &pixelBufferID);
|
|
||||||
#else
|
|
||||||
//glTexImage2D(target, 0, internalFormat, texture.getWidth(), texture.getHeight(), 0, texelFormat.format, texelFormat.type, bytes);
|
|
||||||
glTexSubImage2D(target, 0, 0, 0, _gpuTexture.getWidth(), _gpuTexture.getHeight(), texelFormat.format, texelFormat.type, mip->readData());
|
|
||||||
(void)CHECK_GL_ERROR();
|
(void)CHECK_GL_ERROR();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move content bits from the CPU to the GPU
|
// Move content bits from the CPU to the GPU
|
||||||
void GLBackend::GLTexture::transfer() const {
|
void GLBackend::GLTexture::transfer() const {
|
||||||
PROFILE_RANGE(__FUNCTION__);
|
PROFILE_RANGE(__FUNCTION__);
|
||||||
qDebug() << "Transferring texture: " << _texture;
|
//qDebug() << "Transferring texture: " << _privateTexture;
|
||||||
// Need to update the content of the GPU object from the source sysmem of the texture
|
// Need to update the content of the GPU object from the source sysmem of the texture
|
||||||
if (_contentStamp >= _gpuTexture.getDataStamp()) {
|
if (_contentStamp >= _gpuTexture.getDataStamp()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindTexture(_target, _texture);
|
//_secretTexture
|
||||||
|
glBindTexture(_target, _privateTexture);
|
||||||
|
// glBindTexture(_target, _texture);
|
||||||
// GO through the process of allocating the correct storage and/or update the content
|
// GO through the process of allocating the correct storage and/or update the content
|
||||||
switch (_gpuTexture.getType()) {
|
switch (_gpuTexture.getType()) {
|
||||||
case Texture::TEX_2D:
|
case Texture::TEX_2D:
|
||||||
|
@ -186,6 +262,10 @@ void GLBackend::GLTexture::transfer() const {
|
||||||
// Do any post-transfer operations that might be required on the main context / rendering thread
|
// Do any post-transfer operations that might be required on the main context / rendering thread
|
||||||
void GLBackend::GLTexture::postTransfer() {
|
void GLBackend::GLTexture::postTransfer() {
|
||||||
setSyncState(GLTexture::Idle);
|
setSyncState(GLTexture::Idle);
|
||||||
|
|
||||||
|
// The public gltexture becaomes available
|
||||||
|
_texture = _privateTexture;
|
||||||
|
|
||||||
// At this point the mip pixels have been loaded, we can notify the gpu texture to abandon it's memory
|
// At this point the mip pixels have been loaded, we can notify the gpu texture to abandon it's memory
|
||||||
switch (_gpuTexture.getType()) {
|
switch (_gpuTexture.getType()) {
|
||||||
case Texture::TEX_2D:
|
case Texture::TEX_2D:
|
||||||
|
@ -204,7 +284,7 @@ void GLBackend::GLTexture::postTransfer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePointer) {
|
GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePointer, bool needTransfer) {
|
||||||
const Texture& texture = *texturePointer;
|
const Texture& texture = *texturePointer;
|
||||||
if (!texture.isDefined()) {
|
if (!texture.isDefined()) {
|
||||||
// NO texture definition yet so let's avoid thinking
|
// NO texture definition yet so let's avoid thinking
|
||||||
|
@ -218,7 +298,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePoin
|
||||||
}
|
}
|
||||||
|
|
||||||
// Object isn't ready, check what we need to do...
|
// Object isn't ready, check what we need to do...
|
||||||
|
|
||||||
// Create the texture if need be (force re-creation if the storage stamp changes
|
// Create the texture if need be (force re-creation if the storage stamp changes
|
||||||
// for easier use of immutable storage)
|
// for easier use of immutable storage)
|
||||||
if (!object || object->isInvalid()) {
|
if (!object || object->isInvalid()) {
|
||||||
|
@ -226,18 +306,23 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePoin
|
||||||
object = new GLTexture(texture);
|
object = new GLTexture(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
// need to have a gpu object?
|
// Object maybe doens't neet to be tranasferred after creation
|
||||||
if (texture.getNumSlices() != 1) {
|
if (!needTransfer) {
|
||||||
|
object->createTexture();
|
||||||
|
object->_contentStamp = texturePointer->getDataStamp();
|
||||||
|
object->postTransfer();
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Object might be outdated, if so, start the transfer
|
// Object might be outdated, if so, start the transfer
|
||||||
// (outdated objects that are already in transfer will have reported 'true' for ready()
|
// (outdated objects that are already in transfer will have reported 'true' for ready()
|
||||||
if (object->isOutdated()) {
|
if (object->isOutdated()) {
|
||||||
|
Backend::incrementTextureGPUTransferCount();
|
||||||
_textureTransferHelper->transferTexture(texturePointer);
|
_textureTransferHelper->transferTexture(texturePointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GLTexture::Transferred == object->getSyncState()) {
|
if (GLTexture::Transferred == object->getSyncState()) {
|
||||||
|
Backend::decrementTextureGPUTransferCount();
|
||||||
object->postTransfer();
|
object->postTransfer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +423,8 @@ void GLBackend::do_generateTextureMips(Batch& batch, size_t paramOffset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLTexture* object = GLBackend::syncGPUObject(resourceTexture);
|
// DO not transfer the texture, this call is expected for rendering texture
|
||||||
|
GLTexture* object = GLBackend::syncGPUObject(resourceTexture, false);
|
||||||
if (!object) {
|
if (!object) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,26 +9,12 @@
|
||||||
#include "GLBackendTextureTransfer.h"
|
#include "GLBackendTextureTransfer.h"
|
||||||
|
|
||||||
#include "GLBackendShared.h"
|
#include "GLBackendShared.h"
|
||||||
#include "GLTexelFormat.h"
|
|
||||||
|
|
||||||
#ifdef THREADED_TEXTURE_TRANSFER
|
#ifdef THREADED_TEXTURE_TRANSFER
|
||||||
|
|
||||||
#include <gl/OffscreenGLCanvas.h>
|
#include <gl/OffscreenGLCanvas.h>
|
||||||
#include <gl/QOpenGLContextWrapper.h>
|
#include <gl/QOpenGLContextWrapper.h>
|
||||||
|
|
||||||
//#define FORCE_DRAW_AFTER_TRANSFER
|
|
||||||
|
|
||||||
#ifdef FORCE_DRAW_AFTER_TRANSFER
|
|
||||||
|
|
||||||
#include <gl/OglplusHelpers.h>
|
|
||||||
|
|
||||||
static ProgramPtr _program;
|
|
||||||
static ProgramPtr _cubeProgram;
|
|
||||||
static ShapeWrapperPtr _plane;
|
|
||||||
static ShapeWrapperPtr _skybox;
|
|
||||||
static BasicFramebufferWrapperPtr _framebuffer;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -50,30 +36,18 @@ GLTextureTransferHelper::GLTextureTransferHelper() {
|
||||||
void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texturePointer) {
|
void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texturePointer) {
|
||||||
GLBackend::GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(*texturePointer);
|
GLBackend::GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(*texturePointer);
|
||||||
#ifdef THREADED_TEXTURE_TRANSFER
|
#ifdef THREADED_TEXTURE_TRANSFER
|
||||||
TextureTransferPackage package { texturePointer, glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0) };
|
TextureTransferPackage package{ texturePointer, 0};
|
||||||
glFlush();
|
|
||||||
object->setSyncState(GLBackend::GLTexture::Pending);
|
object->setSyncState(GLBackend::GLTexture::Pending);
|
||||||
queueItem(package);
|
queueItem(package);
|
||||||
#else
|
#else
|
||||||
object->transfer();
|
object->transfer();
|
||||||
object->postTransfer();
|
object->setSyncState(GLBackend::GLTexture::Transferred);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLTextureTransferHelper::setup() {
|
void GLTextureTransferHelper::setup() {
|
||||||
#ifdef THREADED_TEXTURE_TRANSFER
|
#ifdef THREADED_TEXTURE_TRANSFER
|
||||||
_canvas->makeCurrent();
|
_canvas->makeCurrent();
|
||||||
|
|
||||||
#ifdef FORCE_DRAW_AFTER_TRANSFER
|
|
||||||
_program = loadDefaultShader();
|
|
||||||
_plane = loadPlane(_program);
|
|
||||||
_cubeProgram = loadCubemapShader();
|
|
||||||
_skybox = loadSkybox(_cubeProgram);
|
|
||||||
_framebuffer = std::make_shared<BasicFramebufferWrapper>();
|
|
||||||
_framebuffer->Init({ 100, 100 });
|
|
||||||
_framebuffer->fbo.Bind(oglplus::FramebufferTarget::Draw);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,8 +59,6 @@ void GLTextureTransferHelper::shutdown() {
|
||||||
|
|
||||||
bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
|
bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
|
||||||
for (auto package : messages) {
|
for (auto package : messages) {
|
||||||
glWaitSync(package.fence, 0, GL_TIMEOUT_IGNORED);
|
|
||||||
glDeleteSync(package.fence);
|
|
||||||
TexturePointer texturePointer = package.texture.lock();
|
TexturePointer texturePointer = package.texture.lock();
|
||||||
// Texture no longer exists, move on to the next
|
// Texture no longer exists, move on to the next
|
||||||
if (!texturePointer) {
|
if (!texturePointer) {
|
||||||
|
@ -94,37 +66,17 @@ bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
|
||||||
}
|
}
|
||||||
|
|
||||||
GLBackend::GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(*texturePointer);
|
GLBackend::GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(*texturePointer);
|
||||||
|
object->createTexture();
|
||||||
|
|
||||||
object->transfer();
|
object->transfer();
|
||||||
|
|
||||||
#ifdef FORCE_DRAW_AFTER_TRANSFER
|
object->updateSize();
|
||||||
// Now force a draw using the texture
|
|
||||||
try {
|
|
||||||
switch (texturePointer->getType()) {
|
|
||||||
case Texture::TEX_2D:
|
|
||||||
_program->Use();
|
|
||||||
_plane->Use();
|
|
||||||
_plane->Draw();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Texture::TEX_CUBE:
|
|
||||||
_cubeProgram->Use();
|
|
||||||
_skybox->Use();
|
|
||||||
_skybox->Draw();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
qCWarning(gpulogging) << __FUNCTION__ << " case for Texture Type " << texturePointer->getType() << " not supported";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (const std::runtime_error& error) {
|
|
||||||
qWarning() << "Failed to render texture on background thread: " << error.what();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
glBindTexture(object->_target, 0);
|
glBindTexture(object->_target, 0);
|
||||||
auto writeSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
auto writeSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
glClientWaitSync(writeSync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
glClientWaitSync(writeSync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
||||||
glDeleteSync(writeSync);
|
glDeleteSync(writeSync);
|
||||||
|
|
||||||
object->_contentStamp = texturePointer->getDataStamp();
|
object->_contentStamp = texturePointer->getDataStamp();
|
||||||
object->setSyncState(GLBackend::GLTexture::Transferred);
|
object->setSyncState(GLBackend::GLTexture::Transferred);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,375 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Bradley Austin Davis on 2016/04/03
|
|
||||||
// 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"
|
|
||||||
|
|
||||||
class GLTexelFormat {
|
|
||||||
public:
|
|
||||||
GLenum internalFormat;
|
|
||||||
GLenum format;
|
|
||||||
GLenum type;
|
|
||||||
|
|
||||||
static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat) {
|
|
||||||
return evalGLTexelFormat(dstFormat, dstFormat);
|
|
||||||
}
|
|
||||||
static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat, const gpu::Element& srcFormat) {
|
|
||||||
using namespace gpu;
|
|
||||||
if (dstFormat != srcFormat) {
|
|
||||||
GLTexelFormat texel = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE };
|
|
||||||
|
|
||||||
switch (dstFormat.getDimension()) {
|
|
||||||
case gpu::SCALAR: {
|
|
||||||
texel.format = GL_RED;
|
|
||||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
|
||||||
|
|
||||||
switch (dstFormat.getSemantic()) {
|
|
||||||
case gpu::RGB:
|
|
||||||
case gpu::RGBA:
|
|
||||||
texel.internalFormat = GL_R8;
|
|
||||||
break;
|
|
||||||
case gpu::DEPTH:
|
|
||||||
texel.internalFormat = GL_DEPTH_COMPONENT32;
|
|
||||||
break;
|
|
||||||
case gpu::DEPTH_STENCIL:
|
|
||||||
texel.type = GL_UNSIGNED_INT_24_8;
|
|
||||||
texel.format = GL_DEPTH_STENCIL;
|
|
||||||
texel.internalFormat = GL_DEPTH24_STENCIL8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case gpu::VEC2: {
|
|
||||||
texel.format = GL_RG;
|
|
||||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
|
||||||
|
|
||||||
switch (dstFormat.getSemantic()) {
|
|
||||||
case gpu::RGB:
|
|
||||||
case gpu::RGBA:
|
|
||||||
texel.internalFormat = GL_RG8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case gpu::VEC3: {
|
|
||||||
texel.format = GL_RGB;
|
|
||||||
|
|
||||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
|
||||||
|
|
||||||
switch (dstFormat.getSemantic()) {
|
|
||||||
case gpu::RGB:
|
|
||||||
case gpu::RGBA:
|
|
||||||
texel.internalFormat = GL_RGB8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case gpu::VEC4: {
|
|
||||||
texel.format = GL_RGBA;
|
|
||||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
|
||||||
|
|
||||||
switch (srcFormat.getSemantic()) {
|
|
||||||
case gpu::BGRA:
|
|
||||||
case gpu::SBGRA:
|
|
||||||
texel.format = GL_BGRA;
|
|
||||||
break;
|
|
||||||
case gpu::RGB:
|
|
||||||
case gpu::RGBA:
|
|
||||||
case gpu::SRGB:
|
|
||||||
case gpu::SRGBA:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (dstFormat.getSemantic()) {
|
|
||||||
case gpu::RGB:
|
|
||||||
texel.internalFormat = GL_RGB8;
|
|
||||||
break;
|
|
||||||
case gpu::RGBA:
|
|
||||||
texel.internalFormat = GL_RGBA8;
|
|
||||||
break;
|
|
||||||
case gpu::SRGB:
|
|
||||||
texel.internalFormat = GL_SRGB8;
|
|
||||||
break;
|
|
||||||
case gpu::SRGBA:
|
|
||||||
texel.internalFormat = GL_SRGB8_ALPHA8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
|
||||||
}
|
|
||||||
return texel;
|
|
||||||
} else {
|
|
||||||
GLTexelFormat texel = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE };
|
|
||||||
|
|
||||||
switch (dstFormat.getDimension()) {
|
|
||||||
case gpu::SCALAR: {
|
|
||||||
texel.format = GL_RED;
|
|
||||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
|
||||||
|
|
||||||
switch (dstFormat.getSemantic()) {
|
|
||||||
case gpu::RGB:
|
|
||||||
case gpu::RGBA:
|
|
||||||
case gpu::SRGB:
|
|
||||||
case gpu::SRGBA:
|
|
||||||
texel.internalFormat = GL_R8;
|
|
||||||
switch (dstFormat.getType()) {
|
|
||||||
case gpu::UINT32: {
|
|
||||||
texel.internalFormat = GL_R32UI;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::INT32: {
|
|
||||||
texel.internalFormat = GL_R32I;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::NUINT32: {
|
|
||||||
texel.internalFormat = GL_R8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::NINT32: {
|
|
||||||
texel.internalFormat = GL_R8_SNORM;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::FLOAT: {
|
|
||||||
texel.internalFormat = GL_R32F;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::UINT16: {
|
|
||||||
texel.internalFormat = GL_R16UI;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::INT16: {
|
|
||||||
texel.internalFormat = GL_R16I;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::NUINT16: {
|
|
||||||
texel.internalFormat = GL_R16;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::NINT16: {
|
|
||||||
texel.internalFormat = GL_R16_SNORM;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::HALF: {
|
|
||||||
texel.internalFormat = GL_R16F;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::UINT8: {
|
|
||||||
texel.internalFormat = GL_R8UI;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::INT8: {
|
|
||||||
texel.internalFormat = GL_R8I;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::NUINT8: {
|
|
||||||
if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) {
|
|
||||||
texel.internalFormat = GL_SLUMINANCE8;
|
|
||||||
} else {
|
|
||||||
texel.internalFormat = GL_R8;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::NINT8: {
|
|
||||||
texel.internalFormat = GL_R8_SNORM;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::NUM_TYPES: { // quiet compiler
|
|
||||||
Q_UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case gpu::R11G11B10:
|
|
||||||
texel.format = GL_RGB;
|
|
||||||
// the type should be float
|
|
||||||
texel.internalFormat = GL_R11F_G11F_B10F;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case gpu::DEPTH:
|
|
||||||
texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it
|
|
||||||
texel.internalFormat = GL_DEPTH_COMPONENT32;
|
|
||||||
switch (dstFormat.getType()) {
|
|
||||||
case gpu::UINT32:
|
|
||||||
case gpu::INT32:
|
|
||||||
case gpu::NUINT32:
|
|
||||||
case gpu::NINT32: {
|
|
||||||
texel.internalFormat = GL_DEPTH_COMPONENT32;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::FLOAT: {
|
|
||||||
texel.internalFormat = GL_DEPTH_COMPONENT32F;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::UINT16:
|
|
||||||
case gpu::INT16:
|
|
||||||
case gpu::NUINT16:
|
|
||||||
case gpu::NINT16:
|
|
||||||
case gpu::HALF: {
|
|
||||||
texel.internalFormat = GL_DEPTH_COMPONENT16;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::UINT8:
|
|
||||||
case gpu::INT8:
|
|
||||||
case gpu::NUINT8:
|
|
||||||
case gpu::NINT8: {
|
|
||||||
texel.internalFormat = GL_DEPTH_COMPONENT24;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case gpu::NUM_TYPES: { // quiet compiler
|
|
||||||
Q_UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case gpu::DEPTH_STENCIL:
|
|
||||||
texel.type = GL_UNSIGNED_INT_24_8;
|
|
||||||
texel.format = GL_DEPTH_STENCIL;
|
|
||||||
texel.internalFormat = GL_DEPTH24_STENCIL8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case gpu::VEC2: {
|
|
||||||
texel.format = GL_RG;
|
|
||||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
|
||||||
|
|
||||||
switch (dstFormat.getSemantic()) {
|
|
||||||
case gpu::RGB:
|
|
||||||
case gpu::RGBA:
|
|
||||||
texel.internalFormat = GL_RG8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case gpu::VEC3: {
|
|
||||||
texel.format = GL_RGB;
|
|
||||||
|
|
||||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
|
||||||
|
|
||||||
switch (dstFormat.getSemantic()) {
|
|
||||||
case gpu::RGB:
|
|
||||||
case gpu::RGBA:
|
|
||||||
texel.internalFormat = GL_RGB8;
|
|
||||||
break;
|
|
||||||
case gpu::SRGB:
|
|
||||||
case gpu::SRGBA:
|
|
||||||
texel.internalFormat = GL_SRGB8; // standard 2.2 gamma correction color
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case gpu::VEC4: {
|
|
||||||
texel.format = GL_RGBA;
|
|
||||||
texel.type = _elementTypeToGLType[dstFormat.getType()];
|
|
||||||
|
|
||||||
switch (dstFormat.getSemantic()) {
|
|
||||||
case gpu::RGB:
|
|
||||||
texel.internalFormat = GL_RGB8;
|
|
||||||
break;
|
|
||||||
case gpu::RGBA:
|
|
||||||
texel.internalFormat = GL_RGBA8;
|
|
||||||
switch (dstFormat.getType()) {
|
|
||||||
case gpu::UINT32:
|
|
||||||
texel.format = GL_RGBA_INTEGER;
|
|
||||||
texel.internalFormat = GL_RGBA32UI;
|
|
||||||
break;
|
|
||||||
case gpu::INT32:
|
|
||||||
texel.format = GL_RGBA_INTEGER;
|
|
||||||
texel.internalFormat = GL_RGBA32I;
|
|
||||||
break;
|
|
||||||
case gpu::FLOAT:
|
|
||||||
texel.internalFormat = GL_RGBA32F;
|
|
||||||
break;
|
|
||||||
case gpu::UINT16:
|
|
||||||
texel.format = GL_RGBA_INTEGER;
|
|
||||||
texel.internalFormat = GL_RGBA16UI;
|
|
||||||
break;
|
|
||||||
case gpu::INT16:
|
|
||||||
texel.format = GL_RGBA_INTEGER;
|
|
||||||
texel.internalFormat = GL_RGBA16I;
|
|
||||||
break;
|
|
||||||
case gpu::NUINT16:
|
|
||||||
texel.format = GL_RGBA;
|
|
||||||
texel.internalFormat = GL_RGBA16;
|
|
||||||
break;
|
|
||||||
case gpu::NINT16:
|
|
||||||
texel.format = GL_RGBA;
|
|
||||||
texel.internalFormat = GL_RGBA16_SNORM;
|
|
||||||
break;
|
|
||||||
case gpu::HALF:
|
|
||||||
texel.format = GL_RGBA;
|
|
||||||
texel.internalFormat = GL_RGBA16F;
|
|
||||||
break;
|
|
||||||
case gpu::UINT8:
|
|
||||||
texel.format = GL_RGBA_INTEGER;
|
|
||||||
texel.internalFormat = GL_RGBA8UI;
|
|
||||||
break;
|
|
||||||
case gpu::INT8:
|
|
||||||
texel.format = GL_RGBA_INTEGER;
|
|
||||||
texel.internalFormat = GL_RGBA8I;
|
|
||||||
break;
|
|
||||||
case gpu::NUINT8:
|
|
||||||
texel.format = GL_RGBA;
|
|
||||||
texel.internalFormat = GL_RGBA8;
|
|
||||||
break;
|
|
||||||
case gpu::NINT8:
|
|
||||||
texel.format = GL_RGBA;
|
|
||||||
texel.internalFormat = GL_RGBA8_SNORM;
|
|
||||||
break;
|
|
||||||
case gpu::NUINT32:
|
|
||||||
case gpu::NINT32:
|
|
||||||
case gpu::NUM_TYPES: // quiet compiler
|
|
||||||
Q_UNREACHABLE();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case gpu::SRGB:
|
|
||||||
texel.internalFormat = GL_SRGB8;
|
|
||||||
break;
|
|
||||||
case gpu::SRGBA:
|
|
||||||
texel.internalFormat = GL_SRGB8_ALPHA8; // standard 2.2 gamma correction color
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
|
||||||
}
|
|
||||||
return texel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -46,10 +46,17 @@ uint32_t Texture::getTextureGPUCount() {
|
||||||
|
|
||||||
Texture::Size Texture::getTextureGPUMemoryUsage() {
|
Texture::Size Texture::getTextureGPUMemoryUsage() {
|
||||||
return Context::getTextureGPUMemoryUsage();
|
return Context::getTextureGPUMemoryUsage();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = {1, 1, 1, 6};
|
Texture::Size Texture::getTextureGPUVirtualMemoryUsage() {
|
||||||
|
return Context::getTextureGPUVirtualMemoryUsage();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Texture::getTextureGPUTransferCount() {
|
||||||
|
return Context::getTextureGPUTransferCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = { 1, 1, 1, 6 };
|
||||||
|
|
||||||
Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) :
|
Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) :
|
||||||
_format(format),
|
_format(format),
|
||||||
|
|
|
@ -146,6 +146,8 @@ public:
|
||||||
static Size getTextureCPUMemoryUsage();
|
static Size getTextureCPUMemoryUsage();
|
||||||
static uint32_t getTextureGPUCount();
|
static uint32_t getTextureGPUCount();
|
||||||
static Size getTextureGPUMemoryUsage();
|
static Size getTextureGPUMemoryUsage();
|
||||||
|
static Size getTextureGPUVirtualMemoryUsage();
|
||||||
|
static uint32_t getTextureGPUTransferCount();
|
||||||
|
|
||||||
class Usage {
|
class Usage {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -417,7 +417,7 @@ NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textur
|
||||||
{
|
{
|
||||||
_textures = Textures(MapChannel::NUM_MAP_CHANNELS);
|
_textures = Textures(MapChannel::NUM_MAP_CHANNELS);
|
||||||
if (!material.albedoTexture.filename.isEmpty()) {
|
if (!material.albedoTexture.filename.isEmpty()) {
|
||||||
auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, DEFAULT_TEXTURE, MapChannel::ALBEDO_MAP);
|
auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP);
|
||||||
_albedoTransform = material.albedoTexture.transform;
|
_albedoTransform = material.albedoTexture.transform;
|
||||||
map->setTextureTransform(_albedoTransform);
|
map->setTextureTransform(_albedoTransform);
|
||||||
|
|
||||||
|
@ -488,7 +488,7 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) {
|
||||||
|
|
||||||
if (!albedoName.isEmpty()) {
|
if (!albedoName.isEmpty()) {
|
||||||
auto url = textureMap.contains(albedoName) ? textureMap[albedoName].toUrl() : QUrl();
|
auto url = textureMap.contains(albedoName) ? textureMap[albedoName].toUrl() : QUrl();
|
||||||
auto map = fetchTextureMap(url, DEFAULT_TEXTURE, MapChannel::ALBEDO_MAP);
|
auto map = fetchTextureMap(url, ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP);
|
||||||
map->setTextureTransform(_albedoTransform);
|
map->setTextureTransform(_albedoTransform);
|
||||||
// when reassigning the albedo texture we also check for the alpha channel used as opacity
|
// when reassigning the albedo texture we also check for the alpha channel used as opacity
|
||||||
map->setUseAlphaChannel(true);
|
map->setUseAlphaChannel(true);
|
||||||
|
@ -497,7 +497,7 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) {
|
||||||
|
|
||||||
if (!normalName.isEmpty()) {
|
if (!normalName.isEmpty()) {
|
||||||
auto url = textureMap.contains(normalName) ? textureMap[normalName].toUrl() : QUrl();
|
auto url = textureMap.contains(normalName) ? textureMap[normalName].toUrl() : QUrl();
|
||||||
auto map = fetchTextureMap(url, DEFAULT_TEXTURE, MapChannel::NORMAL_MAP);
|
auto map = fetchTextureMap(url, NORMAL_TEXTURE, MapChannel::NORMAL_MAP);
|
||||||
setTextureMap(MapChannel::NORMAL_MAP, map);
|
setTextureMap(MapChannel::NORMAL_MAP, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -203,6 +203,18 @@ NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& texture
|
||||||
|
|
||||||
NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
|
NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
|
case ALBEDO_TEXTURE: {
|
||||||
|
return TextureLoaderFunc(model::TextureUsage::createAlbedoTextureFromImage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EMISSIVE_TEXTURE: {
|
||||||
|
return TextureLoaderFunc(model::TextureUsage::createEmissiveTextureFromImage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LIGHTMAP_TEXTURE: {
|
||||||
|
return TextureLoaderFunc(model::TextureUsage::createLightmapTextureFromImage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case CUBE_TEXTURE: {
|
case CUBE_TEXTURE: {
|
||||||
return TextureLoaderFunc(model::TextureUsage::createCubeTextureFromImage);
|
return TextureLoaderFunc(model::TextureUsage::createCubeTextureFromImage);
|
||||||
break;
|
break;
|
||||||
|
@ -232,7 +244,6 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DEFAULT_TEXTURE:
|
case DEFAULT_TEXTURE:
|
||||||
case EMISSIVE_TEXTURE:
|
|
||||||
default: {
|
default: {
|
||||||
return TextureLoaderFunc(model::TextureUsage::create2DTextureFromImage);
|
return TextureLoaderFunc(model::TextureUsage::create2DTextureFromImage);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -31,6 +31,7 @@ typedef QSharedPointer<NetworkTexture> NetworkTexturePointer;
|
||||||
|
|
||||||
enum TextureType {
|
enum TextureType {
|
||||||
DEFAULT_TEXTURE,
|
DEFAULT_TEXTURE,
|
||||||
|
ALBEDO_TEXTURE,
|
||||||
NORMAL_TEXTURE,
|
NORMAL_TEXTURE,
|
||||||
BUMP_TEXTURE,
|
BUMP_TEXTURE,
|
||||||
SPECULAR_TEXTURE,
|
SPECULAR_TEXTURE,
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
using namespace model;
|
using namespace model;
|
||||||
using namespace gpu;
|
using namespace gpu;
|
||||||
|
|
||||||
|
// FIXME: Declare this to enable compression
|
||||||
|
//#define COMPRESS_TEXTURES
|
||||||
|
|
||||||
|
|
||||||
void TextureMap::setTextureSource(TextureSourcePointer& textureSource) {
|
void TextureMap::setTextureSource(TextureSourcePointer& textureSource) {
|
||||||
_textureSource = textureSource;
|
_textureSource = textureSource;
|
||||||
|
@ -49,12 +52,10 @@ void TextureMap::setLightmapOffsetScale(float offset, float scale) {
|
||||||
_lightmapOffsetScale.y = scale;
|
_lightmapOffsetScale.y = scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QImage TextureUsage::process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask) {
|
||||||
// FIXME why is this in the model library? Move to GPU or GPU_GL
|
|
||||||
gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
|
||||||
QImage image = srcImage;
|
QImage image = srcImage;
|
||||||
bool validAlpha = false;
|
validAlpha = false;
|
||||||
bool alphaAsMask = true;
|
alphaAsMask = true;
|
||||||
const uint8 OPAQUE_ALPHA = 255;
|
const uint8 OPAQUE_ALPHA = 255;
|
||||||
const uint8 TRANSPARENT_ALPHA = 0;
|
const uint8 TRANSPARENT_ALPHA = 0;
|
||||||
if (image.hasAlphaChannel()) {
|
if (image.hasAlphaChannel()) {
|
||||||
|
@ -63,7 +64,7 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con
|
||||||
if (image.format() != QImage::Format_ARGB32) {
|
if (image.format() != QImage::Format_ARGB32) {
|
||||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actual alpha channel? create the histogram
|
// Actual alpha channel? create the histogram
|
||||||
for (int y = 0; y < image.height(); ++y) {
|
for (int y = 0; y < image.height(); ++y) {
|
||||||
const QRgb* data = reinterpret_cast<const QRgb*>(image.constScanLine(y));
|
const QRgb* data = reinterpret_cast<const QRgb*>(image.constScanLine(y));
|
||||||
|
@ -83,23 +84,77 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con
|
||||||
|
|
||||||
alphaAsMask = ((numTranslucents / (double)totalNumPixels) < 0.05);
|
alphaAsMask = ((numTranslucents / (double)totalNumPixels) < 0.05);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validAlpha && image.format() != QImage::Format_RGB888) {
|
if (!validAlpha && image.format() != QImage::Format_RGB888) {
|
||||||
image = image.convertToFormat(QImage::Format_RGB888);
|
image = image.convertToFormat(QImage::Format_RGB888);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureUsage::defineColorTexelFormats(gpu::Element& formatGPU, gpu::Element& formatMip,
|
||||||
|
const QImage& image, bool isLinear, bool doCompress) {
|
||||||
|
|
||||||
|
#ifdef COMPRESS_TEXTURES
|
||||||
|
#else
|
||||||
|
doCompress = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (image.hasAlphaChannel()) {
|
||||||
|
gpu::Semantic gpuSemantic;
|
||||||
|
gpu::Semantic mipSemantic;
|
||||||
|
if (isLinear) {
|
||||||
|
mipSemantic = gpu::SBGRA;
|
||||||
|
if (doCompress) {
|
||||||
|
gpuSemantic = gpu::COMPRESSED_SRGBA;
|
||||||
|
} else {
|
||||||
|
gpuSemantic = gpu::SRGBA;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mipSemantic = gpu::BGRA;
|
||||||
|
if (doCompress) {
|
||||||
|
gpuSemantic = gpu::COMPRESSED_RGBA;
|
||||||
|
} else {
|
||||||
|
gpuSemantic = gpu::RGBA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpuSemantic);
|
||||||
|
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, mipSemantic);
|
||||||
|
} else {
|
||||||
|
gpu::Semantic gpuSemantic;
|
||||||
|
gpu::Semantic mipSemantic;
|
||||||
|
if (isLinear) {
|
||||||
|
mipSemantic = gpu::SRGB;
|
||||||
|
if (doCompress) {
|
||||||
|
gpuSemantic = gpu::COMPRESSED_SRGB;
|
||||||
|
} else {
|
||||||
|
gpuSemantic = gpu::SRGB;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mipSemantic = gpu::RGB;
|
||||||
|
if (doCompress) {
|
||||||
|
gpuSemantic = gpu::COMPRESSED_RGB;
|
||||||
|
} else {
|
||||||
|
gpuSemantic = gpu::RGB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpuSemantic);
|
||||||
|
formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, mipSemantic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImage, bool isLinear, bool doCompress, bool generateMips) {
|
||||||
|
bool validAlpha = false;
|
||||||
|
bool alphaAsMask = true;
|
||||||
|
QImage image = process2DImageColor(srcImage, validAlpha, alphaAsMask);
|
||||||
|
|
||||||
gpu::Texture* theTexture = nullptr;
|
gpu::Texture* theTexture = nullptr;
|
||||||
if ((image.width() > 0) && (image.height() > 0)) {
|
if ((image.width() > 0) && (image.height() > 0)) {
|
||||||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
|
||||||
bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
|
||||||
|
|
||||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
gpu::Element formatGPU;
|
||||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
gpu::Element formatMip;
|
||||||
if (image.hasAlphaChannel()) {
|
defineColorTexelFormats(formatGPU, formatMip, image, isLinear, doCompress);
|
||||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
|
||||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
|
||||||
}
|
|
||||||
|
|
||||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||||
|
|
||||||
|
@ -113,40 +168,46 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con
|
||||||
theTexture->setUsage(usage.build());
|
theTexture->setUsage(usage.build());
|
||||||
|
|
||||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||||
theTexture->autoGenerateMips(-1);
|
|
||||||
|
|
||||||
// FIXME queue for transfer to GPU and block on completion
|
|
||||||
|
|
||||||
|
if (generateMips) {
|
||||||
|
theTexture->autoGenerateMips(-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return theTexture;
|
return theTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||||
|
return process2DTextureColorFromImage(srcImage, true, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gpu::Texture* TextureUsage::createAlbedoTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||||
|
return process2DTextureColorFromImage(srcImage, true, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
gpu::Texture* TextureUsage::createEmissiveTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||||
|
return process2DTextureColorFromImage(srcImage, true, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||||
|
return process2DTextureColorFromImage(srcImage, true, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& srcImage, const std::string& srcImageName) {
|
gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||||
QImage image = srcImage;
|
QImage image = srcImage;
|
||||||
|
|
||||||
if (!image.hasAlphaChannel()) {
|
if (image.format() != QImage::Format_RGB888) {
|
||||||
if (image.format() != QImage::Format_RGB888) {
|
image = image.convertToFormat(QImage::Format_RGB888);
|
||||||
image = image.convertToFormat(QImage::Format_RGB888);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (image.format() != QImage::Format_ARGB32) {
|
|
||||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::Texture* theTexture = nullptr;
|
gpu::Texture* theTexture = nullptr;
|
||||||
if ((image.width() > 0) && (image.height() > 0)) {
|
if ((image.width() > 0) && (image.height() > 0)) {
|
||||||
|
|
||||||
|
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB);
|
||||||
|
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB);
|
||||||
|
|
||||||
bool isLinearRGB = true;
|
|
||||||
|
|
||||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
|
||||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
|
||||||
if (image.hasAlphaChannel()) {
|
|
||||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
|
||||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
|
||||||
}
|
|
||||||
|
|
||||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||||
|
@ -179,7 +240,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm
|
||||||
const double pStrength = 2.0;
|
const double pStrength = 2.0;
|
||||||
int width = image.width();
|
int width = image.width();
|
||||||
int height = image.height();
|
int height = image.height();
|
||||||
QImage result(width, height, image.format());
|
QImage result(width, height, QImage::Format_RGB888);
|
||||||
|
|
||||||
for (int i = 0; i < width; i++) {
|
for (int i = 0; i < width; i++) {
|
||||||
const int iNextClamped = clampPixelCoordinate(i + 1, width - 1);
|
const int iNextClamped = clampPixelCoordinate(i + 1, width - 1);
|
||||||
|
@ -227,23 +288,16 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm
|
||||||
|
|
||||||
gpu::Texture* theTexture = nullptr;
|
gpu::Texture* theTexture = nullptr;
|
||||||
if ((image.width() > 0) && (image.height() > 0)) {
|
if ((image.width() > 0) && (image.height() > 0)) {
|
||||||
|
|
||||||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB);
|
||||||
bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB);
|
||||||
|
|
||||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
|
||||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
|
||||||
if (image.hasAlphaChannel()) {
|
|
||||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
|
||||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||||
theTexture->autoGenerateMips(-1);
|
theTexture->autoGenerateMips(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return theTexture;
|
return theTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,8 +317,11 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcIma
|
||||||
|
|
||||||
gpu::Texture* theTexture = nullptr;
|
gpu::Texture* theTexture = nullptr;
|
||||||
if ((image.width() > 0) && (image.height() > 0)) {
|
if ((image.width() > 0) && (image.height() > 0)) {
|
||||||
|
#ifdef COMPRESS_TEXTURES
|
||||||
|
gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::COMPRESSED_R);
|
||||||
|
#else
|
||||||
gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
||||||
|
#endif
|
||||||
gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
||||||
|
|
||||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||||
|
@ -297,9 +354,13 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& s
|
||||||
gpu::Texture* theTexture = nullptr;
|
gpu::Texture* theTexture = nullptr;
|
||||||
if ((image.width() > 0) && (image.height() > 0)) {
|
if ((image.width() > 0) && (image.height() > 0)) {
|
||||||
|
|
||||||
|
#ifdef COMPRESS_TEXTURES
|
||||||
|
gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::COMPRESSED_R);
|
||||||
|
#else
|
||||||
gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
||||||
|
#endif
|
||||||
gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
||||||
|
|
||||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||||
theTexture->autoGenerateMips(-1);
|
theTexture->autoGenerateMips(-1);
|
||||||
|
@ -327,7 +388,11 @@ gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImag
|
||||||
gpu::Texture* theTexture = nullptr;
|
gpu::Texture* theTexture = nullptr;
|
||||||
if ((image.width() > 0) && (image.height() > 0)) {
|
if ((image.width() > 0) && (image.height() > 0)) {
|
||||||
|
|
||||||
|
#ifdef COMPRESS_TEXTURES
|
||||||
|
gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::COMPRESSED_R);
|
||||||
|
#else
|
||||||
gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
||||||
|
#endif
|
||||||
gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB);
|
||||||
|
|
||||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||||
|
@ -372,315 +437,181 @@ public:
|
||||||
_faceYNeg(fYN),
|
_faceYNeg(fYN),
|
||||||
_faceZPos(fZP),
|
_faceZPos(fZP),
|
||||||
_faceZNeg(fZN) {}
|
_faceZNeg(fZN) {}
|
||||||
|
|
||||||
|
|
||||||
|
static const CubeLayout CUBEMAP_LAYOUTS[];
|
||||||
|
static const int NUM_CUBEMAP_LAYOUTS;
|
||||||
|
|
||||||
|
static int findLayout(int width, int height) {
|
||||||
|
// Find the layout of the cubemap in the 2D image
|
||||||
|
int foundLayout = -1;
|
||||||
|
for (int i = 0; i < NUM_CUBEMAP_LAYOUTS; i++) {
|
||||||
|
if ((height * CUBEMAP_LAYOUTS[i]._widthRatio) == (width * CUBEMAP_LAYOUTS[i]._heightRatio)) {
|
||||||
|
foundLayout = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return foundLayout;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
const CubeLayout CubeLayout::CUBEMAP_LAYOUTS[] = {
|
||||||
QImage image = srcImage;
|
// Here is the expected layout for the faces in an image with the 1/6 aspect ratio:
|
||||||
|
//
|
||||||
int imageArea = image.width() * image.height();
|
// WIDTH
|
||||||
|
// <------>
|
||||||
|
// ^ +------+
|
||||||
qCDebug(modelLog) << "Cube map size:" << QString(srcImageName.c_str()) << image.width() << image.height();
|
// | | |
|
||||||
|
// | | +X |
|
||||||
int opaquePixels = 0;
|
// | | |
|
||||||
int translucentPixels = 0;
|
// H +------+
|
||||||
//bool isTransparent = false;
|
// E | |
|
||||||
int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
// I | -X |
|
||||||
const int EIGHT_BIT_MAXIMUM = 255;
|
// G | |
|
||||||
QColor averageColor(EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM);
|
// H +------+
|
||||||
|
// T | |
|
||||||
if (!image.hasAlphaChannel()) {
|
// | | +Y |
|
||||||
if (image.format() != QImage::Format_RGB888) {
|
// | | |
|
||||||
image = image.convertToFormat(QImage::Format_RGB888);
|
// | +------+
|
||||||
}
|
// | | |
|
||||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0;
|
// | | -Y |
|
||||||
for (int y = 0; y < image.height(); y++) {
|
// | | |
|
||||||
for (int x = 0; x < image.width(); x++) {
|
// H +------+
|
||||||
QRgb rgb = image.pixel(x, y);
|
// E | |
|
||||||
redTotal += qRed(rgb);
|
// I | +Z |
|
||||||
greenTotal += qGreen(rgb);
|
// G | |
|
||||||
blueTotal += qBlue(rgb);
|
// H +------+
|
||||||
}
|
// T | |
|
||||||
}
|
// | | -Z |
|
||||||
if (imageArea > 0) {
|
// | | |
|
||||||
averageColor.setRgb(redTotal / imageArea, greenTotal / imageArea, blueTotal / imageArea);
|
// V +------+
|
||||||
}
|
//
|
||||||
} else {
|
// FaceWidth = width = height / 6
|
||||||
if (image.format() != QImage::Format_ARGB32) {
|
{ 1, 6,
|
||||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
{ 0, 0, true, false },
|
||||||
}
|
{ 0, 1, true, false },
|
||||||
|
{ 0, 2, false, true },
|
||||||
// check for translucency/false transparency
|
{ 0, 3, false, true },
|
||||||
// int opaquePixels = 0;
|
{ 0, 4, true, false },
|
||||||
// int translucentPixels = 0;
|
{ 0, 5, true, false }
|
||||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
},
|
||||||
for (int y = 0; y < image.height(); y++) {
|
|
||||||
for (int x = 0; x < image.width(); x++) {
|
// Here is the expected layout for the faces in an image with the 3/4 aspect ratio:
|
||||||
QRgb rgb = image.pixel(x, y);
|
//
|
||||||
redTotal += qRed(rgb);
|
// <-----------WIDTH----------->
|
||||||
greenTotal += qGreen(rgb);
|
// ^ +------+------+------+------+
|
||||||
blueTotal += qBlue(rgb);
|
// | | | | | |
|
||||||
int alpha = qAlpha(rgb);
|
// | | | +Y | | |
|
||||||
alphaTotal += alpha;
|
// | | | | | |
|
||||||
if (alpha == EIGHT_BIT_MAXIMUM) {
|
// H +------+------+------+------+
|
||||||
opaquePixels++;
|
// E | | | | |
|
||||||
} else if (alpha != 0) {
|
// I | -X | -Z | +X | +Z |
|
||||||
translucentPixels++;
|
// G | | | | |
|
||||||
}
|
// H +------+------+------+------+
|
||||||
}
|
// T | | | | |
|
||||||
}
|
// | | | -Y | | |
|
||||||
if (opaquePixels == imageArea) {
|
// | | | | | |
|
||||||
qCDebug(modelLog) << "Image with alpha channel is completely opaque:" << QString(srcImageName.c_str());
|
// V +------+------+------+------+
|
||||||
image = image.convertToFormat(QImage::Format_RGB888);
|
//
|
||||||
}
|
// FaceWidth = width / 4 = height / 3
|
||||||
|
{ 4, 3,
|
||||||
averageColor = QColor(redTotal / imageArea,
|
{ 2, 1, true, false },
|
||||||
greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea);
|
{ 0, 1, true, false },
|
||||||
|
{ 1, 0, false, true },
|
||||||
//isTransparent = (translucentPixels >= imageArea / 2);
|
{ 1, 2, false, true },
|
||||||
|
{ 3, 1, true, false },
|
||||||
|
{ 1, 1, true, false }
|
||||||
|
},
|
||||||
|
|
||||||
|
// Here is the expected layout for the faces in an image with the 4/3 aspect ratio:
|
||||||
|
//
|
||||||
|
// <-------WIDTH-------->
|
||||||
|
// ^ +------+------+------+
|
||||||
|
// | | | | |
|
||||||
|
// | | | +Y | |
|
||||||
|
// | | | | |
|
||||||
|
// H +------+------+------+
|
||||||
|
// E | | | |
|
||||||
|
// I | -X | -Z | +X |
|
||||||
|
// G | | | |
|
||||||
|
// H +------+------+------+
|
||||||
|
// T | | | |
|
||||||
|
// | | | -Y | |
|
||||||
|
// | | | | |
|
||||||
|
// | +------+------+------+
|
||||||
|
// | | | | |
|
||||||
|
// | | | +Z! | | <+Z is upside down!
|
||||||
|
// | | | | |
|
||||||
|
// V +------+------+------+
|
||||||
|
//
|
||||||
|
// FaceWidth = width / 3 = height / 4
|
||||||
|
{ 3, 4,
|
||||||
|
{ 2, 1, true, false },
|
||||||
|
{ 0, 1, true, false },
|
||||||
|
{ 1, 0, false, true },
|
||||||
|
{ 1, 2, false, true },
|
||||||
|
{ 1, 3, false, true },
|
||||||
|
{ 1, 1, true, false }
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
const int CubeLayout::NUM_CUBEMAP_LAYOUTS = sizeof(CubeLayout::CUBEMAP_LAYOUTS) / sizeof(CubeLayout);
|
||||||
|
|
||||||
|
gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips, bool generateIrradiance) {
|
||||||
|
|
||||||
|
bool validAlpha = false;
|
||||||
|
bool alphaAsMask = true;
|
||||||
|
QImage image = process2DImageColor(srcImage, validAlpha, alphaAsMask);
|
||||||
|
|
||||||
gpu::Texture* theTexture = nullptr;
|
gpu::Texture* theTexture = nullptr;
|
||||||
if ((image.width() > 0) && (image.height() > 0)) {
|
if ((image.width() > 0) && (image.height() > 0)) {
|
||||||
|
|
||||||
|
gpu::Element formatGPU;
|
||||||
|
gpu::Element formatMip;
|
||||||
|
defineColorTexelFormats(formatGPU, formatMip, image, isLinear, doCompress);
|
||||||
|
|
||||||
|
// Find the layout of the cubemap in the 2D image
|
||||||
|
int foundLayout = CubeLayout::findLayout(image.width(), image.height());
|
||||||
|
|
||||||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
std::vector<QImage> faces;
|
||||||
bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
// If found, go extract the faces as separate images
|
||||||
|
if (foundLayout >= 0) {
|
||||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
auto& layout = CubeLayout::CUBEMAP_LAYOUTS[foundLayout];
|
||||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
int faceWidth = image.width() / layout._widthRatio;
|
||||||
if (image.hasAlphaChannel()) {
|
|
||||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
faces.push_back(image.copy(QRect(layout._faceXPos._x * faceWidth, layout._faceXPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXPos._horizontalMirror, layout._faceXPos._verticalMirror));
|
||||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
faces.push_back(image.copy(QRect(layout._faceXNeg._x * faceWidth, layout._faceXNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXNeg._horizontalMirror, layout._faceXNeg._verticalMirror));
|
||||||
|
faces.push_back(image.copy(QRect(layout._faceYPos._x * faceWidth, layout._faceYPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYPos._horizontalMirror, layout._faceYPos._verticalMirror));
|
||||||
|
faces.push_back(image.copy(QRect(layout._faceYNeg._x * faceWidth, layout._faceYNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYNeg._horizontalMirror, layout._faceYNeg._verticalMirror));
|
||||||
|
faces.push_back(image.copy(QRect(layout._faceZPos._x * faceWidth, layout._faceZPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZPos._horizontalMirror, layout._faceZPos._verticalMirror));
|
||||||
|
faces.push_back(image.copy(QRect(layout._faceZNeg._x * faceWidth, layout._faceZNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZNeg._horizontalMirror, layout._faceZNeg._verticalMirror));
|
||||||
|
} else {
|
||||||
|
qCDebug(modelLog) << "Failed to find a known cube map layout from this image:" << QString(srcImageName.c_str());
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const CubeLayout CUBEMAP_LAYOUTS[] = {
|
// If the 6 faces have been created go on and define the true Texture
|
||||||
// Here is the expected layout for the faces in an image with the 1/6 aspect ratio:
|
if (faces.size() == gpu::Texture::NUM_FACES_PER_TYPE[gpu::Texture::TEX_CUBE]) {
|
||||||
//
|
theTexture = gpu::Texture::createCube(formatGPU, faces[0].width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
|
||||||
// WIDTH
|
int f = 0;
|
||||||
// <------>
|
for (auto& face : faces) {
|
||||||
// ^ +------+
|
theTexture->assignStoredMipFace(0, formatMip, face.byteCount(), face.constBits(), f);
|
||||||
// | | |
|
f++;
|
||||||
// | | +X |
|
|
||||||
// | | |
|
|
||||||
// H +------+
|
|
||||||
// E | |
|
|
||||||
// I | -X |
|
|
||||||
// G | |
|
|
||||||
// H +------+
|
|
||||||
// T | |
|
|
||||||
// | | +Y |
|
|
||||||
// | | |
|
|
||||||
// | +------+
|
|
||||||
// | | |
|
|
||||||
// | | -Y |
|
|
||||||
// | | |
|
|
||||||
// H +------+
|
|
||||||
// E | |
|
|
||||||
// I | +Z |
|
|
||||||
// G | |
|
|
||||||
// H +------+
|
|
||||||
// T | |
|
|
||||||
// | | -Z |
|
|
||||||
// | | |
|
|
||||||
// V +------+
|
|
||||||
//
|
|
||||||
// FaceWidth = width = height / 6
|
|
||||||
{ 1, 6,
|
|
||||||
{0, 0, true, false},
|
|
||||||
{0, 1, true, false},
|
|
||||||
{0, 2, false, true},
|
|
||||||
{0, 3, false, true},
|
|
||||||
{0, 4, true, false},
|
|
||||||
{0, 5, true, false}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Here is the expected layout for the faces in an image with the 3/4 aspect ratio:
|
|
||||||
//
|
|
||||||
// <-----------WIDTH----------->
|
|
||||||
// ^ +------+------+------+------+
|
|
||||||
// | | | | | |
|
|
||||||
// | | | +Y | | |
|
|
||||||
// | | | | | |
|
|
||||||
// H +------+------+------+------+
|
|
||||||
// E | | | | |
|
|
||||||
// I | -X | -Z | +X | +Z |
|
|
||||||
// G | | | | |
|
|
||||||
// H +------+------+------+------+
|
|
||||||
// T | | | | |
|
|
||||||
// | | | -Y | | |
|
|
||||||
// | | | | | |
|
|
||||||
// V +------+------+------+------+
|
|
||||||
//
|
|
||||||
// FaceWidth = width / 4 = height / 3
|
|
||||||
{ 4, 3,
|
|
||||||
{2, 1, true, false},
|
|
||||||
{0, 1, true, false},
|
|
||||||
{1, 0, false, true},
|
|
||||||
{1, 2, false, true},
|
|
||||||
{3, 1, true, false},
|
|
||||||
{1, 1, true, false}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Here is the expected layout for the faces in an image with the 4/3 aspect ratio:
|
|
||||||
//
|
|
||||||
// <-------WIDTH-------->
|
|
||||||
// ^ +------+------+------+
|
|
||||||
// | | | | |
|
|
||||||
// | | | +Y | |
|
|
||||||
// | | | | |
|
|
||||||
// H +------+------+------+
|
|
||||||
// E | | | |
|
|
||||||
// I | -X | -Z | +X |
|
|
||||||
// G | | | |
|
|
||||||
// H +------+------+------+
|
|
||||||
// T | | | |
|
|
||||||
// | | | -Y | |
|
|
||||||
// | | | | |
|
|
||||||
// | +------+------+------+
|
|
||||||
// | | | | |
|
|
||||||
// | | | +Z! | | <+Z is upside down!
|
|
||||||
// | | | | |
|
|
||||||
// V +------+------+------+
|
|
||||||
//
|
|
||||||
// FaceWidth = width / 3 = height / 4
|
|
||||||
{ 3, 4,
|
|
||||||
{2, 1, true, false},
|
|
||||||
{0, 1, true, false},
|
|
||||||
{1, 0, false, true},
|
|
||||||
{1, 2, false, true},
|
|
||||||
{1, 3, false, true},
|
|
||||||
{1, 1, true, false}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const int NUM_CUBEMAP_LAYOUTS = sizeof(CUBEMAP_LAYOUTS) / sizeof(CubeLayout);
|
|
||||||
|
|
||||||
// Find the layout of the cubemap in the 2D image
|
|
||||||
int foundLayout = -1;
|
|
||||||
for (int i = 0; i < NUM_CUBEMAP_LAYOUTS; i++) {
|
|
||||||
if ((image.height() * CUBEMAP_LAYOUTS[i]._widthRatio) == (image.width() * CUBEMAP_LAYOUTS[i]._heightRatio)) {
|
|
||||||
foundLayout = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<QImage> faces;
|
if (generateMips) {
|
||||||
// If found, go extract the faces as separate images
|
|
||||||
if (foundLayout >= 0) {
|
|
||||||
auto& layout = CUBEMAP_LAYOUTS[foundLayout];
|
|
||||||
int faceWidth = image.width() / layout._widthRatio;
|
|
||||||
|
|
||||||
faces.push_back(image.copy(QRect(layout._faceXPos._x * faceWidth, layout._faceXPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXPos._horizontalMirror, layout._faceXPos._verticalMirror));
|
|
||||||
faces.push_back(image.copy(QRect(layout._faceXNeg._x * faceWidth, layout._faceXNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXNeg._horizontalMirror, layout._faceXNeg._verticalMirror));
|
|
||||||
faces.push_back(image.copy(QRect(layout._faceYPos._x * faceWidth, layout._faceYPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYPos._horizontalMirror, layout._faceYPos._verticalMirror));
|
|
||||||
faces.push_back(image.copy(QRect(layout._faceYNeg._x * faceWidth, layout._faceYNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYNeg._horizontalMirror, layout._faceYNeg._verticalMirror));
|
|
||||||
faces.push_back(image.copy(QRect(layout._faceZPos._x * faceWidth, layout._faceZPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZPos._horizontalMirror, layout._faceZPos._verticalMirror));
|
|
||||||
faces.push_back(image.copy(QRect(layout._faceZNeg._x * faceWidth, layout._faceZNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZNeg._horizontalMirror, layout._faceZNeg._verticalMirror));
|
|
||||||
} else {
|
|
||||||
qCDebug(modelLog) << "Failed to find a known cube map layout from this image:" << QString(srcImageName.c_str());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the 6 faces have been created go on and define the true Texture
|
|
||||||
if (faces.size() == gpu::Texture::NUM_FACES_PER_TYPE[gpu::Texture::TEX_CUBE]) {
|
|
||||||
theTexture = gpu::Texture::createCube(formatGPU, faces[0].width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
|
|
||||||
theTexture->autoGenerateMips(-1);
|
theTexture->autoGenerateMips(-1);
|
||||||
int f = 0;
|
}
|
||||||
for (auto& face : faces) {
|
|
||||||
theTexture->assignStoredMipFace(0, formatMip, face.byteCount(), face.constBits(), f);
|
|
||||||
f++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate irradiance while we are at it
|
// Generate irradiance while we are at it
|
||||||
|
if (generateIrradiance) {
|
||||||
theTexture->generateIrradiance();
|
theTexture->generateIrradiance();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return theTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
|
||||||
QImage image = srcImage;
|
|
||||||
|
|
||||||
int imageArea = image.width() * image.height();
|
|
||||||
|
|
||||||
int opaquePixels = 0;
|
|
||||||
int translucentPixels = 0;
|
|
||||||
//bool isTransparent = false;
|
|
||||||
int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
|
||||||
const int EIGHT_BIT_MAXIMUM = 255;
|
|
||||||
QColor averageColor(EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM);
|
|
||||||
|
|
||||||
if (!image.hasAlphaChannel()) {
|
|
||||||
if (image.format() != QImage::Format_RGB888) {
|
|
||||||
image = image.convertToFormat(QImage::Format_RGB888);
|
|
||||||
}
|
}
|
||||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0;
|
|
||||||
for (int y = 0; y < image.height(); y++) {
|
|
||||||
for (int x = 0; x < image.width(); x++) {
|
|
||||||
QRgb rgb = image.pixel(x, y);
|
|
||||||
redTotal += qRed(rgb);
|
|
||||||
greenTotal += qGreen(rgb);
|
|
||||||
blueTotal += qBlue(rgb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (imageArea > 0) {
|
|
||||||
averageColor.setRgb(redTotal / imageArea, greenTotal / imageArea, blueTotal / imageArea);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (image.format() != QImage::Format_ARGB32) {
|
|
||||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for translucency/false transparency
|
|
||||||
// int opaquePixels = 0;
|
|
||||||
// int translucentPixels = 0;
|
|
||||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
|
||||||
for (int y = 0; y < image.height(); y++) {
|
|
||||||
for (int x = 0; x < image.width(); x++) {
|
|
||||||
QRgb rgb = image.pixel(x, y);
|
|
||||||
redTotal += qRed(rgb);
|
|
||||||
greenTotal += qGreen(rgb);
|
|
||||||
blueTotal += qBlue(rgb);
|
|
||||||
int alpha = qAlpha(rgb);
|
|
||||||
alphaTotal += alpha;
|
|
||||||
if (alpha == EIGHT_BIT_MAXIMUM) {
|
|
||||||
opaquePixels++;
|
|
||||||
} else if (alpha != 0) {
|
|
||||||
translucentPixels++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (opaquePixels == imageArea) {
|
|
||||||
qCDebug(modelLog) << "Image with alpha channel is completely opaque:" << QString(srcImageName.c_str());
|
|
||||||
image = image.convertToFormat(QImage::Format_RGB888);
|
|
||||||
}
|
|
||||||
|
|
||||||
averageColor = QColor(redTotal / imageArea,
|
|
||||||
greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea);
|
|
||||||
|
|
||||||
//isTransparent = (translucentPixels >= imageArea / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
gpu::Texture* theTexture = nullptr;
|
|
||||||
if ((image.width() > 0) && (image.height() > 0)) {
|
|
||||||
|
|
||||||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
|
||||||
bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
|
||||||
|
|
||||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
|
||||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
|
||||||
if (image.hasAlphaChannel()) {
|
|
||||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
|
||||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
|
||||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
|
||||||
theTexture->autoGenerateMips(-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return theTexture;
|
return theTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||||
|
return processCubeTextureColorFromImage(srcImage, srcImageName, false, true, true, true);
|
||||||
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@ public:
|
||||||
int _environmentUsage = 0;
|
int _environmentUsage = 0;
|
||||||
|
|
||||||
static gpu::Texture* create2DTextureFromImage(const QImage& image, const std::string& srcImageName);
|
static gpu::Texture* create2DTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||||
|
static gpu::Texture* createAlbedoTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||||
|
static gpu::Texture* createEmissiveTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||||
static gpu::Texture* createNormalTextureFromNormalImage(const QImage& image, const std::string& srcImageName);
|
static gpu::Texture* createNormalTextureFromNormalImage(const QImage& image, const std::string& srcImageName);
|
||||||
static gpu::Texture* createNormalTextureFromBumpImage(const QImage& image, const std::string& srcImageName);
|
static gpu::Texture* createNormalTextureFromBumpImage(const QImage& image, const std::string& srcImageName);
|
||||||
static gpu::Texture* createRoughnessTextureFromImage(const QImage& image, const std::string& srcImageName);
|
static gpu::Texture* createRoughnessTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||||
|
@ -40,6 +42,13 @@ public:
|
||||||
static gpu::Texture* createCubeTextureFromImage(const QImage& image, const std::string& srcImageName);
|
static gpu::Texture* createCubeTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||||
static gpu::Texture* createLightmapTextureFromImage(const QImage& image, const std::string& srcImageName);
|
static gpu::Texture* createLightmapTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||||
|
|
||||||
|
|
||||||
|
static const QImage process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask);
|
||||||
|
static void defineColorTexelFormats(gpu::Element& formatGPU, gpu::Element& formatMip,
|
||||||
|
const QImage& srcImage, bool isLinear, bool doCompress);
|
||||||
|
static gpu::Texture* process2DTextureColorFromImage(const QImage& srcImage, bool isLinear, bool doCompress, bool generateMips);
|
||||||
|
static gpu::Texture* processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips, bool generateIrradiance);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ void ResourceRequest::send() {
|
||||||
QMetaObject::invokeMethod(this, "send", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "send", Qt::QueuedConnection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_ASSERT(_state == NotStarted);
|
Q_ASSERT(_state == NotStarted);
|
||||||
|
|
||||||
_state = InProgress;
|
_state = InProgress;
|
||||||
|
|
|
@ -85,11 +85,11 @@ void UserActivityLogger::launch(QString applicationVersion, bool previousSession
|
||||||
logAction(ACTION_NAME, actionDetails);
|
logAction(ACTION_NAME, actionDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserActivityLogger::insufficientGLVersion(QString glVersion) {
|
void UserActivityLogger::insufficientGLVersion(const QJsonObject& glData) {
|
||||||
const QString ACTION_NAME = "insufficient_gl";
|
const QString ACTION_NAME = "insufficient_gl";
|
||||||
QJsonObject actionDetails;
|
QJsonObject actionDetails;
|
||||||
QString GL_VERSION = "glVersion";
|
QString GL_DATA = "glData";
|
||||||
actionDetails.insert(GL_VERSION, glVersion);
|
actionDetails.insert(GL_DATA, glData);
|
||||||
|
|
||||||
logAction(ACTION_NAME, actionDetails);
|
logAction(ACTION_NAME, actionDetails);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ public slots:
|
||||||
|
|
||||||
void launch(QString applicationVersion, bool previousSessionCrashed, int previousSessionRuntime);
|
void launch(QString applicationVersion, bool previousSessionCrashed, int previousSessionRuntime);
|
||||||
|
|
||||||
void insufficientGLVersion(QString glVersion);
|
void insufficientGLVersion(const QJsonObject& glData);
|
||||||
|
|
||||||
void changedDisplayName(QString displayName);
|
void changedDisplayName(QString displayName);
|
||||||
void changedModel(QString typeOfModel, QString modelURL);
|
void changedModel(QString typeOfModel, QString modelURL);
|
||||||
|
@ -48,4 +48,4 @@ private:
|
||||||
bool _disabled;
|
bool _disabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_UserActivityLogger_h
|
#endif // hifi_UserActivityLogger_h
|
||||||
|
|
|
@ -66,7 +66,7 @@ public:
|
||||||
/// By default, all HMDs are stereo
|
/// By default, all HMDs are stereo
|
||||||
virtual bool isStereo() const { return isHmd(); }
|
virtual bool isStereo() const { return isHmd(); }
|
||||||
virtual bool isThrottled() const { return false; }
|
virtual bool isThrottled() const { return false; }
|
||||||
virtual float getTargetFrameRate() { return 0.0f; }
|
virtual float getTargetFrameRate() const { return 0.0f; }
|
||||||
|
|
||||||
/// Returns a boolean value indicating whether the display is currently visible
|
/// Returns a boolean value indicating whether the display is currently visible
|
||||||
/// to the user. For monitor displays, false might indicate that a screensaver,
|
/// to the user. For monitor displays, false might indicate that a screensaver,
|
||||||
|
@ -142,7 +142,12 @@ public:
|
||||||
virtual void abandonCalibration() {}
|
virtual void abandonCalibration() {}
|
||||||
virtual void resetSensors() {}
|
virtual void resetSensors() {}
|
||||||
virtual float devicePixelRatio() { return 1.0f; }
|
virtual float devicePixelRatio() { return 1.0f; }
|
||||||
virtual float presentRate() { return -1.0f; }
|
// Rate at which we present to the display device
|
||||||
|
virtual float presentRate() const { return -1.0f; }
|
||||||
|
// Rate at which new frames are being presented to the display device
|
||||||
|
virtual float newFramePresentRate() const { return -1.0f; }
|
||||||
|
// Rate at which rendered frames are being skipped
|
||||||
|
virtual float droppedFrameRate() const { return -1.0f; }
|
||||||
uint32_t presentCount() const { return _presentedFrameIndex; }
|
uint32_t presentCount() const { return _presentedFrameIndex; }
|
||||||
|
|
||||||
virtual void cycleDebugOutput() {}
|
virtual void cycleDebugOutput() {}
|
||||||
|
|
|
@ -32,6 +32,8 @@ void EngineStats::run(const SceneContextPointer& sceneContext, const RenderConte
|
||||||
config->textureGPUCount = gpu::Texture::getTextureGPUCount();
|
config->textureGPUCount = gpu::Texture::getTextureGPUCount();
|
||||||
config->textureCPUMemoryUsage = gpu::Texture::getTextureCPUMemoryUsage();
|
config->textureCPUMemoryUsage = gpu::Texture::getTextureCPUMemoryUsage();
|
||||||
config->textureGPUMemoryUsage = gpu::Texture::getTextureGPUMemoryUsage();
|
config->textureGPUMemoryUsage = gpu::Texture::getTextureGPUMemoryUsage();
|
||||||
|
config->textureGPUVirtualMemoryUsage = gpu::Texture::getTextureGPUVirtualMemoryUsage();
|
||||||
|
config->textureGPUTransferCount = gpu::Texture::getTextureGPUTransferCount();
|
||||||
|
|
||||||
gpu::ContextStats gpuStats(_gpuStats);
|
gpu::ContextStats gpuStats(_gpuStats);
|
||||||
renderContext->args->_context->getStats(_gpuStats);
|
renderContext->args->_context->getStats(_gpuStats);
|
||||||
|
@ -45,6 +47,7 @@ void EngineStats::run(const SceneContextPointer& sceneContext, const RenderConte
|
||||||
|
|
||||||
config->frameTextureCount = _gpuStats._RSNumTextureBounded - gpuStats._RSNumTextureBounded;
|
config->frameTextureCount = _gpuStats._RSNumTextureBounded - gpuStats._RSNumTextureBounded;
|
||||||
config->frameTextureRate = config->frameTextureCount * frequency;
|
config->frameTextureRate = config->frameTextureCount * frequency;
|
||||||
|
config->frameTextureMemoryUsage = _gpuStats._RSAmountTextureMemoryBounded - gpuStats._RSAmountTextureMemoryBounded;
|
||||||
|
|
||||||
config->emitDirty();
|
config->emitDirty();
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,8 @@ namespace render {
|
||||||
Q_PROPERTY(quint32 textureGPUCount MEMBER textureGPUCount NOTIFY dirty)
|
Q_PROPERTY(quint32 textureGPUCount MEMBER textureGPUCount NOTIFY dirty)
|
||||||
Q_PROPERTY(qint64 textureCPUMemoryUsage MEMBER textureCPUMemoryUsage NOTIFY dirty)
|
Q_PROPERTY(qint64 textureCPUMemoryUsage MEMBER textureCPUMemoryUsage NOTIFY dirty)
|
||||||
Q_PROPERTY(qint64 textureGPUMemoryUsage MEMBER textureGPUMemoryUsage NOTIFY dirty)
|
Q_PROPERTY(qint64 textureGPUMemoryUsage MEMBER textureGPUMemoryUsage NOTIFY dirty)
|
||||||
|
Q_PROPERTY(qint64 textureGPUVirtualMemoryUsage MEMBER textureGPUVirtualMemoryUsage NOTIFY dirty)
|
||||||
|
Q_PROPERTY(quint32 textureGPUTransferCount MEMBER textureGPUTransferCount NOTIFY dirty)
|
||||||
|
|
||||||
Q_PROPERTY(quint32 frameAPIDrawcallCount MEMBER frameAPIDrawcallCount NOTIFY dirty)
|
Q_PROPERTY(quint32 frameAPIDrawcallCount MEMBER frameAPIDrawcallCount NOTIFY dirty)
|
||||||
Q_PROPERTY(quint32 frameDrawcallCount MEMBER frameDrawcallCount NOTIFY dirty)
|
Q_PROPERTY(quint32 frameDrawcallCount MEMBER frameDrawcallCount NOTIFY dirty)
|
||||||
|
@ -43,7 +45,7 @@ namespace render {
|
||||||
|
|
||||||
Q_PROPERTY(quint32 frameTextureCount MEMBER frameTextureCount NOTIFY dirty)
|
Q_PROPERTY(quint32 frameTextureCount MEMBER frameTextureCount NOTIFY dirty)
|
||||||
Q_PROPERTY(quint32 frameTextureRate MEMBER frameTextureRate NOTIFY dirty)
|
Q_PROPERTY(quint32 frameTextureRate MEMBER frameTextureRate NOTIFY dirty)
|
||||||
|
Q_PROPERTY(quint32 frameTextureMemoryUsage MEMBER frameTextureMemoryUsage NOTIFY dirty)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EngineStatsConfig() : Job::Config(true) {}
|
EngineStatsConfig() : Job::Config(true) {}
|
||||||
|
@ -57,6 +59,8 @@ namespace render {
|
||||||
quint32 textureGPUCount{ 0 };
|
quint32 textureGPUCount{ 0 };
|
||||||
qint64 textureCPUMemoryUsage{ 0 };
|
qint64 textureCPUMemoryUsage{ 0 };
|
||||||
qint64 textureGPUMemoryUsage{ 0 };
|
qint64 textureGPUMemoryUsage{ 0 };
|
||||||
|
qint64 textureGPUVirtualMemoryUsage{ 0 };
|
||||||
|
quint32 textureGPUTransferCount{ 0 };
|
||||||
|
|
||||||
quint32 frameAPIDrawcallCount{ 0 };
|
quint32 frameAPIDrawcallCount{ 0 };
|
||||||
quint32 frameDrawcallCount{ 0 };
|
quint32 frameDrawcallCount{ 0 };
|
||||||
|
@ -67,6 +71,7 @@ namespace render {
|
||||||
|
|
||||||
quint32 frameTextureCount{ 0 };
|
quint32 frameTextureCount{ 0 };
|
||||||
quint32 frameTextureRate{ 0 };
|
quint32 frameTextureRate{ 0 };
|
||||||
|
qint64 frameTextureMemoryUsage{ 0 };
|
||||||
|
|
||||||
void emitDirty() { emit dirty(); }
|
void emitDirty() { emit dirty(); }
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,19 @@ ScriptEngines::ScriptEngines()
|
||||||
_scriptsModelFilter.setSourceModel(&_scriptsModel);
|
_scriptsModelFilter.setSourceModel(&_scriptsModel);
|
||||||
_scriptsModelFilter.sort(0, Qt::AscendingOrder);
|
_scriptsModelFilter.sort(0, Qt::AscendingOrder);
|
||||||
_scriptsModelFilter.setDynamicSortFilter(true);
|
_scriptsModelFilter.setDynamicSortFilter(true);
|
||||||
|
|
||||||
|
static const int SCRIPT_SAVE_COUNTDOWN_INTERVAL_MS = 5000;
|
||||||
|
QTimer* scriptSaveTimer = new QTimer(this);
|
||||||
|
scriptSaveTimer->setSingleShot(true);
|
||||||
|
QMetaObject::Connection timerConnection = connect(scriptSaveTimer, &QTimer::timeout, [] {
|
||||||
|
DependencyManager::get<ScriptEngines>()->saveScripts();
|
||||||
|
});
|
||||||
|
connect(qApp, &QCoreApplication::aboutToQuit, [=] {
|
||||||
|
disconnect(timerConnection);
|
||||||
|
});
|
||||||
|
connect(this, &ScriptEngines::scriptCountChanged, this, [scriptSaveTimer] {
|
||||||
|
scriptSaveTimer->start(SCRIPT_SAVE_COUNTDOWN_INTERVAL_MS);
|
||||||
|
}, Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
QUrl normalizeScriptURL(const QUrl& rawScriptURL) {
|
QUrl normalizeScriptURL(const QUrl& rawScriptURL) {
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
//
|
|
||||||
// CPUID.cpp
|
|
||||||
//
|
|
||||||
// Created by Ryan Huffman on 3/25/16.
|
|
||||||
// Copyright 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 "CPUID.h"
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
|
|
||||||
const CPUID::CPUID_Internal CPUID::CPU_Rep;
|
|
||||||
|
|
||||||
std::vector<CPUID::Feature> CPUID::getAllFeatures() {
|
|
||||||
std::vector<CPUID::Feature> features;
|
|
||||||
|
|
||||||
features.push_back({ "3DNOW", CPUID::_3DNOW() });
|
|
||||||
features.push_back({ "3DNOWEXT", CPUID::_3DNOWEXT() });
|
|
||||||
features.push_back({ "ABM", CPUID::ABM() });
|
|
||||||
features.push_back({ "ADX", CPUID::ADX() });
|
|
||||||
features.push_back({ "AES", CPUID::AES() });
|
|
||||||
features.push_back({ "AVX", CPUID::AVX() });
|
|
||||||
features.push_back({ "AVX2", CPUID::AVX2() });
|
|
||||||
features.push_back({ "AVX512CD", CPUID::AVX512CD() });
|
|
||||||
features.push_back({ "AVX512ER", CPUID::AVX512ER() });
|
|
||||||
features.push_back({ "AVX512F", CPUID::AVX512F() });
|
|
||||||
features.push_back({ "AVX512PF", CPUID::AVX512PF() });
|
|
||||||
features.push_back({ "BMI1", CPUID::BMI1() });
|
|
||||||
features.push_back({ "BMI2", CPUID::BMI2() });
|
|
||||||
features.push_back({ "CLFSH", CPUID::CLFSH() });
|
|
||||||
features.push_back({ "CMPXCHG16B", CPUID::CMPXCHG16B() });
|
|
||||||
features.push_back({ "CX8", CPUID::CX8() });
|
|
||||||
features.push_back({ "ERMS", CPUID::ERMS() });
|
|
||||||
features.push_back({ "F16C", CPUID::F16C() });
|
|
||||||
features.push_back({ "FMA", CPUID::FMA() });
|
|
||||||
features.push_back({ "FSGSBASE", CPUID::FSGSBASE() });
|
|
||||||
features.push_back({ "FXSR", CPUID::FXSR() });
|
|
||||||
features.push_back({ "HLE", CPUID::HLE() });
|
|
||||||
features.push_back({ "INVPCID", CPUID::INVPCID() });
|
|
||||||
features.push_back({ "LAHF", CPUID::LAHF() });
|
|
||||||
features.push_back({ "LZCNT", CPUID::LZCNT() });
|
|
||||||
features.push_back({ "MMX", CPUID::MMX() });
|
|
||||||
features.push_back({ "MMXEXT", CPUID::MMXEXT() });
|
|
||||||
features.push_back({ "MONITOR", CPUID::MONITOR() });
|
|
||||||
features.push_back({ "MOVBE", CPUID::MOVBE() });
|
|
||||||
features.push_back({ "MSR", CPUID::MSR() });
|
|
||||||
features.push_back({ "OSXSAVE", CPUID::OSXSAVE() });
|
|
||||||
features.push_back({ "PCLMULQDQ", CPUID::PCLMULQDQ() });
|
|
||||||
features.push_back({ "POPCNT", CPUID::POPCNT() });
|
|
||||||
features.push_back({ "PREFETCHWT1", CPUID::PREFETCHWT1() });
|
|
||||||
features.push_back({ "RDRAND", CPUID::RDRAND() });
|
|
||||||
features.push_back({ "RDSEED", CPUID::RDSEED() });
|
|
||||||
features.push_back({ "RDTSCP", CPUID::RDTSCP() });
|
|
||||||
features.push_back({ "RTM", CPUID::RTM() });
|
|
||||||
features.push_back({ "SEP", CPUID::SEP() });
|
|
||||||
features.push_back({ "SHA", CPUID::SHA() });
|
|
||||||
features.push_back({ "SSE", CPUID::SSE() });
|
|
||||||
features.push_back({ "SSE2", CPUID::SSE2() });
|
|
||||||
features.push_back({ "SSE3", CPUID::SSE3() });
|
|
||||||
features.push_back({ "SSE4.1", CPUID::SSE41() });
|
|
||||||
features.push_back({ "SSE4.2", CPUID::SSE42() });
|
|
||||||
features.push_back({ "SSE4a", CPUID::SSE4a() });
|
|
||||||
features.push_back({ "SSSE3", CPUID::SSSE3() });
|
|
||||||
features.push_back({ "SYSCALL", CPUID::SYSCALL() });
|
|
||||||
features.push_back({ "TBM", CPUID::TBM() });
|
|
||||||
features.push_back({ "XOP", CPUID::XOP() });
|
|
||||||
features.push_back({ "XSAVE", CPUID::XSAVE() });
|
|
||||||
|
|
||||||
return features;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
75
libraries/shared/src/CPUIdent.cpp
Normal file
75
libraries/shared/src/CPUIdent.cpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
//
|
||||||
|
// CPUIdent.cpp
|
||||||
|
//
|
||||||
|
// Created by Ryan Huffman on 3/25/16.
|
||||||
|
// Copyright 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 "CPUIdent.h"
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
|
||||||
|
const CPUIdent::CPUIdent_Internal CPUIdent::CPU_Rep;
|
||||||
|
|
||||||
|
std::vector<CPUIdent::Feature> CPUIdent::getAllFeatures() {
|
||||||
|
std::vector<CPUIdent::Feature> features;
|
||||||
|
|
||||||
|
features.push_back({ "3DNOW", CPUIdent::_3DNOW() });
|
||||||
|
features.push_back({ "3DNOWEXT", CPUIdent::_3DNOWEXT() });
|
||||||
|
features.push_back({ "ABM", CPUIdent::ABM() });
|
||||||
|
features.push_back({ "ADX", CPUIdent::ADX() });
|
||||||
|
features.push_back({ "AES", CPUIdent::AES() });
|
||||||
|
features.push_back({ "AVX", CPUIdent::AVX() });
|
||||||
|
features.push_back({ "AVX2", CPUIdent::AVX2() });
|
||||||
|
features.push_back({ "AVX512CD", CPUIdent::AVX512CD() });
|
||||||
|
features.push_back({ "AVX512ER", CPUIdent::AVX512ER() });
|
||||||
|
features.push_back({ "AVX512F", CPUIdent::AVX512F() });
|
||||||
|
features.push_back({ "AVX512PF", CPUIdent::AVX512PF() });
|
||||||
|
features.push_back({ "BMI1", CPUIdent::BMI1() });
|
||||||
|
features.push_back({ "BMI2", CPUIdent::BMI2() });
|
||||||
|
features.push_back({ "CLFSH", CPUIdent::CLFSH() });
|
||||||
|
features.push_back({ "CMPXCHG16B", CPUIdent::CMPXCHG16B() });
|
||||||
|
features.push_back({ "CX8", CPUIdent::CX8() });
|
||||||
|
features.push_back({ "ERMS", CPUIdent::ERMS() });
|
||||||
|
features.push_back({ "F16C", CPUIdent::F16C() });
|
||||||
|
features.push_back({ "FMA", CPUIdent::FMA() });
|
||||||
|
features.push_back({ "FSGSBASE", CPUIdent::FSGSBASE() });
|
||||||
|
features.push_back({ "FXSR", CPUIdent::FXSR() });
|
||||||
|
features.push_back({ "HLE", CPUIdent::HLE() });
|
||||||
|
features.push_back({ "INVPCID", CPUIdent::INVPCID() });
|
||||||
|
features.push_back({ "LAHF", CPUIdent::LAHF() });
|
||||||
|
features.push_back({ "LZCNT", CPUIdent::LZCNT() });
|
||||||
|
features.push_back({ "MMX", CPUIdent::MMX() });
|
||||||
|
features.push_back({ "MMXEXT", CPUIdent::MMXEXT() });
|
||||||
|
features.push_back({ "MONITOR", CPUIdent::MONITOR() });
|
||||||
|
features.push_back({ "MOVBE", CPUIdent::MOVBE() });
|
||||||
|
features.push_back({ "MSR", CPUIdent::MSR() });
|
||||||
|
features.push_back({ "OSXSAVE", CPUIdent::OSXSAVE() });
|
||||||
|
features.push_back({ "PCLMULQDQ", CPUIdent::PCLMULQDQ() });
|
||||||
|
features.push_back({ "POPCNT", CPUIdent::POPCNT() });
|
||||||
|
features.push_back({ "PREFETCHWT1", CPUIdent::PREFETCHWT1() });
|
||||||
|
features.push_back({ "RDRAND", CPUIdent::RDRAND() });
|
||||||
|
features.push_back({ "RDSEED", CPUIdent::RDSEED() });
|
||||||
|
features.push_back({ "RDTSCP", CPUIdent::RDTSCP() });
|
||||||
|
features.push_back({ "RTM", CPUIdent::RTM() });
|
||||||
|
features.push_back({ "SEP", CPUIdent::SEP() });
|
||||||
|
features.push_back({ "SHA", CPUIdent::SHA() });
|
||||||
|
features.push_back({ "SSE", CPUIdent::SSE() });
|
||||||
|
features.push_back({ "SSE2", CPUIdent::SSE2() });
|
||||||
|
features.push_back({ "SSE3", CPUIdent::SSE3() });
|
||||||
|
features.push_back({ "SSE4.1", CPUIdent::SSE41() });
|
||||||
|
features.push_back({ "SSE4.2", CPUIdent::SSE42() });
|
||||||
|
features.push_back({ "SSE4a", CPUIdent::SSE4a() });
|
||||||
|
features.push_back({ "SSSE3", CPUIdent::SSSE3() });
|
||||||
|
features.push_back({ "SYSCALL", CPUIdent::SYSCALL() });
|
||||||
|
features.push_back({ "TBM", CPUIdent::TBM() });
|
||||||
|
features.push_back({ "XOP", CPUIdent::XOP() });
|
||||||
|
features.push_back({ "XSAVE", CPUIdent::XSAVE() });
|
||||||
|
|
||||||
|
return features;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// CPUID.h
|
// CPUIdent.h
|
||||||
//
|
//
|
||||||
// Adapted from Microsoft's example for using the cpuid intrinsic,
|
// Adapted from Microsoft's example for using the cpuid intrinsic,
|
||||||
// found at https://msdn.microsoft.com/en-us/library/hskdteyh.aspx
|
// found at https://msdn.microsoft.com/en-us/library/hskdteyh.aspx
|
||||||
|
@ -15,8 +15,8 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef hifi_CPUID_h
|
#ifndef hifi_CPUIdent_h
|
||||||
#define hifi_CPUID_h
|
#define hifi_CPUIdent_h
|
||||||
|
|
||||||
#include <QtCore/QtGlobal>
|
#include <QtCore/QtGlobal>
|
||||||
|
|
||||||
|
@ -29,10 +29,10 @@
|
||||||
|
|
||||||
#include <intrin.h>
|
#include <intrin.h>
|
||||||
|
|
||||||
class CPUID
|
class CPUIdent
|
||||||
{
|
{
|
||||||
// forward declarations
|
// forward declarations
|
||||||
class CPUID_Internal;
|
class CPUIdent_Internal;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct Feature {
|
struct Feature {
|
||||||
|
@ -104,12 +104,12 @@ public:
|
||||||
static bool _3DNOW(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[31]; }
|
static bool _3DNOW(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[31]; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const CPUID_Internal CPU_Rep;
|
static const CPUIdent_Internal CPU_Rep;
|
||||||
|
|
||||||
class CPUID_Internal
|
class CPUIdent_Internal
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CPUID_Internal()
|
CPUIdent_Internal()
|
||||||
: nIds_ { 0 },
|
: nIds_ { 0 },
|
||||||
nExIds_ { 0 },
|
nExIds_ { 0 },
|
||||||
isIntel_ { false },
|
isIntel_ { false },
|
||||||
|
@ -209,4 +209,4 @@ private:
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // hifi_CPUID_h
|
#endif // hifi_CPUIdent_h
|
|
@ -24,7 +24,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include "CPUID.h"
|
#include "CPUIdent.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -758,10 +758,10 @@ void printSystemInformation() {
|
||||||
|
|
||||||
qDebug() << "CPUID";
|
qDebug() << "CPUID";
|
||||||
|
|
||||||
qDebug() << "\tCPU Vendor: " << CPUID::Vendor().c_str();
|
qDebug() << "\tCPU Vendor: " << CPUIdent::Vendor().c_str();
|
||||||
qDebug() << "\tCPU Brand: " << CPUID::Brand().c_str();
|
qDebug() << "\tCPU Brand: " << CPUIdent::Brand().c_str();
|
||||||
|
|
||||||
for (auto& feature : CPUID::getAllFeatures()) {
|
for (auto& feature : CPUIdent::getAllFeatures()) {
|
||||||
qDebug().nospace().noquote() << "\t[" << (feature.supported ? "x" : " ") << "] " << feature.name.c_str();
|
qDebug().nospace().noquote() << "\t[" << (feature.supported ? "x" : " ") << "] " << feature.name.c_str();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -777,4 +777,4 @@ void printSystemInformation() {
|
||||||
qDebug().noquote().nospace() << "\t" <<
|
qDebug().noquote().nospace() << "\t" <<
|
||||||
(envVariables.contains(env) ? " = " + envVariables.value(env) : " NOT FOUND");
|
(envVariables.contains(env) ? " = " + envVariables.value(env) : " NOT FOUND");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
49
libraries/shared/src/shared/RateCounter.h
Normal file
49
libraries/shared/src/shared/RateCounter.h
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis 2016/04/10
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef hifi_Shared_RateCounter_h
|
||||||
|
#define hifi_Shared_RateCounter_h
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <QtCore/QElapsedTimer>
|
||||||
|
|
||||||
|
#include "../SharedUtil.h"
|
||||||
|
#include "../NumericalConstants.h"
|
||||||
|
|
||||||
|
template <uint32_t INTERVAL = MSECS_PER_SECOND, uint8_t PRECISION = 2>
|
||||||
|
class RateCounter {
|
||||||
|
public:
|
||||||
|
void increment(size_t count = 1) {
|
||||||
|
auto now = usecTimestampNow();
|
||||||
|
auto currentIntervalMs = (uint32_t)((now - _start) / USECS_PER_MSEC);
|
||||||
|
if (currentIntervalMs > INTERVAL) {
|
||||||
|
float currentCount = _count;
|
||||||
|
float intervalSeconds = (float)currentIntervalMs / (float)MSECS_PER_SECOND;
|
||||||
|
_rate = roundf(currentCount / intervalSeconds * _scale) / _scale;
|
||||||
|
_start = now;
|
||||||
|
_count = 0;
|
||||||
|
};
|
||||||
|
_count += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
float rate() const { return _rate; }
|
||||||
|
|
||||||
|
uint8_t precision() const { return PRECISION; }
|
||||||
|
|
||||||
|
uint32_t interval() const { return INTERVAL; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t _start { usecTimestampNow() };
|
||||||
|
size_t _count { 0 };
|
||||||
|
float _rate { 0 };
|
||||||
|
const float _scale { powf(10, PRECISION) };
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -15,6 +15,8 @@
|
||||||
#include <QtQuick/QQuickWindow>
|
#include <QtQuick/QQuickWindow>
|
||||||
#include <QtQml/QtQml>
|
#include <QtQml/QtQml>
|
||||||
|
|
||||||
|
#include <gl/GLHelpers.h>
|
||||||
|
|
||||||
#include <AbstractUriHandler.h>
|
#include <AbstractUriHandler.h>
|
||||||
#include <AccountManager.h>
|
#include <AccountManager.h>
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ public:
|
||||||
// Stereo specific methods
|
// Stereo specific methods
|
||||||
virtual void resetSensors() override final;
|
virtual void resetSensors() override final;
|
||||||
virtual void beginFrameRender(uint32_t frameIndex) override;
|
virtual void beginFrameRender(uint32_t frameIndex) override;
|
||||||
float getTargetFrameRate() override { return _hmdDesc.DisplayRefreshRate; }
|
float getTargetFrameRate() const override { return _hmdDesc.DisplayRefreshRate; }
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -181,7 +181,7 @@ int OculusLegacyDisplayPlugin::getHmdScreen() const {
|
||||||
return _hmdScreen;
|
return _hmdScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
float OculusLegacyDisplayPlugin::getTargetFrameRate() {
|
float OculusLegacyDisplayPlugin::getTargetFrameRate() const {
|
||||||
return TARGET_RATE_OculusLegacy;
|
return TARGET_RATE_OculusLegacy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ public:
|
||||||
virtual void resetSensors() override;
|
virtual void resetSensors() override;
|
||||||
virtual void beginFrameRender(uint32_t frameIndex) override;
|
virtual void beginFrameRender(uint32_t frameIndex) override;
|
||||||
|
|
||||||
virtual float getTargetFrameRate() override;
|
virtual float getTargetFrameRate() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool internalActivate() override;
|
virtual bool internalActivate() override;
|
||||||
|
|
|
@ -21,7 +21,7 @@ public:
|
||||||
virtual bool isSupported() const override;
|
virtual bool isSupported() const override;
|
||||||
virtual const QString& getName() const override { return NAME; }
|
virtual const QString& getName() const override { return NAME; }
|
||||||
|
|
||||||
virtual float getTargetFrameRate() override { return TARGET_RATE_OpenVr; }
|
virtual float getTargetFrameRate() const override { return TARGET_RATE_OpenVr; }
|
||||||
|
|
||||||
virtual void customizeContext() override;
|
virtual void customizeContext() override;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue