mirror of
https://github.com/overte-org/overte.git
synced 2025-04-14 14:47:19 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into orange
This commit is contained in:
commit
e28e85a29c
16 changed files with 262 additions and 125 deletions
|
@ -235,6 +235,11 @@ void AssignmentClient::sendAssignmentRequest() {
|
|||
void AssignmentClient::handleCreateAssignmentPacket(QSharedPointer<ReceivedMessage> message) {
|
||||
qCDebug(assigmnentclient) << "Received a PacketType::CreateAssignment - attempting to unpack.";
|
||||
|
||||
if (_currentAssignment) {
|
||||
qCWarning(assigmnentclient) << "Received a PacketType::CreateAssignment while still running an active assignment. Ignoring.";
|
||||
return;
|
||||
}
|
||||
|
||||
// construct the deployed assignment from the packet data
|
||||
_currentAssignment = AssignmentFactory::unpackAssignment(*message);
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects.
|
||||
// Also supports touch and equipping objects.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -305,7 +304,6 @@ function MyController(hand) {
|
|||
switch (this.state) {
|
||||
case STATE_OFF:
|
||||
this.off();
|
||||
this.touchTest();
|
||||
break;
|
||||
case STATE_SEARCHING:
|
||||
case STATE_HOLD_SEARCHING:
|
||||
|
@ -1672,71 +1670,6 @@ function MyController(hand) {
|
|||
this.callEntityMethodOnGrabbed("continueFarTrigger");
|
||||
};
|
||||
|
||||
_this.allTouchedIDs = {};
|
||||
|
||||
this.touchTest = function() {
|
||||
var maxDistance = 0.05;
|
||||
var leftHandPosition = MyAvatar.getLeftPalmPosition();
|
||||
var rightHandPosition = MyAvatar.getRightPalmPosition();
|
||||
var leftEntities = Entities.findEntities(leftHandPosition, maxDistance);
|
||||
var rightEntities = Entities.findEntities(rightHandPosition, maxDistance);
|
||||
var ids = [];
|
||||
|
||||
if (leftEntities.length !== 0) {
|
||||
leftEntities.forEach(function(entity) {
|
||||
ids.push(entity);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
if (rightEntities.length !== 0) {
|
||||
rightEntities.forEach(function(entity) {
|
||||
ids.push(entity);
|
||||
});
|
||||
}
|
||||
|
||||
ids.forEach(function(id) {
|
||||
var props = Entities.getEntityProperties(id, ["boundingBox", "name"]);
|
||||
if (!props ||
|
||||
!props.boundingBox ||
|
||||
props.name === 'pointer') {
|
||||
return;
|
||||
}
|
||||
var entityMinPoint = props.boundingBox.brn;
|
||||
var entityMaxPoint = props.boundingBox.tfl;
|
||||
var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint);
|
||||
var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint);
|
||||
|
||||
if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) {
|
||||
// we haven't been touched before, but either right or left is touching us now
|
||||
_this.allTouchedIDs[id] = true;
|
||||
_this.startTouch(id);
|
||||
} else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) {
|
||||
// we have been touched before and are still being touched
|
||||
// continue touch
|
||||
_this.continueTouch(id);
|
||||
} else if (_this.allTouchedIDs[id]) {
|
||||
delete _this.allTouchedIDs[id];
|
||||
_this.stopTouch(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.startTouch = function(entityID) {
|
||||
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
|
||||
Entities.callEntityMethod(entityID, "startTouch", args);
|
||||
};
|
||||
|
||||
this.continueTouch = function(entityID) {
|
||||
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
|
||||
Entities.callEntityMethod(entityID, "continueTouch", args);
|
||||
};
|
||||
|
||||
this.stopTouch = function(entityID) {
|
||||
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
|
||||
Entities.callEntityMethod(entityID, "stopTouch", args);
|
||||
};
|
||||
|
||||
this.release = function() {
|
||||
this.turnLightsOff();
|
||||
this.turnOffVisualizations();
|
||||
|
|
21
examples/utilities/cache/cacheStats.js
vendored
Normal file
21
examples/utilities/cache/cacheStats.js
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// cacheStats.js
|
||||
// examples/utilities/cache
|
||||
//
|
||||
// Zach Pomerantz, created on 4/1/2016.
|
||||
// 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
|
||||
//
|
||||
|
||||
// Set up the qml ui
|
||||
var qml = Script.resolvePath('stats.qml');
|
||||
var window = new OverlayWindow({
|
||||
title: 'Cache Stats',
|
||||
source: qml,
|
||||
width: 300,
|
||||
height: 200
|
||||
});
|
||||
window.setPosition(500, 50);
|
||||
window.closed.connect(function() { Script.stop(); });
|
77
examples/utilities/cache/stats.qml
vendored
Normal file
77
examples/utilities/cache/stats.qml
vendored
Normal file
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// stats.qml
|
||||
// examples/utilities/cache
|
||||
//
|
||||
// Created by Zach Pomerantz on 4/1/2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import "../lib/plotperf"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
anchors.fill: parent
|
||||
|
||||
property var caches: [["Animation", AnimationCache], ["Model", ModelCache], ["Texture", TextureCache], ["Sound", SoundCache]]
|
||||
|
||||
Grid {
|
||||
id: grid
|
||||
rows: root.caches.length; columns: 1; spacing: 8
|
||||
anchors.fill: parent
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
|
||||
model: root.caches
|
||||
|
||||
Row {
|
||||
PlotPerf {
|
||||
title: modelData[0] + " Count"
|
||||
anchors.left: parent
|
||||
height: (grid.height - (grid.spacing * (root.caches.length + 1))) / root.caches.length
|
||||
width: grid.width / 2 - grid.spacing * 1.5
|
||||
object: modelData[1]
|
||||
valueNumDigits: "1"
|
||||
plots: [
|
||||
{
|
||||
prop: "numTotal",
|
||||
label: "total",
|
||||
color: "#00B4EF"
|
||||
},
|
||||
{
|
||||
prop: "numCached",
|
||||
label: "cached",
|
||||
color: "#1AC567"
|
||||
}
|
||||
]
|
||||
}
|
||||
PlotPerf {
|
||||
title: modelData[0] + " Size"
|
||||
anchors.right: parent
|
||||
height: (grid.height - (grid.spacing * (root.caches.length + 1))) / root.caches.length
|
||||
width: grid.width / 2 - grid.spacing * 1.5
|
||||
object: modelData[1]
|
||||
valueScale: 1048576
|
||||
valueUnit: "Mb"
|
||||
valueNumDigits: "1"
|
||||
plots: [
|
||||
{
|
||||
prop: "sizeTotal",
|
||||
label: "total",
|
||||
color: "#00B4EF"
|
||||
},
|
||||
{
|
||||
prop: "sizeCached",
|
||||
label: "cached",
|
||||
color: "#1AC567"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,12 +19,8 @@ Item {
|
|||
// The title of the graph
|
||||
property string title
|
||||
|
||||
// THe object used as the default source object for the prop plots
|
||||
// The object used as the default source object for the prop plots
|
||||
property var object
|
||||
|
||||
// THis is my hack to get a property and assign it to a trigger var in order to get
|
||||
// a signal called whenever the value changed
|
||||
property var trigger
|
||||
|
||||
// Plots is an array of plot descriptor
|
||||
// a default plot descriptor expects the following object:
|
||||
|
@ -55,45 +51,38 @@ Item {
|
|||
property var tick : 0
|
||||
|
||||
function createValues() {
|
||||
print("trigger is: " + JSON.stringify(trigger))
|
||||
if (Array.isArray(plots)) {
|
||||
for (var i =0; i < plots.length; i++) {
|
||||
var plot = plots[i];
|
||||
print(" a pnew Plot:" + JSON.stringify(plot));
|
||||
_values.push( {
|
||||
object: (plot["object"] !== undefined ? plot["object"] : root.object),
|
||||
value: plot["prop"],
|
||||
valueMax: 1,
|
||||
numSamplesConstantMax: 0,
|
||||
valueHistory: new Array(),
|
||||
label: (plot["label"] !== undefined ? plot["label"] : ""),
|
||||
color: (plot["color"] !== undefined ? plot["color"] : "white"),
|
||||
scale: (plot["scale"] !== undefined ? plot["scale"] : 1),
|
||||
unit: (plot["unit"] !== undefined ? plot["unit"] : valueUnit)
|
||||
})
|
||||
}
|
||||
for (var i =0; i < plots.length; i++) {
|
||||
var plot = plots[i];
|
||||
_values.push( {
|
||||
object: (plot["object"] !== undefined ? plot["object"] : root.object),
|
||||
value: plot["prop"],
|
||||
valueMax: 1,
|
||||
numSamplesConstantMax: 0,
|
||||
valueHistory: new Array(),
|
||||
label: (plot["label"] !== undefined ? plot["label"] : ""),
|
||||
color: (plot["color"] !== undefined ? plot["color"] : "white"),
|
||||
scale: (plot["scale"] !== undefined ? plot["scale"] : 1),
|
||||
unit: (plot["unit"] !== undefined ? plot["unit"] : valueUnit)
|
||||
})
|
||||
}
|
||||
print("in creator" + JSON.stringify(_values));
|
||||
|
||||
pullFreshValues();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
createValues();
|
||||
print(JSON.stringify(_values));
|
||||
|
||||
}
|
||||
|
||||
function pullFreshValues() {
|
||||
//print("pullFreshValues");
|
||||
// Wait until values are created to begin pulling
|
||||
if (!_values) { return; }
|
||||
|
||||
var VALUE_HISTORY_SIZE = 100;
|
||||
var UPDATE_CANVAS_RATE = 20;
|
||||
tick++;
|
||||
|
||||
|
||||
var currentValueMax = 0
|
||||
for (var i = 0; i < _values.length; i++) {
|
||||
|
||||
var currentVal = _values[i].object[_values[i].value] * _values[i].scale;
|
||||
var currentVal = (+_values[i].object[_values[i].value]) * _values[i].scale;
|
||||
|
||||
_values[i].valueHistory.push(currentVal)
|
||||
_values[i].numSamplesConstantMax++;
|
||||
|
@ -125,11 +114,13 @@ Item {
|
|||
valueMax = currentValueMax;
|
||||
}
|
||||
|
||||
if (tick % UPDATE_CANVAS_RATE == 0) {
|
||||
mycanvas.requestPaint()
|
||||
}
|
||||
mycanvas.requestPaint()
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 100; running: true; repeat: true
|
||||
onTriggered: pullFreshValues()
|
||||
}
|
||||
onTriggerChanged: pullFreshValues()
|
||||
|
||||
Canvas {
|
||||
id: mycanvas
|
||||
|
@ -165,9 +156,9 @@ Item {
|
|||
ctx.fillStyle = val.color;
|
||||
var bestValue = val.valueHistory[val.valueHistory.length -1];
|
||||
ctx.textAlign = "right";
|
||||
ctx.fillText(displayValue(bestValue, val.unit), width, (num + 2) * lineHeight * 1.5);
|
||||
ctx.fillText(displayValue(bestValue, val.unit), width, (num + 2) * lineHeight * 1);
|
||||
ctx.textAlign = "left";
|
||||
ctx.fillText(val.label, 0, (num + 2) * lineHeight * 1.5);
|
||||
ctx.fillText(val.label, 0, (num + 2) * lineHeight * 1);
|
||||
}
|
||||
|
||||
function displayTitle(ctx, text, maxVal) {
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import "plotperf"
|
||||
import "../lib/plotperf"
|
||||
|
||||
Item {
|
||||
id: statsUI
|
||||
|
@ -32,7 +32,6 @@ Item {
|
|||
title: "Num Buffers"
|
||||
height: parent.evalEvenHeight()
|
||||
object: stats.config
|
||||
trigger: stats.config["bufferCPUCount"]
|
||||
plots: [
|
||||
{
|
||||
prop: "bufferCPUCount",
|
||||
|
@ -50,7 +49,6 @@ Item {
|
|||
title: "gpu::Buffer Memory"
|
||||
height: parent.evalEvenHeight()
|
||||
object: stats.config
|
||||
trigger: stats.config["bufferCPUMemoryUsage"]
|
||||
valueScale: 1048576
|
||||
valueUnit: "Mb"
|
||||
valueNumDigits: "1"
|
||||
|
@ -71,7 +69,6 @@ Item {
|
|||
title: "Num Textures"
|
||||
height: parent.evalEvenHeight()
|
||||
object: stats.config
|
||||
trigger: stats.config["textureCPUCount"]
|
||||
plots: [
|
||||
{
|
||||
prop: "textureCPUCount",
|
||||
|
@ -99,7 +96,6 @@ Item {
|
|||
title: "gpu::Texture Memory"
|
||||
height: parent.evalEvenHeight()
|
||||
object: stats.config
|
||||
trigger: stats.config["textureCPUMemoryUsage"]
|
||||
valueScale: 1048576
|
||||
valueUnit: "Mb"
|
||||
valueNumDigits: "1"
|
||||
|
@ -132,7 +128,6 @@ Item {
|
|||
title: "Triangles"
|
||||
height: parent.evalEvenHeight()
|
||||
object: stats.config
|
||||
trigger: stats.config["frameTriangleCount"]
|
||||
valueScale: 1000
|
||||
valueUnit: "K"
|
||||
plots: [
|
||||
|
@ -154,7 +149,6 @@ Item {
|
|||
title: "Drawcalls"
|
||||
height: parent.evalEvenHeight()
|
||||
object: stats.config
|
||||
trigger: stats.config["frameDrawcallCount"]
|
||||
plots: [
|
||||
{
|
||||
prop: "frameAPIDrawcallCount",
|
||||
|
@ -184,7 +178,6 @@ Item {
|
|||
title: "Items"
|
||||
height: parent.evalEvenHeight()
|
||||
object: parent.drawOpaqueConfig
|
||||
trigger: Render.getConfig("DrawOpaqueDeferred")["numDrawn"]
|
||||
plots: [
|
||||
{
|
||||
object: Render.getConfig("DrawOpaqueDeferred"),
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
|
||||
#include <QtMultimedia/QMediaPlayer>
|
||||
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
|
||||
#include <ResourceScriptingInterface.h>
|
||||
|
@ -561,9 +563,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
// Model background downloads need to happen on the Datagram Processor Thread. The idle loop will
|
||||
// emit checkBackgroundDownloads to cause the ModelCache to check it's queue for requested background
|
||||
// downloads.
|
||||
QSharedPointer<ModelCache> modelCacheP = DependencyManager::get<ModelCache>();
|
||||
ResourceCache* modelCache = modelCacheP.data();
|
||||
connect(this, &Application::checkBackgroundDownloads, modelCache, &ResourceCache::checkAsynchronousGets);
|
||||
auto modelCache = DependencyManager::get<ModelCache>();
|
||||
connect(this, &Application::checkBackgroundDownloads, modelCache.data(), &ModelCache::checkAsynchronousGets);
|
||||
|
||||
// put the audio processing on a separate thread
|
||||
QThread* audioThread = new QThread();
|
||||
|
@ -1008,6 +1009,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
RenderableWebEntityItem* webEntity = dynamic_cast<RenderableWebEntityItem*>(entity.get());
|
||||
if (webEntity) {
|
||||
webEntity->setProxyWindow(_window->windowHandle());
|
||||
if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) {
|
||||
_keyboardMouseDevice->pluginFocusOutEvent();
|
||||
}
|
||||
_keyboardFocusedItem = entityItemID;
|
||||
_lastAcceptedKeyPress = usecTimestampNow();
|
||||
if (_keyboardFocusHighlightID < 0 || !getOverlays().isAddedOverlay(_keyboardFocusHighlightID)) {
|
||||
|
@ -1120,6 +1124,10 @@ void Application::aboutToQuit() {
|
|||
}
|
||||
|
||||
void Application::cleanupBeforeQuit() {
|
||||
// add a logline indicating if QTWEBENGINE_REMOTE_DEBUGGING is set or not
|
||||
QString webengineRemoteDebugging = QProcessEnvironment::systemEnvironment().value("QTWEBENGINE_REMOTE_DEBUGGING", "false");
|
||||
qCDebug(interfaceapp) << "QTWEBENGINE_REMOTE_DEBUGGING =" << webengineRemoteDebugging;
|
||||
|
||||
// Stop third party processes so that they're not left running in the event of a subsequent shutdown crash.
|
||||
#ifdef HAVE_DDE
|
||||
DependencyManager::get<DdeFaceTracker>()->setEnabled(false);
|
||||
|
@ -1329,7 +1337,6 @@ void Application::initializeUi() {
|
|||
// though I can't find it. Hence, "ApplicationInterface"
|
||||
rootContext->setContextProperty("SnapshotUploader", new SnapshotUploader());
|
||||
rootContext->setContextProperty("ApplicationInterface", this);
|
||||
rootContext->setContextProperty("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
||||
rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance());
|
||||
rootContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
|
||||
rootContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
|
||||
|
@ -1359,8 +1366,13 @@ void Application::initializeUi() {
|
|||
rootContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
|
||||
rootContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
|
||||
rootContext->setContextProperty("AudioDevice", AudioDeviceScriptingInterface::getInstance());
|
||||
|
||||
// Caches
|
||||
rootContext->setContextProperty("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
||||
rootContext->setContextProperty("TextureCache", DependencyManager::get<TextureCache>().data());
|
||||
rootContext->setContextProperty("ModelCache", DependencyManager::get<ModelCache>().data());
|
||||
rootContext->setContextProperty("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||
|
||||
rootContext->setContextProperty("Account", AccountScriptingInterface::getInstance());
|
||||
rootContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface);
|
||||
rootContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
|
||||
|
@ -2564,6 +2576,15 @@ void Application::idle(uint64_t now) {
|
|||
_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();
|
||||
// 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
|
||||
|
@ -4353,8 +4374,13 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
scriptEngine->registerGlobalObject("Stats", Stats::getInstance());
|
||||
scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance());
|
||||
scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance());
|
||||
|
||||
// Caches
|
||||
scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
||||
scriptEngine->registerGlobalObject("TextureCache", DependencyManager::get<TextureCache>().data());
|
||||
scriptEngine->registerGlobalObject("ModelCache", DependencyManager::get<ModelCache>().data());
|
||||
scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||
|
||||
scriptEngine->registerGlobalObject("Account", AccountScriptingInterface::getInstance());
|
||||
scriptEngine->registerGlobalObject("DialogsManager", _dialogsManagerScriptingInterface);
|
||||
|
||||
|
|
|
@ -518,6 +518,8 @@ private:
|
|||
std::mutex _preRenderLambdasLock;
|
||||
|
||||
std::atomic<uint32_t> _processOctreeStatsCounter { 0 };
|
||||
|
||||
bool _keyboardDeviceHasFocus { true };
|
||||
};
|
||||
|
||||
#endif // hifi_Application_h
|
||||
|
|
|
@ -434,6 +434,8 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
_showCollisionHull = shouldShowCollisionHull;
|
||||
render::PendingChanges pendingChanges;
|
||||
|
||||
_model->removeFromScene(scene, pendingChanges);
|
||||
|
||||
render::Item::Status::Getters statusGetters;
|
||||
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
|
||||
_model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull);
|
||||
|
|
|
@ -371,7 +371,7 @@ void NetworkTexture::setImage(void* voidTexture, int originalWidth,
|
|||
if (gpuTexture) {
|
||||
_width = gpuTexture->getWidth();
|
||||
_height = gpuTexture->getHeight();
|
||||
setBytes(gpuTexture->getStoredSize());
|
||||
setSize(gpuTexture->getStoredSize());
|
||||
} else {
|
||||
// FIXME: If !gpuTexture, we failed to load!
|
||||
_width = _height = 0;
|
||||
|
|
|
@ -38,6 +38,7 @@ ResourceCache::~ResourceCache() {
|
|||
void ResourceCache::refreshAll() {
|
||||
// Clear all unused resources so we don't have to reload them
|
||||
clearUnusedResource();
|
||||
resetResourceCounters();
|
||||
|
||||
// Refresh all remaining resources in use
|
||||
foreach (auto resource, _resources) {
|
||||
|
@ -53,9 +54,27 @@ void ResourceCache::refresh(const QUrl& url) {
|
|||
resource->refresh();
|
||||
} else {
|
||||
_resources.remove(url);
|
||||
resetResourceCounters();
|
||||
}
|
||||
}
|
||||
|
||||
QVariantList ResourceCache::getResourceList() {
|
||||
QVariantList list;
|
||||
if (QThread::currentThread() != thread()) {
|
||||
// NOTE: invokeMethod does not allow a const QObject*
|
||||
QMetaObject::invokeMethod(this, "getResourceList", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QVariantList, list));
|
||||
} else {
|
||||
auto resources = _resources.uniqueKeys();
|
||||
list.reserve(resources.size());
|
||||
for (auto& resource : resources) {
|
||||
list << resource;
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void ResourceCache::setRequestLimit(int limit) {
|
||||
_requestLimit = limit;
|
||||
|
||||
|
@ -114,6 +133,7 @@ QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl&
|
|||
void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) {
|
||||
_unusedResourcesMaxSize = clamp(unusedResourcesMaxSize, MIN_UNUSED_MAX_SIZE, MAX_UNUSED_MAX_SIZE);
|
||||
reserveUnusedResource(0);
|
||||
resetResourceCounters();
|
||||
}
|
||||
|
||||
void ResourceCache::addUnusedResource(const QSharedPointer<Resource>& resource) {
|
||||
|
@ -127,6 +147,8 @@ void ResourceCache::addUnusedResource(const QSharedPointer<Resource>& resource)
|
|||
resource->setLRUKey(++_lastLRUKey);
|
||||
_unusedResources.insert(resource->getLRUKey(), resource);
|
||||
_unusedResourcesSize += resource->getBytes();
|
||||
|
||||
resetResourceCounters();
|
||||
}
|
||||
|
||||
void ResourceCache::removeUnusedResource(const QSharedPointer<Resource>& resource) {
|
||||
|
@ -134,6 +156,7 @@ void ResourceCache::removeUnusedResource(const QSharedPointer<Resource>& resourc
|
|||
_unusedResources.remove(resource->getLRUKey());
|
||||
_unusedResourcesSize -= resource->getBytes();
|
||||
}
|
||||
resetResourceCounters();
|
||||
}
|
||||
|
||||
void ResourceCache::reserveUnusedResource(qint64 resourceSize) {
|
||||
|
@ -142,8 +165,13 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) {
|
|||
// unload the oldest resource
|
||||
QMap<int, QSharedPointer<Resource> >::iterator it = _unusedResources.begin();
|
||||
|
||||
_unusedResourcesSize -= it.value()->getBytes();
|
||||
it.value()->setCache(nullptr);
|
||||
auto size = it.value()->getBytes();
|
||||
|
||||
_totalResourcesSize -= size;
|
||||
_resources.remove(it.value()->getURL());
|
||||
|
||||
_unusedResourcesSize -= size;
|
||||
_unusedResources.erase(it);
|
||||
}
|
||||
}
|
||||
|
@ -159,6 +187,17 @@ void ResourceCache::clearUnusedResource() {
|
|||
}
|
||||
}
|
||||
|
||||
void ResourceCache::resetResourceCounters() {
|
||||
_numTotalResources = _resources.size();
|
||||
_numUnusedResources = _unusedResources.size();
|
||||
emit dirty();
|
||||
}
|
||||
|
||||
void ResourceCache::updateTotalSize(const qint64& oldSize, const qint64& newSize) {
|
||||
_totalResourcesSize += (newSize - oldSize);
|
||||
emit dirty();
|
||||
}
|
||||
|
||||
void ResourceCacheSharedItems::appendActiveRequest(Resource* resource) {
|
||||
Lock lock(_mutex);
|
||||
_loadingRequests.append(resource);
|
||||
|
@ -377,6 +416,11 @@ void Resource::finishedLoading(bool success) {
|
|||
emit finished(success);
|
||||
}
|
||||
|
||||
void Resource::setSize(const qint64& bytes) {
|
||||
QMetaObject::invokeMethod(_cache.data(), "updateTotalSize", Q_ARG(qint64, _bytes), Q_ARG(qint64, bytes));
|
||||
_bytes = bytes;
|
||||
}
|
||||
|
||||
void Resource::reinsert() {
|
||||
_cache->_resources.insert(_url, _self);
|
||||
}
|
||||
|
@ -412,7 +456,7 @@ void Resource::handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTota
|
|||
void Resource::handleReplyFinished() {
|
||||
Q_ASSERT_X(_request, "Resource::handleReplyFinished", "Request should not be null while in handleReplyFinished");
|
||||
|
||||
_bytes = _bytesTotal;
|
||||
setSize(_bytesTotal);
|
||||
|
||||
if (!_request || _request != sender()) {
|
||||
// This can happen in the edge case that a request is timed out, but a `finished` signal is emitted before it is deleted.
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
#ifndef hifi_ResourceCache_h
|
||||
#define hifi_ResourceCache_h
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QObject>
|
||||
|
@ -29,6 +31,8 @@
|
|||
|
||||
#include "ResourceManager.h"
|
||||
|
||||
Q_DECLARE_METATYPE(size_t)
|
||||
|
||||
class QNetworkReply;
|
||||
class QTimer;
|
||||
|
||||
|
@ -79,8 +83,20 @@ private:
|
|||
/// Base class for resource caches.
|
||||
class ResourceCache : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(size_t numTotal READ getNumTotalResources NOTIFY dirty)
|
||||
Q_PROPERTY(size_t numCached READ getNumCachedResources NOTIFY dirty)
|
||||
Q_PROPERTY(size_t sizeTotal READ getSizeTotalResources NOTIFY dirty)
|
||||
Q_PROPERTY(size_t sizeCached READ getSizeCachedResources NOTIFY dirty)
|
||||
|
||||
public:
|
||||
size_t getNumTotalResources() const { return _numTotalResources; }
|
||||
size_t getSizeTotalResources() const { return _totalResourcesSize; }
|
||||
|
||||
size_t getNumCachedResources() const { return _numUnusedResources; }
|
||||
size_t getSizeCachedResources() const { return _unusedResourcesSize; }
|
||||
|
||||
Q_INVOKABLE QVariantList getResourceList();
|
||||
|
||||
static void setRequestLimit(int limit);
|
||||
static int getRequestLimit() { return _requestLimit; }
|
||||
|
||||
|
@ -101,15 +117,21 @@ public:
|
|||
void refreshAll();
|
||||
void refresh(const QUrl& url);
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
|
||||
public slots:
|
||||
void checkAsynchronousGets();
|
||||
|
||||
protected slots:
|
||||
void updateTotalSize(const qint64& oldSize, const qint64& newSize);
|
||||
|
||||
protected:
|
||||
/// Loads a resource from the specified URL.
|
||||
/// \param fallback a fallback URL to load if the desired one is unavailable
|
||||
/// \param delayLoad if true, don't load the resource immediately; wait until load is first requested
|
||||
/// \param extra extra data to pass to the creator, if appropriate
|
||||
Q_INVOKABLE QSharedPointer<Resource> getResource(const QUrl& url, const QUrl& fallback = QUrl(),
|
||||
QSharedPointer<Resource> getResource(const QUrl& url, const QUrl& fallback = QUrl(),
|
||||
bool delayLoad = false, void* extra = NULL);
|
||||
|
||||
/// Creates a new resource.
|
||||
|
@ -118,18 +140,20 @@ protected:
|
|||
|
||||
void addUnusedResource(const QSharedPointer<Resource>& resource);
|
||||
void removeUnusedResource(const QSharedPointer<Resource>& resource);
|
||||
void reserveUnusedResource(qint64 resourceSize);
|
||||
void clearUnusedResource();
|
||||
|
||||
/// Attempt to load a resource if requests are below the limit, otherwise queue the resource for loading
|
||||
/// \return true if the resource began loading, otherwise false if the resource is in the pending queue
|
||||
Q_INVOKABLE static bool attemptRequest(Resource* resource);
|
||||
static bool attemptRequest(Resource* resource);
|
||||
static void requestCompleted(Resource* resource);
|
||||
static bool attemptHighestPriorityRequest();
|
||||
|
||||
private:
|
||||
friend class Resource;
|
||||
|
||||
void reserveUnusedResource(qint64 resourceSize);
|
||||
void clearUnusedResource();
|
||||
void resetResourceCounters();
|
||||
|
||||
QHash<QUrl, QWeakPointer<Resource>> _resources;
|
||||
int _lastLRUKey = 0;
|
||||
|
||||
|
@ -140,8 +164,13 @@ private:
|
|||
QReadWriteLock _resourcesToBeGottenLock;
|
||||
QQueue<QUrl> _resourcesToBeGotten;
|
||||
|
||||
std::atomic<size_t> _numTotalResources { 0 };
|
||||
std::atomic<size_t> _numUnusedResources { 0 };
|
||||
|
||||
std::atomic<qint64> _totalResourcesSize { 0 };
|
||||
std::atomic<qint64> _unusedResourcesSize { 0 };
|
||||
|
||||
qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE;
|
||||
qint64 _unusedResourcesSize = 0;
|
||||
QMap<int, QSharedPointer<Resource>> _unusedResources;
|
||||
};
|
||||
|
||||
|
@ -226,7 +255,7 @@ protected:
|
|||
virtual void downloadFinished(const QByteArray& data) { finishedLoading(true); }
|
||||
|
||||
/// Called when the download is finished and processed, sets the number of actual bytes.
|
||||
void setBytes(qint64 bytes) { _bytes = bytes; }
|
||||
void setSize(const qint64& bytes);
|
||||
|
||||
/// Called when the download is finished and processed.
|
||||
/// This should be called by subclasses that override downloadFinished to mark the end of processing.
|
||||
|
|
|
@ -447,7 +447,7 @@ void OffscreenUi::createDesktop(const QUrl& url) {
|
|||
|
||||
new KeyboardFocusHack();
|
||||
|
||||
connect(_desktop, SIGNAL(showDesktop()), this, SLOT(showDesktop()));
|
||||
connect(_desktop, SIGNAL(showDesktop()), this, SIGNAL(showDesktop()));
|
||||
}
|
||||
|
||||
QQuickItem* OffscreenUi::getDesktop() {
|
||||
|
|
|
@ -52,6 +52,16 @@ void OculusDisplayPlugin::customizeContext() {
|
|||
}
|
||||
|
||||
void OculusDisplayPlugin::uncustomizeContext() {
|
||||
using namespace oglplus;
|
||||
|
||||
// Present a final black frame to the HMD
|
||||
_compositeFramebuffer->Bound(FramebufferTarget::Draw, [] {
|
||||
Context::ClearColor(0, 0, 0, 1);
|
||||
Context::Clear().ColorBuffer();
|
||||
});
|
||||
|
||||
hmdPresent();
|
||||
|
||||
#if (OVR_MAJOR_VERSION >= 6)
|
||||
_sceneFbo.reset();
|
||||
#endif
|
||||
|
|
|
@ -90,12 +90,16 @@ ovrSession acquireOculusSession() {
|
|||
|
||||
void releaseOculusSession() {
|
||||
Q_ASSERT(refCount > 0 && session);
|
||||
// HACK the Oculus runtime doesn't seem to play well with repeated shutdown / restart.
|
||||
// So for now we'll just hold on to the session
|
||||
#if 0
|
||||
if (!--refCount) {
|
||||
qCDebug(oculus) << "oculus: zero refcount, shutdown SDK and session";
|
||||
ovr_Destroy(session);
|
||||
ovr_Shutdown();
|
||||
session = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue