Merge branch 'master' of https://github.com/highfidelity/hifi into orange

This commit is contained in:
samcake 2016-04-06 09:30:53 -07:00
commit e28e85a29c
16 changed files with 262 additions and 125 deletions

View file

@ -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);

View file

@ -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
View 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
View 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"
}
]
}
}
}
}
}

View file

@ -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) {

View file

@ -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"),

View file

@ -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);

View file

@ -518,6 +518,8 @@ private:
std::mutex _preRenderLambdasLock;
std::atomic<uint32_t> _processOctreeStatsCounter { 0 };
bool _keyboardDeviceHasFocus { true };
};
#endif // hifi_Application_h

View file

@ -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);

View file

@ -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;

View file

@ -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.

View file

@ -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.

View file

@ -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() {

View file

@ -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

View file

@ -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
}